diff options
Diffstat (limited to 'src/rs256.c')
-rw-r--r-- | src/rs256.c | 204 |
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 | ||
17 | static int | ||
18 | RSA_bits(const RSA *r) | ||
19 | { | ||
20 | return (BN_num_bits(r->n)); | ||
21 | } | ||
22 | |||
23 | static int | ||
24 | RSA_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 | |||
33 | static void | ||
34 | RSA_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 | |||
42 | static int | ||
43 | decode_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 | |||
57 | static int | ||
58 | decode_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 | |||
76 | int | ||
77 | rs256_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 | |||
89 | rs256_pk_t * | ||
90 | rs256_pk_new(void) | ||
91 | { | ||
92 | return (calloc(1, sizeof(rs256_pk_t))); | ||
93 | } | ||
94 | |||
95 | void | ||
96 | rs256_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 | |||
109 | int | ||
110 | rs256_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 | |||
120 | EVP_PKEY * | ||
121 | rs256_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; | ||
156 | fail: | ||
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 | |||
171 | int | ||
172 | rs256_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 | } | ||