diff --git a/src/i18n/de/translation.json b/src/i18n/de/translation.json
index 071444e6d7beb1ab8f6df1a47a359e36e2882881..eca9504d819a41a522eae7cb4d2cec3462c77ec8 100644
--- a/src/i18n/de/translation.json
+++ b/src/i18n/de/translation.json
@@ -5,9 +5,12 @@
     "word3": "Leidenschaft"
   },
   "pdf-upload": {
-    "field-label": "PDF Dateien zum Signieren hochladen",
+    "upload-field-label": "PDF Dateien zum Signieren hochladen",
     "upload-area-text": "Sie können in diesem Bereich PDF Dateien per Drag & Drop oder per Direktauswahl hochladen",
-    "upload-button-label": "PDF Dateien auswählen"
+    "signed-files-label": "Signierte Dateien",
+    "download-zip-button": "Als ZIP Datei herunterladen",
+    "upload-button-label": "PDF Dateien auswählen",
+    "download-file-button-title": "Signiertes PDF herunterladen"
   },
   "welcome": {
     "headline": "Willkommen beim Amtssignaturservice der TU Graz",
diff --git a/src/i18n/en/translation.json b/src/i18n/en/translation.json
index c5c1957441b8dbe109bcaafbf5b3286de3805bb9..0d4378a0de535d14ca4e22adf0f840d06c21fc72 100644
--- a/src/i18n/en/translation.json
+++ b/src/i18n/en/translation.json
@@ -5,9 +5,12 @@
     "word3": "Technology"
   },
   "pdf-upload": {
-    "field-label": "Upload PDF files to sign",
+    "upload-field-label": "Upload PDF files to sign",
     "upload-area-text": "In this area you can upload PDF files via Drag & Drop or by selecting them directly",
-    "upload-button-label": "Select PDF files"
+    "signed-files-label": "Signed files",
+    "download-zip-button": "Download ZIP",
+    "upload-button-label": "Select PDF files",
+    "download-file-button-title": "Download signed PDF"
   },
   "welcome": {
     "headline": "Welcome to the official signature service of the TU Graz",
diff --git a/src/utils.js b/src/utils.js
index 979060c887dfeb331b41099a9e108902b1794185..f6ecedb659cc50a622200e64bd69f5ae217e59dc 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -18,3 +18,29 @@ export const findObjectInApiResults = (identifier, results, identifierAttribute
         }
     }
 };
+
+export const getPDFFileBase64Content = (file) => {
+    return file.file.replace("data:application/pdf;base64,", "");
+};
+
+export const convertDataURIToBinary = (dataURI) => {
+    const BASE64_MARKER = ';base64,';
+    const base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
+    const base64 = dataURI.substring(base64Index);
+    const raw = window.atob(base64);
+    const rawLength = raw.length;
+    let array = new Uint8Array(rawLength);
+
+    for(let i = 0; i < rawLength; i++) {
+        array[i] = raw.charCodeAt(i);
+    }
+
+    return array;
+};
+
+export const getDataURIContentType = (dataURI) => {
+    const BASE64_MARKER = ';base64,';
+    const base64Index = dataURI.indexOf(BASE64_MARKER);
+
+    return dataURI.substring(5, base64Index);
+};
diff --git a/src/vpu-signature-lit-element.js b/src/vpu-signature-lit-element.js
index b254e8d792ab64f019095d80817a0f72512a5a9d..bbff7c1b39b32ef9a3d3afaf3d0df6f8c6400dde 100644
--- a/src/vpu-signature-lit-element.js
+++ b/src/vpu-signature-lit-element.js
@@ -8,7 +8,7 @@ export default class VPUSignatureLitElement extends LitElement {
     }
 
     hasSignaturePermissions() {
-        // TODO: Roles need to be discussed
+        // TODO: Roles need to be discussed, e.g. implement role scopes
         // return (window.VPUPerson && Array.isArray(window.VPUPerson.roles) && window.VPUPerson.roles.indexOf('ROLE_F_BIB_F') !== -1);
         return window.VPUPerson && Array.isArray(window.VPUPerson.roles);
     }
