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