xref: /openbsd-src/sys/lib/libsa/softraid.c (revision f2133c794d40a69ff90521845af4024bbe945f67)
1 /*	$OpenBSD: softraid.c,v 1.1 2016/09/11 17:49:36 jsing 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/hmac_sha1.h>
26 #include <lib/libsa/pkcs5_pbkdf2.h>
27 #include <lib/libsa/rijndael.h>
28 
29 #include "stand.h"
30 #include "softraid.h"
31 
32 #define RIJNDAEL128_BLOCK_LEN     16
33 #define PASSPHRASE_LENGTH 1024
34 
35 #define SR_CRYPTO_KEYBLOCK_BYTES SR_CRYPTO_MAXKEYS * SR_CRYPTO_KEYBYTES
36 
37 /* List of softraid volumes. */
38 struct sr_boot_volume_head sr_volumes;
39 
40 /* List of softraid keydisks. */
41 struct sr_boot_keydisk_head sr_keydisks;
42 
43 #ifdef DEBUG
44 void
45 printhex(const char *s, const u_int8_t *buf, size_t len)
46 {
47 	u_int8_t n1, n2;
48 	size_t i;
49 
50 	printf("%s: ", s);
51 	for (i = 0; i < len; i++) {
52 		n1 = buf[i] & 0x0f;
53 		n2 = buf[i] >> 4;
54 		printf("%c", n2 > 9 ? n2 + 'a' - 10 : n2 + '0');
55 		printf("%c", n1 > 9 ? n1 + 'a' - 10 : n1 + '0');
56 	}
57 	printf("\n");
58 }
59 #endif
60 
61 void
62 sr_clear_keys(void)
63 {
64 	struct sr_boot_volume *bv;
65 	struct sr_boot_keydisk *kd;
66 
67 	SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
68 		if (bv->sbv_level != 'C')
69 			continue;
70 		if (bv->sbv_keys != NULL) {
71 			explicit_bzero(bv->sbv_keys, SR_CRYPTO_KEYBLOCK_BYTES);
72 			free(bv->sbv_keys, SR_CRYPTO_KEYBLOCK_BYTES);
73 			bv->sbv_keys = NULL;
74 		}
75 		if (bv->sbv_maskkey != NULL) {
76 			explicit_bzero(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES);
77 			free(bv->sbv_maskkey, SR_CRYPTO_MAXKEYBYTES);
78 			bv->sbv_maskkey = NULL;
79 		}
80 	}
81 	SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
82 		explicit_bzero(kd, sizeof(*kd));
83 		free(kd, sizeof(*kd));
84 	}
85 }
86 
87 void
88 sr_crypto_calculate_check_hmac_sha1(u_int8_t *maskkey, int maskkey_size,
89     u_int8_t *key, int key_size, u_char *check_digest)
90 {
91 	u_int8_t check_key[SHA1_DIGEST_LENGTH];
92 	SHA1_CTX shactx;
93 
94 	explicit_bzero(check_key, sizeof(check_key));
95 	explicit_bzero(&shactx, sizeof(shactx));
96 
97 	/* k = SHA1(mask_key) */
98 	SHA1Init(&shactx);
99 	SHA1Update(&shactx, maskkey, maskkey_size);
100 	SHA1Final(check_key, &shactx);
101 
102 	/* mac = HMAC_SHA1_k(unencrypted key) */
103 	hmac_sha1(key, key_size, check_key, sizeof(check_key), check_digest);
104 
105 	explicit_bzero(check_key, sizeof(check_key));
106 	explicit_bzero(&shactx, sizeof(shactx));
107 }
108 
109 int
110 sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
111 {
112 	struct sr_meta_crypto *cm;
113 	struct sr_boot_keydisk	*kd;
114 	struct sr_meta_opt_item *omi;
115 	struct sr_crypto_pbkdf *kdfhint;
116 	struct sr_crypto_kdfinfo kdfinfo;
117 	char passphrase[PASSPHRASE_LENGTH];
118 	u_int8_t digest[SHA1_DIGEST_LENGTH];
119 	u_int8_t *keys = NULL;
120 	u_int8_t *kp, *cp;
121 	rijndael_ctx ctx;
122 	int rv = -1;
123 	int c, i;
124 
125 	SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link)
126 		if (omi->omi_som->som_type == SR_OPT_CRYPTO)
127 			break;
128 
129 	if (omi == NULL) {
130 		printf("Crypto metadata not found!\n");
131 		goto done;
132 	}
133 
134 	cm = (struct sr_meta_crypto *)omi->omi_som;
135 	kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint;
136 
137 	switch (cm->scm_mask_alg) {
138 	case SR_CRYPTOM_AES_ECB_256:
139 		break;
140 	default:
141 		printf("unsupported encryption algorithm %u\n",
142 		    cm->scm_mask_alg);
143 		goto done;
144 	}
145 
146 	SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
147 		if (bcmp(&kd->kd_uuid, &bv->sbv_uuid, sizeof(kd->kd_uuid)) == 0)
148 			break;
149 	}
150 	if (kd) {
151 		bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey));
152 	} else {
153 		printf("Passphrase: ");
154 		for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
155 			c = cngetc();
156 			if (c == '\r' || c == '\n')
157 				break;
158 			else if (c == '\b') {
159 				i = i > 0 ? i - 2 : -1;
160 				continue;
161 			}
162 			passphrase[i] = (c & 0xff);
163 		}
164 		passphrase[i] = 0;
165 		printf("\n");
166 
167 #ifdef DEBUG
168 		printf("Got passphrase: %s with len %d\n",
169 		    passphrase, strlen(passphrase));
170 #endif
171 
172 		if (pkcs5_pbkdf2(passphrase, strlen(passphrase), kdfhint->salt,
173 		    sizeof(kdfhint->salt), kdfinfo.maskkey,
174 		    sizeof(kdfinfo.maskkey), kdfhint->rounds) != 0) {
175 			printf("pbkdf2 failed\n");
176 			goto done;
177 		}
178 	}
179 
180 	/* kdfinfo->maskkey now has key. */
181 
182 	/* Decrypt disk keys. */
183 	keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES);
184 	bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
185 
186 	if (rijndael_set_key(&ctx, kdfinfo.maskkey, 256) != 0)
187 		goto done;
188 
189 	cp = (u_int8_t *)cm->scm_key;
190 	kp = keys;
191 	for (i = 0; i < SR_CRYPTO_KEYBLOCK_BYTES; i += RIJNDAEL128_BLOCK_LEN)
192 		rijndael_decrypt(&ctx, (u_char *)(cp + i), (u_char *)(kp + i));
193 
194 	/* Check that the key decrypted properly. */
195 	sr_crypto_calculate_check_hmac_sha1(kdfinfo.maskkey,
196 	    sizeof(kdfinfo.maskkey), keys, SR_CRYPTO_KEYBLOCK_BYTES, digest);
197 
198 	if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest))) {
199 		printf("incorrect passphrase or keydisk\n");
200 		goto done;
201 	}
202 
203 	/* Keys and keydisks will be cleared before boot and from _rtt. */
204 	bv->sbv_keys = keys;
205 	bv->sbv_maskkey = alloc(sizeof(kdfinfo.maskkey));
206 	bcopy(&kdfinfo.maskkey, bv->sbv_maskkey, sizeof(kdfinfo.maskkey));
207 
208 	rv = 0;
209 
210 done:
211 	explicit_bzero(passphrase, PASSPHRASE_LENGTH);
212 	explicit_bzero(&kdfinfo, sizeof(kdfinfo));
213 	explicit_bzero(digest, sizeof(digest));
214 
215 	if (keys != NULL && rv != 0) {
216 		explicit_bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
217 		free(keys, SR_CRYPTO_KEYBLOCK_BYTES);
218 	}
219 
220 	return (rv);
221 }
222