Coverage Report

Created: 2025-03-01 02:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/libfido2/src/rs256.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2018-2022 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
 * SPDX-License-Identifier: BSD-2-Clause
6
 */
7
8
#include <openssl/bn.h>
9
#include <openssl/rsa.h>
10
#include <openssl/obj_mac.h>
11
12
#include "fido.h"
13
#include "fido/rs256.h"
14
15
#if OPENSSL_VERSION_NUMBER >= 0x30000000
16
288
#define get0_RSA(x)     EVP_PKEY_get0_RSA((x))
17
#else
18
#define get0_RSA(x)     EVP_PKEY_get0((x))
19
#endif
20
21
#if defined(__GNUC__)
22
#define PRAGMA(s) _Pragma(s)
23
#else
24
#define PRAGMA(s)
25
#endif
26
27
static EVP_MD *
28
rs256_get_EVP_MD(void)
29
177
{
30
177
PRAGMA("GCC diagnostic push")
31
177
PRAGMA("GCC diagnostic ignored \"-Wcast-qual\"")
32
177
        return ((EVP_MD *)EVP_sha256());
33
177
PRAGMA("GCC diagnostic pop")
34
177
}
35
36
static int
37
decode_bignum(const cbor_item_t *item, void *ptr, size_t len)
38
692
{
39
692
        if (cbor_isa_bytestring(item) == false ||
40
692
            cbor_bytestring_is_definite(item) == false ||
41
692
            cbor_bytestring_length(item) != len) {
42
36
                fido_log_debug("%s: cbor type", __func__);
43
36
                return (-1);
44
36
        }
45
46
656
        memcpy(ptr, cbor_bytestring_handle(item), len);
47
48
656
        return (0);
49
692
}
50
51
static int
52
decode_rsa_pubkey(const cbor_item_t *key, const cbor_item_t *val, void *arg)
53
2.11k
{
54
2.11k
        rs256_pk_t *k = arg;
55
56
2.11k
        if (cbor_isa_negint(key) == false ||
57
2.11k
            cbor_int_get_width(key) != CBOR_INT_8)
58
1.29k
                return (0); /* ignore */
59
60
819
        switch (cbor_get_uint8(key)) {
61
360
        case 0: /* modulus */
62
360
                return (decode_bignum(val, &k->n, sizeof(k->n)));
63
332
        case 1: /* public exponent */
64
332
                return (decode_bignum(val, &k->e, sizeof(k->e)));
65
819
        }
66
67
127
        return (0); /* ignore */
68
819
}
69
70
int
71
rs256_pk_decode(const cbor_item_t *item, rs256_pk_t *k)
72
560
{
73
560
        if (cbor_isa_map(item) == false ||
74
560
            cbor_map_is_definite(item) == false ||
75
560
            cbor_map_iter(item, k, decode_rsa_pubkey) < 0) {
76
56
                fido_log_debug("%s: cbor type", __func__);
77
56
                return (-1);
78
56
        }
79
80
504
        return (0);
81
560
}
82
83
rs256_pk_t *
84
rs256_pk_new(void)
85
3.09k
{
86
3.09k
        return (calloc(1, sizeof(rs256_pk_t)));
87
3.09k
}
88
89
void
90
rs256_pk_free(rs256_pk_t **pkp)
91
13.9k
{
92
13.9k
        rs256_pk_t *pk;
93
94
13.9k
        if (pkp == NULL || (pk = *pkp) == NULL)
95
10.8k
                return;
96
97
3.07k
        freezero(pk, sizeof(*pk));
98
3.07k
        *pkp = NULL;
99
3.07k
}
100
101
int
102
rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len)
103
2.78k
{
104
2.78k
        EVP_PKEY *pkey;
105
106
2.78k
        if (len < sizeof(*pk))
107
2.24k
                return (FIDO_ERR_INVALID_ARGUMENT);
108
109
541
        memcpy(pk, ptr, sizeof(*pk));
110
111
541
        if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
112
246
                fido_log_debug("%s: rs256_pk_to_EVP_PKEY", __func__);
113
246
                return (FIDO_ERR_INVALID_ARGUMENT);
114
246
        }
115
116
295
        EVP_PKEY_free(pkey);
117
118
295
        return (FIDO_OK);
119
541
}
120
121
EVP_PKEY *
122
rs256_pk_to_EVP_PKEY(const rs256_pk_t *k)
123
3.65k
{
124
3.65k
        RSA             *rsa = NULL;
125
3.65k
        EVP_PKEY        *pkey = NULL;
126
3.65k
        BIGNUM          *n = NULL;
127
3.65k
        BIGNUM          *e = NULL;
128
3.65k
        int              ok = -1;
129
130
3.65k
        if ((n = BN_new()) == NULL || (e = BN_new()) == NULL)
131
82
                goto fail;
132
133
3.57k
        if (BN_bin2bn(k->n, sizeof(k->n), n) == NULL ||
134
3.57k
            BN_bin2bn(k->e, sizeof(k->e), e) == NULL) {
135
147
                fido_log_debug("%s: BN_bin2bn", __func__);
136
147
                goto fail;
137
147
        }
138
139
3.42k
        if ((rsa = RSA_new()) == NULL || RSA_set0_key(rsa, n, e, NULL) == 0) {
140
78
                fido_log_debug("%s: RSA_set0_key", __func__);
141
78
                goto fail;
142
78
        }
143
144
        /* at this point, n and e belong to rsa */
145
3.35k
        n = NULL;
146
3.35k
        e = NULL;
147
148
3.35k
        if (RSA_bits(rsa) != 2048) {
149
2.55k
                fido_log_debug("%s: invalid key length", __func__);
150
2.55k
                goto fail;
151
2.55k
        }
152
153
799
        if ((pkey = EVP_PKEY_new()) == NULL ||
154
799
            EVP_PKEY_assign_RSA(pkey, rsa) == 0) {
155
35
                fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__);
156
35
                goto fail;
157
35
        }
