Coverage Report

Created: 2021-07-20 18:14

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