diff --git a/src/vpu-signature-pdf-upload.js b/src/vpu-signature-pdf-upload.js
index 5755df05b60c74b3e97f13da552dd0f84072209f..14da48e0b2c8d9ba4e422193d2304a7c4d58fc34 100644
--- a/src/vpu-signature-pdf-upload.js
+++ b/src/vpu-signature-pdf-upload.js
@@ -1,7 +1,9 @@
 import {createI18nInstance} from './i18n.js';
+import {humanFileSize} from 'vpu-common/i18next.js';
 import {css, html} from 'lit-element';
 import VPUSignatureLitElement from "./vpu-signature-lit-element";
 import * as commonUtils from 'vpu-common/utils';
+import * as utils from './utils';
 import JSZip from 'jszip/dist/jszip.js';
 import 'file-saver';
 import * as commonStyles from 'vpu-common/styles';
@@ -17,12 +19,15 @@ class SignaturePdfUpload extends VPUSignatureLitElement {
         this.lang = i18n.language;
         this.entryPointUrl = commonUtils.getAPiUrl();
         this.files = [];
+        this.filesCount = 0;
     }
 
     static get properties() {
         return {
             lang: { type: String },
             entryPointUrl: { type: String, attribute: 'entry-point-url' },
+            files: { type: Array, attribute: false },
+            filesCount: { type: Number, attribute: false },
         };
     }
 
@@ -32,27 +37,24 @@ class SignaturePdfUpload extends VPUSignatureLitElement {
         this.updateComplete.then(()=>{
             this.shadowRoot.querySelectorAll('vpu-fileupload')
                 .forEach(element => {
-                    element.addEventListener('vpu-fileupload-finished', this.addLogEntry.bind(this));
+                    element.addEventListener('vpu-fileupload-finished', this.onUploadFinished.bind(this));
                 });
         });
     }
 
     /**
-     * TODO: Implement real box
-     *
      * @param ev
      */
