Skip to content

Commit

Permalink
Use x-sd-export mimetype and full disk encryption for export
Browse files Browse the repository at this point in the history
This is based off of early decryption flow introduced in 9b4c37e
  • Loading branch information
emkll committed May 28, 2019
1 parent 7765ce2 commit 440920b
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 35 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ remove-sd-gpg: assert-dom0 ## Destroys SD GPG keystore VM
@./scripts/destroy-vm sd-gpg

remove-sd-export: assert-dom0 ## Destroys SD EXPORT VMs
@qvm-kill sd-export-usb
@qvm-kill sd-export-usb || true
@qvm-usb detach sd-export-usb || true
@./scripts/destroy-vm sd-export-usb
@./scripts/destroy-vm sd-export-dvm
Expand Down Expand Up @@ -143,7 +143,7 @@ prep-dom0: prep-salt # Copies dom0 config files for VM updates
list-vms: ## Prints all Qubes VMs managed by Workstation salt config
@./scripts/list-vms

destroy-all: remove-sd-export ## Destroys all VMs managed by Workstation salt config
destroy-all: ## Destroys all VMs managed by Workstation salt config
@./scripts/list-vms | xargs ./scripts/destroy-vm

# Explanation of the below shell command should it ever break.
Expand Down
34 changes: 25 additions & 9 deletions dom0/sd-export-files.sls
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,29 @@ sd-export-send-to-usb-script:
- mode: 755
- makedirs: True

sd-export-template-mimetype:
file.blockreplace:
- name: /etc/mailcap
- prepend_if_not_found: False
- marker_start: "# ----- User Section Begins ----- #"
- marker_end: "# ----- User Section Ends ----- #"
- content: |
application/octet-stream; /usr/bin/send-to-usb '%s';
sd-export-desktop-file:
file.managed:
- name: /usr/share/applications/send-to-usb.desktop
- source: salt://sd/sd-export/send-to-usb.desktop
- user: root
- group: root
- mode: 755
- makedirs: True
cmd.run:
- name: sudo update-desktop-database /usr/share/applications
- require:
- file: sd-export-desktop-file

sd-export-file-format:
file.managed:
- name: /usr/share/mime/packages/application-x-sd-export.xml
- source: salt://sd/sd-export/application-x-sd-export.xml
- user: root
- group: root
- mode: 755
- makedirs: True
cmd.run:
- name: sudo update-mime
- name: sudo update-mime-database /usr/share/mime
- require:
- file: sd-export-file-format
- file: sd-export-desktop-file
2 changes: 1 addition & 1 deletion scripts/list-vms
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ declare -a sd_workstation_vm_names=(
sd-svs-disp-template
sd-export-template
sd-export-dvm
sd-export
sd-export-usb
)

for vm in "${sd_workstation_vm_names[@]}" ; do
Expand Down
7 changes: 7 additions & 0 deletions sd-export/application-x-sd-export.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/x-sd-export">
<comment>Archive for transfering files from the SecureDrop workstation to an external USB device.</comment>
<glob pattern="*.sd-export"/>
</mime-type>
</mime-info>
92 changes: 69 additions & 23 deletions sd-export/send-to-usb
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,38 +1,84 @@
#! /usr/bin/python3

import datetime
import json
import os
import shutil
import subprocess
import sys
import tarfile
import tempfile

DEVICE = "/dev/sda1"
MOUNTPOINT = "/tmp/usb"
MOUNTPOINT = "/media/usb"
ENCRYPTED_DEVICE = "encrypted_volume"
FILE = sys.argv[1]
folder_name = ""
encryption_method = ""
encryption_key = ""
target_folder = "sd-export-{}".format(datetime.datetime.now().isoformat())

tmpdir = tempfile.mkdtemp()

if os.path.exists(FILE):
# mount target not created
if not os.path.exists(MOUNTPOINT):
os.makedirs(MOUNTPOINT)

# check if drive already mounted
rc = subprocess.call(
["mountpoint", MOUNTPOINT], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
if rc:
# drive is not already mounted, so...
out = subprocess.run(["sudo", "mount", "-o", "uid=1000,gid=1000", DEVICE, MOUNTPOINT])
try:
with tarfile.open(FILE) as tar:
tar.extractall(tmpdir)
except Exception as e:
# exit with 0 return code otherwise the os will attempt to open
# the file with another application
print("Error opening export bundle")
sys.exit(0)

rc = subprocess.call(
["mountpoint", MOUNTPOINT], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL
)
if rc:
# drive still not mounted
sys.exit(1)
try:
folder_name = os.path.basename(FILE).split(".")[0]
with open(os.path.join(tmpdir, folder_name, "metadata.json")) as json_data:
data = json.load(json_data)
encryption_method = data["encryption-method"]
encryption_key = data["encryption-key"]
except Exception as e:
print("Error parsing metadata")
sys.exit(0)

# copy files to drive (overwrites existing files) and unmount drive
shutil.copy(FILE, os.path.join(MOUNTPOINT, os.path.basename(FILE)))
# we only support luks for now
if encryption_method != "luks":
print("Unsupported export encryption")
sys.exit(0)

# the luks device is not already unlocked

if not os.path.exists(os.path.join("/dev/mapper/", ENCRYPTED_DEVICE)):
p = subprocess.Popen(
["sudo", "cryptsetup", "luksOpen", DEVICE, ENCRYPTED_DEVICE],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
stdout_data = p.communicate(input=str.encode(encryption_key, "utf-8"))[0]
rc = p.returncode
if rc != 0:
print("Bad passphrase or luks error")
sys.exit(0)

# mount target not created
if not os.path.exists(MOUNTPOINT):
out = subprocess.call(["sudo", "mkdir", MOUNTPOINT])
out = subprocess.call(["sudo", "chown", "-R", "user:user", MOUNTPOINT])
out = subprocess.call(
["sudo", "mount", os.path.join("/dev/mapper/", ENCRYPTED_DEVICE), MOUNTPOINT]
)

# sync to ensure the files are fully written before unmounting
subprocess.run(["sync"])
# move files to drive (overrites files with same filename) and unmount drive
target_folder_path = os.path.join(MOUNTPOINT, target_folder)
subprocess.call(["mkdir", target_folder_path])
export_data = os.path.join(tmpdir, folder_name, "export_data/")
shutil.move(export_data, target_folder_path)

# finally, unmount the USB device
subprocess.run(["sudo", "umount", MOUNTPOINT])
# sync the filesystem, unmount drive and lock the luks volume
# we use call here to ensure they are blocking and avoid races
subprocess.call(["sync"])
subprocess.call(["sudo", "umount", MOUNTPOINT])
subprocess.call(["sudo", "cryptsetup", "luksClose", ENCRYPTED_DEVICE])
# race condition when using shutils
subprocess.call(["rm", "-rf", tmpdir])
5 changes: 5 additions & 0 deletions sd-export/send-to-usb.desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[Desktop Entry]
Type=Application
MimeType=application/x-sd-export
Name="Export SD submission to USB"
Exec=/usr/bin/send-to-usb

0 comments on commit 440920b

Please sign in to comment.