summaryrefslogtreecommitdiffstats
path: root/sys/lib/libsa/softraid.c
diff options
context:
space:
mode:
authorjsing <jsing@openbsd.org>2018-08-10 16:41:35 +0000
committerjsing <jsing@openbsd.org>2018-08-10 16:41:35 +0000
commit27bea9a3c7fdba43cfa7c5fb6f268efe98f7720b (patch)
tree1da260d940b6c8ce23eab4507a7d3b21838c9371 /sys/lib/libsa/softraid.c
parentRun the wycheproof ECDSA test vectors against libcrypto. (diff)
downloadwireguard-openbsd-27bea9a3c7fdba43cfa7c5fb6f268efe98f7720b.tar.xz
wireguard-openbsd-27bea9a3c7fdba43cfa7c5fb6f268efe98f7720b.zip
Retry on incorrect passphrase for softraid crypto boot.
Historically, the softraid crypto support in the boot loaders has only given one attempt to provide the correct passphrase. There were a few reasons for this, including the fact that pkcs5_pbkdf2() allows an empty passphrase and that returning EPERM allowed for another attempt. With the event of KARL and the need for bsd.booted with hibernate resumption, this becomes much more of an issue - if you get the passphrase wrong you fail to resume. There are also other situations like using /etc/boot.conf to switch serial console, but an incorrect passphrase results in the config not being read. Also, bcrypt_pbkdf() does not permit empty passphrases. This reworks the softraid crypto support in the boot loaders so that it loops requesting a valid passphrase until one is provided, or an empty passphrase is entered (at which point it will abort). ok mortimer@ tb@
Diffstat (limited to 'sys/lib/libsa/softraid.c')
-rw-r--r--sys/lib/libsa/softraid.c190
1 files changed, 120 insertions, 70 deletions
diff --git a/sys/lib/libsa/softraid.c b/sys/lib/libsa/softraid.c
index 84824038de7..41e964f879e 100644
--- a/sys/lib/libsa/softraid.c
+++ b/sys/lib/libsa/softraid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: softraid.c,v 1.3 2017/11/10 16:50:59 sunil Exp $ */
+/* $OpenBSD: softraid.c,v 1.4 2018/08/10 16:41:35 jsing Exp $ */
/*
* Copyright (c) 2012 Joel Sing <jsing@openbsd.org>
@@ -107,66 +107,54 @@ sr_crypto_calculate_check_hmac_sha1(u_int8_t *maskkey, int maskkey_size,
explicit_bzero(&shactx, sizeof(shactx));
}
-int
-sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
+static int
+sr_crypto_decrypt_keys(struct sr_meta_crypto *cm,
+ struct sr_crypto_kdfinfo *kdfinfo, u_int8_t *kp)
{
- struct sr_meta_crypto *cm;
- struct sr_boot_keydisk *kd;
- struct sr_meta_opt_item *omi;
- struct sr_crypto_pbkdf *kdfhint;
- struct sr_crypto_kdfinfo kdfinfo;
- char passphrase[PASSPHRASE_LENGTH];
u_int8_t digest[SHA1_DIGEST_LENGTH];
- u_int8_t *keys = NULL;
- u_int8_t *kp, *cp;
rijndael_ctx ctx;
- u_int32_t type;
+ u_int8_t *cp;
int rv = -1;
- int c, i;
+ int i;
- SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link)
- if (omi->omi_som->som_type == SR_OPT_CRYPTO)
- break;
-
- if (omi == NULL) {
- printf("Crypto metadata not found!\n");
+ if (rijndael_set_key(&ctx, kdfinfo->maskkey, 256) != 0)
goto done;
- }
- cm = (struct sr_meta_crypto *)omi->omi_som;
- kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint;
+ cp = (u_int8_t *)cm->scm_key;
+ for (i = 0; i < SR_CRYPTO_KEYBLOCK_BYTES; i += RIJNDAEL128_BLOCK_LEN)
+ rijndael_decrypt(&ctx, (u_char *)(cp + i), (u_char *)(kp + i));
- switch (cm->scm_mask_alg) {
- case SR_CRYPTOM_AES_ECB_256:
- break;
- default:
- printf("unsupported encryption algorithm %u\n",
- cm->scm_mask_alg);
- goto done;
- }
+ /* Check that the key decrypted properly. */
+ sr_crypto_calculate_check_hmac_sha1(kdfinfo->maskkey,
+ sizeof(kdfinfo->maskkey), kp, SR_CRYPTO_KEYBLOCK_BYTES, digest);
- SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
- if (bcmp(&kd->kd_uuid, &bv->sbv_uuid, sizeof(kd->kd_uuid)) == 0)
- break;
- }
- if (kd) {
- bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey));
- } else if (kdfhint->generic.type == SR_CRYPTOKDFT_KEYDISK) {
- printf("keydisk not found\n");
- goto done;
- } else {
- if (kdfhint->generic.type != SR_CRYPTOKDFT_PKCS5_PBKDF2 &&
- kdfhint->generic.type != SR_CRYPTOKDFT_BCRYPT_PBKDF) {
- printf("unknown KDF type %u\n", kdfhint->generic.type);
- goto done;
- }
+ if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest)) == 0)
+ rv = 0;
+
+ done:
+ explicit_bzero(digest, sizeof(digest));
+
+ return rv;
+}
+
+static int
+sr_crypto_passphrase_decrypt(struct sr_meta_crypto *cm,
+ struct sr_crypto_kdfinfo *kdfinfo, u_int8_t *kp)
+{
+ char passphrase[PASSPHRASE_LENGTH];
+ struct sr_crypto_pbkdf *kdfhint;
+ int rv = -1;
+ int c, i;
+ kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint;
+
+ for (;;) {
printf("Passphrase: ");
for (i = 0; i < PASSPHRASE_LENGTH - 1; i++) {
c = cngetc();
- if (c == '\r' || c == '\n')
+ if (c == '\r' || c == '\n') {
break;
- else if (c == '\b') {
+ } else if (c == '\b') {
i = i > 0 ? i - 2 : -1;
continue;
}
@@ -175,54 +163,118 @@ sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
passphrase[i] = 0;
printf("\n");
+ /* Abort on an empty passphrase. */
+ if (i == 0) {
+ printf("aborting...\n");
+ goto done;
+ }
+
#ifdef DEBUG
printf("Got passphrase: %s with len %d\n",
passphrase, strlen(passphrase));
#endif
- type = kdfhint->generic.type;
- if (type == SR_CRYPTOKDFT_PKCS5_PBKDF2) {
+ switch (kdfhint->generic.type) {
+ case SR_CRYPTOKDFT_PKCS5_PBKDF2:
if (pkcs5_pbkdf2(passphrase, strlen(passphrase),
kdfhint->salt, sizeof(kdfhint->salt),
- kdfinfo.maskkey, sizeof(kdfinfo.maskkey),
+ kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
kdfhint->rounds) != 0) {
printf("pkcs5_pbkdf2 failed\n");
goto done;
}
- } else if (type == SR_CRYPTOKDFT_BCRYPT_PBKDF) {
+ break;
+
+ case SR_CRYPTOKDFT_BCRYPT_PBKDF:
if (bcrypt_pbkdf(passphrase, strlen(passphrase),
kdfhint->salt, sizeof(kdfhint->salt),
- kdfinfo.maskkey, sizeof(kdfinfo.maskkey),
+ kdfinfo->maskkey, sizeof(kdfinfo->maskkey),
kdfhint->rounds) != 0) {
printf("bcrypt_pbkdf failed\n");
goto done;
}
- } else {
+ break;
+
+ default:
printf("unknown KDF type %u\n", kdfhint->generic.type);
goto done;
}
+
+ if (sr_crypto_decrypt_keys(cm, kdfinfo, kp) == 0) {
+ rv = 0;
+ goto done;
+ }
+
+ printf("incorrect passphrase\n");
}
- /* kdfinfo->maskkey now has key. */
+ done:
+ explicit_bzero(passphrase, PASSPHRASE_LENGTH);
- /* Decrypt disk keys. */
- keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES);
- bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
+ return rv;
+}
+
+int
+sr_crypto_unlock_volume(struct sr_boot_volume *bv)
+{
+ struct sr_meta_crypto *cm;
+ struct sr_boot_keydisk *kd;
+ struct sr_meta_opt_item *omi;
+ struct sr_crypto_pbkdf *kdfhint;
+ struct sr_crypto_kdfinfo kdfinfo;
+ u_int8_t *keys = NULL;
+ int rv = -1;
+
+ SLIST_FOREACH(omi, &bv->sbv_meta_opt, omi_link)
+ if (omi->omi_som->som_type == SR_OPT_CRYPTO)
+ break;
- if (rijndael_set_key(&ctx, kdfinfo.maskkey, 256) != 0)
+ if (omi == NULL) {
+ printf("crypto metadata not found!\n");
goto done;
+ }
- cp = (u_int8_t *)cm->scm_key;
- kp = keys;
- for (i = 0; i < SR_CRYPTO_KEYBLOCK_BYTES; i += RIJNDAEL128_BLOCK_LEN)
- rijndael_decrypt(&ctx, (u_char *)(cp + i), (u_char *)(kp + i));
+ cm = (struct sr_meta_crypto *)omi->omi_som;
+ kdfhint = (struct sr_crypto_pbkdf *)&cm->scm_kdfhint;
- /* Check that the key decrypted properly. */
- sr_crypto_calculate_check_hmac_sha1(kdfinfo.maskkey,
- sizeof(kdfinfo.maskkey), keys, SR_CRYPTO_KEYBLOCK_BYTES, digest);
+ switch (cm->scm_mask_alg) {
+ case SR_CRYPTOM_AES_ECB_256:
+ break;
+ default:
+ printf("unsupported encryption algorithm %u\n",
+ cm->scm_mask_alg);
+ goto done;
+ }
- if (bcmp(digest, cm->chk_hmac_sha1.sch_mac, sizeof(digest))) {
- printf("incorrect passphrase or keydisk\n");
+ keys = alloc(SR_CRYPTO_KEYBLOCK_BYTES);
+ bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);
+
+ switch (kdfhint->generic.type) {
+ case SR_CRYPTOKDFT_KEYDISK:
+ SLIST_FOREACH(kd, &sr_keydisks, kd_link) {
+ if (bcmp(&kd->kd_uuid, &bv->sbv_uuid,
+ sizeof(kd->kd_uuid)) == 0)
+ break;
+ }
+ if (kd == NULL) {
+ printf("keydisk not found\n");
+ goto done;
+ }
+ bcopy(&kd->kd_key, &kdfinfo.maskkey, sizeof(kdfinfo.maskkey));
+ if (sr_crypto_decrypt_keys(cm, &kdfinfo, keys) != 0) {
+ printf("incorrect keydisk\n");
+ goto done;
+ }
+ break;
+
+ case SR_CRYPTOKDFT_BCRYPT_PBKDF:
+ case SR_CRYPTOKDFT_PKCS5_PBKDF2:
+ if (sr_crypto_passphrase_decrypt(cm, &kdfinfo, keys) != 0)
+ goto done;
+ break;
+
+ default:
+ printf("unknown KDF type %u\n", kdfhint->generic.type);
goto done;
}
@@ -233,10 +285,8 @@ sr_crypto_decrypt_keys(struct sr_boot_volume *bv)
rv = 0;
-done:
- explicit_bzero(passphrase, PASSPHRASE_LENGTH);
+ done:
explicit_bzero(&kdfinfo, sizeof(kdfinfo));
- explicit_bzero(digest, sizeof(digest));
if (keys != NULL && rv != 0) {
explicit_bzero(keys, SR_CRYPTO_KEYBLOCK_BYTES);