1ba9bdd8bSchristos /*
2*2d40c451Schristos * Copyright (c) 2019-2021 Yubico AB. All rights reserved.
3ba9bdd8bSchristos * Use of this source code is governed by a BSD-style
4ba9bdd8bSchristos * license that can be found in the LICENSE file.
5*2d40c451Schristos * SPDX-License-Identifier: BSD-2-Clause
6ba9bdd8bSchristos */
7ba9bdd8bSchristos
8ba9bdd8bSchristos #include <openssl/bn.h>
9ba9bdd8bSchristos #include <openssl/obj_mac.h>
10ba9bdd8bSchristos
11ba9bdd8bSchristos #include "fido.h"
12ba9bdd8bSchristos #include "fido/eddsa.h"
13ba9bdd8bSchristos
14*2d40c451Schristos #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3070000f
15ba9bdd8bSchristos EVP_PKEY *
EVP_PKEY_new_raw_public_key(int type,ENGINE * e,const unsigned char * key,size_t keylen)16ba9bdd8bSchristos EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *key,
17ba9bdd8bSchristos size_t keylen)
18ba9bdd8bSchristos {
19ba9bdd8bSchristos (void)type;
20ba9bdd8bSchristos (void)e;
21ba9bdd8bSchristos (void)key;
22ba9bdd8bSchristos (void)keylen;
23ba9bdd8bSchristos
241fc1e710Schristos fido_log_debug("%s: unimplemented", __func__);
251fc1e710Schristos
26ba9bdd8bSchristos return (NULL);
27ba9bdd8bSchristos }
28ba9bdd8bSchristos
29ba9bdd8bSchristos int
EVP_PKEY_get_raw_public_key(const EVP_PKEY * pkey,unsigned char * pub,size_t * len)30ba9bdd8bSchristos EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub,
31ba9bdd8bSchristos size_t *len)
32ba9bdd8bSchristos {
33ba9bdd8bSchristos (void)pkey;
34ba9bdd8bSchristos (void)pub;
35ba9bdd8bSchristos (void)len;
36ba9bdd8bSchristos
371fc1e710Schristos fido_log_debug("%s: unimplemented", __func__);
381fc1e710Schristos
39ba9bdd8bSchristos return (0);
40ba9bdd8bSchristos }
41*2d40c451Schristos #endif /* LIBRESSL_VERSION_NUMBER */
42ba9bdd8bSchristos
43*2d40c451Schristos #if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3040000f
44ba9bdd8bSchristos int
EVP_DigestVerify(EVP_MD_CTX * ctx,const unsigned char * sigret,size_t siglen,const unsigned char * tbs,size_t tbslen)45ba9bdd8bSchristos EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen,
46ba9bdd8bSchristos const unsigned char *tbs, size_t tbslen)
47ba9bdd8bSchristos {
48ba9bdd8bSchristos (void)ctx;
49ba9bdd8bSchristos (void)sigret;
50ba9bdd8bSchristos (void)siglen;
51ba9bdd8bSchristos (void)tbs;
52ba9bdd8bSchristos (void)tbslen;
53ba9bdd8bSchristos
541fc1e710Schristos fido_log_debug("%s: unimplemented", __func__);
551fc1e710Schristos
56ba9bdd8bSchristos return (0);
57ba9bdd8bSchristos }
58*2d40c451Schristos #endif /* LIBRESSL_VERSION_NUMBER < 0x3040000f */
59ba9bdd8bSchristos
60ba9bdd8bSchristos static int
decode_coord(const cbor_item_t * item,void * xy,size_t xy_len)61ba9bdd8bSchristos decode_coord(const cbor_item_t *item, void *xy, size_t xy_len)
62ba9bdd8bSchristos {
63ba9bdd8bSchristos if (cbor_isa_bytestring(item) == false ||
64ba9bdd8bSchristos cbor_bytestring_is_definite(item) == false ||
65ba9bdd8bSchristos cbor_bytestring_length(item) != xy_len) {
66ba9bdd8bSchristos fido_log_debug("%s: cbor type", __func__);
67ba9bdd8bSchristos return (-1);
68ba9bdd8bSchristos }
69ba9bdd8bSchristos
70ba9bdd8bSchristos memcpy(xy, cbor_bytestring_handle(item), xy_len);
71ba9bdd8bSchristos
72ba9bdd8bSchristos return (0);
73ba9bdd8bSchristos }
74ba9bdd8bSchristos
75ba9bdd8bSchristos static int
decode_pubkey_point(const cbor_item_t * key,const cbor_item_t * val,void * arg)76ba9bdd8bSchristos decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg)
77ba9bdd8bSchristos {
78ba9bdd8bSchristos eddsa_pk_t *k = arg;
79ba9bdd8bSchristos
80ba9bdd8bSchristos if (cbor_isa_negint(key) == false ||
81ba9bdd8bSchristos cbor_int_get_width(key) != CBOR_INT_8)
82ba9bdd8bSchristos return (0); /* ignore */
83ba9bdd8bSchristos
84ba9bdd8bSchristos switch (cbor_get_uint8(key)) {
85ba9bdd8bSchristos case 1: /* x coordinate */
86ba9bdd8bSchristos return (decode_coord(val, &k->x, sizeof(k->x)));
87ba9bdd8bSchristos }
88ba9bdd8bSchristos
89ba9bdd8bSchristos return (0); /* ignore */
90ba9bdd8bSchristos }
91ba9bdd8bSchristos
92ba9bdd8bSchristos int
eddsa_pk_decode(const cbor_item_t * item,eddsa_pk_t * k)93ba9bdd8bSchristos eddsa_pk_decode(const cbor_item_t *item, eddsa_pk_t *k)
94ba9bdd8bSchristos {
95ba9bdd8bSchristos if (cbor_isa_map(item) == false ||
96ba9bdd8bSchristos cbor_map_is_definite(item) == false ||
97ba9bdd8bSchristos cbor_map_iter(item, k, decode_pubkey_point) < 0) {
98ba9bdd8bSchristos fido_log_debug("%s: cbor type", __func__);
99ba9bdd8bSchristos return (-1);
100ba9bdd8bSchristos }
101ba9bdd8bSchristos
102ba9bdd8bSchristos return (0);
103ba9bdd8bSchristos }
104ba9bdd8bSchristos
105ba9bdd8bSchristos eddsa_pk_t *
eddsa_pk_new(void)106ba9bdd8bSchristos eddsa_pk_new(void)
107ba9bdd8bSchristos {
108ba9bdd8bSchristos return (calloc(1, sizeof(eddsa_pk_t)));
109ba9bdd8bSchristos }
110ba9bdd8bSchristos
111ba9bdd8bSchristos void
eddsa_pk_free(eddsa_pk_t ** pkp)112ba9bdd8bSchristos eddsa_pk_free(eddsa_pk_t **pkp)
113ba9bdd8bSchristos {
114ba9bdd8bSchristos eddsa_pk_t *pk;
115ba9bdd8bSchristos
116ba9bdd8bSchristos if (pkp == NULL || (pk = *pkp) == NULL)
117ba9bdd8bSchristos return;
118ba9bdd8bSchristos
11995dbdf32Schristos freezero(pk, sizeof(*pk));
120ba9bdd8bSchristos *pkp = NULL;
121ba9bdd8bSchristos }
122ba9bdd8bSchristos
123ba9bdd8bSchristos int
eddsa_pk_from_ptr(eddsa_pk_t * pk,const void * ptr,size_t len)124ba9bdd8bSchristos eddsa_pk_from_ptr(eddsa_pk_t *pk, const void *ptr, size_t len)
125ba9bdd8bSchristos {
126*2d40c451Schristos EVP_PKEY *pkey;
127*2d40c451Schristos
128ba9bdd8bSchristos if (len < sizeof(*pk))
129ba9bdd8bSchristos return (FIDO_ERR_INVALID_ARGUMENT);
130ba9bdd8bSchristos
131ba9bdd8bSchristos memcpy(pk, ptr, sizeof(*pk));
132ba9bdd8bSchristos
133*2d40c451Schristos if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
134*2d40c451Schristos fido_log_debug("%s: eddsa_pk_to_EVP_PKEY", __func__);
135*2d40c451Schristos return (FIDO_ERR_INVALID_ARGUMENT);
136*2d40c451Schristos }
137*2d40c451Schristos
138*2d40c451Schristos EVP_PKEY_free(pkey);
139*2d40c451Schristos
140ba9bdd8bSchristos return (FIDO_OK);
141ba9bdd8bSchristos }
142ba9bdd8bSchristos
143ba9bdd8bSchristos EVP_PKEY *
eddsa_pk_to_EVP_PKEY(const eddsa_pk_t * k)144ba9bdd8bSchristos eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *k)
145ba9bdd8bSchristos {
146ba9bdd8bSchristos EVP_PKEY *pkey = NULL;
147ba9bdd8bSchristos
148ba9bdd8bSchristos if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, k->x,
149ba9bdd8bSchristos sizeof(k->x))) == NULL)
150ba9bdd8bSchristos fido_log_debug("%s: EVP_PKEY_new_raw_public_key", __func__);
151ba9bdd8bSchristos
152ba9bdd8bSchristos return (pkey);
153ba9bdd8bSchristos }
154ba9bdd8bSchristos
155ba9bdd8bSchristos int
eddsa_pk_from_EVP_PKEY(eddsa_pk_t * pk,const EVP_PKEY * pkey)156ba9bdd8bSchristos eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey)
157ba9bdd8bSchristos {
158ba9bdd8bSchristos size_t len = 0;
159ba9bdd8bSchristos
160*2d40c451Schristos if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519)
161*2d40c451Schristos return (FIDO_ERR_INVALID_ARGUMENT);
162ba9bdd8bSchristos if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 ||
163ba9bdd8bSchristos len != sizeof(pk->x))
164ba9bdd8bSchristos return (FIDO_ERR_INTERNAL);
165ba9bdd8bSchristos if (EVP_PKEY_get_raw_public_key(pkey, pk->x, &len) != 1 ||
166ba9bdd8bSchristos len != sizeof(pk->x))
167ba9bdd8bSchristos return (FIDO_ERR_INTERNAL);
168ba9bdd8bSchristos
169ba9bdd8bSchristos return (FIDO_OK);
170ba9bdd8bSchristos }
171*2d40c451Schristos
172*2d40c451Schristos int
eddsa_verify_sig(const fido_blob_t * dgst,EVP_PKEY * pkey,const fido_blob_t * sig)173*2d40c451Schristos eddsa_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
174*2d40c451Schristos const fido_blob_t *sig)
175*2d40c451Schristos {
176*2d40c451Schristos EVP_MD_CTX *mdctx = NULL;
177*2d40c451Schristos int ok = -1;
178*2d40c451Schristos
179*2d40c451Schristos if (EVP_PKEY_base_id(pkey) != EVP_PKEY_ED25519) {
180*2d40c451Schristos fido_log_debug("%s: EVP_PKEY_base_id", __func__);
181*2d40c451Schristos goto fail;
182*2d40c451Schristos }
183*2d40c451Schristos
184*2d40c451Schristos /* EVP_DigestVerify needs ints */
185*2d40c451Schristos if (dgst->len > INT_MAX || sig->len > INT_MAX) {
186*2d40c451Schristos fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
187*2d40c451Schristos dgst->len, sig->len);
188*2d40c451Schristos return (-1);
189*2d40c451Schristos }
190*2d40c451Schristos
191*2d40c451Schristos if ((mdctx = EVP_MD_CTX_new()) == NULL) {
192*2d40c451Schristos fido_log_debug("%s: EVP_MD_CTX_new", __func__);
193*2d40c451Schristos goto fail;
194*2d40c451Schristos }
195*2d40c451Schristos
196*2d40c451Schristos if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
197*2d40c451Schristos fido_log_debug("%s: EVP_DigestVerifyInit", __func__);
198*2d40c451Schristos goto fail;
199*2d40c451Schristos }
200*2d40c451Schristos
201*2d40c451Schristos if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr,
202*2d40c451Schristos dgst->len) != 1) {
203*2d40c451Schristos fido_log_debug("%s: EVP_DigestVerify", __func__);
204*2d40c451Schristos goto fail;
205*2d40c451Schristos }
206*2d40c451Schristos
207*2d40c451Schristos ok = 0;
208*2d40c451Schristos fail:
209*2d40c451Schristos EVP_MD_CTX_free(mdctx);
210*2d40c451Schristos
211*2d40c451Schristos return (ok);
212*2d40c451Schristos }
213*2d40c451Schristos
214*2d40c451Schristos int
eddsa_pk_verify_sig(const fido_blob_t * dgst,const eddsa_pk_t * pk,const fido_blob_t * sig)215*2d40c451Schristos eddsa_pk_verify_sig(const fido_blob_t *dgst, const eddsa_pk_t *pk,
216*2d40c451Schristos const fido_blob_t *sig)
217*2d40c451Schristos {
218*2d40c451Schristos EVP_PKEY *pkey;
219*2d40c451Schristos int ok = -1;
220*2d40c451Schristos
221*2d40c451Schristos if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL ||
222*2d40c451Schristos eddsa_verify_sig(dgst, pkey, sig) < 0) {
223*2d40c451Schristos fido_log_debug("%s: eddsa_verify_sig", __func__);
224*2d40c451Schristos goto fail;
225*2d40c451Schristos }
226*2d40c451Schristos
227*2d40c451Schristos ok = 0;
228*2d40c451Schristos fail:
229*2d40c451Schristos EVP_PKEY_free(pkey);
230*2d40c451Schristos
231*2d40c451Schristos return (ok);
232*2d40c451Schristos }
233