xref: /openbsd-src/sys/lib/libsa/softraid.c (revision c2111d31835619f42dfae07a0b4925f019bfe0c7)
1*c2111d31Skn /*	$OpenBSD: softraid.c,v 1.7 2024/04/25 18:31:49 kn Exp $	*/
294e1d415Sjsing 
394e1d415Sjsing /*
494e1d415Sjsing  * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
594e1d415Sjsing  *
694e1d415Sjsing  * Permission to use, copy, modify, and distribute this software for any
794e1d415Sjsing  * purpose with or without fee is hereby granted, provided that the above
894e1d415Sjsing  * copyright notice and this permission notice appear in all copies.
994e1d415Sjsing  *
1094e1d415Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1194e1d415Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1294e1d415Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1394e1d415Sjsing  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1494e1d415Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1594e1d415Sjsing  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1694e1d415Sjsing  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1794e1d415Sjsing  */
1894e1d415Sjsing 
1994e1d415Sjsing #include <sys/param.h>
2094e1d415Sjsing #include <sys/queue.h>
2194e1d415Sjsing 
2294e1d415Sjsing #include <dev/biovar.h>
2394e1d415Sjsing #include <dev/softraidvar.h>
2494e1d415Sjsing 
25df1890a2Sjsing #include <lib/libsa/bcrypt_pbkdf.h>
2694e1d415Sjsing #include <lib/libsa/hmac_sha1.h>
2794e1d415Sjsing #include <lib/libsa/pkcs5_pbkdf2.h>
2894e1d415Sjsing #include <lib/libsa/rijndael.h>
2994e1d415Sjsing 
3094e1d415Sjsing #include "stand.h"
3194e1d415Sjsing #include "softraid.h"
3294e1d415Sjsing 
3394e1d415Sjsing #define RIJNDAEL128_BLOCK_LEN     16
3494e1d415Sjsing #define PASSPHRASE_LENGTH 1024
3594e1d415Sjsing 
3694e1d415Sjsing #define SR_CRYPTO_KEYBLOCK_BYTES SR_CRYPTO_MAXKEYS * SR_CRYPTO_KEYBYTES
3794e1d415Sjsing 
3894e1d415Sjsing /* List of softraid volumes. */
3994e1d415Sjsing struct sr_boot_volume_head sr_volumes;
4094e1d415Sjsing 
4194e1d415Sjsing /* List of softraid keydisks. */
4294e1d415Sjsing struct sr_boot_keydisk_head sr_keydisks;
4394e1d415Sjsing 
4494e1d415Sjsing #ifdef DEBUG
4594e1d415Sjsing void
printhex(const char * s,const u_int8_t * buf,size_t len)4694e1d415Sjsing printhex(const char *s, const u_int8_t *buf, size_t len)
4794e1d415Sjsing {
4894e1d415Sjsing 	u_int8_t n1, n2;
4994e1d415Sjsing 	size_t i;
5094e1d415Sjsing 
5194e1d415Sjsing 	printf("%s: ", s);
5294e1d415Sjsing 	for (i = 0; i < len; i++) {
5394e1d415Sjsing 		n1 = buf[i] & 0x0f;
5494e1d415Sjsing 		n2 = buf[i] >> 4;
5594e1d415Sjsing 		printf("%c", n2 > 9 ? n2 + 'a' - 10 : n2 + '0');
5694e1d415Sjsing 		printf("%c", n1 > 9 ? n1 + 'a' - 10 : n1 + '0');
5794e1d415Sjsing 	}
5894e1d415Sjsing 	printf("\n");
5994e1d415Sjsing }
6094e1d415Sjsing #endif
6194e1d415Sjsing 
6294e1d415Sjsing void
sr_clear_keys(void)6394e1d415Sjsing sr_clear_keys(void)
6494e1d415Sjsing {
6594e1d415Sjsing 	struct sr_boot_volume *bv;
660c95ab44Sjsg 	struct sr_boot_keydisk *kd, *nkd;
6794e1d415Sjsing 
6894e1d415Sjsing 	SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
69855f8c03Sstsp 		if (bv->sbv_level != 'C' && bv->sbv_level != 0x1C)
7094e1d415Sjsing 			continue;
7194e1d415Sjsing 		if (bv->sbv_keys != NULL) {
7294e1d415Sjsing 			explicit_bzero(bv->sbv_keys, SR_CRYPTO_KEYBLOCK_BYTES);
7394e1d415Sjsing 			free(bv->sbv_keys, SR_CRYPTO_KEYBLOCK_BYTES);
7494e1d415Sjsing 			bv->sbv_keys = NULL;
7594e1d415Sjsing 		}
7694e1d415Sjsing 		if (bv->sbv_maskkey != NULL) {
7794e1d415Sjsing 			explicit_bzero(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES);
7894e1d415Sjsing 			free(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES);
7994e1d415Sjsing 			bv->sbv_maskkey = NULL;
8094e1d415Sjsing 		}
8194e1d415Sjsing 	}
820c95ab44Sjsg 	SLIST_FOREACH_SAFE(kd, &sr_keydisks, kd_link, nkd) {
8394e1d415Sjsing 		explicit_bzero(kd, sizeof(*kd));
8494e1d415Sjsing 		free(kd, sizeof(*kd));
8594e1d415Sjsing 	}
8694e1d415Sjsing }
8794e1d415Sjsing 
8894e1d415Sjsing void
sr_crypto_calculate_check_hmac_sha1(u_int8_t * maskkey,int maskkey_size,u_int8_t * key,int key_size,u_char * check_digest)8994e1d415Sjsing sr_crypto_calculate_check_hmac_sha1(u_int8_t *maskkey, int maskkey_size,
9094e1d415Sjsing     u_int8_t *key, int key_size, u_char *check_digest)
9194e1d415Sjsing {
9294e1d415Sjsing 	u_int8_t check_key[SHA1_DIGEST_LENGTH];
9394e1d415Sjsing 	SHA1_CTX shactx;
9494e1d415Sjsing 
9594e1d415Sjsing 	explicit_bzero(check_key, sizeof(check_key));
9694e1d415Sjsing 	explicit_bzero(&shactx, sizeof(shactx));
9794e1d415Sjsing 
9894e1d415Sjsing 	/* k = SHA1(mask_key) */
9994e1d415Sjsing 	SHA1Init(&shactx);
10094e1d415Sjsing 	SHA1Update(&shactx, maskkey, maskkey_size);
10194e1d415Sjsing 	SHA1Final(check_key, &shactx);
10294e1d415Sjsing 
10394e1d415Sjsing 	/* mac = HMAC_SHA1_k(unencrypted key) */
10494e1d415Sjsing 	hmac_sha1(key, key_size, check_key, sizeof(check_key), check_digest);
10594e1d415Sjsing 
10694e1d415Sjsing 	explicit_bzero(check_key, sizeof(check_key));
10794e1d415Sjsing 	explicit_bzero(&shactx, sizeof(shactx));
10894e1d415Sjsing }
10994e1d415Sjsing 
11027bea9a3Sjsing static int
sr_crypto_decrypt_keys(struct sr_meta_crypto * cm,struct sr_crypto_kdfinfo * kdfinfo,u_int8_t * kp)11127bea9a3Sjsing sr_crypto_decrypt_keys(struct sr_meta_crypto *cm,
11227bea9a3Sjsing     struct sr_crypto_kdfinfo *kdfinfo, u_int8_t *kp)
11327bea9a3Sjsing {
11427bea9a3Sjsing 	u_int8_t digest[SHA1_DIGEST_LENGTH];
11527bea9a3Sjsing 	rijndael_ctx ctx;
11627bea9a3Sjsing 	u_int8_t *cp;
11727bea9a3Sjsing 	int rv = -1;
11827bea9a3Sjsing 	int i;
11927bea9a3Sjsing 
12027bea9a3Sjsing 	if (rijndael_set_key(&ctx, kdfinfo->maskkey, 256) != 0)
12127bea9a3Sjsing 		goto done;
12227bea9a3Sjsing 
12327bea9a3Sjsing 	cp = (u_int8_t *)cm->scm_key;
12427bea9a3Sjsing 	for (i = 0; i < SR_CRYPTO_KEYBLOCK_BYTES; i += RIJNDAEL128_BLOCK_LEN)
12527bea9a3Sjsing 		rijndael_decrypt(&ctx, (u_char *)(cp + i), (u_char *)(kp + i));
12627bea9a3Sjsing 
12727bea9a3Sjsing 	/* Check that the key decrypted properly. */
12827bea9a3Sjsing 	sr_crypto_calculate_check_hmac_sha1(kdfinfo->maskkey,
12927bea9a3Sjsing 	    sizeof(kdfinfo->maskkey), kp, SR_CRYPTO_KEYBLOCK_BYTES, digest);
13027bea9a3Sjsing 
13127bea9a3Sjsing 	if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest)) == 0)
13227bea9a3Sjsing 		rv = 0;
13327bea9a3Sjsing 
13427bea9a3Sjsing  done:
13527bea9a3Sjsing 	explicit_bzero(digest, sizeof(digest));
13627bea9a3Sjsing 
13727bea9a3Sjsing 	return rv;
13827bea9a3Sjsing }
13927bea9a3Sjsing 
14027bea9a3Sjsing static int
sr_crypto_passphrase_decrypt(struct sr_meta_crypto * cm,struct sr_crypto_kdfinfo * kdfinfo,u_int8_t * kp)14127bea9a3Sjsing sr_crypto_passphrase_decrypt(struct sr_meta_crypto *cm,
14227bea9a3Sjsing     struct sr_crypto_kdfinfo *kdfinfo, u_int8_t *kp)
14327bea9a3Sjsing {
14427bea9a3Sjsing 	char passphrase[PASSPHRASE_LENGTH];
14527bea9a3Sjsing 	struct sr_crypto_pbkdf *kdfhint;
14627bea9a3Sjsing 	int rv = -1;
14727bea9a3Sjsing 	int c, i;
14827bea9a3Sjsing 
14927bea9a3Sjsing 	kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint;
15027bea9a3Sjsing 
15127bea9a3Sjsing 	for (;;) {
15227bea9a3Sjsing 		printf("Passphrase: ");
153*c2111d31Skn #ifdef IDLE_POWEROFF
154*c2111d31Skn extern int idle_poweroff(void);
155*c2111d31Skn 		idle_poweroff();
156*c2111d31Skn #endif /* IDLE_POWEROFF */
15727bea9a3Sjsing 		for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
15827bea9a3Sjsing 			c = cngetc();
15927bea9a3Sjsing 			if (c == '\r' || c == '\n') {
16027bea9a3Sjsing 				break;
16127bea9a3Sjsing 			} else if (c == '\b') {
16227bea9a3Sjsing 				i = i > 0 ? i - 2 : -1;
16327bea9a3Sjsing 				continue;
16427bea9a3Sjsing 			}
16527bea9a3Sjsing 			passphrase[i] = (c & 0xff);
16627bea9a3Sjsing 		}
16727bea9a3Sjsing 		passphrase[i] = 0;
16827bea9a3Sjsing 		printf("\n");
16927bea9a3Sjsing 
17027bea9a3Sjsing 		/* Abort on an empty passphrase. */
17127bea9a3Sjsing 		if (i == 0) {
17227bea9a3Sjsing 			printf("aborting...\n");
17327bea9a3Sjsing 			goto done;
17427bea9a3Sjsing 		}
17527bea9a3Sjsing 
17627bea9a3Sjsing #ifdef DEBUG
17727bea9a3Sjsing 		printf("Got passphrase: %s with len %d\n",
17827bea9a3Sjsing 		    passphrase, strlen(passphrase));
17927bea9a3Sjsing #endif
18027bea9a3Sjsing 
18127bea9a3Sjsing 		switch (kdfhint->generic.type) {
18227bea9a3Sjsing 		case SR_CRYPTOKDFT_PKCS5_PBKDF2:
18327bea9a3Sjsing 			if (pkcs5_pbkdf2(passphrase, strlen(passphrase),
18427bea9a3Sjsing 			    kdfhint->salt, sizeof(kdfhint->salt),
18527bea9a3Sjsing 			    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
18627bea9a3Sjsing 			    kdfhint->rounds) != 0) {
18727bea9a3Sjsing 				printf("pkcs5_pbkdf2 failed\n");
18827bea9a3Sjsing 				goto done;
18927bea9a3Sjsing 			}
19027bea9a3Sjsing 			break;
19127bea9a3Sjsing 
19227bea9a3Sjsing 		case SR_CRYPTOKDFT_BCRYPT_PBKDF:
19327bea9a3Sjsing 			if (bcrypt_pbkdf(passphrase, strlen(passphrase),
19427bea9a3Sjsing 			    kdfhint->salt, sizeof(kdfhint->salt),
19527bea9a3Sjsing 			    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
19627bea9a3Sjsing 			    kdfhint->rounds) != 0) {
19727bea9a3Sjsing 				printf("bcrypt_pbkdf failed\n");
19827bea9a3Sjsing 				goto done;
19927bea9a3Sjsing 			}
20027bea9a3Sjsing 			break;
20127bea9a3Sjsing 
20227bea9a3Sjsing 		default:
20327bea9a3Sjsing 			printf("unknown KDF type %u\n", kdfhint->generic.type);
20427bea9a3Sjsing 			goto done;
20527bea9a3Sjsing 		}
20627bea9a3Sjsing 
20727bea9a3Sjsing 		if (sr_crypto_decrypt_keys(cm, kdfinfo, kp) == 0) {
20827bea9a3Sjsing 			rv = 0;
20927bea9a3Sjsing 			goto done;
21027bea9a3Sjsing 		}
21127bea9a3Sjsing 
21227bea9a3Sjsing 		printf("incorrect passphrase\n");
21327bea9a3Sjsing 	}
21427bea9a3Sjsing 
21527bea9a3Sjsing  done:
21627bea9a3Sjsing 	explicit_bzero(passphrase, PASSPHRASE_LENGTH);
21727bea9a3Sjsing 
21827bea9a3Sjsing 	return rv;
21927bea9a3Sjsing }
22027bea9a3Sjsing 
22194e1d415Sjsing int
sr_crypto_unlock_volume(struct sr_boot_volume * bv)22227bea9a3Sjsing sr_crypto_unlock_volume(struct sr_boot_volume *bv)
22394e1d415Sjsing {
22494e1d415Sjsing 	struct sr_meta_crypto *cm;
22594e1d415Sjsing 	struct sr_boot_keydisk *kd;
22694e1d415Sjsing 	struct sr_meta_opt_item *omi;
22794e1d415Sjsing 	struct sr_crypto_pbkdf *kdfhint;
22894e1d415Sjsing 	struct sr_crypto_kdfinfo kdfinfo;
22994e1d415Sjsing 	u_int8_t *keys = NULL;
23094e1d415Sjsing 	int rv = -1;
23194e1d415Sjsing 
23294e1d415Sjsing 	SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link)
23394e1d415Sjsing 		if (omi->omi_som->som_type == SR_OPT_CRYPTO)
23494e1d415Sjsing 			break;
23594e1d415Sjsing 
23694e1d415Sjsing 	if (omi == NULL) {
23727bea9a3Sjsing 		printf("crypto metadata not found!\n");
23894e1d415Sjsing 		goto done;
23994e1d415Sjsing 	}
24094e1d415Sjsing 
24194e1d415Sjsing 	cm = (struct sr_meta_crypto *)omi->omi_som;
24294e1d415Sjsing 	kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint;
24394e1d415Sjsing 
24494e1d415Sjsing 	switch (cm->scm_mask_alg) {
24594e1d415Sjsing 	case SR_CRYPTOM_AES_ECB_256:
24694e1d415Sjsing 		break;
24794e1d415Sjsing 	default:
24894e1d415Sjsing 		printf("unsupported encryption algorithm %u\n",
24994e1d415Sjsing 		    cm->scm_mask_alg);
25094e1d415Sjsing 		goto done;
25194e1d415Sjsing 	}
25294e1d415Sjsing 
25394e1d415Sjsing 	keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES);
25494e1d415Sjsing 	bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
25594e1d415Sjsing 
25627bea9a3Sjsing 	switch (kdfhint->generic.type) {
25727bea9a3Sjsing 	case SR_CRYPTOKDFT_KEYDISK:
25827bea9a3Sjsing 		SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
25927bea9a3Sjsing 			if (bcmp(&kd->kd_uuid, &bv->sbv_uuid,
26027bea9a3Sjsing 			    sizeof(kd->kd_uuid)) == 0)
26127bea9a3Sjsing 				break;
26227bea9a3Sjsing 		}
26327bea9a3Sjsing 		if (kd == NULL) {
26427bea9a3Sjsing 			printf("keydisk not found\n");
26594e1d415Sjsing 			goto done;
26627bea9a3Sjsing 		}
26727bea9a3Sjsing 		bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey));
26827bea9a3Sjsing 		if (sr_crypto_decrypt_keys(cm, &kdfinfo, keys) != 0) {
26927bea9a3Sjsing 			printf("incorrect keydisk\n");
27027bea9a3Sjsing 			goto done;
27127bea9a3Sjsing 		}
27227bea9a3Sjsing 		break;
27394e1d415Sjsing 
27427bea9a3Sjsing 	case SR_CRYPTOKDFT_BCRYPT_PBKDF:
27527bea9a3Sjsing 	case SR_CRYPTOKDFT_PKCS5_PBKDF2:
27627bea9a3Sjsing 		if (sr_crypto_passphrase_decrypt(cm, &kdfinfo, keys) != 0)
27727bea9a3Sjsing 			goto done;
27827bea9a3Sjsing 		break;
27994e1d415Sjsing 
28027bea9a3Sjsing 	default:
28127bea9a3Sjsing 		printf("unknown KDF type %u\n", kdfhint->generic.type);
28294e1d415Sjsing 		goto done;
28394e1d415Sjsing 	}
28494e1d415Sjsing 
28594e1d415Sjsing 	/* Keys and keydisks will be cleared before boot and from _rtt. */
28694e1d415Sjsing 	bv->sbv_keys = keys;
28794e1d415Sjsing 	bv->sbv_maskkey = alloc(sizeof(kdfinfo.maskkey));
28894e1d415Sjsing 	bcopy(&kdfinfo.maskkey, bv->sbv_maskkey, sizeof(kdfinfo.maskkey));
28994e1d415Sjsing 
29094e1d415Sjsing 	rv = 0;
29194e1d415Sjsing 
29294e1d415Sjsing  done:
29394e1d415Sjsing 	explicit_bzero(&kdfinfo, sizeof(kdfinfo));
29494e1d415Sjsing 
29594e1d415Sjsing 	if (keys != NULL && rv != 0) {
29694e1d415Sjsing 		explicit_bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
29794e1d415Sjsing 		free(keys, SR_CRYPTO_KEYBLOCK_BYTES);
29894e1d415Sjsing 	}
29994e1d415Sjsing 
30094e1d415Sjsing 	return (rv);
30194e1d415Sjsing }
302