Coverage Report

Created: 2024-06-03 09:43

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