xref: /freebsd/contrib/libfido2/src/rs256.c (revision 3332f1b444d4a73238e9f59cca27bfc95fe936bd)
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/bn.h>
8 #include <openssl/rsa.h>
9 #include <openssl/obj_mac.h>
10 
11 #include "fido.h"
12 #include "fido/rs256.h"
13 
14 #if OPENSSL_VERSION_NUMBER < 0x10100000L
15 static int
16 RSA_bits(const RSA *r)
17 {
18 	return (BN_num_bits(r->n));
19 }
20 
21 static int
22 RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
23 {
24 	r->n = n;
25 	r->e = e;
26 	r->d = d;
27 
28 	return (1);
29 }
30 
31 static void
32 RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
33 {
34 	*n = r->n;
35 	*e = r->e;
36 	*d = r->d;
37 }
38 #endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
39 
40 static int
41 decode_bignum(const cbor_item_t *item, void *ptr, size_t len)
42 {
43 	if (cbor_isa_bytestring(item) == false ||
44 	    cbor_bytestring_is_definite(item) == false ||
45 	    cbor_bytestring_length(item) != len) {
46 		fido_log_debug("%s: cbor type", __func__);
47 		return (-1);
48 	}
49 
50 	memcpy(ptr, cbor_bytestring_handle(item), len);
51 
52 	return (0);
53 }
54 
55 static int
56 decode_rsa_pubkey(const cbor_item_t *key, const cbor_item_t *val, void *arg)
57 {
58 	rs256_pk_t *k = arg;
59 
60 	if (cbor_isa_negint(key) == false ||
61 	    cbor_int_get_width(key) != CBOR_INT_8)
62 		return (0); /* ignore */
63 
64 	switch (cbor_get_uint8(key)) {
65 	case 0: /* modulus */
66 		return (decode_bignum(val, &k->n, sizeof(k->n)));
67 	case 1: /* public exponent */
68 		return (decode_bignum(val, &k->e, sizeof(k->e)));
69 	}
70 
71 	return (0); /* ignore */
72 }
73 
74 int
75 rs256_pk_decode(const cbor_item_t *item, rs256_pk_t *k)
76 {
77 	if (cbor_isa_map(item) == false ||
78 	    cbor_map_is_definite(item) == false ||
79 	    cbor_map_iter(item, k, decode_rsa_pubkey) < 0) {
80 		fido_log_debug("%s: cbor type", __func__);
81 		return (-1);
82 	}
83 
84 	return (0);
85 }
86 
87 rs256_pk_t *
88 rs256_pk_new(void)
89 {
90 	return (calloc(1, sizeof(rs256_pk_t)));
91 }
92 
93 void
94 rs256_pk_free(rs256_pk_t **pkp)
95 {
96 	rs256_pk_t *pk;
97 
98 	if (pkp == NULL || (pk = *pkp) == NULL)
99 		return;
100 
101 	freezero(pk, sizeof(*pk));
102 	*pkp = NULL;
103 }
104 
105 int
106 rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len)
107 {
108 	if (len < sizeof(*pk))
109 		return (FIDO_ERR_INVALID_ARGUMENT);
110 
111 	memcpy(pk, ptr, sizeof(*pk));
112 
113 	return (FIDO_OK);
114 }
115 
116 EVP_PKEY *
117 rs256_pk_to_EVP_PKEY(const rs256_pk_t *k)
118 {
119 	RSA		*rsa = NULL;
120 	EVP_PKEY	*pkey = NULL;
121 	BIGNUM		*n = NULL;
122 	BIGNUM		*e = NULL;
123 	int		 ok = -1;
124 
125 	if ((n = BN_new()) == NULL || (e = BN_new()) == NULL)
126 		goto fail;
127 
128 	if (BN_bin2bn(k->n, sizeof(k->n), n) == NULL ||
129 	    BN_bin2bn(k->e, sizeof(k->e), e) == NULL) {
130 		fido_log_debug("%s: BN_bin2bn", __func__);
131 		goto fail;
132 	}
133 
134 	if ((rsa = RSA_new()) == NULL || RSA_set0_key(rsa, n, e, NULL) == 0) {
135 		fido_log_debug("%s: RSA_set0_key", __func__);
136 		goto fail;
137 	}
138 
139 	/* at this point, n and e belong to rsa */
140 	n = NULL;
141 	e = NULL;
142 
143 	if ((pkey = EVP_PKEY_new()) == NULL ||
144 	    EVP_PKEY_assign_RSA(pkey, rsa) == 0) {
145 		fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__);
146 		goto fail;
147 	}
148 
149 	rsa = NULL; /* at this point, rsa belongs to evp */
150 
151 	ok = 0;
152 fail:
153 	if (n != NULL)
154 		BN_free(n);
155 	if (e != NULL)
156 		BN_free(e);
157 	if (rsa != NULL)
158 		RSA_free(rsa);
159 	if (ok < 0 && pkey != NULL) {
160 		EVP_PKEY_free(pkey);
161 		pkey = NULL;
162 	}
163 
164 	return (pkey);
165 }
166 
167 int
168 rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa)
169 {
170 	const BIGNUM	*n = NULL;
171 	const BIGNUM	*e = NULL;
172 	const BIGNUM	*d = NULL;
173 	int		 k;
174 
175 	if (RSA_bits(rsa) != 2048) {
176 		fido_log_debug("%s: invalid key length", __func__);
177 		return (FIDO_ERR_INVALID_ARGUMENT);
178 	}
179 
180 	RSA_get0_key(rsa, &n, &e, &d);
181 
182 	if (n == NULL || e == NULL) {
183 		fido_log_debug("%s: RSA_get0_key", __func__);
184 		return (FIDO_ERR_INTERNAL);
185 	}
186 
187 	if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) ||
188 	    (k = BN_num_bytes(e)) < 0 || (size_t)k > sizeof(pk->e)) {
189 		fido_log_debug("%s: invalid key", __func__);
190 		return (FIDO_ERR_INTERNAL);
191 	}
192 
193 	if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) ||
194 	    (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) {
195 		fido_log_debug("%s: BN_bn2bin", __func__);
196 		return (FIDO_ERR_INTERNAL);
197 	}
198 
199 	return (FIDO_OK);
200 }
201