| Line | Count | Source | 
| 1 |  | /* | 
| 2 |  |  * Copyright (c) 2018-2021 Yubico AB. All rights reserved. | 
| 3 |  |  * Use of this source code is governed by a BSD-style | 
| 4 |  |  * license that can be found in the LICENSE file. | 
| 5 |  |  * SPDX-License-Identifier: BSD-2-Clause | 
| 6 |  |  */ | 
| 7 |  |  | 
| 8 |  | #include <openssl/evp.h> | 
| 9 |  | #include <openssl/sha.h> | 
| 10 |  | #if defined(LIBRESSL_VERSION_NUMBER) | 
| 11 |  | #include <openssl/hkdf.h> | 
| 12 |  | #else | 
| 13 |  | #include <openssl/kdf.h> | 
| 14 |  | #endif | 
| 15 |  |  | 
| 16 |  | #include "fido.h" | 
| 17 |  | #include "fido/es256.h" | 
| 18 |  |  | 
| 19 |  | #if defined(LIBRESSL_VERSION_NUMBER) | 
| 20 |  | static int | 
| 21 |  | hkdf_sha256(uint8_t *key, const char *info, const fido_blob_t *secret) | 
| 22 |  | { | 
| 23 |  |         const EVP_MD *md; | 
| 24 |  |         uint8_t salt[32]; | 
| 25 |  |  | 
| 26 |  |         memset(salt, 0, sizeof(salt)); | 
| 27 |  |         if ((md = EVP_sha256()) == NULL || | 
| 28 |  |             HKDF(key, SHA256_DIGEST_LENGTH, md, secret->ptr, secret->len, salt, | 
| 29 |  |             sizeof(salt), (const uint8_t *)info, strlen(info)) != 1) | 
| 30 |  |                 return -1; | 
| 31 |  |  | 
| 32 |  |         return 0; | 
| 33 |  | } | 
| 34 |  | #else | 
| 35 |  | static int | 
| 36 |  | hkdf_sha256(uint8_t *key, char *info, fido_blob_t *secret) | 
| 37 | 7.13k | { | 
| 38 | 7.13k |         const EVP_MD *const_md; | 
| 39 | 7.13k |         EVP_MD *md = NULL; | 
| 40 | 7.13k |         EVP_PKEY_CTX *ctx = NULL; | 
| 41 | 7.13k |         size_t keylen = SHA256_DIGEST_LENGTH; | 
| 42 | 7.13k |         uint8_t salt[32]; | 
| 43 | 7.13k |         int ok = -1; | 
| 44 |  |  | 
| 45 | 7.13k |         memset(salt, 0, sizeof(salt)); | 
| 46 | 7.13k |         if (secret->len > INT_MAX || strlen(info) > INT_MAX) { | 
| 47 | 0 |                 fido_log_debug("%s: invalid param", __func__); | 
| 48 | 0 |                 goto fail; | 
| 49 | 0 |         } | 
| 50 | 7.13k |         if ((const_md = EVP_sha256()) == NULL || | 
| 51 | 7.13k |             (md = EVP_MD_meth_dup(const_md)) == NULL || | 
| 52 | 7.13k |             (ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL)) == NULL) { | 
| 53 | 156 |                 fido_log_debug("%s: init", __func__); | 
| 54 | 156 |                 goto fail; | 
| 55 | 156 |         } | 
| 56 | 6.97k |         if (EVP_PKEY_derive_init(ctx) < 1 || | 
| 57 | 6.97k |             EVP_PKEY_CTX_set_hkdf_md(ctx, md) < 1 || | 
| 58 | 6.97k |             EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt, sizeof(salt)) < 1 || | 
| 59 | 6.97k |             EVP_PKEY_CTX_set1_hkdf_key(ctx, secret->ptr, (int)secret->len) < 1 || | 
| 60 | 6.97k |             EVP_PKEY_CTX_add1_hkdf_info(ctx, (void *)info, (int)strlen(info)) < 1) { | 
| 61 | 94 |                 fido_log_debug("%s: EVP_PKEY_CTX", __func__); | 
| 62 | 94 |                 goto fail; | 
| 63 | 94 |         } | 
| 64 | 6.88k |         if (EVP_PKEY_derive(ctx, key, &keylen) < 1) { | 
| 65 | 120 |                 fido_log_debug("%s: EVP_PKEY_derive", __func__); | 
| 66 | 120 |                 goto fail; | 
| 67 | 120 |         } | 
| 68 |  |  | 
| 69 | 6.76k |         ok = 0; | 
| 70 | 7.13k | fail: | 
| 71 | 7.13k |         if (md != NULL) | 
| 72 | 7.06k |                 EVP_MD_meth_free(md); | 
| 73 | 7.13k |         if (ctx != NULL) | 
| 74 | 6.97k |                 EVP_PKEY_CTX_free(ctx); | 
| 75 |  |  | 
| 76 | 7.13k |         return ok; | 
| 77 | 6.76k | } | 
| 78 |  | #endif /* defined(LIBRESSL_VERSION_NUMBER) */ | 
| 79 |  |  | 
| 80 |  | static int | 
| 81 |  | kdf(uint8_t prot, fido_blob_t *key, /* const */ fido_blob_t *secret) | 
| 82 | 22.6k | { | 
| 83 | 22.6k |         char hmac_info[] = "CTAP2 HMAC key"; /* const */ | 
| 84 | 22.6k |         char aes_info[] = "CTAP2 AES key"; /* const */ | 
| 85 |  |  | 
| 86 | 22.6k |         switch (prot) { | 
| 87 | 18.9k |         case CTAP_PIN_PROTOCOL1: | 
| 88 |  |                 /* use sha256 on the resulting secret */ | 
| 89 | 18.9k |                 key->len = SHA256_DIGEST_LENGTH; | 
| 90 | 18.9k |                 if ((key->ptr = calloc(1, key->len)) == NULL || | 
| 91 | 18.9k |                     SHA256(secret->ptr, secret->len, key->ptr) != key->ptr) { | 
| 92 | 98 |                         fido_log_debug("%s: SHA256", __func__); | 
| 93 | 98 |                         return -1; | 
| 94 | 98 |                 } | 
| 95 | 18.8k |                 break; | 
| 96 | 18.8k |         case CTAP_PIN_PROTOCOL2: | 
| 97 |  |                 /* use two instances of hkdf-sha256 on the resulting secret */ | 
| 98 | 3.71k |                 key->len = 2 * SHA256_DIGEST_LENGTH; | 
| 99 | 3.71k |                 if ((key->ptr = calloc(1, key->len)) == NULL || | 
| 100 | 3.71k |                     hkdf_sha256(key->ptr, hmac_info, secret) < 0 || | 
| 101 | 3.71k |                     hkdf_sha256(key->ptr + SHA256_DIGEST_LENGTH, aes_info, | 
| 102 | 3.48k |                     secret) < 0) { | 
| 103 | 432 |                         fido_log_debug("%s: hkdf", __func__); | 
| 104 | 432 |                         return -1; | 
| 105 | 432 |                 } | 
| 106 | 3.28k |                 break; | 
| 107 | 3.28k |         default: | 
| 108 | 0 |                 fido_log_debug("%s: unknown pin protocol %u", __func__, prot); | 
| 109 | 0 |                 return -1; | 
| 110 | 22.6k |         } | 
| 111 |  |  | 
| 112 | 22.1k |         return 0; | 
| 113 | 22.6k | } | 
| 114 |  |  | 
| 115 |  | static int | 
| 116 |  | do_ecdh(const fido_dev_t *dev, const es256_sk_t *sk, const es256_pk_t *pk, | 
| 117 |  |     fido_blob_t **ecdh) | 
| 118 | 28.0k | { | 
| 119 | 28.0k |         EVP_PKEY *pk_evp = NULL; | 
| 120 | 28.0k |         EVP_PKEY *sk_evp = NULL; | 
| 121 | 28.0k |         EVP_PKEY_CTX *ctx = NULL; | 
| 122 | 28.0k |         fido_blob_t *secret = NULL; | 
| 123 | 28.0k |         int ok = -1; | 
| 124 |  |  | 
| 125 | 28.0k |         *ecdh = NULL; | 
| 126 | 28.0k |         if ((secret = fido_blob_new()) == NULL || | 
| 127 | 28.0k |             (*ecdh = fido_blob_new()) == NULL) | 
| 128 | 123 |                 goto fail; | 
| 129 | 27.9k |         if ((pk_evp = es256_pk_to_EVP_PKEY(pk)) == NULL || | 
| 130 | 27.9k |             (sk_evp = es256_sk_to_EVP_PKEY(sk)) == NULL) { | 
| 131 | 4.63k |                 fido_log_debug("%s: es256_to_EVP_PKEY", __func__); | 
| 132 | 4.63k |                 goto fail; | 
| 133 | 4.63k |         } | 
| 134 | 23.3k |         if ((ctx = EVP_PKEY_CTX_new(sk_evp, NULL)) == NULL || | 
| 135 | 23.3k |             EVP_PKEY_derive_init(ctx) <= 0 || | 
| 136 | 23.3k |             EVP_PKEY_derive_set_peer(ctx, pk_evp) <= 0) { | 
| 137 | 358 |                 fido_log_debug("%s: EVP_PKEY_derive_init", __func__); | 
| 138 | 358 |                 goto fail; | 
| 139 | 358 |         } | 
| 140 | 22.9k |         if (EVP_PKEY_derive(ctx, NULL, &secret->len) <= 0 || | 
| 141 | 22.9k |             (secret->ptr = calloc(1, secret->len)) == NULL || | 
| 142 | 22.9k |             EVP_PKEY_derive(ctx, secret->ptr, &secret->len) <= 0) { | 
| 143 | 281 |                 fido_log_debug("%s: EVP_PKEY_derive", __func__); | 
| 144 | 281 |                 goto fail; | 
| 145 | 281 |         } | 
| 146 | 22.6k |         if (kdf(fido_dev_get_pin_protocol(dev), *ecdh, secret) < 0) { | 
| 147 | 530 |                 fido_log_debug("%s: kdf", __func__); | 
| 148 | 530 |                 goto fail; | 
| 149 | 530 |         } | 
| 150 |  |  | 
| 151 | 22.1k |         ok = 0; | 
| 152 | 28.0k | fail: | 
| 153 | 28.0k |         if (pk_evp != NULL) | 
| 154 | 23.7k |                 EVP_PKEY_free(pk_evp); | 
| 155 | 28.0k |         if (sk_evp != NULL) | 
| 156 | 23.3k |                 EVP_PKEY_free(sk_evp); | 
| 157 | 28.0k |         if (ctx != NULL) | 
| 158 | 23.2k |                 EVP_PKEY_CTX_free(ctx); | 
| 159 | 28.0k |         if (ok < 0) | 
| 160 | 5.92k |                 fido_blob_free(ecdh); | 
| 161 |  |  | 
| 162 | 28.0k |         fido_blob_free(&secret); | 
| 163 |  |  | 
| 164 | 28.0k |         return ok; | 
| 165 | 22.1k | } | 
| 166 |  |  | 
| 167 |  | int | 
| 168 |  | fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh, int *ms) | 
| 169 | 112k | { | 
| 170 | 112k |         es256_sk_t *sk = NULL; /* our private key */ | 
| 171 | 112k |         es256_pk_t *ak = NULL; /* authenticator's public key */ | 
| 172 | 112k |         int r; | 
| 173 |  |  | 
| 174 | 112k |         *pk = NULL; | 
| 175 | 112k |         *ecdh = NULL; | 
| 176 | 112k |         if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) { | 
| 177 | 879 |                 r = FIDO_ERR_INTERNAL; | 
| 178 | 879 |                 goto fail; | 
| 179 | 879 |         } | 
| 180 | 111k |         if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) { | 
| 181 | 8.67k |                 fido_log_debug("%s: es256_derive_pk", __func__); | 
| 182 | 8.67k |                 r = FIDO_ERR_INTERNAL; | 
| 183 | 8.67k |                 goto fail; | 
| 184 | 8.67k |         } | 
| 185 | 102k |         if ((ak = es256_pk_new()) == NULL || | 
| 186 | 102k |             fido_dev_authkey(dev, ak, ms) != FIDO_OK) { | 
| 187 | 74.5k |                 fido_log_debug("%s: fido_dev_authkey", __func__); | 
| 188 | 74.5k |                 r = FIDO_ERR_INTERNAL; | 
| 189 | 74.5k |                 goto fail; | 
| 190 | 74.5k |         } | 
| 191 | 28.0k |         if (do_ecdh(dev, sk, ak, ecdh) < 0) { | 
| 192 | 5.92k |                 fido_log_debug("%s: do_ecdh", __func__); | 
| 193 | 5.92k |                 r = FIDO_ERR_INTERNAL; | 
| 194 | 5.92k |                 goto fail; | 
| 195 | 5.92k |         } | 
| 196 |  |  | 
| 197 | 22.1k |         r = FIDO_OK; | 
| 198 | 112k | fail: | 
| 199 | 112k |         es256_sk_free(&sk); | 
| 200 | 112k |         es256_pk_free(&ak); | 
| 201 |  |  | 
| 202 | 112k |         if (r != FIDO_OK) { | 
| 203 | 90.0k |                 es256_pk_free(pk); | 
| 204 | 90.0k |                 fido_blob_free(ecdh); | 
| 205 | 90.0k |         } | 
| 206 |  |  | 
| 207 | 112k |         return r; | 
| 208 | 22.1k | } |