Coverage Report

Created: 2025-10-04 18:33

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
503
#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
461
{
30
461
PRAGMA("GCC diagnostic push")
31
461
PRAGMA("GCC diagnostic ignored \"-Wcast-qual\"")
32
461
        return ((EVP_MD *)EVP_sha256());
33
461
PRAGMA("GCC diagnostic pop")
34
461
}
35
36
static int
37
decode_bignum(const cbor_item_t *item, void *ptr, size_t len)
38
972
{
39
972
        if (cbor_isa_bytestring(item) == false ||
40
972
            cbor_bytestring_is_definite(item) == false ||
41
972
            cbor_bytestring_length(item) != len) {
42
36
                fido_log_debug("%s: cbor type", __func__);
43
36
                return (-1);
44
36
        }
45
46
936
        memcpy(ptr, cbor_bytestring_handle(item), len);
47
48
936
        return (0);
49
972
}
50
51
static int
52
decode_rsa_pubkey(const cbor_item_t *key, const cbor_item_t *val, void *arg)
53
2.72k
{
54
2.72k
        rs256_pk_t *k = arg;
55
56
2.72k
        if (cbor_isa_negint(key) == false ||
57
2.72k
            cbor_int_get_width(key) != CBOR_INT_8)
58
1.62k
                return (0); /* ignore */
59
60
1.10k
        switch (cbor_get_uint8(key)) {
61
503
        case 0: /* modulus */
62
503
                return (decode_bignum(val, &k->n, sizeof(k->n)));
63
469
        case 1: /* public exponent */
64
469
                return (decode_bignum(val, &k->e, sizeof(k->e)));
65
1.10k
        }
66
67
137
        return (0); /* ignore */
68
1.10k
}
69
70
int
71
rs256_pk_decode(const cbor_item_t *item, rs256_pk_t *k)
72
724
{
73
724
        if (cbor_isa_map(item) == false ||
74
724
            cbor_map_is_definite(item) == false ||
75
724
            cbor_map_iter(item, k, decode_rsa_pubkey) < 0) {
76
65
                fido_log_debug("%s: cbor type", __func__);
77
65
                return (-1);
78
65
        }
79
80
659
        return (0);
81
724
}
82
83
rs256_pk_t *
84
rs256_pk_new(void)
85
5.25k
{
86
5.25k
        return (calloc(1, sizeof(rs256_pk_t)));
87
5.25k
}
88
89
void
90
rs256_pk_free(rs256_pk_t **pkp)
91
21.9k
{
92
21.9k
        rs256_pk_t *pk;
93
94
21.9k
        if (pkp == NULL || (pk = *pkp) == NULL)
95
16.7k
                return;
96
97
5.23k
        freezero(pk, sizeof(*pk));
98
5.23k
        *pkp = NULL;
99
5.23k
}
100
101
int
102
rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len)
103
4.73k
{
104
4.73k
        EVP_PKEY *pkey;
105
106
4.73k
        if (len < sizeof(*pk))
107
3.73k
                return (FIDO_ERR_INVALID_ARGUMENT);
108
109
995
        memcpy(pk, ptr, sizeof(*pk));
110
111
995
        if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
112
478
                fido_log_debug("%s: rs256_pk_to_EVP_PKEY", __func__);
113
478
                return (FIDO_ERR_INVALID_ARGUMENT);
114
478
        }
115
116
517
        EVP_PKEY_free(pkey);
117
118
517
        return (FIDO_OK);
119
995
}
120
121
EVP_PKEY *
122
rs256_pk_to_EVP_PKEY(const rs256_pk_t *k)
123
6.46k
{
124
6.46k
        RSA             *rsa = NULL;
125
6.46k
        EVP_PKEY        *pkey = NULL;
126
6.46k
        BIGNUM          *n = NULL;
127
6.46k
        BIGNUM          *e = NULL;
128
6.46k
        int              ok = -1;
129
130
6.46k
        if ((n = BN_new()) == NULL || (e = BN_new()) == NULL)
131
146
                goto fail;
132
133
6.31k
        if (BN_bin2bn(k->n, sizeof(k->n), n) == NULL ||
134
6.31k
            BN_bin2bn(k->e, sizeof(k->e), e) == NULL) {
135
273
                fido_log_debug("%s: BN_bin2bn", __func__);
136
273
                goto fail;
137
273
        }
138
139
6.04k
        if ((rsa = RSA_new()) == NULL || RSA_set0_key(rsa, n, e, NULL) == 0) {
140
158
                fido_log_debug("%s: RSA_set0_key", __func__);
141
158
                goto fail;
142
158
        }
143
144
        /* at this point, n and e belong to rsa */
145
5.88k
        n = NULL;
146
5.88k
        e = NULL;
147
148
5.88k
        if (RSA_bits(rsa) != 2048) {
149
4.36k
                fido_log_debug("%s: invalid key length", __func__);
150
4.36k
                goto fail;
151
4.36k
        }
152
153
1.52k
        if ((pkey = EVP_PKEY_new()) == NULL ||
154
1.52k
            EVP_PKEY_assign_RSA(pkey, rsa) == 0) {
155
36
                fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__);
156
36
                goto fail;
157
36
        }
