1#!/bin/ksh -p 2# 3# CDDL HEADER START 4# 5# This file and its contents are supplied under the terms of the 6# Common Development and Distribution License ("CDDL"), version 1.0. 7# You may only use this file in accordance with the terms of version 8# 1.0 of the CDDL. 9# 10# A full copy of the text of the CDDL should have accompanied this 11# source. A copy of the CDDL is also available via the Internet at 12# http://www.illumos.org/license/CDDL. 13# 14# CDDL HEADER END 15# 16 17# 18# Copyright (c) 2018 by Datto Inc. All rights reserved. 19# 20 21. $STF_SUITE/tests/functional/rsend/rsend.kshlib 22 23# 24# DESCRIPTION: 25# Verify that zfs properly handles encryption properties when receiving 26# send streams. 27# 28# STRATEGY: 29# 1. Create a few unencrypted and encrypted test datasets with some data 30# 2. Take snapshots of these datasets in preparation for sending 31# 3. Verify that 'zfs recv -o keylocation=prompt' fails 32# 4. Verify that 'zfs recv -x <encryption prop>' fails on a raw send stream 33# 5. Verify that encryption properties cannot be changed on incrementals 34# 6. Verify that a simple send can be received as an encryption root 35# 7. Verify that an unencrypted props send can be received as an 36# encryption root 37# 8. Verify that an unencrypted recursive send can be received as an 38# encryption root 39# 9. Verify that an unencrypted props send can be received as an 40# encryption child 41# 10. Verify that an unencrypted recursive send can be received as an 42# encryption child 43# 44 45verify_runnable "both" 46 47function cleanup 48{ 49 destroy_dataset $TESTPOOL/recv "-r" 50 destroy_dataset $TESTPOOL/crypt "-r" 51 destroy_dataset $TESTPOOL/ds "-r" 52 [[ -f $sendfile ]] && log_must rm $sendfile 53 [[ -f $keyfile ]] && log_must rm $keyfile 54} 55log_onexit cleanup 56 57log_assert "'zfs recv' must properly handle encryption properties" 58 59typeset keyfile=/$TESTPOOL/pkey 60typeset sendfile=/$TESTPOOL/sendfile 61typeset snap=$TESTPOOL/ds@snap1 62typeset snap2=$TESTPOOL/ds@snap2 63typeset esnap=$TESTPOOL/crypt@snap1 64typeset esnap2=$TESTPOOL/crypt@snap2 65 66log_must eval "echo 'password' > $keyfile" 67 68log_must zfs create $TESTPOOL/ds 69log_must zfs create $TESTPOOL/ds/ds1 70 71log_must zfs create -o encryption=on -o keyformat=passphrase \ 72 -o keylocation=file://$keyfile $TESTPOOL/crypt 73log_must zfs create $TESTPOOL/crypt/ds1 74log_must zfs create -o keyformat=passphrase -o keylocation=file://$keyfile \ 75 $TESTPOOL/crypt/ds2 76 77log_must mkfile 1M /$TESTPOOL/ds/$TESTFILE0 78log_must cp /$TESTPOOL/ds/$TESTFILE0 /$TESTPOOL/crypt/$TESTFILE0 79typeset cksum=$(md5digest /$TESTPOOL/ds/$TESTFILE0) 80 81log_must zfs snap -r $snap 82log_must zfs snap -r $snap2 83log_must zfs snap -r $esnap 84log_must zfs snap -r $esnap2 85 86# Embedded data is incompatible with encrypted datasets, so we cannot 87# allow embedded streams to be received. 88log_note "Must not be able to receive an embedded stream as encrypted" 89log_mustnot eval "zfs send -e $TESTPOOL/crypt/ds1 | zfs recv $TESTPOOL/recv" 90 91# We currently don't have an elegant and secure way to pass the passphrase 92# in via prompt because the send stream itself is using stdin. 93log_note "Must not be able to use 'keylocation=prompt' on receive" 94log_must eval "zfs send $snap > $sendfile" 95log_mustnot eval "zfs recv -o encryption=on -o keyformat=passphrase" \ 96 "$TESTPOOL/recv < $sendfile" 97log_mustnot eval "zfs recv -o encryption=on -o keyformat=passphrase" \ 98 "-o keylocation=prompt $TESTPOOL/recv < $sendfile" 99 100# Raw sends do not have access to the decrypted data so we cannot override 101# the encryption settings without losing the data. 102log_note "Must not be able to disable encryption properties on raw send" 103log_must eval "zfs send -w $esnap > $sendfile" 104log_mustnot eval "zfs recv -x encryption $TESTPOOL/recv < $sendfile" 105log_mustnot eval "zfs recv -x keyformat $TESTPOOL/recv < $sendfile" 106log_mustnot eval "zfs recv -x pbkdf2iters $TESTPOOL/recv < $sendfile" 107 108# Encryption properties are set upon creating the dataset. Changing them 109# afterwards requires using 'zfs change-key' or an update from a raw send. 110log_note "Must not be able to change encryption properties on incrementals" 111log_must eval "zfs send $esnap | zfs recv -o encryption=on" \ 112 "-o keyformat=passphrase -o keylocation=file://$keyfile $TESTPOOL/recv" 113log_mustnot eval "zfs send -i $esnap $esnap2 |" \ 114 "zfs recv -o encryption=aes-128-ccm $TESTPOOL/recv" 115log_mustnot eval "zfs send -i $esnap $esnap2 |" \ 116 "zfs recv -o keyformat=hex $TESTPOOL/recv" 117log_mustnot eval "zfs send -i $esnap $esnap2 |" \ 118 "zfs recv -o pbkdf2iters=100k $TESTPOOL/recv" 119log_must zfs destroy -r $TESTPOOL/recv 120 121# Test that we can receive a simple stream as an encryption root. 122log_note "Must be able to receive stream as encryption root" 123ds=$TESTPOOL/recv 124log_must eval "zfs send $snap > $sendfile" 125log_must eval "zfs recv -o encryption=on -o keyformat=passphrase" \ 126 "-o keylocation=file://$keyfile $ds < $sendfile" 127log_must test "$(get_prop 'encryption' $ds)" == "aes-256-gcm" 128log_must test "$(get_prop 'encryptionroot' $ds)" == "$ds" 129log_must test "$(get_prop 'keyformat' $ds)" == "passphrase" 130log_must test "$(get_prop 'keylocation' $ds)" == "file://$keyfile" 131log_must test "$(get_prop 'mounted' $ds)" == "yes" 132recv_cksum=$(md5digest /$ds/$TESTFILE0) 133log_must test "$recv_cksum" == "$cksum" 134log_must zfs destroy -r $ds 135 136# Test that we can override sharesmb property for encrypted raw stream. 137log_note "Must be able to override sharesmb property for encrypted raw stream" 138ds=$TESTPOOL/recv 139log_must eval "zfs send -w $esnap > $sendfile" 140log_must eval "zfs recv -o sharesmb=on $ds < $sendfile" 141log_must test "$(get_prop 'sharesmb' $ds)" == "on" 142log_must zfs destroy -r $ds 143 144# Test that we can override encryption properties on a properties stream 145# of an unencrypted dataset, turning it into an encryption root. 146log_note "Must be able to receive stream with props as encryption root" 147ds=$TESTPOOL/recv 148log_must eval "zfs send -p $snap > $sendfile" 149log_must eval "zfs recv -o encryption=on -o keyformat=passphrase" \ 150 "-o keylocation=file://$keyfile $ds < $sendfile" 151log_must test "$(get_prop 'encryption' $ds)" == "aes-256-gcm" 152log_must test "$(get_prop 'encryptionroot' $ds)" == "$ds" 153log_must test "$(get_prop 'keyformat' $ds)" == "passphrase" 154log_must test "$(get_prop 'keylocation' $ds)" == "file://$keyfile" 155log_must test "$(get_prop 'mounted' $ds)" == "yes" 156recv_cksum=$(md5digest /$ds/$TESTFILE0) 157log_must test "$recv_cksum" == "$cksum" 158log_must zfs destroy -r $ds 159 160# Test that we can override encryption properties on a recursive stream 161# of an unencrypted dataset, turning it into an encryption root. The root 162# dataset of the stream should become an encryption root with all children 163# inheriting from it. 164log_note "Must be able to receive recursive stream as encryption root" 165ds=$TESTPOOL/recv 166log_must eval "zfs send -R $snap > $sendfile" 167log_must eval "zfs recv -o encryption=on -o keyformat=passphrase" \ 168 "-o keylocation=file://$keyfile $ds < $sendfile" 169log_must test "$(get_prop 'encryption' $ds)" == "aes-256-gcm" 170log_must test "$(get_prop 'encryptionroot' $ds)" == "$ds" 171log_must test "$(get_prop 'keyformat' $ds)" == "passphrase" 172log_must test "$(get_prop 'keylocation' $ds)" == "file://$keyfile" 173log_must test "$(get_prop 'mounted' $ds)" == "yes" 174recv_cksum=$(md5digest /$ds/$TESTFILE0) 175log_must test "$recv_cksum" == "$cksum" 176log_must zfs destroy -r $ds 177 178# Test that we can override an unencrypted properties stream's encryption 179# settings, receiving it as an encrypted child. 180log_note "Must be able to receive stream with props to encrypted child" 181ds=$TESTPOOL/crypt/recv 182log_must eval "zfs send -p $snap > $sendfile" 183log_must eval "zfs recv -x encryption $ds < $sendfile" 184log_must test "$(get_prop 'encryptionroot' $ds)" == "$TESTPOOL/crypt" 185log_must test "$(get_prop 'encryption' $ds)" == "aes-256-gcm" 186log_must test "$(get_prop 'keyformat' $ds)" == "passphrase" 187log_must test "$(get_prop 'mounted' $ds)" == "yes" 188recv_cksum=$(md5digest /$ds/$TESTFILE0) 189log_must test "$recv_cksum" == "$cksum" 190log_must zfs destroy -r $ds 191 192# Test that we can override an unencrypted recursive stream's encryption 193# settings, receiving all datasets as encrypted children. 194log_note "Must be able to receive recursive stream to encrypted child" 195ds=$TESTPOOL/crypt/recv 196log_must eval "zfs send -R $snap > $sendfile" 197log_must eval "zfs recv -x encryption $ds < $sendfile" 198log_must test "$(get_prop 'encryptionroot' $ds)" == "$TESTPOOL/crypt" 199log_must test "$(get_prop 'encryption' $ds)" == "aes-256-gcm" 200log_must test "$(get_prop 'keyformat' $ds)" == "passphrase" 201log_must test "$(get_prop 'mounted' $ds)" == "yes" 202recv_cksum=$(md5digest /$ds/$TESTFILE0) 203log_must test "$recv_cksum" == "$cksum" 204log_must zfs destroy -r $ds 205 206# Test that we can override an unencrypted, incremental, recursive stream's 207# encryption settings, receiving all datasets as encrypted children. 208log_note "Must be able to receive recursive stream to encrypted child" 209ds=$TESTPOOL/crypt/recv 210log_must eval "zfs send -R $snap2 > $sendfile" 211log_must eval "zfs recv -x encryption $ds < $sendfile" 212log_must test "$(get_prop 'encryptionroot' $ds)" == "$TESTPOOL/crypt" 213log_must test "$(get_prop 'encryption' $ds)" == "aes-256-gcm" 214log_must test "$(get_prop 'keyformat' $ds)" == "passphrase" 215log_must test "$(get_prop 'mounted' $ds)" == "yes" 216recv_cksum=$(md5digest /$ds/$TESTFILE0) 217log_must test "$recv_cksum" == "$cksum" 218log_must zfs destroy -r $ds 219 220# Check that we haven't printed the key to the zpool history log 221log_mustnot eval "zpool history -i | grep -q 'wkeydata'" 222 223log_pass "'zfs recv' properly handles encryption properties" 224