-    addLogEntry(ev) {
-        const ul = this.shadowRoot.querySelector('#log');
-        const li = document.createElement('li');
-        li.innerHTML = `<b>${ev.detail.status}</b> <tt>${ev.detail.filename}</tt>`;
-        console.log(ev.detail);
+    onUploadFinished(ev) {
+        // TODO: check ev.detail.status to show if an error occurred
+        // TODO: on ev.detail.status == 503 we need to upload the file again
 
         if (ev.detail.json) {
+            // this doesn't seem to cause an update() execution
             this.files.push(ev.detail.json);
+            // this causes the correct update() execution
+            this.filesCount++;
         }
-
-        ul.appendChild(li);
     }
 
     update(changedProperties) {
@@ -60,6 +62,8 @@ class SignaturePdfUpload extends VPUSignatureLitElement {
             if (propName === "lang") {
                 i18n.changeLanguage(this.lang);
             }
+
+            console.log(propName, oldValue);
         });
 
         super.update(changedProperties);
@@ -74,64 +78,98 @@ class SignaturePdfUpload extends VPUSignatureLitElement {
         return css`
             ${commonStyles.getThemeCSS()}
             ${commonStyles.getGeneralCSS()}
+            ${commonStyles.getButtonCSS()}
             ${commonStyles.getNotificationCSS()}
 
             .hidden {
                 display: none;
             }
 
-            #location-identifier-block { display: none; }
+            #files-download .file {
+                margin: 10px;
+            }
 
-            #location-identifier-block input {
-                width: 100%;
-                border-radius: var(--vpu-border-radius);
+            #files-download .file button {
+                margin-right: 5px;
             }
         `;
     }
 
     /**
-     * Download signed pdf files
+     * Download signed pdf files as zip
      */
     zipDownloadClickHandler() {
+        // see: https://stuk.github.io/jszip/
         let zip = new JSZip();
         const that = this;
 
         // add all signed pdf files
         this.files.forEach((file) => {
             console.log(file);
-            zip.file(file.fileName, file.file.replace("data:application/pdf;base64,", ""), {base64: true});
+            // TODO: check for duplicate file names
+            zip.file(file.fileName, utils.getPDFFileBase64Content(file), {base64: true});
         });
 
         zip.generateAsync({type:"blob"})
             .then(function(content) {
-                console.log(zip);
-
                 // save with FileSaver.js
+                // see: https://github.com/eligrey/FileSaver.js
                 saveAs(content, "signed-documents.zip");
 
                 that._("#zip-download-button").stop();
+                that.files = [];
+                that.filesCount = 0;
             });
     }
 
+    /**
+     * Download one signed pdf file
+     *
+     * @param file
+     */
+    fileDownloadClickHandler(file) {
+        const arr = utils.convertDataURIToBinary(file.file);
+        const blob = new Blob([arr], { type: utils.getDataURIContentType(file.file) });
+
+        // see: https://github.com/eligrey/FileSaver.js
+        saveAs(blob, file.fileName);
+    }
+
+    getSignedFilesHtml() {
+        return this.files.map(file => html`
+            <div class="file">
+                <button class="button is-small"
+                        title="${i18n.t('pdf-upload.download-file-button-title')}"
+                        @click="${() => {this.fileDownloadClickHandler(file);}}"><vpu-icon name="download"></vpu-icon></button>
+                <strong>${file.fileName}</strong> (${humanFileSize(file.fileSize)})
+            </div>
+        `);
+    }
+
     render() {
         const suggestionsCSS = commonUtils.getAssetURL(suggestionsCSSPath);
 
         return html`
             <link rel="stylesheet" href="${suggestionsCSS}">
 
-            <form class="${classMap({hidden: !this.isLoggedIn() || !this.hasSignaturePermissions()})}">
+            <div class="${classMap({hidden: !this.isLoggedIn() || !this.hasSignaturePermissions()})}">
                 <div class="field">
-                    <label class="label">${i18n.t('pdf-upload.field-label')}</label>
+                    <label class="label">${i18n.t('pdf-upload.upload-field-label')}</label>
                     <div class="control">
                         <vpu-fileupload lang="${this.lang}" url="${this.entryPointUrl}/pdf_official_signing_actions" accept="application/pdf"
                             text="${i18n.t('pdf-upload.upload-area-text')}" button-label="${i18n.t('pdf-upload.upload-button-label')}"></vpu-fileupload>
                     </div>
                 </div>
-            </form>
-            <div id="log"></div>
-            <div class="field">
-                <div class="control">
-                    <vpu-button id="zip-download-button" value="Download ZIP" @click="${this.zipDownloadClickHandler}" type="is-primary"></vpu-button>
+                <div id="files-download" class="field ${classMap({hidden: this.filesCount === 0})}">
+                    <label class="label">${i18n.t('pdf-upload.signed-files-label')}</label>
+                    <div class="control">
+                        ${this.getSignedFilesHtml()}
+                    </div>
+                </div>
+                <div class="field ${classMap({hidden: this.filesCount === 0})}">
+                    <div class="control">
+                        <vpu-button id="zip-download-button" value="${i18n.t('pdf-upload.download-zip-button')}" @click="${this.zipDownloadClickHandler}" type="is-primary"></vpu-button>
+                    </div>
                 </div>
             </div>
             <div class="notification is-warning ${classMap({hidden: this.isLoggedIn()})}">
diff --git a/vendor/common b/vendor/common
index 2c74b7aabd5c51b650004f0ba874809709faa8fe..564b17bf0b128d1ba7b4bbddf9b3c1123a2450c9 160000
--- a/vendor/common
+++ b/vendor/common
@@ -1 +1 @@
-Subproject commit 2c74b7aabd5c51b650004f0ba874809709faa8fe
+Subproject commit 564b17bf0b128d1ba7b4bbddf9b3c1123a2450c9
diff --git a/vendor/file-upload b/vendor/file-upload
index ca511205f4ba5f399a3fcf9401a7b3749b8f72cd..b02716f49afd999a90c9d194d706a04fab861cc1 160000
--- a/vendor/file-upload
+++ b/vendor/file-upload
@@ -1 +1 @@
-Subproject commit ca511205f4ba5f399a3fcf9401a7b3749b8f72cd
+Subproject commit b02716f49afd999a90c9d194d706a04fab861cc1