158
159
1.48k
        rsa = NULL; /* at this point, rsa belongs to evp */
160
161
1.48k
        ok = 0;
162
6.46k
fail:
163
6.46k
        if (n != NULL)
164
536
                BN_free(n);
165
6.46k
        if (e != NULL)
166
431
                BN_free(e);
167
6.46k
        if (rsa != NULL)
168
4.45k
                RSA_free(rsa);
169
6.46k
        if (ok < 0 && pkey != NULL) {
170
22
                EVP_PKEY_free(pkey);
171
22
                pkey = NULL;
172
22
        }
173
174
6.46k
        return (pkey);
175
1.48k
}
176
177
int
178
rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa)
179
498
{
180
498
        const BIGNUM    *n = NULL;
181
498
        const BIGNUM    *e = NULL;
182
498
        const BIGNUM    *d = NULL;
183
498
        int              k;
184
185
498
        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
498
        RSA_get0_key(rsa, &n, &e, &d);
191
192
498
        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
498
        if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) ||
198
498
            (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
498
        if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) ||
204
498
            (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) {
205
11
                fido_log_debug("%s: BN_bn2bin", __func__);
206
11
                return (FIDO_ERR_INTERNAL);
207
11
        }
208
209
487
        return (FIDO_OK);
210
498
}
211
212
int
213
rs256_pk_from_EVP_PKEY(rs256_pk_t *pk, const EVP_PKEY *pkey)
214
503
{
215
503
        const RSA *rsa;
216
217
503
        if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA ||
218
503
            (rsa = get0_RSA(pkey)) == NULL)
219
5
                return (FIDO_ERR_INVALID_ARGUMENT);
220
221
498
        return (rs256_pk_from_RSA(pk, rsa));
222
503
}
223
224
int
225
rs256_verify_sig(const fido_blob_t *dgst, EVP_PKEY *pkey,
226
    const fido_blob_t *sig)
227
465
{
228
465
        EVP_PKEY_CTX    *pctx = NULL;
229
465
        EVP_MD          *md = NULL;
230
465
        int              ok = -1;
231
232
465
        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
461
        if ((md = rs256_get_EVP_MD()) == NULL) {
238
27
                fido_log_debug("%s: rs256_get_EVP_MD", __func__);
239
27
                goto fail;
240
27
        }
241
242
434
        if ((pctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
243
434
            EVP_PKEY_verify_init(pctx) != 1 ||
244
434
            EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING) != 1 ||
245
434
            EVP_PKEY_CTX_set_signature_md(pctx, md) != 1) {
246
69
                fido_log_debug("%s: EVP_PKEY_CTX", __func__);
247
69
                goto fail;
248
69
        }
249
250
365
        if (EVP_PKEY_verify(pctx, sig->ptr, sig->len, dgst->ptr,
251
365
            dgst->len) != 1) {
252
365
                fido_log_debug("%s: EVP_PKEY_verify", __func__);
253
365
                goto fail;
254
365
        }
255
256
0
        ok = 0;
257
465
fail:
258
465
        EVP_PKEY_CTX_free(pctx);
259
260
465
        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
735
{
267
735
        EVP_PKEY        *pkey;
268
735
        int              ok = -1;
269
270
735
        if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
271
735
            rs256_verify_sig(dgst, pkey, sig) < 0) {
272
735
                fido_log_debug("%s: rs256_verify_sig", __func__);
273
735
                goto fail;
274
735
        }
275
276
0
        ok = 0;
277
735
fail:
278
735
        EVP_PKEY_free(pkey);
279
280
735
        return (ok);
281
0
}