158
159
764
        rsa = NULL; /* at this point, rsa belongs to evp */
160
161
764
        ok = 0;
162
3.65k
fail:
163
3.65k
        if (n != NULL)
164
277
                BN_free(n);
165
3.65k
        if (e != NULL)
166
225
                BN_free(e);
167
3.65k
        if (rsa != NULL)
168
2.63k
                RSA_free(rsa);
169
3.65k
        if (ok < 0 && pkey != NULL) {
170
21
                EVP_PKEY_free(pkey);
171
21
                pkey = NULL;
172
21
        }
173
174
3.65k
        return (pkey);
175
764
}
176
177
int
178
rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa)
179
283
{
180
283
        const BIGNUM    *n = NULL;
181
283
        const BIGNUM    *e = NULL;
182
283
        const BIGNUM    *d = NULL;
183
283
        int              k;
184
185
283
        if (RSA_bits(rsa) != 2048) {
186
0
                fido_log_debug("%s: invalid key length", __func__);
187
0
                return (FIDO_ERR_INVALID_ARGUMENT);
188
0
        }
189
190
283
        RSA_get0_key(rsa, &n, &e, &d);
191
192
283
        if (n == NULL || e == NULL) {
193
0
                fido_log_debug("%s: RSA_get0_key", __func__);
194
0
                return (FIDO_ERR_INTERNAL);
195
0
        }
196
197
283
        if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) ||
198
283
            (k = BN_num_bytes(e)) < 0 || (size_t)k > sizeof(pk->e)) {
199
0
                fido_log_debug("%s: invalid key", __func__);
200
0
                return (FIDO_ERR_INTERNAL);
201
0
        }
202
203
283
        if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) ||
204
283
            (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) {
205
10
                fido_log_debug("%s: BN_bn2bin", __func__);
206
10
                return (FIDO_ERR_INTERNAL);
207
10
        }
208
209
273
        return (FIDO_OK);
210
283
}
211
212
int
213
rs256_pk_from_EVP_PKEY(rs256_pk_t *pk, const EVP_PKEY *pkey)
214
288
{
215
288
        const RSA *rsa;
216
217
288
        if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA ||
218
288
            (rsa = get0_RSA(pkey)) == NULL)
219
5
                return (FIDO_ERR_INVALID_ARGUMENT);
220
221
283
        return (rs256_pk_from_RSA(pk, rsa));
222
288
}
223
224
int
225
rs256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
226
    const fido_blob_t *sig)
227
181
{
228
181
        EVP_PKEY_CTX    *pctx = NULL;
229
181
        EVP_MD          *md = NULL;
230
181
        int              ok = -1;
231
232
181
        if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) {
233
4
                fido_log_debug("%s: EVP_PKEY_base_id", __func__);
234
4
                goto fail;
235
4
        }
236
237
177
        if ((md = rs256_get_EVP_MD()) == NULL) {
238
6
                fido_log_debug("%s: rs256_get_EVP_MD", __func__);
239
6
                goto fail;
240
6
        }
241
242
171
        if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
243
171
            EVP_PKEY_verify_init(pctx) != 1 ||
244
171
            EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 ||
245
171
            EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
246
25
                fido_log_debug("%s: EVP_PKEY_CTX", __func__);
247
25
                goto fail;
248
25
        }
249
250
146
        if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
251
146
            dgst->len) != 1) {
252
146
                fido_log_debug("%s: EVP_PKEY_verify", __func__);
253
146
                goto fail;
254
146
        }
255
256
0
        ok = 0;
257
181
fail:
258
181
        EVP_PKEY_CTX_free(pctx);
259
260
181
        return (ok);
261
0
}
262
263
int
264
rs256_pk_verify_sig(const fido_blob_t *dgst, const rs256_pk_t *pk,
265
    const fido_blob_t *sig)
266
327
{
267
327
        EVP_PKEY        *pkey;
268
327
        int              ok = -1;
269
270
327
        if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
271
327
            rs256_verify_sig(dgst, pkey, sig) < 0) {
272
327
                fido_log_debug("%s: rs256_verify_sig", __func__);
273
327
                goto fail;
274
327
        }
275
276
0
        ok = 0;
277
327
fail:
278
327
        EVP_PKEY_free(pkey);
279
280
327
        return (ok);
281
0
}