xref: /openbsd/sys/lib/libsa/softraid.c (revision d415bd75)
1 /*	$OpenBSD: softraid.c,v 1.5 2022/08/12 20:17:46 stsp Exp $	*/
2 
3 /*
4  * Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/queue.h>
21 
22 #include <dev/biovar.h>
23 #include <dev/softraidvar.h>
24 
25 #include <lib/libsa/bcrypt_pbkdf.h>
26 #include <lib/libsa/hmac_sha1.h>
27 #include <lib/libsa/pkcs5_pbkdf2.h>
28 #include <lib/libsa/rijndael.h>
29 
30 #include "stand.h"
31 #include "softraid.h"
32 
33 #define RIJNDAEL128_BLOCK_LEN     16
34 #define PASSPHRASE_LENGTH 1024
35 
36 #define SR_CRYPTO_KEYBLOCK_BYTES SR_CRYPTO_MAXKEYS * SR_CRYPTO_KEYBYTES
37 
38 /* List of softraid volumes. */
39 struct sr_boot_volume_head sr_volumes;
40 
41 /* List of softraid keydisks. */
42 struct sr_boot_keydisk_head sr_keydisks;
43 
44 #ifdef DEBUG
45 void
46 printhex(const char *s, const u_int8_t *buf, size_t len)
47 {
48 	u_int8_t n1, n2;
49 	size_t i;
50 
51 	printf("%s: ", s);
52 	for (i = 0; i < len; i++) {
53 		n1 = buf[i] & 0x0f;
54 		n2 = buf[i] >> 4;
55 		printf("%c", n2 > 9 ? n2 + 'a' - 10 : n2 + '0');
56 		printf("%c", n1 > 9 ? n1 + 'a' - 10 : n1 + '0');
57 	}
58 	printf("\n");
59 }
60 #endif
61 
62 void
63 sr_clear_keys(void)
64 {
65 	struct sr_boot_volume *bv;
66 	struct sr_boot_keydisk *kd;
67 
68 	SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
69 		if (bv->sbv_level != 'C' && bv->sbv_level != 0x1C)
70 			continue;
71 		if (bv->sbv_keys != NULL) {
72 			explicit_bzero(bv->sbv_keys, SR_CRYPTO_KEYBLOCK_BYTES);
73 			free(bv->sbv_keys, SR_CRYPTO_KEYBLOCK_BYTES);
74 			bv->sbv_keys = NULL;
75 		}
76 		if (bv->sbv_maskkey != NULL) {
77 			explicit_bzero(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES);
78 			free(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES);
79 			bv->sbv_maskkey = NULL;
80 		}
81 	}
82 	SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
83 		explicit_bzero(kd, sizeof(*kd));
84 		free(kd, sizeof(*kd));
85 	}
86 }
87 
88 void
89 sr_crypto_calculate_check_hmac_sha1(u_int8_t *maskkey, int maskkey_size,
90     u_int8_t *key, int key_size, u_char *check_digest)
91 {
92 	u_int8_t check_key[SHA1_DIGEST_LENGTH];
93 	SHA1_CTX shactx;
94 
95 	explicit_bzero(check_key, sizeof(check_key));
96 	explicit_bzero(&shactx, sizeof(shactx));
97 
98 	/* k = SHA1(mask_key) */
99 	SHA1Init(&shactx);
100 	SHA1Update(&shactx, maskkey, maskkey_size);
101 	SHA1Final(check_key, &shactx);
102 
103 	/* mac = HMAC_SHA1_k(unencrypted key) */
104 	hmac_sha1(key, key_size, check_key, sizeof(check_key), check_digest);
105 
106 	explicit_bzero(check_key, sizeof(check_key));
107 	explicit_bzero(&shactx, sizeof(shactx));
108 }
109 
110 static int
111 sr_crypto_decrypt_keys(struct sr_meta_crypto *cm,
112     struct sr_crypto_kdfinfo *kdfinfo, u_int8_t *kp)
113 {
114 	u_int8_t digest[SHA1_DIGEST_LENGTH];
115 	rijndael_ctx ctx;
116 	u_int8_t *cp;
117 	int rv = -1;
118 	int i;
119 
120 	if (rijndael_set_key(&ctx, kdfinfo->maskkey, 256) != 0)
121 		goto done;
122 
123 	cp = (u_int8_t *)cm->scm_key;
124 	for (i = 0; i < SR_CRYPTO_KEYBLOCK_BYTES; i += RIJNDAEL128_BLOCK_LEN)
125 		rijndael_decrypt(&ctx, (u_char *)(cp + i), (u_char *)(kp + i));
126 
127 	/* Check that the key decrypted properly. */
128 	sr_crypto_calculate_check_hmac_sha1(kdfinfo->maskkey,
129 	    sizeof(kdfinfo->maskkey), kp, SR_CRYPTO_KEYBLOCK_BYTES, digest);
130 
131 	if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest)) == 0)
132 		rv = 0;
133 
134  done:
135 	explicit_bzero(digest, sizeof(digest));
136 
137 	return rv;
138 }
139 
140 static int
141 sr_crypto_passphrase_decrypt(struct sr_meta_crypto *cm,
142     struct sr_crypto_kdfinfo *kdfinfo, u_int8_t *kp)
143 {
144 	char passphrase[PASSPHRASE_LENGTH];
145 	struct sr_crypto_pbkdf *kdfhint;
146 	int rv = -1;
147 	int c, i;
148 
149 	kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint;
150 
151 	for (;;) {
152 		printf("Passphrase: ");
153 		for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
154 			c = cngetc();
155 			if (c == '\r' || c == '\n') {
156 				break;
157 			} else if (c == '\b') {
158 				i = i > 0 ? i - 2 : -1;
159 				continue;
160 			}
161 			passphrase[i] = (c & 0xff);
162 		}
163 		passphrase[i] = 0;
164 		printf("\n");
165 
166 		/* Abort on an empty passphrase. */
167 		if (i == 0) {
168 			printf("aborting...\n");
169 			goto done;
170 		}
171 
172 #ifdef DEBUG
173 		printf("Got passphrase: %s with len %d\n",
174 		    passphrase, strlen(passphrase));
175 #endif
176 
177 		switch (kdfhint->generic.type) {
178 		case SR_CRYPTOKDFT_PKCS5_PBKDF2:
179 			if (pkcs5_pbkdf2(passphrase, strlen(passphrase),
180 			    kdfhint->salt, sizeof(kdfhint->salt),
181 			    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
182 			    kdfhint->rounds) != 0) {
183 				printf("pkcs5_pbkdf2 failed\n");
184 				goto done;
185 			}
186 			break;
187 
188 		case SR_CRYPTOKDFT_BCRYPT_PBKDF:
189 			if (bcrypt_pbkdf(passphrase, strlen(passphrase),
190 			    kdfhint->salt, sizeof(kdfhint->salt),
191 			    kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
192 			    kdfhint->rounds) != 0) {
193 				printf("bcrypt_pbkdf failed\n");
194 				goto done;
195 			}
196 			break;
197 
198 		default:
199 			printf("unknown KDF type %u\n", kdfhint->generic.type);
200 			goto done;
201 		}
202 
203 		if (sr_crypto_decrypt_keys(cm, kdfinfo, kp) == 0) {
204 			rv = 0;
205 			goto done;
206 		}
207 
208 		printf("incorrect passphrase\n");
209 	}
210 
211  done:
212 	explicit_bzero(passphrase, PASSPHRASE_LENGTH);
213 
214 	return rv;
215 }
216 
217 int
218 sr_crypto_unlock_volume(struct sr_boot_volume *bv)
219 {
220 	struct sr_meta_crypto *cm;
221 	struct sr_boot_keydisk *kd;
222 	struct sr_meta_opt_item *omi;
223 	struct sr_crypto_pbkdf *kdfhint;
224 	struct sr_crypto_kdfinfo kdfinfo;
225 	u_int8_t *keys = NULL;
226 	int rv = -1;
227 
228 	SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link)
229 		if (omi->omi_som->som_type == SR_OPT_CRYPTO)
230 			break;
231 
232 	if (omi == NULL) {
233 		printf("crypto metadata not found!\n");
234 		goto done;
235 	}
236 
237 	cm = (struct sr_meta_crypto *)omi->omi_som;
238 	kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint;
239 
240 	switch (cm->scm_mask_alg) {
241 	case SR_CRYPTOM_AES_ECB_256:
242 		break;
243 	default:
244 		printf("unsupported encryption algorithm %u\n",
245 		    cm->scm_mask_alg);
246 		goto done;
247 	}
248 
249 	keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES);
250 	bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
251 
252 	switch (kdfhint->generic.type) {
253 	case SR_CRYPTOKDFT_KEYDISK:
254 		SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
255 			if (bcmp(&kd->kd_uuid, &bv->sbv_uuid,
256 			    sizeof(kd->kd_uuid)) == 0)
257 				break;
258 		}
259 		if (kd == NULL) {
260 			printf("keydisk not found\n");
261 			goto done;
262 		}
263 		bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey));
264 		if (sr_crypto_decrypt_keys(cm, &kdfinfo, keys) != 0) {
265 			printf("incorrect keydisk\n");
266 			goto done;
267 		}
268 		break;
269 
270 	case SR_CRYPTOKDFT_BCRYPT_PBKDF:
271 	case SR_CRYPTOKDFT_PKCS5_PBKDF2:
272 		if (sr_crypto_passphrase_decrypt(cm, &kdfinfo, keys) != 0)
273 			goto done;
274 		break;
275 
276 	default:
277 		printf("unknown KDF type %u\n", kdfhint->generic.type);
278 		goto done;
279 	}
280 
281 	/* Keys and keydisks will be cleared before boot and from _rtt. */
282 	bv->sbv_keys = keys;
283 	bv->sbv_maskkey = alloc(sizeof(kdfinfo.maskkey));
284 	bcopy(&kdfinfo.maskkey, bv->sbv_maskkey, sizeof(kdfinfo.maskkey));
285 
286 	rv = 0;
287 
288  done:
289 	explicit_bzero(&kdfinfo, sizeof(kdfinfo));
290 
291 	if (keys != NULL && rv != 0) {
292 		explicit_bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
293 		free(keys, SR_CRYPTO_KEYBLOCK_BYTES);
294 	}
295 
296 	return (rv);
297 }
298