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