1 /* 2 * Copyright (c) 2018 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 */ 6 7 #include <openssl/evp.h> 8 #include <openssl/sha.h> 9 10 #include "fido.h" 11 #include "fido/es256.h" 12 13 static int 14 do_ecdh(const es256_sk_t *sk, const es256_pk_t *pk, fido_blob_t **ecdh) 15 { 16 EVP_PKEY *pk_evp = NULL; 17 EVP_PKEY *sk_evp = NULL; 18 EVP_PKEY_CTX *ctx = NULL; 19 fido_blob_t *secret = NULL; 20 int ok = -1; 21 22 *ecdh = NULL; 23 24 /* allocate blobs for secret & ecdh */ 25 if ((secret = fido_blob_new()) == NULL || 26 (*ecdh = fido_blob_new()) == NULL) 27 goto fail; 28 29 /* wrap the keys as openssl objects */ 30 if ((pk_evp = es256_pk_to_EVP_PKEY(pk)) == NULL || 31 (sk_evp = es256_sk_to_EVP_PKEY(sk)) == NULL) { 32 log_debug("%s: es256_to_EVP_PKEY", __func__); 33 goto fail; 34 } 35 36 /* set ecdh parameters */ 37 if ((ctx = EVP_PKEY_CTX_new(sk_evp, NULL)) == NULL || 38 EVP_PKEY_derive_init(ctx) <= 0 || 39 EVP_PKEY_derive_set_peer(ctx, pk_evp) <= 0) { 40 log_debug("%s: EVP_PKEY_derive_init", __func__); 41 goto fail; 42 } 43 44 /* perform ecdh */ 45 if (EVP_PKEY_derive(ctx, NULL, &secret->len) <= 0 || 46 (secret->ptr = calloc(1, secret->len)) == NULL || 47 EVP_PKEY_derive(ctx, secret->ptr, &secret->len) <= 0) { 48 log_debug("%s: EVP_PKEY_derive", __func__); 49 goto fail; 50 } 51 52 /* use sha256 as a kdf on the resulting secret */ 53 (*ecdh)->len = SHA256_DIGEST_LENGTH; 54 if (((*ecdh)->ptr = calloc(1, (*ecdh)->len)) == NULL || 55 SHA256(secret->ptr, secret->len, (*ecdh)->ptr) != (*ecdh)->ptr) { 56 log_debug("%s: sha256", __func__); 57 goto fail; 58 } 59 60 ok = 0; 61 fail: 62 if (pk_evp != NULL) 63 EVP_PKEY_free(pk_evp); 64 if (sk_evp != NULL) 65 EVP_PKEY_free(sk_evp); 66 if (ctx != NULL) 67 EVP_PKEY_CTX_free(ctx); 68 if (ok < 0) 69 fido_blob_free(ecdh); 70 71 fido_blob_free(&secret); 72 73 return (ok); 74 } 75 76 int 77 fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh) 78 { 79 es256_sk_t *sk = NULL; /* our private key */ 80 es256_pk_t *ak = NULL; /* authenticator's public key */ 81 int r; 82 83 *pk = NULL; /* our public key; returned */ 84 *ecdh = NULL; /* shared ecdh secret; returned */ 85 86 if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) { 87 r = FIDO_ERR_INTERNAL; 88 goto fail; 89 } 90 91 if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) { 92 log_debug("%s: es256_derive_pk", __func__); 93 r = FIDO_ERR_INTERNAL; 94 goto fail; 95 } 96 97 if ((ak = es256_pk_new()) == NULL || 98 fido_dev_authkey(dev, ak) != FIDO_OK) { 99 log_debug("%s: fido_dev_authkey", __func__); 100 r = FIDO_ERR_INTERNAL; 101 goto fail; 102 } 103 104 if (do_ecdh(sk, ak, ecdh) < 0) { 105 log_debug("%s: do_ecdh", __func__); 106 r = FIDO_ERR_INTERNAL; 107 goto fail; 108 } 109 110 r = FIDO_OK; 111 fail: 112 es256_sk_free(&sk); 113 es256_pk_free(&ak); 114 115 if (r != FIDO_OK) { 116 es256_pk_free(pk); 117 fido_blob_free(ecdh); 118 } 119 120 return (r); 121 } 122