1 /* $OpenBSD: softraid.c,v 1.7 2024/04/25 18:31:49 kn 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
printhex(const char * s,const u_int8_t * buf,size_t len)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
sr_clear_keys(void)63 sr_clear_keys(void)
64 {
65 struct sr_boot_volume *bv;
66 struct sr_boot_keydisk *kd, *nkd;
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_SAFE(kd, &sr_keydisks, kd_link, nkd) {
83 explicit_bzero(kd, sizeof(*kd));
84 free(kd, sizeof(*kd));
85 }
86 }
87
88 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)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
sr_crypto_decrypt_keys(struct sr_meta_crypto * cm,struct sr_crypto_kdfinfo * kdfinfo,u_int8_t * kp)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
sr_crypto_passphrase_decrypt(struct sr_meta_crypto * cm,struct sr_crypto_kdfinfo * kdfinfo,u_int8_t * kp)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 #ifdef IDLE_POWEROFF
154 extern int idle_poweroff(void);
155 idle_poweroff();
156 #endif /* IDLE_POWEROFF */
157 for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
158 c = cngetc();
159 if (c == '\r' || c == '\n') {
160 break;
161 } else if (c == '\b') {
162 i = i > 0 ? i - 2 : -1;
163 continue;
164 }
165 passphrase[i] = (c & 0xff);
166 }
167 passphrase[i] = 0;
168 printf("\n");
169
170 /* Abort on an empty passphrase. */
171 if (i == 0) {
172 printf("aborting...\n");
173 goto done;
174 }
175
176 #ifdef DEBUG
177 printf("Got passphrase: %s with len %d\n",
178 passphrase, strlen(passphrase));
179 #endif
180
181 switch (kdfhint->generic.type) {
182 case SR_CRYPTOKDFT_PKCS5_PBKDF2:
183 if (pkcs5_pbkdf2(passphrase, strlen(passphrase),
184 kdfhint->salt, sizeof(kdfhint->salt),
185 kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
186 kdfhint->rounds) != 0) {
187 printf("pkcs5_pbkdf2 failed\n");
188 goto done;
189 }
190 break;
191
192 case SR_CRYPTOKDFT_BCRYPT_PBKDF:
193 if (bcrypt_pbkdf(passphrase, strlen(passphrase),
194 kdfhint->salt, sizeof(kdfhint->salt),
195 kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
196 kdfhint->rounds) != 0) {
197 printf("bcrypt_pbkdf failed\n");
198 goto done;
199 }
200 break;
201
202 default:
203 printf("unknown KDF type %u\n", kdfhint->generic.type);
204 goto done;
205 }
206
207 if (sr_crypto_decrypt_keys(cm, kdfinfo, kp) == 0) {
208 rv = 0;
209 goto done;
210 }
211
212 printf("incorrect passphrase\n");
213 }
214
215 done:
216 explicit_bzero(passphrase, PASSPHRASE_LENGTH);
217
218 return rv;
219 }
220
221 int
sr_crypto_unlock_volume(struct sr_boot_volume * bv)222 sr_crypto_unlock_volume(struct sr_boot_volume *bv)
223 {
224 struct sr_meta_crypto *cm;
225 struct sr_boot_keydisk *kd;
226 struct sr_meta_opt_item *omi;
227 struct sr_crypto_pbkdf *kdfhint;
228 struct sr_crypto_kdfinfo kdfinfo;
229 u_int8_t *keys = NULL;
230 int rv = -1;
231
232 SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link)
233 if (omi->omi_som->som_type == SR_OPT_CRYPTO)
234 break;
235
236 if (omi == NULL) {
237 printf("crypto metadata not found!\n");
238 goto done;
239 }
240
241 cm = (struct sr_meta_crypto *)omi->omi_som;
242 kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint;
243
244 switch (cm->scm_mask_alg) {
245 case SR_CRYPTOM_AES_ECB_256:
246 break;
247 default:
248 printf("unsupported encryption algorithm %u\n",
249 cm->scm_mask_alg);
250 goto done;
251 }
252
253 keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES);
254 bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
255
256 switch (kdfhint->generic.type) {
257 case SR_CRYPTOKDFT_KEYDISK:
258 SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
259 if (bcmp(&kd->kd_uuid, &bv->sbv_uuid,
260 sizeof(kd->kd_uuid)) == 0)
261 break;
262 }
263 if (kd == NULL) {
264 printf("keydisk not found\n");
265 goto done;
266 }
267 bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey));
268 if (sr_crypto_decrypt_keys(cm, &kdfinfo, keys) != 0) {
269 printf("incorrect keydisk\n");
270 goto done;
271 }
272 break;
273
274 case SR_CRYPTOKDFT_BCRYPT_PBKDF:
275 case SR_CRYPTOKDFT_PKCS5_PBKDF2:
276 if (sr_crypto_passphrase_decrypt(cm, &kdfinfo, keys) != 0)
277 goto done;
278 break;
279
280 default:
281 printf("unknown KDF type %u\n", kdfhint->generic.type);
282 goto done;
283 }
284
285 /* Keys and keydisks will be cleared before boot and from _rtt. */
286 bv->sbv_keys = keys;
287 bv->sbv_maskkey = alloc(sizeof(kdfinfo.maskkey));
288 bcopy(&kdfinfo.maskkey, bv->sbv_maskkey, sizeof(kdfinfo.maskkey));
289
290 rv = 0;
291
292 done:
293 explicit_bzero(&kdfinfo, sizeof(kdfinfo));
294
295 if (keys != NULL && rv != 0) {
296 explicit_bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
297 free(keys, SR_CRYPTO_KEYBLOCK_BYTES);
298 }
299
300 return (rv);
301 }
302