/home/pedro/projects/libfido2/fuzz/uniform_random.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
3
 *
4
 * Permission to use, copy, modify, and distribute this software for any
5
 * purpose with or without fee is hereby granted, provided that the above
6
 * copyright notice and this permission notice appear in all copies.
7
 *
8
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
 */
16
17
#include <stdint.h>
18
#include <stdlib.h>
19
20
uint32_t uniform_random(uint32_t);
21
22
/*
23
 * Calculate a uniformly distributed random number less than upper_bound
24
 * avoiding "modulo bias".
25
 *
26
 * Uniformity is achieved by generating new random numbers until the one
27
 * returned is outside the range [0, 2**32 % upper_bound).  This
28
 * guarantees the selected random number will be inside
29
 * [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
30
 * after reduction modulo upper_bound.
31
 */
32
uint32_t
33
uniform_random(uint32_t upper_bound)
34
556k
{
35
556k
        uint32_t r, min;
36
556k
37
556k
        if (upper_bound < 2)
38
0
                return 0;
39
556k
40
556k
        /* 2**32 % x == (2**32 - x) % x */
41
556k
        min = -upper_bound % upper_bound;
42
556k
43
556k
        /*
44
556k
         * This could theoretically loop forever but each retry has
45
556k
         * p > 0.5 (worst case, usually far better) of selecting a
46
556k
         * number inside the range we need, so it should rarely need
47
556k
         * to re-roll.
48
556k
         */
49
556k
        for (;;) {
50
556k
                r = (uint32_t)random();
51
556k
                if (r >= min)
52
556k
                        break;
53
556k
        }
54
556k
55
556k
        return r % upper_bound;
56
556k
}
/home/pedro/projects/libfido2/fuzz/wrap.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2019 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/evp.h>
9
#include <openssl/sha.h>
10
11
#include <cbor.h>
12
#include <fido.h>
13
14
#include <stdbool.h>
15
#include <stdint.h>
16
#include <stdio.h>
17
#include <stdlib.h>
18
19
#include "mutator_aux.h"
20
21
/*
22
 * Build wrappers around functions of interest, and have them fail
23
 * in a pseudo-random manner.
24
 */
25
26
#define WRAP(type, name, args, retval, param, prob)     \
27
extern type __wrap_##name args;                         \
28
extern type __real_##name args;                         \
29
529k
type __wrap_##name args {                               \
30
529k
        if (uniform_random(400) < (prob)) {               \
31
2.74k
                return (retval);                        \
32
2.74k
        }                                                \
33
529k
                                                        \
34
529k
        return (__real_##name param);                       \
35
529k
}
__wrap_malloc
Line
Count
Source
29
125k
type __wrap_##name args {                               \
30
125k
        if (uniform_random(400) < (prob)) {               \
31
486
                return (retval);                        \
32
486
        }                                                \
33
125k
                                                        \
34
125k
        return (__real_##name param);                       \
35
125k
}
__wrap_calloc
Line
Count
Source
29
81.7k
type __wrap_##name args {                               \
30
81.7k
        if (uniform_random(400) < (prob)) {               \
31
496
                return (retval);                        \
32
496
        }                                                \
33
81.7k
                                                        \
34
81.7k
        return (__real_##name param);                       \
35
81.7k
}
__wrap_strdup
Line
Count
Source
29
20.0k
type __wrap_##name args {                               \
30
20.0k
        if (uniform_random(400) < (prob)) {               \
31
90
                return (retval);                        \
32
90
        }                                                \
33
20.0k
                                                        \
34
20.0k
        return (__real_##name param);                       \
35
20.0k
}
__wrap_EVP_CIPHER_CTX_new
Line
Count
Source
29
2.53k
type __wrap_##name args {                               \
30
2.53k
        if (uniform_random(400) < (prob)) {               \
31
34
                return (retval);                        \
32
34
        }                                                \
33
2.53k
                                                        \
34
2.53k
        return (__real_##name param);                       \
35
2.53k
}
__wrap_EVP_EncryptInit_ex
Line
Count
Source
29
1.51k
type __wrap_##name args {                               \
30
1.51k
        if (uniform_random(400) < (prob)) {               \
31
14
                return (retval);                        \
32
14
        }                                                \
33
1.51k
                                                        \
34
1.51k
        return (__real_##name param);                       \
35
1.51k
}
__wrap_EVP_CIPHER_CTX_set_padding
Line
Count
Source
29
2.47k
type __wrap_##name args {                               \
30
2.47k
        if (uniform_random(400) < (prob)) {               \
31
31
                return (retval);                        \
32
31
        }                                                \
33
2.47k
                                                        \
34
2.47k
        return (__real_##name param);                       \
35
2.47k
}
__wrap_EVP_EncryptUpdate
Line
Count
Source
29
1.48k
type __wrap_##name args {                               \
30
1.48k
        if (uniform_random(400) < (prob)) {               \
31
17
                return (retval);                        \
32
17
        }                                                \
33
1.48k
                                                        \
34
1.48k
        return (__real_##name param);                       \
35
1.48k
}
__wrap_EVP_DecryptInit_ex
Line
Count
Source
29
984
type __wrap_##name args {                               \
30
984
        if (uniform_random(400) < (prob)) {               \
31
8
                return (retval);                        \
32
8
        }                                                \
33
984
                                                        \
34
984
        return (__real_##name param);                       \
35
984
}
__wrap_EVP_DecryptUpdate
Line
Count
Source
29
965
type __wrap_##name args {                               \
30
965
        if (uniform_random(400) < (prob)) {               \
31
8
                return (retval);                        \
32
8
        }                                                \
33
965
                                                        \
34
965
        return (__real_##name param);                       \
35
965
}
__wrap_SHA256_Init
Line
Count
Source
29
118
type __wrap_##name args {                               \
30
118
        if (uniform_random(400) < (prob)) {               \
31
3
                return (retval);                        \
32
3
        }                                                \
33
118
                                                        \
34
118
        return (__real_##name param);                       \
35
118
}
__wrap_SHA256_Update
Line
Count
Source
29
261
type __wrap_##name args {                               \
30
261
        if (uniform_random(400) < (prob)) {               \
31
13
                return (retval);                        \
32
13
        }                                                \
33
261
                                                        \
34
261
        return (__real_##name param);                       \
35
261
}
__wrap_SHA256_Final
Line
Count
Source
29
102
type __wrap_##name args {                               \
30
102
        if (uniform_random(400) < (prob)) {               \
31
3
                return (retval);                        \
32
3
        }                                                \
33
102
                                                        \
34
102
        return (__real_##name param);                       \
35
102
}
__wrap_EVP_PKEY_get0_RSA
Line
Count
Source
29
35
type __wrap_##name args {                               \
30
35
        if (uniform_random(400) < (prob)) {               \
31
1
                return (retval);                        \
32
1
        }                                                \
33
35
                                                        \
34
35
        return (__real_##name param);                       \
35
35
}
__wrap_EVP_MD_CTX_new
Line
Count
Source
29
14
type __wrap_##name args {                               \
30
14
        if (uniform_random(400) < (prob)) {               \
31
2
                return (retval);                        \
32
2
        }                                                \
33
14
                                                        \
34
14
        return (__real_##name param);                       \
35
14
}
__wrap_EVP_DigestVerifyInit
Line
Count
Source
29
12
type __wrap_##name args {                               \
30
12
        if (uniform_random(400) < (prob)) {               \
31
1
                return (retval);                        \
32
1
        }                                                \
33
12
                                                        \
34
12
        return (__real_##name param);                       \
35
12
}
__wrap_BN_bin2bn
Line
Count
Source
29
10.7k
type __wrap_##name args {                               \
30
10.7k
        if (uniform_random(400) < (prob)) {               \
31
93
                return (retval);                        \
32
93
        }                                                \
33
10.7k
                                                        \
34
10.7k
        return (__real_##name param);                       \
35
10.7k
}
__wrap_BN_CTX_get
Line
Count
Source
29
14.0k
type __wrap_##name args {                               \
30
14.0k
        if (uniform_random(400) < (prob)) {               \
31
112
                return (retval);                        \
32
112
        }                                                \
33
14.0k
                                                        \
34
14.0k
        return (__real_##name param);                       \
35
14.0k
}
__wrap_BN_CTX_new
Line
Count
Source
29
8.08k
type __wrap_##name args {                               \
30
8.08k
        if (uniform_random(400) < (prob)) {               \
31
61
                return (retval);                        \
32
61
        }                                                \
33
8.08k
                                                        \
34
8.08k
        return (__real_##name param);                       \
35
8.08k
}
__wrap_BN_new
Line
Count
Source
29
350
type __wrap_##name args {                               \
30
350
        if (uniform_random(400) < (prob)) {               \
31
8
                return (retval);                        \
32
8
        }                                                \
33
350
                                                        \
34
350
        return (__real_##name param);                       \
35
350
}
__wrap_RSA_set0_key
Line
Count
Source
29
161
type __wrap_##name args {                               \
30
161
        if (uniform_random(400) < (prob)) {               \
31
3
                return (retval);                        \
32
3
        }                                                \
33
161
                                                        \
34
161
        return (__real_##name param);                       \
35
161
}
__wrap_EC_KEY_new_by_curve_name
Line
Count
Source
29
8.01k
type __wrap_##name args {                               \
30
8.01k
        if (uniform_random(400) < (prob)) {               \
31
63
                return (retval);                        \
32
63
        }                                                \
33
8.01k
                                                        \
34
8.01k
        return (__real_##name param);                       \
35
8.01k
}
__wrap_EC_KEY_get0_group
Line
Count
Source
29
9.72k
type __wrap_##name args {                               \
30
9.72k
        if (uniform_random(400) < (prob)) {               \
31
71
                return (retval);                        \
32
71
        }                                                \
33
9.72k
                                                        \
34
9.72k
        return (__real_##name param);                       \
35
9.72k
}
__wrap_EC_POINT_new
Line
Count
Source
29
5.99k
type __wrap_##name args {                               \
30
5.99k
        if (uniform_random(400) < (prob)) {               \
31
36
                return (retval);                        \
32
36
        }                                                \
33
5.99k
                                                        \
34
5.99k
        return (__real_##name param);                       \
35
5.99k
}
__wrap_EVP_PKEY_new
Line
Count
Source
29
4.10k
type __wrap_##name args {                               \
30
4.10k
        if (uniform_random(400) < (prob)) {               \
31
37
                return (retval);                        \
32
37
        }                                                \
33
4.10k
                                                        \
34
4.10k
        return (__real_##name param);                       \
35
4.10k
}
__wrap_EVP_PKEY_assign
Line
Count
Source
29
4.06k
type __wrap_##name args {                               \
30
4.06k
        if (uniform_random(400) < (prob)) {               \
31
44
                return (retval);                        \
32
44
        }                                                \
33
4.06k
                                                        \
34
4.06k
        return (__real_##name param);                       \
35
4.06k
}
__wrap_EVP_PKEY_new_raw_public_key
Line
Count
Source
29
166
type __wrap_##name args {                               \
30
166
        if (uniform_random(400) < (prob)) {               \
31
4
                return (retval);                        \
32
4
        }                                                \
33
166
                                                        \
34
166
        return (__real_##name param);                       \
35
166
}
__wrap_EVP_PKEY_CTX_new
Line
Count
Source
29
5.67k
type __wrap_##name args {                               \
30
5.67k
        if (uniform_random(400) < (prob)) {               \
31
37
                return (retval);                        \
32
37
        }                                                \
33
5.67k
                                                        \
34
5.67k
        return (__real_##name param);                       \
35
5.67k
}
__wrap_EVP_PKEY_derive_init
Line
Count
Source
29
1.85k
type __wrap_##name args {                               \
30
1.85k
        if (uniform_random(400) < (prob)) {               \
31
15
                return (retval);                        \
32
15
        }                                                \
33
1.85k
                                                        \
34
1.85k
        return (__real_##name param);                       \
35
1.85k
}
__wrap_EVP_PKEY_derive_set_peer
Line
Count
Source
29
1.84k
type __wrap_##name args {                               \
30
1.84k
        if (uniform_random(400) < (prob)) {               \
31
17
                return (retval);                        \
32
17
        }                                                \
33
1.84k
                                                        \
34
1.84k
        return (__real_##name param);                       \
35
1.84k
}
__wrap_EVP_sha256
Line
Count
Source
29
1.26k
type __wrap_##name args {                               \
30
1.26k
        if (uniform_random(400) < (prob)) {               \
31
22
                return (retval);                        \
32
22
        }                                                \
33
1.26k
                                                        \
34
1.26k
        return (__real_##name param);                       \
35
1.26k
}
__wrap_HMAC
Line
Count
Source
29
1.21k
type __wrap_##name args {                               \
30
1.21k
        if (uniform_random(400) < (prob)) {               \
31
17
                return (retval);                        \
32
17
        }                                                \
33
1.21k
                                                        \
34
1.21k
        return (__real_##name param);                       \
35
1.21k
}
__wrap_HMAC_CTX_new
Line
Count
Source
29
37
type __wrap_##name args {                               \
30
37
        if (uniform_random(400) < (prob)) {               \
31
1
                return (retval);                        \
32
1
        }                                                \
33
37
                                                        \
34
37
        return (__real_##name param);                       \
35
37
}
__wrap_HMAC_Init_ex
Line
Count
Source
29
34
type __wrap_##name args {                               \
30
34
        if (uniform_random(400) < (prob)) {               \
31
1
                return (retval);                        \
32
1
        }                                                \
33
34
                                                        \
34
34
        return (__real_##name param);                       \
35
34
}
__wrap_HMAC_Update
Line
Count
Source
29
65
type __wrap_##name args {                               \
30
65
        if (uniform_random(400) < (prob)) {               \
31
2
                return (retval);                        \
32
2
        }                                                \
33
65
                                                        \
34
65
        return (__real_##name param);                       \
35
65
}
__wrap_HMAC_Final
Line
Count
Source
29
31
type __wrap_##name args {                               \
30
31
        if (uniform_random(400) < (prob)) {               \
31
1
                return (retval);                        \
32
1
        }                                                \
33
31
                                                        \
34
31
        return (__real_##name param);                       \
35
31
}
__wrap_SHA256
Line
Count
Source
29
4.57k
type __wrap_##name args {                               \
30
4.57k
        if (uniform_random(400) < (prob)) {               \
31
52
                return (retval);                        \
32
52
        }                                                \
33
4.57k
                                                        \
34
4.57k
        return (__real_##name param);                       \
35
4.57k
}
__wrap_cbor_build_string
Line
Count
Source
29
29.3k
type __wrap_##name args {                               \
30
29.3k
        if (uniform_random(400) < (prob)) {               \
31
29
                return (retval);                        \
32
29
        }                                                \
33
29.3k
                                                        \
34
29.3k
        return (__real_##name param);                       \
35
29.3k
}
__wrap_cbor_build_bytestring
Line
Count
Source
29
16.0k
type __wrap_##name args {                               \
30
16.0k
        if (uniform_random(400) < (prob)) {               \
31
77
                return (retval);                        \
32
77
        }                                                \
33
16.0k
                                                        \
34
16.0k
        return (__real_##name param);                       \
35
16.0k
}
__wrap_cbor_load
Line
Count
Source
29
7.07k
type __wrap_##name args {                               \
30
7.07k
        if (uniform_random(400) < (prob)) {               \
31
36
                return (retval);                        \
32
36
        }                                                \
33
7.07k
                                                        \
34
7.07k
        return (__real_##name param);                       \
35
7.07k
}
__wrap_cbor_build_uint8
Line
Count
Source
29
45.7k
type __wrap_##name args {                               \
30
45.7k
        if (uniform_random(400) < (prob)) {               \
31
241
                return (retval);                        \
32
241
        }                                                \
33
45.7k
                                                        \
34
45.7k
        return (__real_##name param);                       \
35
45.7k
}
__wrap_cbor_map_handle
Line
Count
Source
29
11.6k
type __wrap_##name args {                               \
30
11.6k
        if (uniform_random(400) < (prob)) {               \
31
36
                return (retval);                        \
32
36
        }                                                \
33
11.6k
                                                        \
34
11.6k
        return (__real_##name param);                       \
35
11.6k
}
__wrap_cbor_array_handle
Line
Count
Source
29
239
type __wrap_##name args {                               \
30
239
        if (uniform_random(400) < (prob)) {               \
31
3
                return (retval);                        \
32
3
        }                                                \
33
239
                                                        \
34
239
        return (__real_##name param);                       \
35
239
}
__wrap_cbor_map_add
Line
Count
Source
29
48.7k
type __wrap_##name args {                               \
30
48.7k
        if (uniform_random(400) < (prob)) {               \
31
196
                return (retval);                        \
32
196
        }                                                \
33
48.7k
                                                        \
34
48.7k
        return (__real_##name param);                       \
35
48.7k
}
__wrap_cbor_new_definite_map
Line
Count
Source
29
20.5k
type __wrap_##name args {                               \
30
20.5k
        if (uniform_random(400) < (prob)) {               \
31
63
                return (retval);                        \
32
63
        }                                                \
33
20.5k
                                                        \
34
20.5k
        return (__real_##name param);                       \
35
20.5k
}
__wrap_cbor_serialize_alloc
Line
Count
Source
29
9.50k
type __wrap_##name args {                               \
30
9.50k
        if (uniform_random(400) < (prob)) {               \
31
57
                return (retval);                        \
32
57
        }                                                \
33
9.50k
                                                        \
34
9.50k
        return (__real_##name param);                       \
35
9.50k
}
__wrap_fido_tx
Line
Count
Source
29
19.4k
type __wrap_##name args {                               \
30
19.4k
        if (uniform_random(400) < (prob)) {               \
31
99
                return (retval);                        \
32
99
        }                                                \
33
19.4k
                                                        \
34
19.4k
        return (__real_##name param);                       \
35
19.4k
}
__wrap_usleep
Line
Count
Source
29
1.13k
type __wrap_##name args {                               \
30
1.13k
        if (uniform_random(400) < (prob)) {               \
31
4
                return (retval);                        \
32
4
        }                                                \
33
1.13k
                                                        \
34
1.13k
        return (__real_##name param);                       \
35
1.13k
}
36
37
WRAP(void *,
38
        malloc,
39
        (size_t size),
40
        NULL,
41
        (size),
42
        1
43
)
44
45
WRAP(void *,
46
        calloc,
47
        (size_t nmemb, size_t size),
48
        NULL,
49
        (nmemb, size),
50
        1
51
)
52
53
WRAP(char *,
54
        strdup,
55
        (const char *s),
56
        NULL,
57
        (s),
58
        1
59
)
60
61
WRAP(EVP_CIPHER_CTX *,
62
        EVP_CIPHER_CTX_new,
63
        (void),
64
        NULL,
65
        (),
66
        1
67
)
68
69
WRAP(int, EVP_EncryptInit_ex,
70
        (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
71
            const unsigned char *key, const unsigned char *iv),
72
        0,
73
        (ctx, type, impl, key, iv),
74
        1
75
)
76
77
WRAP(int,
78
        EVP_CIPHER_CTX_set_padding,
79
        (EVP_CIPHER_CTX *x, int padding),
80
        0,
81
        (x, padding),
82
        1
83
)
84
85
WRAP(int,
86
        EVP_EncryptUpdate,
87
        (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
88
            const unsigned char *in, int inl),
89
        0,
90
        (ctx, out, outl, in, inl),
91
        1
92
)
93
94
WRAP(int,
95
        EVP_DecryptInit_ex,
96
        (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl,
97
            const unsigned char *key, const unsigned char *iv),
98
        0,
99
        (ctx, type, impl, key, iv),
100
        1
101
)
102
103
WRAP(int,
104
        EVP_DecryptUpdate,
105
        (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl,
106
            const unsigned char *in, int inl),
107
        0,
108
        (ctx, out, outl, in, inl),
109
        1
110
)
111
112
WRAP(int,
113
        SHA256_Init,
114
        (SHA256_CTX *c),
115
        0,
116
        (c),
117
        1
118
)
119
120
WRAP(int,
121
        SHA256_Update,
122
        (SHA256_CTX *c, const void *data, size_t len),
123
        0,
124
        (c, data, len),
125
        1
126
)
127
128
WRAP(int,
129
        SHA256_Final,
130
        (unsigned char *md, SHA256_CTX *c),
131
        0,
132
        (md, c),
133
        1
134
)
135
136
WRAP(RSA *,
137
        EVP_PKEY_get0_RSA,
138
        (EVP_PKEY *pkey),
139
        NULL,
140
        (pkey),
141
        1
142
)
143
144
WRAP(EVP_MD_CTX *,
145
        EVP_MD_CTX_new,
146
        (void),
147
        NULL,
148
        (),
149
        1
150
)
151
152
WRAP(int,
153
        EVP_DigestVerifyInit,
154
        (EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e,
155
            EVP_PKEY *pkey),
156
        0,
157
        (ctx, pctx, type, e, pkey),
158
        1
159
)
160
161
WRAP(BIGNUM *,
162
        BN_bin2bn,
163
        (const unsigned char *s, int len, BIGNUM *ret),
164
        NULL,
165
        (s, len, ret),
166
        1
167
)
168
169
WRAP(BIGNUM *,
170
        BN_CTX_get,
171
        (BN_CTX *ctx),
172
        NULL,
173
        (ctx),
174
        1
175
)
176
177
WRAP(BN_CTX *,
178
        BN_CTX_new,
179
        (void),
180
        NULL,
181
        (),
182
        1
183
)
184
185
WRAP(BIGNUM *,
186
        BN_new,
187
        (void),
188
        NULL,
189
        (),
190
        1
191
)
192
193
WRAP(int,
194
        RSA_set0_key,
195
        (RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d),
196
        0,
197
        (r, n, e, d),
198
        1
199
)
200
201
WRAP(EC_KEY *,
202
        EC_KEY_new_by_curve_name,
203
        (int nid),
204
        NULL,
205
        (nid),
206
        1
207
)
208
209
WRAP(const EC_GROUP *,
210
        EC_KEY_get0_group,
211
        (const EC_KEY *key),
212
        NULL,
213
        (key),
214
        1
215
)
216
217
WRAP(EC_POINT *,
218
        EC_POINT_new,
219
        (const EC_GROUP *group),
220
        NULL,
221
        (group),
222
        1
223
)
224
225
WRAP(EVP_PKEY *,
226
        EVP_PKEY_new,
227
        (void),
228
        NULL,
229
        (),
230
        1
231
)
232
233
WRAP(int,
234
        EVP_PKEY_assign,
235
        (EVP_PKEY *pkey, int type, void *key),
236
        0,
237
        (pkey, type, key),
238
        1
239
)
240
241
WRAP(EVP_PKEY *,
242
        EVP_PKEY_new_raw_public_key,
243
        (int type, ENGINE *e, const unsigned char *key, size_t keylen),
244
        NULL,
245
        (type, e, key, keylen),
246
        1
247
)
248
249
WRAP(EVP_PKEY_CTX *,
250
        EVP_PKEY_CTX_new,
251
        (EVP_PKEY *pkey, ENGINE *e),
252
        NULL,
253
        (pkey, e),
254
        1
255
)
256
257
WRAP(int,
258
        EVP_PKEY_derive_init,
259
        (EVP_PKEY_CTX *ctx),
260
        0,
261
        (ctx),
262
        1
263
)
264
265
WRAP(int,
266
        EVP_PKEY_derive_set_peer,
267
        (EVP_PKEY_CTX *ctx, EVP_PKEY *peer),
268
        0,
269
        (ctx, peer),
270
        1
271
)
272
273
WRAP(const EVP_MD *,
274
        EVP_sha256,
275
        (void),
276
        NULL,
277
        (),
278
        1
279
)
280
281
WRAP(unsigned char *,
282
        HMAC,
283
        (const EVP_MD *evp_md, const void *key, int key_len,
284
            const unsigned char *d, int n, unsigned char *md,
285
            unsigned int *md_len),
286
        NULL,
287
        (evp_md, key, key_len, d, n, md, md_len),
288
        1
289
)
290
291
WRAP(HMAC_CTX *,
292
        HMAC_CTX_new,
293
        (void),
294
        NULL,
295
        (),
296
        1
297
)
298
299
WRAP(int,
300
        HMAC_Init_ex,
301
        (HMAC_CTX *ctx, const void *key, int key_len, const EVP_MD *md,
302
            ENGINE *impl),
303
        0,
304
        (ctx, key, key_len, md, impl),
305
        1
306
)
307
308
WRAP(int,
309
        HMAC_Update,
310
        (HMAC_CTX *ctx, const unsigned char *data, int len),
311
        0,
312
        (ctx, data, len),
313
        1
314
)
315
316
WRAP(int,
317
        HMAC_Final,
318
        (HMAC_CTX *ctx, unsigned char *md, unsigned int *len),
319
        0,
320
        (ctx, md, len),
321
        1
322
)
323
324
WRAP(unsigned char *,
325
        SHA256,
326
        (const unsigned char *d, size_t n, unsigned char *md),
327
        NULL,
328
        (d, n, md),
329
        1
330
)
331
332
WRAP(cbor_item_t *,
333
        cbor_build_string,
334
        (const char *val),
335
        NULL,
336
        (val),
337
        1
338
)
339
340
WRAP(cbor_item_t *,
341
        cbor_build_bytestring,
342
        (cbor_data handle, size_t length),
343
        NULL,
344
        (handle, length),
345
        1
346
)
347
348
WRAP(cbor_item_t *,
349
        cbor_load,
350
        (cbor_data source, size_t source_size, struct cbor_load_result *result),
351
        NULL,
352
        (source, source_size, result),
353
        1
354
)
355
356
WRAP(cbor_item_t *,
357
        cbor_build_uint8,
358
        (uint8_t value),
359
        NULL,
360
        (value),
361
        1
362
)
363
364
WRAP(struct cbor_pair *,
365
        cbor_map_handle,
366
        (const cbor_item_t *item),
367
        NULL,
368
        (item),
369
        1
370
)
371
372
WRAP(cbor_item_t **,
373
        cbor_array_handle,
374
        (const cbor_item_t *item),
375
        NULL,
376
        (item),
377
        1
378
)
379
380
WRAP(bool,
381
        cbor_map_add,
382
        (cbor_item_t *item, struct cbor_pair pair),
383
        false,
384
        (item, pair),
385
        1
386
)
387
388
WRAP(cbor_item_t *,
389
        cbor_new_definite_map,
390
        (size_t size),
391
        NULL,
392
        (size),
393
        1
394
)
395
396
WRAP(size_t,
397
        cbor_serialize_alloc,
398
        (const cbor_item_t *item, cbor_mutable_data *buffer,
399
            size_t *buffer_size),
400
        0,
401
        (item, buffer, buffer_size),
402
        1
403
)
404
405
WRAP(int,
406
        fido_tx,
407
        (fido_dev_t *d, uint8_t cmd, const void *buf, size_t count),
408
        -1,
409
        (d, cmd, buf, count),
410
        1
411
)
412
413
WRAP(int,
414
        usleep,
415
        (unsigned int usec),
416
        -1,
417
        (usec),
418
        1
419
)
/home/pedro/projects/libfido2/openbsd-compat/explicit_bzero.c
Line
Count
Source
1
/* OPENBSD ORIGINAL: lib/libc/string/explicit_bzero.c */
2
/*      $OpenBSD: explicit_bzero.c,v 1.1 2014/01/22 21:06:45 tedu Exp $ */
3
/*
4
 * Public domain.
5
 * Written by Ted Unangst
6
 */
7
8
#include "openbsd-compat.h"
9
10
#if !defined(HAVE_EXPLICIT_BZERO) && !defined(_WIN32)
11
12
#include <string.h>
13
14
/*
15
 * explicit_bzero - don't let the compiler optimize away bzero
16
 */
17
18
#ifdef HAVE_MEMSET_S
19
20
void
21
explicit_bzero(void *p, size_t n)
22
{
23
        if (n == 0)
24
                return;
25
        (void)memset_s(p, n, 0, n);
26
}
27
28
#else /* HAVE_MEMSET_S */
29
30
/*
31
 * Indirect bzero through a volatile pointer to hopefully avoid
32
 * dead-store optimisation eliminating the call.
33
 */
34
static void (* volatile ssh_bzero)(void *, size_t) = bzero;
35
36
void
37
explicit_bzero(void *p, size_t n)
38
141k
{
39
141k
        if (n == 0)
40
249
                return;
41
141k
        /*
42
141k
         * clang -fsanitize=memory needs to intercept memset-like functions
43
141k
         * to correctly detect memory initialisation. Make sure one is called
44
141k
         * directly since our indirection trick above successfully confuses it.
45
141k
         */
46
141k
#if defined(__has_feature)
47
# if __has_feature(memory_sanitizer)
48
        memset(p, 0, n);
49
# endif
50
#endif
51
141k
52
141k
        ssh_bzero(p, n);
53
141k
}
54
55
#endif /* HAVE_MEMSET_S */
56
57
#endif /* !defined(HAVE_EXPLICIT_BZERO) && !defined(_WIN32) */
/home/pedro/projects/libfido2/openbsd-compat/recallocarray.c
Line
Count
Source (jump to first uncovered line)
1
/*      $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $  */
2
/*
3
 * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
/* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */
19
20
#include "openbsd-compat.h"
21
22
#if !defined(HAVE_RECALLOCARRAY)
23
24
#include <errno.h>
25
#include <stdlib.h>
26
#include <stdint.h>
27
#include <string.h>
28
#ifdef HAVE_UNISTD_H
29
#include <unistd.h>
30
#endif
31
32
/*
33
 * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
34
 * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
35
 */
36
263k
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
37
38
void *
39
recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
40
60.7k
{
41
60.7k
        size_t oldsize, newsize;
42
60.7k
        void *newptr;
43
60.7k
44
60.7k
        if (ptr == NULL)
45
60.7k
                return calloc(newnmemb, size);
46
43.8k
47
43.8k
        if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
48
43.8k
            newnmemb > 0 && SIZE_MAX / newnmemb < size) {
49
0
                errno = ENOMEM;
50
0
                return NULL;
51
0
        }
52
43.8k
        newsize = newnmemb * size;
53
43.8k
54
43.8k
        if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
55
43.8k
            oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
56
0
                errno = EINVAL;
57
0
                return NULL;
58
0
        }
59
43.8k
        oldsize = oldnmemb * size;
60
43.8k
        
61
43.8k
        /*
62
43.8k
         * Don't bother too much if we're shrinking just a bit,
63
43.8k
         * we do not shrink for series of small steps, oh well.
64
43.8k
         */
65
43.8k
        if (newsize <= oldsize) {
66
1
                size_t d = oldsize - newsize;
67
1
68
1
                if (d < oldsize / 2 && d < (size_t)getpagesize()) {
69
1
                        memset((char *)ptr + newsize, 0, d);
70
1
                        return ptr;
71
1
                }
72
43.8k
        }
73
43.8k
74
43.8k
        newptr = malloc(newsize);
75
43.8k
        if (newptr == NULL)
76
43.8k
                return NULL;
77
43.7k
78
43.7k
        if (newsize > oldsize) {
79
43.7k
                memcpy(newptr, ptr, oldsize);
80
43.7k
                memset((char *)newptr + oldsize, 0, newsize - oldsize);
81
43.7k
        } else
82
0
                memcpy(newptr, ptr, newsize);
83
43.7k
84
43.7k
        explicit_bzero(ptr, oldsize);
85
43.7k
        free(ptr);
86
43.7k
87
43.7k
        return newptr;
88
43.7k
}
89
/* DEF_WEAK(recallocarray); */
90
91
#endif /* !defined(HAVE_RECALLOCARRAY) */
/home/pedro/projects/libfido2/openbsd-compat/timingsafe_bcmp.c
Line
Count
Source
1
/*      $OpenBSD: timingsafe_bcmp.c,v 1.1 2010/09/24 13:33:00 matthew Exp $     */
2
/*
3
 * Copyright (c) 2010 Damien Miller.  All rights reserved.
4
 *
5
 * Permission to use, copy, modify, and distribute this software for any
6
 * purpose with or without fee is hereby granted, provided that the above
7
 * copyright notice and this permission notice appear in all copies.
8
 *
9
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
 */
17
18
/* OPENBSD ORIGINAL: lib/libc/string/timingsafe_bcmp.c */
19
20
#include "openbsd-compat.h"
21
22
#if !defined(HAVE_TIMINGSAFE_BCMP)
23
24
int
25
timingsafe_bcmp(const void *b1, const void *b2, size_t n)
26
162
{
27
162
        const unsigned char *p1 = b1, *p2 = b2;
28
162
        int ret = 0;
29
162
30
5.34k
        for (; n > 0; n--)
31
5.18k
                ret |= *p1++ ^ *p2++;
32
162
        return (ret != 0);
33
162
}
34
35
#endif /* !defined(HAVE_TIMINGSAFE_BCMP) */
/home/pedro/projects/libfido2/src/aes256.c
Line
Count
Source
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/evp.h>
8
#include <string.h>
9
10
#include "fido.h"
11
12
int
13
aes256_cbc_enc(const fido_blob_t *key, const fido_blob_t *in, fido_blob_t *out)
14
1.55k
{
15
1.55k
        EVP_CIPHER_CTX  *ctx = NULL;
16
1.55k
        unsigned char    iv[32];
17
1.55k
        int              len;
18
1.55k
        int              ok = -1;
19
1.55k
20
1.55k
        memset(iv, 0, sizeof(iv));
21
1.55k
        out->ptr = NULL;
22
1.55k
        out->len = 0;
23
1.55k
24
1.55k
        /* sanity check */
25
1.55k
        if (in->len > INT_MAX || (in->len % 16) != 0 ||
26
1.55k
            (out->ptr = calloc(1, in->len)) == NULL) {
27
16
                fido_log_debug("%s: in->len=%zu", __func__, in->len);
28
16
                goto fail;
29
16
        }
30
1.53k
31
1.53k
        if ((ctx = EVP_CIPHER_CTX_new()) == NULL || key->len != 32 ||
32
1.53k
            !EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key->ptr, iv) ||
33
1.53k
            !EVP_CIPHER_CTX_set_padding(ctx, 0) ||
34
1.53k
            !EVP_EncryptUpdate(ctx, out->ptr, &len, in->ptr, (int)in->len) ||
35
1.53k
            len < 0 || (size_t)len != in->len) {
36
73
                fido_log_debug("%s: EVP_Encrypt", __func__);
37
73
                goto fail;
38
73
        }
39
1.46k
40
1.46k
        out->len = (size_t)len;
41
1.46k
42
1.46k
        ok = 0;
43
1.55k
fail:
44
1.55k
        if (ctx != NULL)
45
1.55k
                EVP_CIPHER_CTX_free(ctx);
46
1.55k
47
1.55k
        if (ok < 0) {
48
89
                free(out->ptr);
49
89
                out->ptr = NULL;
50
89
                out->len = 0;
51
89
        }
52
1.55k
53
1.55k
        return (ok);
54
1.46k
}
55
56
int
57
aes256_cbc_dec(const fido_blob_t *key, const fido_blob_t *in, fido_blob_t *out)
58
1.03k
{
59
1.03k
        EVP_CIPHER_CTX  *ctx = NULL;
60
1.03k
        unsigned char    iv[32];
61
1.03k
        int              len;
62
1.03k
        int              ok = -1;
63
1.03k
64
1.03k
        memset(iv, 0, sizeof(iv));
65
1.03k
        out->ptr = NULL;
66
1.03k
        out->len = 0;
67
1.03k
68
1.03k
        /* sanity check */
69
1.03k
        if (in->len > INT_MAX || (in->len % 16) != 0 ||
70
1.03k
            (out->ptr = calloc(1, in->len)) == NULL) {
71
37
                fido_log_debug("%s: in->len=%zu", __func__, in->len);
72
37
                goto fail;
73
37
        }
74
996
75
996
        if ((ctx = EVP_CIPHER_CTX_new()) == NULL || key->len != 32 ||
76
996
            !EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key->ptr, iv) ||
77
996
            !EVP_CIPHER_CTX_set_padding(ctx, 0) ||
78
996
            !EVP_DecryptUpdate(ctx, out->ptr, &len, in->ptr, (int)in->len) ||
79
996
            len < 0 || (size_t)len > in->len + 32) {
80
39
                fido_log_debug("%s: EVP_Decrypt", __func__);
81
39
                goto fail;
82
39
        }
83
957
84
957
        out->len = (size_t)len;
85
957
86
957
        ok = 0;
87
1.03k
fail:
88
1.03k
        if (ctx != NULL)
89
1.03k
                EVP_CIPHER_CTX_free(ctx);
90
1.03k
91
1.03k
        if (ok < 0) {
92
76
                free(out->ptr);
93
76
                out->ptr = NULL;
94
76
                out->len = 0;
95
76
        }
96
1.03k
97
1.03k
        return (ok);
98
957
}
/home/pedro/projects/libfido2/src/assert.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/ec.h>
8
#include <openssl/ecdsa.h>
9
#include <openssl/evp.h>
10
#include <openssl/sha.h>
11
12
#include <string.h>
13
#include "fido.h"
14
#include "fido/es256.h"
15
#include "fido/rs256.h"
16
#include "fido/eddsa.h"
17
18
static int
19
adjust_assert_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
20
192
{
21
192
        fido_assert_t   *assert = arg;
22
192
        uint64_t         n;
23
192
24
192
        /* numberOfCredentials; see section 6.2 */
25
192
        if (cbor_isa_uint(key) == false ||
26
192
            cbor_int_get_width(key) != CBOR_INT_8 ||
27
192
            cbor_get_uint8(key) != 5) {
28
174
                fido_log_debug("%s: cbor_type", __func__);
29
174
                return (0); /* ignore */
30
174
        }
31
18
32
18
        if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
33
1
                fido_log_debug("%s: cbor_decode_uint64", __func__);
34
1
                return (-1);
35
1
        }
36
17
37
17
        if (assert->stmt_len != 0 || assert->stmt_cnt != 1 ||
38
17
            (size_t)n < assert->stmt_cnt) {
39
1
                fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu, n=%zu",
40
1
                    __func__, assert->stmt_len, assert->stmt_cnt, (size_t)n);
41
1
                return (-1);
42
1
        }
43
16
44
16
        if (fido_assert_set_count(assert, (size_t)n) != FIDO_OK) {
45
1
                fido_log_debug("%s: fido_assert_set_count", __func__);
46
1
                return (-1);
47
1
        }
48
15
49
15
        assert->stmt_len = 0; /* XXX */
50
15
51
15
        return (0);
52
15
}
53
54
static int
55
parse_assert_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
56
224
{
57
224
        fido_assert_stmt *stmt = arg;
58
224
59
224
        if (cbor_isa_uint(key) == false ||
60
224
            cbor_int_get_width(key) != CBOR_INT_8) {
61
16
                fido_log_debug("%s: cbor type", __func__);
62
16
                return (0); /* ignore */
63
16
        }
64
208
65
208
        switch (cbor_get_uint8(key)) {
66
208
        case 1: /* credential id */
67
79
                return (cbor_decode_cred_id(val, &stmt->id));
68
208
        case 2: /* authdata */
69
50
                return (cbor_decode_assert_authdata(val, &stmt->authdata_cbor,
70
50
                    &stmt->authdata, &stmt->authdata_ext,
71
50
                    &stmt->hmac_secret_enc));
72
208
        case 3: /* signature */
73
38
                return (fido_blob_decode(val, &stmt->sig));
74
208
        case 4: /* user attributes */
75
6
                return (cbor_decode_user(val, &stmt->user));
76
208
        default: /* ignore */
77
35
                fido_log_debug("%s: cbor type", __func__);
78
35
                return (0);
79
208
        }
80
208
}
81
82
static int
83
fido_dev_get_assert_tx(fido_dev_t *dev, fido_assert_t *assert,
84
    const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin)
85
164
{
86
164
        fido_blob_t      f;
87
164
        cbor_item_t     *argv[7];
88
164
        int              r;
89
164
90
164
        memset(argv, 0, sizeof(argv));
91
164
        memset(&f, 0, sizeof(f));
92
164
93
164
        /* do we have everything we need? */
94
164
        if (assert->rp_id == NULL || assert->cdh.ptr == NULL) {
95
0
                fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__,
96
0
                    (void *)assert->rp_id, (void *)assert->cdh.ptr);
97
0
                r = FIDO_ERR_INVALID_ARGUMENT;
98
0
                goto fail;
99
0
        }
100
164
101
164
        if ((argv[0] = cbor_build_string(assert->rp_id)) == NULL ||
102
164
            (argv[1] = fido_blob_encode(&assert->cdh)) == NULL) {
103
2
                fido_log_debug("%s: cbor encode", __func__);
104
2
                r = FIDO_ERR_INTERNAL;
105
2
                goto fail;
106
2
        }
107
162
108
162
        /* allowed credentials */
109
162
        if (assert->allow_list.len) {
110
111
                const fido_blob_array_t *cl = &assert->allow_list;
111
111
                if ((argv[2] = cbor_encode_pubkey_list(cl)) == NULL) {
112
9
                        fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
113
9
                        r = FIDO_ERR_INTERNAL;
114
9
                        goto fail;
115
9
                }
116
153
        }
117
153
118
153
        /* hmac-secret extension */
119
153
        if (assert->ext & FIDO_EXT_HMAC_SECRET)
120
153
                if ((argv[3] = cbor_encode_hmac_secret_param(ecdh, pk,
121
25
                    &assert->hmac_salt)) == NULL) {
122
14
                        fido_log_debug("%s: cbor_encode_hmac_secret_param",
123
14
                            __func__);
124
14
                        r = FIDO_ERR_INTERNAL;
125
14
                        goto fail;
126
14
                }
127
139
128
139
        /* options */
129
139
        if (assert->up != FIDO_OPT_OMIT || assert->uv != FIDO_OPT_OMIT)
130
98
                if ((argv[4] = cbor_encode_assert_options(assert->up,
131
98
                    assert->uv)) == NULL) {
132
4
                        fido_log_debug("%s: cbor_encode_assert_options",
133
4
                            __func__);
134
4
                        r = FIDO_ERR_INTERNAL;
135
4
                        goto fail;
136
4
                }
137
135
138
135
        /* pin authentication */
139
135
        if (pin) {
140
135
                if (pk == NULL || ecdh == NULL) {
141
0
                        fido_log_debug("%s: pin=%p, pk=%p, ecdh=%p", __func__,
142
0
                            (const void *)pin, (const void *)pk,
143
0
                            (const void *)ecdh);
144
0
                        r = FIDO_ERR_INVALID_ARGUMENT;
145
0
                        goto fail;
146
0
                }
147
135
                if ((r = cbor_add_pin_params(dev, &assert->cdh, pk, ecdh, pin,
148
135
                    &argv[5], &argv[6])) != FIDO_OK) {
149
50
                        fido_log_debug("%s: cbor_add_pin_params", __func__);
150
50
                        goto fail;
151
50
                }
152
85
        }
153
85
154
85
        /* frame and transmit */
155
85
        if (cbor_build_frame(CTAP_CBOR_ASSERT, argv, 7, &f) < 0 ||
156
85
            fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
157
6
                fido_log_debug("%s: fido_tx", __func__);
158
6
                r = FIDO_ERR_TX;
159
6
                goto fail;
160
6
        }
161
79
162
79
        r = FIDO_OK;
163
164
fail:
164
164
        cbor_vector_free(argv, nitems(argv));
165
164
        free(f.ptr);
166
164
167
164
        return (r);
168
79
}
169
170
static int
171
fido_dev_get_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
172
79
{
173
79
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
174
79
        unsigned char   reply[2048];
175
79
        int             reply_len;
176
79
        int             r;
177
79
178
79
        fido_assert_reset_rx(assert);
179
79
180
79
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
181
11
                fido_log_debug("%s: fido_rx", __func__);
182
11
                return (FIDO_ERR_RX);
183
11
        }
184
68
185
68
        /* start with room for a single assertion */
186
68
        if ((assert->stmt = calloc(1, sizeof(fido_assert_stmt))) == NULL)
187
68
                return (FIDO_ERR_INTERNAL);
188
67
189
67
        assert->stmt_len = 0;
190
67
        assert->stmt_cnt = 1;
191
67
192
67
        /* adjust as needed */
193
67
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, assert,
194
67
            adjust_assert_count)) != FIDO_OK) {
195
6
                fido_log_debug("%s: adjust_assert_count", __func__);
196
6
                return (r);
197
6
        }
198
61
199
61
        /* parse the first assertion */
200
61
        if ((r = cbor_parse_reply(reply, (size_t)reply_len,
201
61
            &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) {
202
13
                fido_log_debug("%s: parse_assert_reply", __func__);
203
13
                return (r);
204
13
        }
205
48
206
48
        assert->stmt_len++;
207
48
208
48
        return (FIDO_OK);
209
48
}
210
211
static int
212
fido_get_next_assert_tx(fido_dev_t *dev)
213
35
{
214
35
        const unsigned char     cbor[] = { CTAP_CBOR_NEXT_ASSERT };
215
35
        const uint8_t           cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
216
35
217
35
        if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) {
218
1
                fido_log_debug("%s: fido_tx", __func__);
219
1
                return (FIDO_ERR_TX);
220
1
        }
221
34
222
34
        return (FIDO_OK);
223
34
}
224
225
static int
226
fido_get_next_assert_rx(fido_dev_t *dev, fido_assert_t *assert, int ms)
227
34
{
228
34
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
229
34
        unsigned char   reply[2048];
230
34
        int             reply_len;
231
34
        int             r;
232
34
233
34
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
234
6
                fido_log_debug("%s: fido_rx", __func__);
235
6
                return (FIDO_ERR_RX);
236
6
        }
237
28
238
28
        /* sanity check */
239
28
        if (assert->stmt_len >= assert->stmt_cnt) {
240
0
                fido_log_debug("%s: stmt_len=%zu, stmt_cnt=%zu", __func__,
241
0
                    assert->stmt_len, assert->stmt_cnt);
242
0
                return (FIDO_ERR_INTERNAL);
243
0
        }
244
28
245
28
        if ((r = cbor_parse_reply(reply, (size_t)reply_len,
246
28
            &assert->stmt[assert->stmt_len], parse_assert_reply)) != FIDO_OK) {
247
7
                fido_log_debug("%s: parse_assert_reply", __func__);
248
7
                return (r);
249
7
        }
250
21
251
21
        return (FIDO_OK);
252
21
}
253
254
static int
255
fido_dev_get_assert_wait(fido_dev_t *dev, fido_assert_t *assert,
256
    const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin, int ms)
257
164
{
258
164
        int r;
259
164
260
164
        if ((r = fido_dev_get_assert_tx(dev, assert, pk, ecdh, pin)) != FIDO_OK ||
261
164
            (r = fido_dev_get_assert_rx(dev, assert, ms)) != FIDO_OK)
262
164
                return (r);
263
48
264
69
        while (assert->stmt_len < assert->stmt_cnt) {
265
35
                if ((r = fido_get_next_assert_tx(dev)) != FIDO_OK ||
266
35
                    (r = fido_get_next_assert_rx(dev, assert, ms)) != FIDO_OK)
267
35
                        return (r);
268
21
                assert->stmt_len++;
269
21
        }
270
48
271
48
        return (FIDO_OK);
272
48
}
273
274
static int
275
decrypt_hmac_secrets(fido_assert_t *assert, const fido_blob_t *key)
276
3
{
277
6
        for (size_t i = 0; i < assert->stmt_cnt; i++) {
278
3
                fido_assert_stmt *stmt = &assert->stmt[i];
279
3
                if (stmt->hmac_secret_enc.ptr != NULL) {
280
1
                        if (aes256_cbc_dec(key, &stmt->hmac_secret_enc,
281
1
                            &stmt->hmac_secret) < 0) {
282
0
                                fido_log_debug("%s: aes256_cbc_dec %zu",
283
0
                                    __func__, i);
284
0
                                return (-1);
285
0
                        }
286
1
                }
287
3
        }
288
3
289
3
        return (0);
290
3
}
291
292
int
293
fido_dev_get_assert(fido_dev_t *dev, fido_assert_t *assert, const char *pin)
294
434
{
295
434
        fido_blob_t     *ecdh = NULL;
296
434
        es256_pk_t      *pk = NULL;
297
434
        int              r;
298
434
299
434
        if (assert->rp_id == NULL || assert->cdh.ptr == NULL) {
300
2
                fido_log_debug("%s: rp_id=%p, cdh.ptr=%p", __func__,
301
2
                    (void *)assert->rp_id, (void *)assert->cdh.ptr);
302
2
                return (FIDO_ERR_INVALID_ARGUMENT);
303
2
        }
304
432
305
432
        if (fido_dev_is_fido2(dev) == false) {
306
150
                if (pin != NULL || assert->ext != 0)
307
14
                        return (FIDO_ERR_UNSUPPORTED_OPTION);
308
136
                return (u2f_authenticate(dev, assert, -1));
309
136
        }
310
282
311
282
        if (pin != NULL || assert->ext != 0) {
312
282
                if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
313
118
                        fido_log_debug("%s: fido_do_ecdh", __func__);
314
118
                        goto fail;
315
118
                }
316
164
        }
317
164
 
318
164
        r = fido_dev_get_assert_wait(dev, assert, pk, ecdh, pin, -1);
319
164
        if (r == FIDO_OK && assert->ext & FIDO_EXT_HMAC_SECRET)
320
164
                if (decrypt_hmac_secrets(assert, ecdh) < 0) {
321
0
                        fido_log_debug("%s: decrypt_hmac_secrets", __func__);
322
0
                        r = FIDO_ERR_INTERNAL;
323
0
                        goto fail;
324
0
                }
325
282
326
282
fail:
327
282
        es256_pk_free(&pk);
328
282
        fido_blob_free(&ecdh);
329
282
330
282
        return (r);
331
164
}
332
333
int
334
fido_check_flags(uint8_t flags, fido_opt_t up, fido_opt_t uv)
335
159
{
336
159
        fido_log_debug("%s: flags=%02x", __func__, flags);
337
159
        fido_log_debug("%s: up=%d, uv=%d", __func__, up, uv);
338
159
339
159
        if (up == FIDO_OPT_TRUE &&
340
159
            (flags & CTAP_AUTHDATA_USER_PRESENT) == 0) {
341
11
                fido_log_debug("%s: CTAP_AUTHDATA_USER_PRESENT", __func__);
342
11
                return (-1); /* user not present */
343
11
        }
344
148
345
148
        if (uv == FIDO_OPT_TRUE &&
346
148
            (flags & CTAP_AUTHDATA_USER_VERIFIED) == 0) {
347
2
                fido_log_debug("%s: CTAP_AUTHDATA_USER_VERIFIED", __func__);
348
2
                return (-1); /* user not verified */
349
2
        }
350
146
351
146
        return (0);
352
146
}
353
354
static int
355
check_extensions(int authdata_ext, int ext)
356
122
{
357
122
        if (authdata_ext != ext) {
358
1
                fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__,
359
1
                    authdata_ext, ext);
360
1
                return (-1);
361
1
        }
362
121
363
121
        return (0);
364
121
}
365
366
static int
367
get_signed_hash(int cose_alg, fido_blob_t *dgst, const fido_blob_t *clientdata,
368
    const fido_blob_t *authdata_cbor)
369
115
{
370
115
        cbor_item_t             *item = NULL;
371
115
        unsigned char           *authdata_ptr = NULL;
372
115
        size_t                   authdata_len;
373
115
        struct cbor_load_result  cbor;
374
115
        SHA256_CTX               ctx;
375
115
        int                      ok = -1;
376
115
377
115
        if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len,
378
115
            &cbor)) == NULL || cbor_isa_bytestring(item) == false ||
379
115
            cbor_bytestring_is_definite(item) == false) {
380
1
                fido_log_debug("%s: authdata", __func__);
381
1
                goto fail;
382
1
        }
383
114
384
114
        authdata_ptr = cbor_bytestring_handle(item);
385
114
        authdata_len = cbor_bytestring_length(item);
386
114
387
114
        if (cose_alg != COSE_EDDSA) {
388
97
                if (dgst->len < SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
389
97
                    SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 ||
390
97
                    SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
391
97
                    SHA256_Final(dgst->ptr, &ctx) == 0) {
392
5
                        fido_log_debug("%s: sha256", __func__);
393
5
                        goto fail;
394
5
                }
395
92
                dgst->len = SHA256_DIGEST_LENGTH;
396
92
        } else {
397
17
                if (SIZE_MAX - authdata_len < clientdata->len ||
398
17
                    dgst->len < authdata_len + clientdata->len) {
399
1
                        fido_log_debug("%s: memcpy", __func__);
400
1
                        goto fail;
401
1
                }
402
16
                memcpy(dgst->ptr, authdata_ptr, authdata_len);
403
16
                memcpy(dgst->ptr + authdata_len, clientdata->ptr,
404
16
                    clientdata->len);
405
16
                dgst->len = authdata_len + clientdata->len;
406
16
        }
407
114
408
114
        ok = 0;
409
115
fail:
410
115
        if (item != NULL)
411
115
                cbor_decref(&item);
412
115
413
115
        return (ok);
414
108
}
415
416
int
417
fido_verify_sig_es256(const fido_blob_t *dgst, const es256_pk_t *pk,
418
    const fido_blob_t *sig)
419
51
{
420
51
        EVP_PKEY        *pkey = NULL;
421
51
        EC_KEY          *ec = NULL;
422
51
        int              ok = -1;
423
51
424
51
        /* ECDSA_verify needs ints */
425
51
        if (dgst->len > INT_MAX || sig->len > INT_MAX) {
426
0
                fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
427
0
                    dgst->len, sig->len);
428
0
                return (-1);
429
0
        }
430
51
431
51
        if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL ||
432
51
            (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
433
46
                fido_log_debug("%s: pk -> ec", __func__);
434
46
                goto fail;
435
46
        }
436
5
437
5
        if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
438
5
            (int)sig->len, ec) != 1) {
439
5
                fido_log_debug("%s: ECDSA_verify", __func__);
440
5
                goto fail;
441
5
        }
442
0
443
0
        ok = 0;
444
51
fail:
445
51
        if (pkey != NULL)
446
51
                EVP_PKEY_free(pkey);
447
51
448
51
        return (ok);
449
0
}
450
451
int
452
fido_verify_sig_rs256(const fido_blob_t *dgst, const rs256_pk_t *pk,
453
    const fido_blob_t *sig)
454
43
{
455
43
        EVP_PKEY        *pkey = NULL;
456
43
        RSA             *rsa = NULL;
457
43
        int              ok = -1;
458
43
459
43
        /* RSA_verify needs unsigned ints */
460
43
        if (dgst->len > UINT_MAX || sig->len > UINT_MAX) {
461
0
                fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
462
0
                    dgst->len, sig->len);
463
0
                return (-1);
464
0
        }
465
43
466
43
        if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL ||
467
43
            (rsa = EVP_PKEY_get0_RSA(pkey)) == NULL) {
468
9
                fido_log_debug("%s: pk -> ec", __func__);
469
9
                goto fail;
470
9
        }
471
34
472
34
        if (RSA_verify(NID_sha256, dgst->ptr, (unsigned int)dgst->len, sig->ptr,
473
34
            (unsigned int)sig->len, rsa) != 1) {
474
34
                fido_log_debug("%s: RSA_verify", __func__);
475
34
                goto fail;
476
34
        }
477
0
478
0
        ok = 0;
479
43
fail:
480
43
        if (pkey != NULL)
481
43
                EVP_PKEY_free(pkey);
482
43
483
43
        return (ok);
484
0
}
485
486
int
487
fido_verify_sig_eddsa(const fido_blob_t *dgst, const eddsa_pk_t *pk,
488
    const fido_blob_t *sig)
489
16
{
490
16
        EVP_PKEY        *pkey = NULL;
491
16
        EVP_MD_CTX      *mdctx = NULL;
492
16
        int              ok = -1;
493
16
494
16
        /* EVP_DigestVerify needs ints */
495
16
        if (dgst->len > INT_MAX || sig->len > INT_MAX) {
496
0
                fido_log_debug("%s: dgst->len=%zu, sig->len=%zu", __func__,
497
0
                    dgst->len, sig->len);
498
0
                return (-1);
499
0
        }
500
16
501
16
        if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
502
2
                fido_log_debug("%s: pk -> pkey", __func__);
503
2
                goto fail;
504
2
        }
505
14
506
14
        if ((mdctx = EVP_MD_CTX_new()) == NULL) {
507
2
                fido_log_debug("%s: EVP_MD_CTX_new", __func__);
508
2
                goto fail;
509
2
        }
510
12
511
12
        if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) {
512
1
                fido_log_debug("%s: EVP_DigestVerifyInit", __func__);
513
1
                goto fail;
514
1
        }
515
11
516
11
        if (EVP_DigestVerify(mdctx, sig->ptr, sig->len, dgst->ptr,
517
11
            dgst->len) != 1) {
518
11
                fido_log_debug("%s: EVP_DigestVerify", __func__);
519
11
                goto fail;
520
11
        }
521
0
522
0
        ok = 0;
523
16
fail:
524
16
        if (mdctx != NULL)
525
16
                EVP_MD_CTX_free(mdctx);
526
16
527
16
        if (pkey != NULL)
528
16
                EVP_PKEY_free(pkey);
529
16
530
16
        return (ok);
531
0
}
532
533
int
534
fido_assert_verify(const fido_assert_t *assert, size_t idx, int cose_alg,
535
    const void *pk)
536
15.7k
{
537
15.7k
        unsigned char            buf[1024];
538
15.7k
        fido_blob_t              dgst;
539
15.7k
        const fido_assert_stmt  *stmt = NULL;
540
15.7k
        int                      ok = -1;
541
15.7k
        int                      r;
542
15.7k
543
15.7k
        dgst.ptr = buf;
544
15.7k
        dgst.len = sizeof(buf);
545
15.7k
546
15.7k
        if (idx >= assert->stmt_len || pk == NULL) {
547
56
                r = FIDO_ERR_INVALID_ARGUMENT;
548
56
                goto out;
549
56
        }
550
15.7k
551
15.7k
        stmt = &assert->stmt[idx];
552
15.7k
553
15.7k
        /* do we have everything we need? */
554
15.7k
        if (assert->cdh.ptr == NULL || assert->rp_id == NULL ||
555
15.7k
            stmt->authdata_cbor.ptr == NULL || stmt->sig.ptr == NULL) {
556
15.6k
                fido_log_debug("%s: cdh=%p, rp_id=%s, authdata=%p, sig=%p",
557
15.6k
                    __func__, (void *)assert->cdh.ptr, assert->rp_id,
558
15.6k
                    (void *)stmt->authdata_cbor.ptr, (void *)stmt->sig.ptr);
559
15.6k
                r = FIDO_ERR_INVALID_ARGUMENT;
560
15.6k
                goto out;
561
15.6k
        }
562
133
563
133
        if (fido_check_flags(stmt->authdata.flags, assert->up,
564
133
            assert->uv) < 0) {
565
11
                fido_log_debug("%s: fido_check_flags", __func__);
566
11
                r = FIDO_ERR_INVALID_PARAM;
567
11
                goto out;
568
11
        }
569
122
570
122
        if (check_extensions(stmt->authdata_ext, assert->ext) < 0) {
571
1
                fido_log_debug("%s: check_extensions", __func__);
572
1
                r = FIDO_ERR_INVALID_PARAM;
573
1
                goto out;
574
1
        }
575
121
576
121
        if (fido_check_rp_id(assert->rp_id, stmt->authdata.rp_id_hash) != 0) {
577
6
                fido_log_debug("%s: fido_check_rp_id", __func__);
578
6
                r = FIDO_ERR_INVALID_PARAM;
579
6
                goto out;
580
6
        }
581
115
582
115
        if (get_signed_hash(cose_alg, &dgst, &assert->cdh,
583
115
            &stmt->authdata_cbor) < 0) {
584
7
                fido_log_debug("%s: get_signed_hash", __func__);
585
7
                r = FIDO_ERR_INTERNAL;
586
7
                goto out;
587
7
        }
588
108
589
108
        switch (cose_alg) {
590
108
        case COSE_ES256:
591
49
                ok = fido_verify_sig_es256(&dgst, pk, &stmt->sig);
592
49
                break;
593
108
        case COSE_RS256:
594
43
                ok = fido_verify_sig_rs256(&dgst, pk, &stmt->sig);
595
43
                break;
596
108
        case COSE_EDDSA:
597
16
                ok = fido_verify_sig_eddsa(&dgst, pk, &stmt->sig);
598
16
                break;
599
108
        default:
600
0
                fido_log_debug("%s: unsupported cose_alg %d", __func__,
601
0
                    cose_alg);
602
0
                r = FIDO_ERR_UNSUPPORTED_OPTION;
603
0
                goto out;
604
108
        }
605
108
606
108
        if (ok < 0)
607
108
                r = FIDO_ERR_INVALID_SIG;
608
108
        else
609
108
                r = FIDO_OK;
610
15.7k
out:
611
15.7k
        explicit_bzero(buf, sizeof(buf));
612
15.7k
613
15.7k
        return (r);
614
108
}
615
616
int
617
fido_assert_set_clientdata_hash(fido_assert_t *assert,
618
    const unsigned char *hash, size_t hash_len)
619
16.2k
{
620
16.2k
        if (fido_blob_set(&assert->cdh, hash, hash_len) < 0)
621
82
                return (FIDO_ERR_INVALID_ARGUMENT);
622
16.1k
623
16.1k
        return (FIDO_OK);
624
16.1k
}
625
626
int
627
fido_assert_set_hmac_salt(fido_assert_t *assert, const unsigned char *salt,
628
    size_t salt_len)
629
434
{
630
434
        if ((salt_len != 32 && salt_len != 64) ||
631
434
            fido_blob_set(&assert->hmac_salt, salt, salt_len) < 0)
632
408
                return (FIDO_ERR_INVALID_ARGUMENT);
633
26
634
26
        return (FIDO_OK);
635
26
}
636
637
int
638
fido_assert_set_rp(fido_assert_t *assert, const char *id)
639
16.2k
{
640
16.2k
        if (assert->rp_id != NULL) {
641
0
                free(assert->rp_id);
642
0
                assert->rp_id = NULL;
643
0
        }
644
16.2k
645
16.2k
        if (id == NULL)
646
16.2k
                return (FIDO_ERR_INVALID_ARGUMENT);
647
16.2k
648
16.2k
        if ((assert->rp_id = strdup(id)) == NULL)
649
16.2k
                return (FIDO_ERR_INTERNAL);
650
16.1k
651
16.1k
        return (FIDO_OK);
652
16.1k
}
653
654
int
655
fido_assert_allow_cred(fido_assert_t *assert, const unsigned char *ptr,
656
    size_t len)
657
31.4k
{
658
31.4k
        fido_blob_t      id;
659
31.4k
        fido_blob_t     *list_ptr;
660
31.4k
        int              r;
661
31.4k
662
31.4k
        memset(&id, 0, sizeof(id));
663
31.4k
664
31.4k
        if (assert->allow_list.len == SIZE_MAX) {
665
0
                r = FIDO_ERR_INVALID_ARGUMENT;
666
0
                goto fail;
667
0
        }
668
31.4k
669
31.4k
        if (fido_blob_set(&id, ptr, len) < 0 || (list_ptr =
670
31.4k
            recallocarray(assert->allow_list.ptr, assert->allow_list.len,
671
31.4k
            assert->allow_list.len + 1, sizeof(fido_blob_t))) == NULL) {
672
175
                r = FIDO_ERR_INVALID_ARGUMENT;
673
175
                goto fail;
674
175
        }
675
31.3k
676
31.3k
        list_ptr[assert->allow_list.len++] = id;
677
31.3k
        assert->allow_list.ptr = list_ptr;
678
31.3k
679
31.3k
        return (FIDO_OK);
680
175
fail:
681
175
        free(id.ptr);
682
175
683
175
        return (r);
684
31.3k
685
31.3k
}
686
687
int
688
fido_assert_set_extensions(fido_assert_t *assert, int ext)
689
15.8k
{
690
15.8k
        if (ext != 0 && ext != FIDO_EXT_HMAC_SECRET)
691
15.8k
                return (FIDO_ERR_INVALID_ARGUMENT);
692
1.42k
693
1.42k
        assert->ext = ext;
694
1.42k
695
1.42k
        return (FIDO_OK);
696
1.42k
}
697
698
int
699
fido_assert_set_options(fido_assert_t *assert, bool up, bool uv)
700
0
{
701
0
        assert->up = up ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
702
0
        assert->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
703
0
704
0
        return (FIDO_OK);
705
0
}
706
707
int
708
fido_assert_set_up(fido_assert_t *assert, fido_opt_t up)
709
6.36k
{
710
6.36k
        assert->up = up;
711
6.36k
712
6.36k
        return (FIDO_OK);
713
6.36k
}
714
715
int
716
fido_assert_set_uv(fido_assert_t *assert, fido_opt_t uv)
717
327
{
718
327
        assert->uv = uv;
719
327
720
327
        return (FIDO_OK);
721
327
}
722
723
const unsigned char *
724
fido_assert_clientdata_hash_ptr(const fido_assert_t *assert)
725
15.8k
{
726
15.8k
        return (assert->cdh.ptr);
727
15.8k
}
728
729
size_t
730
fido_assert_clientdata_hash_len(const fido_assert_t *assert)
731
15.8k
{
732
15.8k
        return (assert->cdh.len);
733
15.8k
}
734
735
fido_assert_t *
736
fido_assert_new(void)
737
16.3k
{
738
16.3k
        return (calloc(1, sizeof(fido_assert_t)));
739
16.3k
}
740
741
void
742
fido_assert_reset_tx(fido_assert_t *assert)
743
16.2k
{
744
16.2k
        free(assert->rp_id);
745
16.2k
        free(assert->cdh.ptr);
746
16.2k
        free(assert->hmac_salt.ptr);
747
16.2k
        fido_free_blob_array(&assert->allow_list);
748
16.2k
749
16.2k
        memset(&assert->cdh, 0, sizeof(assert->cdh));
750
16.2k
        memset(&assert->hmac_salt, 0, sizeof(assert->hmac_salt));
751
16.2k
        memset(&assert->allow_list, 0, sizeof(assert->allow_list));
752
16.2k
753
16.2k
        assert->rp_id = NULL;
754
16.2k
        assert->up = FIDO_OPT_OMIT;
755
16.2k
        assert->uv = FIDO_OPT_OMIT;
756
16.2k
        assert->ext = 0;
757
16.2k
}
758
759
void
760
fido_assert_reset_rx(fido_assert_t *assert)
761
16.3k
{
762
48.1k
        for (size_t i = 0; i < assert->stmt_cnt; i++) {
763
31.7k
                free(assert->stmt[i].user.id.ptr);
764
31.7k
                free(assert->stmt[i].user.icon);
765
31.7k
                free(assert->stmt[i].user.name);
766
31.7k
                free(assert->stmt[i].user.display_name);
767
31.7k
                free(assert->stmt[i].id.ptr);
768
31.7k
                if (assert->stmt[i].hmac_secret.ptr != NULL) {
769
1
                        explicit_bzero(assert->stmt[i].hmac_secret.ptr,
770
1
                            assert->stmt[i].hmac_secret.len);
771
1
                }
772
31.7k
                free(assert->stmt[i].hmac_secret.ptr);
773
31.7k
                free(assert->stmt[i].hmac_secret_enc.ptr);
774
31.7k
                free(assert->stmt[i].authdata_cbor.ptr);
775
31.7k
                free(assert->stmt[i].sig.ptr);
776
31.7k
                memset(&assert->stmt[i], 0, sizeof(assert->stmt[i]));
777
31.7k
        }
778
16.3k
779
16.3k
        free(assert->stmt);
780
16.3k
781
16.3k
        assert->stmt = NULL;
782
16.3k
        assert->stmt_len = 0;
783
16.3k
        assert->stmt_cnt = 0;
784
16.3k
}
785
786
void
787
fido_assert_free(fido_assert_t **assert_p)
788
16.2k
{
789
16.2k
        fido_assert_t *assert;
790
16.2k
791
16.2k
        if (assert_p == NULL || (assert = *assert_p) == NULL)
792
16.2k
                return;
793
16.2k
794
16.2k
        fido_assert_reset_tx(assert);
795
16.2k
        fido_assert_reset_rx(assert);
796
16.2k
797
16.2k
        free(assert);
798
16.2k
799
16.2k
        *assert_p = NULL;
800
16.2k
}
801
802
size_t
803
fido_assert_count(const fido_assert_t *assert)
804
16.3k
{
805
16.3k
        return (assert->stmt_len);
806
16.3k
}
807
808
const char *
809
fido_assert_rp_id(const fido_assert_t *assert)
810
15.8k
{
811
15.8k
        return (assert->rp_id);
812
15.8k
}
813
814
uint8_t
815
fido_assert_flags(const fido_assert_t *assert, size_t idx)
816
15.8k
{
817
15.8k
        if (idx >= assert->stmt_len)
818
457
                return (0);
819
15.3k
820
15.3k
        return (assert->stmt[idx].authdata.flags);
821
15.3k
}
822
823
uint32_t
824
fido_assert_sigcount(const fido_assert_t *assert, size_t idx)
825
15.8k
{
826
15.8k
        if (idx >= assert->stmt_len)
827
457
                return (0);
828
15.3k
829
15.3k
        return (assert->stmt[idx].authdata.sigcount);
830
15.3k
}
831
832
const unsigned char *
833
fido_assert_authdata_ptr(const fido_assert_t *assert, size_t idx)
834
15.8k
{
835
15.8k
        if (idx >= assert->stmt_len)
836
457
                return (NULL);
837
15.3k
838
15.3k
        return (assert->stmt[idx].authdata_cbor.ptr);
839
15.3k
}
840
841
size_t
842
fido_assert_authdata_len(const fido_assert_t *assert, size_t idx)
843
15.8k
{
844
15.8k
        if (idx >= assert->stmt_len)
845
457
                return (0);
846
15.3k
847
15.3k
        return (assert->stmt[idx].authdata_cbor.len);
848
15.3k
}
849
850
const unsigned char *
851
fido_assert_sig_ptr(const fido_assert_t *assert, size_t idx)
852
15.8k
{
853
15.8k
        if (idx >= assert->stmt_len)
854
457
                return (NULL);
855
15.3k
856
15.3k
        return (assert->stmt[idx].sig.ptr);
857
15.3k
}
858
859
size_t
860
fido_assert_sig_len(const fido_assert_t *assert, size_t idx)
861
15.8k
{
862
15.8k
        if (idx >= assert->stmt_len)
863
457
                return (0);
864
15.3k
865
15.3k
        return (assert->stmt[idx].sig.len);
866
15.3k
}
867
868
const unsigned char *
869
fido_assert_id_ptr(const fido_assert_t *assert, size_t idx)
870
15.8k
{
871
15.8k
        if (idx >= assert->stmt_len)
872
457
                return (NULL);
873
15.3k
874
15.3k
        return (assert->stmt[idx].id.ptr);
875
15.3k
}
876
877
size_t
878
fido_assert_id_len(const fido_assert_t *assert, size_t idx)
879
15.8k
{
880
15.8k
        if (idx >= assert->stmt_len)
881
457
                return (0);
882
15.3k
883
15.3k
        return (assert->stmt[idx].id.len);
884
15.3k
}
885
886
const unsigned char *
887
fido_assert_user_id_ptr(const fido_assert_t *assert, size_t idx)
888
15.8k
{
889
15.8k
        if (idx >= assert->stmt_len)
890
457
                return (NULL);
891
15.3k
892
15.3k
        return (assert->stmt[idx].user.id.ptr);
893
15.3k
}
894
895
size_t
896
fido_assert_user_id_len(const fido_assert_t *assert, size_t idx)
897
15.8k
{
898
15.8k
        if (idx >= assert->stmt_len)
899
457
                return (0);
900
15.3k
901
15.3k
        return (assert->stmt[idx].user.id.len);
902
15.3k
}
903
904
const char *
905
fido_assert_user_icon(const fido_assert_t *assert, size_t idx)
906
31.7k
{
907
31.7k
        if (idx >= assert->stmt_len)
908
914
                return (NULL);
909
30.7k
910
30.7k
        return (assert->stmt[idx].user.icon);
911
30.7k
}
912
913
const char *
914
fido_assert_user_name(const fido_assert_t *assert, size_t idx)
915
31.7k
{
916
31.7k
        if (idx >= assert->stmt_len)
917
914
                return (NULL);
918
30.7k
919
30.7k
        return (assert->stmt[idx].user.name);
920
30.7k
}
921
922
const char *
923
fido_assert_user_display_name(const fido_assert_t *assert, size_t idx)
924
31.7k
{
925
31.7k
        if (idx >= assert->stmt_len)
926
914
                return (NULL);
927
30.7k
928
30.7k
        return (assert->stmt[idx].user.display_name);
929
30.7k
}
930
931
const unsigned char *
932
fido_assert_hmac_secret_ptr(const fido_assert_t *assert, size_t idx)
933
15.8k
{
934
15.8k
        if (idx >= assert->stmt_len)
935
457
                return (NULL);
936
15.3k
937
15.3k
        return (assert->stmt[idx].hmac_secret.ptr);
938
15.3k
}
939
940
size_t
941
fido_assert_hmac_secret_len(const fido_assert_t *assert, size_t idx)
942
15.8k
{
943
15.8k
        if (idx >= assert->stmt_len)
944
457
                return (0);
945
15.3k
946
15.3k
        return (assert->stmt[idx].hmac_secret.len);
947
15.3k
}
948
949
static void
950
fido_assert_clean_authdata(fido_assert_stmt *as)
951
306
{
952
306
        free(as->authdata_cbor.ptr);
953
306
        free(as->hmac_secret_enc.ptr);
954
306
955
306
        memset(&as->authdata_ext, 0, sizeof(as->authdata_ext));
956
306
        memset(&as->authdata_cbor, 0, sizeof(as->authdata_cbor));
957
306
        memset(&as->authdata, 0, sizeof(as->authdata));
958
306
        memset(&as->hmac_secret_enc, 0, sizeof(as->hmac_secret_enc));
959
306
}
960
961
int
962
fido_assert_set_authdata(fido_assert_t *assert, size_t idx,
963
    const unsigned char *ptr, size_t len)
964
15.9k
{
965
15.9k
        cbor_item_t             *item = NULL;
966
15.9k
        fido_assert_stmt        *stmt = NULL;
967
15.9k
        struct cbor_load_result  cbor;
968
15.9k
        int                      r;
969
15.9k
970
15.9k
        if (idx >= assert->stmt_len || ptr == NULL || len == 0)
971
15.6k
                return (FIDO_ERR_INVALID_ARGUMENT);
972
288
973
288
        stmt = &assert->stmt[idx];
974
288
        fido_assert_clean_authdata(stmt);
975
288
976
288
        if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
977
3
                fido_log_debug("%s: cbor_load", __func__);
978
3
                r = FIDO_ERR_INVALID_ARGUMENT;
979
3
                goto fail;
980
3
        }
981
285
982
285
        if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor,
983
285
            &stmt->authdata, &stmt->authdata_ext, &stmt->hmac_secret_enc) < 0) {
984
4
                fido_log_debug("%s: cbor_decode_assert_authdata", __func__);
985
4
                r = FIDO_ERR_INVALID_ARGUMENT;
986
4
                goto fail;
987
4
        }
988
281
989
281
        r = FIDO_OK;
990
288
fail:
991
288
        if (item != NULL)
992
288
                cbor_decref(&item);
993
288
994
288
        if (r != FIDO_OK)
995
288
                fido_assert_clean_authdata(stmt);
996
288
997
288
        return (r);
998
281
}
999
1000
int
1001
fido_assert_set_authdata_raw(fido_assert_t *assert, size_t idx,
1002
    const unsigned char *ptr, size_t len)
1003
15.6k
{
1004
15.6k
        cbor_item_t             *item = NULL;
1005
15.6k
        fido_assert_stmt        *stmt = NULL;
1006
15.6k
        int                      r;
1007
15.6k
1008
15.6k
        if (idx >= assert->stmt_len || ptr == NULL || len == 0)
1009
15.6k
                return (FIDO_ERR_INVALID_ARGUMENT);
1010
6
1011
6
        stmt = &assert->stmt[idx];
1012
6
        fido_assert_clean_authdata(stmt);
1013
6
1014
6
        if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
1015
1
                fido_log_debug("%s: cbor_build_bytestring", __func__);
1016
1
                r = FIDO_ERR_INTERNAL;
1017
1
                goto fail;
1018
1
        }
1019
5
1020
5
        if (cbor_decode_assert_authdata(item, &stmt->authdata_cbor,
1021
5
            &stmt->authdata, &stmt->authdata_ext, &stmt->hmac_secret_enc) < 0) {
1022
4
                fido_log_debug("%s: cbor_decode_assert_authdata", __func__);
1023
4
                r = FIDO_ERR_INVALID_ARGUMENT;
1024
4
                goto fail;
1025
4
        }
1026
1
1027
1
        r = FIDO_OK;
1028
6
fail:
1029
6
        if (item != NULL)
1030
6
                cbor_decref(&item);
1031
6
1032
6
        if (r != FIDO_OK)
1033
6
                fido_assert_clean_authdata(stmt);
1034
6
1035
6
        return (r);
1036
1
}
1037
1038
static void
1039
fido_assert_clean_sig(fido_assert_stmt *as)
1040
275
{
1041
275
        free(as->sig.ptr);
1042
275
        as->sig.ptr = NULL;
1043
275
        as->sig.len = 0;
1044
275
}
1045
1046
int
1047
fido_assert_set_sig(fido_assert_t *a, size_t idx, const unsigned char *ptr,
1048
    size_t len)
1049
15.9k
{
1050
15.9k
        unsigned char *sig;
1051
15.9k
1052
15.9k
        if (idx >= a->stmt_len || ptr == NULL || len == 0)
1053
15.6k
                return (FIDO_ERR_INVALID_ARGUMENT);
1054
275
1055
275
        fido_assert_clean_sig(&a->stmt[idx]);
1056
275
1057
275
        if ((sig = malloc(len)) == NULL)
1058
275
                return (FIDO_ERR_INTERNAL);
1059
273
1060
273
        memcpy(sig, ptr, len);
1061
273
        a->stmt[idx].sig.ptr = sig;
1062
273
        a->stmt[idx].sig.len = len;
1063
273
1064
273
        return (FIDO_OK);
1065
273
}
1066
1067
/* XXX shrinking leaks memory; fortunately that shouldn't happen */
1068
int
1069
fido_assert_set_count(fido_assert_t *assert, size_t n)
1070
15.9k
{
1071
15.9k
        void *new_stmt;
1072
15.9k
1073
15.9k
#ifdef FIDO_FUZZ
1074
15.9k
        if (n > UINT8_MAX) {
1075
1
                fido_log_debug("%s: n > UINT8_MAX", __func__);
1076
1
                return (FIDO_ERR_INTERNAL);
1077
1
        }
1078
15.9k
#endif
1079
15.9k
1080
15.9k
        new_stmt = recallocarray(assert->stmt, assert->stmt_cnt, n,
1081
15.9k
            sizeof(fido_assert_stmt));
1082
15.9k
        if (new_stmt == NULL)
1083
15.9k
                return (FIDO_ERR_INTERNAL);
1084
15.8k
1085
15.8k
        assert->stmt = new_stmt;
1086
15.8k
        assert->stmt_cnt = n;
1087
15.8k
        assert->stmt_len = n;
1088
15.8k
1089
15.8k
        return (FIDO_OK);
1090
15.8k
}
/home/pedro/projects/libfido2/src/authkey.c
Line
Count
Source
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 <string.h>
8
#include "fido.h"
9
10
static int
11
parse_authkey(const cbor_item_t *key, const cbor_item_t *val, void *arg)
12
3.42k
{
13
3.42k
        es256_pk_t *authkey = arg;
14
3.42k
15
3.42k
        if (cbor_isa_uint(key) == false ||
16
3.42k
            cbor_int_get_width(key) != CBOR_INT_8 ||
17
3.42k
            cbor_get_uint8(key) != 1) {
18
650
                fido_log_debug("%s: cbor type", __func__);
19
650
                return (0); /* ignore */
20
650
        }
21
2.77k
22
2.77k
        return (es256_pk_decode(val, authkey));
23
2.77k
}
24
25
static int
26
fido_dev_authkey_tx(fido_dev_t *dev)
27
3.57k
{
28
3.57k
        fido_blob_t      f;
29
3.57k
        cbor_item_t     *argv[2];
30
3.57k
        int              r;
31
3.57k
32
3.57k
        fido_log_debug("%s: dev=%p", __func__, (void *)dev);
33
3.57k
34
3.57k
        memset(&f, 0, sizeof(f));
35
3.57k
        memset(argv, 0, sizeof(argv));
36
3.57k
37
3.57k
        /* add command parameters */
38
3.57k
        if ((argv[0] = cbor_build_uint8(1)) == NULL ||
39
3.57k
            (argv[1] = cbor_build_uint8(2)) == NULL) {
40
44
                fido_log_debug("%s: cbor_build", __func__);
41
44
                r = FIDO_ERR_INTERNAL;
42
44
                goto fail;
43
44
        }
44
3.52k
45
3.52k
        /* frame and transmit */
46
3.52k
        if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 2, &f) < 0 ||
47
3.52k
            fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
48
107
                fido_log_debug("%s: fido_tx", __func__);
49
107
                r = FIDO_ERR_TX;
50
107
                goto fail;
51
107
        }
52
3.41k
53
3.41k
        r = FIDO_OK;
54
3.57k
fail:
55
3.57k
        cbor_vector_free(argv, nitems(argv));
56
3.57k
        free(f.ptr);
57
3.57k
58
3.57k
        return (r);
59
3.41k
}
60
61
static int
62
fido_dev_authkey_rx(fido_dev_t *dev, es256_pk_t *authkey, int ms)
63
3.41k
{
64
3.41k
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
65
3.41k
        unsigned char   reply[2048];
66
3.41k
        int             reply_len;
67
3.41k
68
3.41k
        fido_log_debug("%s: dev=%p, authkey=%p, ms=%d", __func__, (void *)dev,
69
3.41k
            (void *)authkey, ms);
70
3.41k
71
3.41k
        memset(authkey, 0, sizeof(*authkey));
72
3.41k
73
3.41k
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
74
291
                fido_log_debug("%s: fido_rx", __func__);
75
291
                return (FIDO_ERR_RX);
76
291
        }
77
3.12k
78
3.12k
        return (cbor_parse_reply(reply, (size_t)reply_len, authkey,
79
3.12k
            parse_authkey));
80
3.12k
}
81
82
static int
83
fido_dev_authkey_wait(fido_dev_t *dev, es256_pk_t *authkey, int ms)
84
3.57k
{
85
3.57k
        int r;
86
3.57k
87
3.57k
        if ((r = fido_dev_authkey_tx(dev)) != FIDO_OK ||
88
3.57k
            (r = fido_dev_authkey_rx(dev, authkey, ms)) != FIDO_OK)
89
3.57k
                return (r);
90
2.41k
91
2.41k
        return (FIDO_OK);
92
2.41k
}
93
94
int
95
fido_dev_authkey(fido_dev_t *dev, es256_pk_t *authkey)
96
3.57k
{
97
3.57k
        return (fido_dev_authkey_wait(dev, authkey, -1));
98
3.57k
}
/home/pedro/projects/libfido2/src/bio.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2019 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 <string.h>
8
9
#include "fido.h"
10
#include "fido/bio.h"
11
#include "fido/es256.h"
12
13
125
#define CMD_ENROLL_BEGIN        0x01
14
291
#define CMD_ENROLL_NEXT         0x02
15
0
#define CMD_ENROLL_CANCEL       0x03
16
338
#define CMD_ENUM                0x04
17
310
#define CMD_SET_NAME            0x05
18
326
#define CMD_ENROLL_REMOVE       0x06
19
137
#define CMD_GET_INFO            0x07
20
21
static int
22
bio_prepare_hmac(uint8_t cmd, cbor_item_t **argv, size_t argc,
23
    cbor_item_t **param, fido_blob_t *hmac_data)
24
1.34k
{
25
1.34k
        const uint8_t    prefix[2] = { 0x01 /* modality */, cmd };
26
1.34k
        int              ok = -1;
27
1.34k
        size_t           cbor_alloc_len;
28
1.34k
        size_t           cbor_len;
29
1.34k
        unsigned char   *cbor = NULL;
30
1.34k
31
1.34k
        if (argv == NULL || param == NULL)
32
1.34k
                return (fido_blob_set(hmac_data, prefix, sizeof(prefix)));
33
1.01k
34
1.01k
        if ((*param = cbor_flatten_vector(argv, argc)) == NULL) {
35
23
                fido_log_debug("%s: cbor_flatten_vector", __func__);
36
23
                goto fail;
37
23
        }
38
992
39
992
        if ((cbor_len = cbor_serialize_alloc(*param, &cbor,
40
992
            &cbor_alloc_len)) == 0 || cbor_len > SIZE_MAX - sizeof(prefix)) {
41
7
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
42
7
                goto fail;
43
7
        }
44
985
45
985
        if ((hmac_data->ptr = malloc(cbor_len + sizeof(prefix))) == NULL) {
46
9
                fido_log_debug("%s: malloc", __func__);
47
9
                goto fail;
48
9
        }
49
976
50
976
        memcpy(hmac_data->ptr, prefix, sizeof(prefix));
51
976
        memcpy(hmac_data->ptr + sizeof(prefix), cbor, cbor_len);
52
976
        hmac_data->len = cbor_len + sizeof(prefix);
53
976
54
976
        ok = 0;
55
1.01k
fail:
56
1.01k
        free(cbor);
57
1.01k
58
1.01k
        return (ok);
59
976
}
60
61
static int
62
bio_tx(fido_dev_t *dev, uint8_t cmd, cbor_item_t **sub_argv, size_t sub_argc,
63
    const char *pin, const fido_blob_t *token)
64
1.49k
{
65
1.49k
        cbor_item_t     *argv[5];
66
1.49k
        es256_pk_t      *pk = NULL;
67
1.49k
        fido_blob_t     *ecdh = NULL;
68
1.49k
        fido_blob_t      f;
69
1.49k
        fido_blob_t      hmac;
70
1.49k
        int              r = FIDO_ERR_INTERNAL;
71
1.49k
72
1.49k
        memset(&f, 0, sizeof(f));
73
1.49k
        memset(&hmac, 0, sizeof(hmac));
74
1.49k
        memset(&argv, 0, sizeof(argv));
75
1.49k
76
1.49k
        /* modality, subCommand */
77
1.49k
        if ((argv[0] = cbor_build_uint8(1)) == NULL ||
78
1.49k
            (argv[1] = cbor_build_uint8(cmd)) == NULL) {
79
18
                fido_log_debug("%s: cbor encode", __func__);
80
18
                goto fail;
81
18
        }
82
1.48k
83
1.48k
        /* subParams */
84
1.48k
        if (pin || token) {
85
1.34k
                if (bio_prepare_hmac(cmd, sub_argv, sub_argc, &argv[2],
86
1.34k
                    &hmac) < 0) {
87
40
                        fido_log_debug("%s: bio_prepare_hmac", __func__);
88
40
                        goto fail;
89
40
                }
90
1.44k
        }
91
1.44k
92
1.44k
        /* pinProtocol, pinAuth */
93
1.44k
        if (pin) {
94
948
                if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
95
578
                        fido_log_debug("%s: fido_do_ecdh", __func__);
96
578
                        goto fail;
97
578
                }
98
370
                if ((r = cbor_add_pin_params(dev, &hmac, pk, ecdh, pin,
99
370
                    &argv[4], &argv[3])) != FIDO_OK) {
100
219
                        fido_log_debug("%s: cbor_add_pin_params", __func__);
101
219
                        goto fail;
102
219
                }
103
492
        } else if (token) {
104
361
                if ((argv[3] = cbor_encode_pin_opt()) == NULL ||
105
361
                    (argv[4] = cbor_encode_pin_auth(token, &hmac)) == NULL) {
106
27
                        fido_log_debug("%s: encode pin", __func__);
107
27
                        goto fail;
108
27
                }
109
616
        }
110
616
111
616
        /* framing and transmission */
112
616
        if (cbor_build_frame(CTAP_CBOR_BIO_ENROLL_PRE, argv, 5, &f) < 0 ||
113
616
            fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
114
84
                fido_log_debug("%s: fido_tx", __func__);
115
84
                r = FIDO_ERR_TX;
116
84
                goto fail;
117
84
        }
118
532
119
532
        r = FIDO_OK;
120
1.49k
fail:
121
1.49k
        cbor_vector_free(argv, nitems(argv));
122
1.49k
        es256_pk_free(&pk);
123
1.49k
        fido_blob_free(&ecdh);
124
1.49k
        free(f.ptr);
125
1.49k
        free(hmac.ptr);
126
1.49k
127
1.49k
        return (r);
128
532
}
129
130
static void
131
bio_reset_template(fido_bio_template_t *t)
132
1.34k
{
133
1.34k
        free(t->name);
134
1.34k
        free(t->id.ptr);
135
1.34k
        t->name = NULL;
136
1.34k
        memset(&t->id, 0, sizeof(t->id));
137
1.34k
}
138
139
static void
140
bio_reset_template_array(fido_bio_template_array_t *ta)
141
415
{
142
619
        for (size_t i = 0; i < ta->n_alloc; i++)
143
204
                bio_reset_template(&ta->ptr[i]);
144
415
145
415
        free(ta->ptr);
146
415
        ta->ptr = NULL;
147
415
        memset(ta, 0, sizeof(*ta));
148
415
}
149
150
static int
151
decode_template(const cbor_item_t *key, const cbor_item_t *val, void *arg)
152
124
{
153
124
        fido_bio_template_t *t = arg;
154
124
155
124
        if (cbor_isa_uint(key) == false ||
156
124
            cbor_int_get_width(key) != CBOR_INT_8) {
157
19
                fido_log_debug("%s: cbor type", __func__);
158
19
                return (0); /* ignore */
159
19
        }
160
105
161
105
        switch (cbor_get_uint8(key)) {
162
105
        case 1: /* id */
163
52
                return (fido_blob_decode(val, &t->id));
164
105
        case 2: /* name */
165
38
                return (cbor_string_copy(val, &t->name));
166
15
        }
167
15
168
15
        return (0); /* ignore */
169
15
}
170
171
static int
172
decode_template_array(const cbor_item_t *item, void *arg)
173
139
{
174
139
        fido_bio_template_array_t *ta = arg;
175
139
176
139
        if (cbor_isa_map(item) == false ||
177
139
            cbor_map_is_definite(item) == false) {
178
13
                fido_log_debug("%s: cbor type", __func__);
179
13
                return (-1);
180
13
        }
181
126
182
126
        if (ta->n_rx >= ta->n_alloc) {
183
0
                fido_log_debug("%s: n_rx >= n_alloc", __func__);
184
0
                return (-1);
185
0
        }
186
126
187
126
        if (cbor_map_iter(item, &ta->ptr[ta->n_rx], decode_template) < 0) {
188
7
                fido_log_debug("%s: decode_template", __func__);
189
7
                return (-1);
190
7
        }
191
119
192
119
        ta->n_rx++;
193
119
194
119
        return (0);
195
119
}
196
197
static int
198
bio_parse_template_array(const cbor_item_t *key, const cbor_item_t *val,
199
    void *arg)
200
91
{
201
91
        fido_bio_template_array_t *ta = arg;
202
91
203
91
        if (cbor_isa_uint(key) == false ||
204
91
            cbor_int_get_width(key) != CBOR_INT_8 ||
205
91
            cbor_get_uint8(key) != 7) {
206
55
                fido_log_debug("%s: cbor type", __func__);
207
55
                return (0); /* ignore */
208
55
        }
209
36
210
36
        if (cbor_isa_array(val) == false ||
211
36
            cbor_array_is_definite(val) == false) {
212
2
                fido_log_debug("%s: cbor type", __func__);
213
2
                return (-1);
214
2
        }
215
34
216
34
        if (ta->ptr != NULL || ta->n_alloc != 0 || ta->n_rx != 0) {
217
0
                fido_log_debug("%s: ptr != NULL || n_alloc != 0 || n_rx != 0",
218
0
                    __func__);
219
0
                return (-1);
220
0
        }
221
34
222
34
        if ((ta->ptr = calloc(cbor_array_size(val), sizeof(*ta->ptr))) == NULL)
223
34
                return (-1);
224
33
225
33
        ta->n_alloc = cbor_array_size(val);
226
33
227
33
        if (cbor_array_iter(val, ta, decode_template_array) < 0) {
228
21
                fido_log_debug("%s: decode_template_array", __func__);
229
21
                return (-1);
230
21
        }
231
12
232
12
        return (0);
233
12
}
234
235
static int
236
bio_rx_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta, int ms)
237
77
{
238
77
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
239
77
        unsigned char   reply[2048];
240
77
        int             reply_len;
241
77
        int             r;
242
77
243
77
        bio_reset_template_array(ta);
244
77
245
77
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
246
20
                fido_log_debug("%s: fido_rx", __func__);
247
20
                return (FIDO_ERR_RX);
248
20
        }
249
57
250
57
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, ta,
251
57
            bio_parse_template_array)) != FIDO_OK) {
252
33
                fido_log_debug("%s: bio_parse_template_array" , __func__);
253
33
                return (r);
254
33
        }
255
24
256
24
        return (FIDO_OK);
257
24
}
258
259
static int
260
bio_get_template_array_wait(fido_dev_t *dev, fido_bio_template_array_t *ta,
261
    const char *pin, int ms)
262
338
{
263
338
        int r;
264
338
265
338
        if ((r = bio_tx(dev, CMD_ENUM, NULL, 0, pin, NULL)) != FIDO_OK ||
266
338
            (r = bio_rx_template_array(dev, ta, ms)) != FIDO_OK)
267
338
                return (r);
268
24
269
24
        return (FIDO_OK);
270
24
}
271
272
int
273
fido_bio_dev_get_template_array(fido_dev_t *dev, fido_bio_template_array_t *ta,
274
    const char *pin)
275
338
{
276
338
        if (pin == NULL)
277
338
                return (FIDO_ERR_INVALID_ARGUMENT);
278
338
279
338
        return (bio_get_template_array_wait(dev, ta, pin, -1));
280
338
}
281
282
static int
283
bio_set_template_name_wait(fido_dev_t *dev, const fido_bio_template_t *t,
284
    const char *pin, int ms)
285
316
{
286
316
        cbor_item_t     *argv[2];
287
316
        int              r = FIDO_ERR_INTERNAL;
288
316
289
316
        memset(&argv, 0, sizeof(argv));
290
316
291
316
        if ((argv[0] = fido_blob_encode(&t->id)) == NULL ||
292
316
            (argv[1] = cbor_build_string(t->name)) == NULL) {
293
6
                fido_log_debug("%s: cbor encode", __func__);
294
6
                goto fail;
295
6
        }
296
310
297
310
        if ((r = bio_tx(dev, CMD_SET_NAME, argv, 2, pin, NULL)) != FIDO_OK ||
298
310
            (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
299
308
                fido_log_debug("%s: tx/rx", __func__);
300
308
                goto fail;
301
308
        }
302
2
303
2
        r = FIDO_OK;
304
316
fail:
305
316
        cbor_vector_free(argv, nitems(argv));
306
316
307
316
        return (r);
308
2
}
309
310
int
311
fido_bio_dev_set_template_name(fido_dev_t *dev, const fido_bio_template_t *t,
312
    const char *pin)
313
317
{
314
317
        if (pin == NULL || t->name == NULL)
315
317
                return (FIDO_ERR_INVALID_ARGUMENT);
316
316
317
316
        return (bio_set_template_name_wait(dev, t, pin, -1));
318
316
}
319
320
static void
321
bio_reset_enroll(fido_bio_enroll_t *e)
322
382
{
323
382
        e->remaining_samples = 0;
324
382
        e->last_status = 0;
325
382
326
382
        if (e->token)
327
125
                fido_blob_free(&e->token);
328
382
}
329
330
static int
331
bio_parse_enroll_status(const cbor_item_t *key, const cbor_item_t *val,
332
    void *arg)
333
524
{
334
524
        fido_bio_enroll_t *e = arg;
335
524
        uint64_t x;
336
524
337
524
        if (cbor_isa_uint(key) == false ||
338
524
            cbor_int_get_width(key) != CBOR_INT_8) {
339
35
                fido_log_debug("%s: cbor type", __func__);
340
35
                return (0); /* ignore */
341
35
        }
342
489
343
489
        switch (cbor_get_uint8(key)) {
344
489
        case 5:
345
160
                if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
346
2
                        fido_log_debug("%s: cbor_decode_uint64", __func__);
347
2
                        return (-1);
348
2
                }
349
158
                e->last_status = (uint8_t)x;
350
158
                break;
351
170
        case 6:
352
170
                if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
353
3
                        fido_log_debug("%s: cbor_decode_uint64", __func__);
354
3
                        return (-1);
355
3
                }
356
167
                e->remaining_samples = (uint8_t)x;
357
167
                break;
358
167
        default:
359
159
                return (0); /* ignore */
360
325
        }
361
325
362
325
        return (0);
363
325
}
364
365
static int
366
bio_parse_template_id(const cbor_item_t *key, const cbor_item_t *val,
367
    void *arg)
368
266
{
369
266
        fido_blob_t *id = arg;
370
266
371
266
        if (cbor_isa_uint(key) == false ||
372
266
            cbor_int_get_width(key) != CBOR_INT_8 ||
373
266
            cbor_get_uint8(key) != 4) {
374
192
                fido_log_debug("%s: cbor type", __func__);
375
192
                return (0); /* ignore */
376
192
        }
377
74
378
74
        return (fido_blob_decode(val, id));
379
74
}
380
381
static int
382
bio_rx_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
383
    fido_bio_enroll_t *e, int ms)
384
119
{
385
119
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
386
119
        unsigned char   reply[2048];
387
119
        int             reply_len;
388
119
        int             r;
389
119
390
119
        bio_reset_template(t);
391
119
392
119
        e->remaining_samples = 0;
393
119
        e->last_status = 0;
394
119
395
119
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
396
21
                fido_log_debug("%s: fido_rx", __func__);
397
21
                return (FIDO_ERR_RX);
398
21
        }
399
98
400
98
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, e,
401
98
            bio_parse_enroll_status)) != FIDO_OK) {
402
10
                fido_log_debug("%s: bio_parse_enroll_status", __func__);
403
10
                return (r);
404
10
        }
405
88
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, &t->id,
406
88
            bio_parse_template_id)) != FIDO_OK) {
407
2
                fido_log_debug("%s: bio_parse_template_id", __func__);
408
2
                return (r);
409
2
        }
410
86
    
411
86
        return (FIDO_OK);
412
86
}
413
414
static int
415
bio_enroll_begin_wait(fido_dev_t *dev, fido_bio_template_t *t,
416
    fido_bio_enroll_t *e, uint32_t timo_ms, int ms)
417
125
{
418
125
        cbor_item_t     *argv[3];
419
125
        const uint8_t    cmd = CMD_ENROLL_BEGIN;
420
125
        int              r = FIDO_ERR_INTERNAL;
421
125
422
125
        memset(&argv, 0, sizeof(argv));
423
125
424
125
        if ((argv[2] = cbor_build_uint32(timo_ms)) == NULL) {
425
0
                fido_log_debug("%s: cbor encode", __func__);
426
0
                goto fail;
427
0
        }
428
125
429
125
        if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK ||
430
125
            (r = bio_rx_enroll_begin(dev, t, e, ms)) != FIDO_OK) {
431
39
                fido_log_debug("%s: tx/rx", __func__);
432
39
                goto fail;
433
39
        }
434
86
435
86
        r = FIDO_OK;
436
125
fail:
437
125
        cbor_vector_free(argv, nitems(argv));
438
125
439
125
        return (r);
440
86
}
441
442
int
443
fido_bio_dev_enroll_begin(fido_dev_t *dev, fido_bio_template_t *t,
444
    fido_bio_enroll_t *e, uint32_t timo_ms, const char *pin)
445
382
{
446
382
        es256_pk_t      *pk = NULL;
447
382
        fido_blob_t     *ecdh = NULL;
448
382
        fido_blob_t     *token = NULL;
449
382
        int              r;
450
382
451
382
        if (pin == NULL || e->token != NULL)
452
382
                return (FIDO_ERR_INVALID_ARGUMENT);
453
382
454
382
        if ((token = fido_blob_new()) == NULL) {
455
2
                r = FIDO_ERR_INTERNAL;
456
2
                goto fail;
457
2
        }
458
380
459
380
        if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
460
178
                fido_log_debug("%s: fido_do_ecdh", __func__);
461
178
                goto fail;
462
178
        }
463
202
464
202
        if ((r = fido_dev_get_pin_token(dev, pin, ecdh, pk, token)) != FIDO_OK) {
465
77
                fido_log_debug("%s: fido_dev_get_pin_token", __func__);
466
77
                goto fail;
467
77
        }
468
125
469
125
        e->token = token;
470
125
        token = NULL;
471
382
fail:
472
382
        es256_pk_free(&pk);
473
382
        fido_blob_free(&ecdh);
474
382
        fido_blob_free(&token);
475
382
476
382
        if (r != FIDO_OK)
477
382
                return (r);
478
125
479
125
        return (bio_enroll_begin_wait(dev, t, e, timo_ms, -1));
480
125
}
481
482
static int
483
bio_rx_enroll_continue(fido_dev_t *dev, fido_bio_enroll_t *e, int ms)
484
149
{
485
149
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
486
149
        unsigned char   reply[2048];
487
149
        int             reply_len;
488
149
        int             r;
489
149
490
149
        e->remaining_samples = 0;
491
149
        e->last_status = 0;
492
149
493
149
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
494
40
                fido_log_debug("%s: fido_rx", __func__);
495
40
                return (FIDO_ERR_RX);
496
40
        }
497
109
498
109
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, e,
499
109
            bio_parse_enroll_status)) != FIDO_OK) {
500
35
                fido_log_debug("%s: bio_parse_enroll_status", __func__);
501
35
                return (r);
502
35
        }
503
74
    
504
74
        return (FIDO_OK);
505
74
}
506
507
static int
508
bio_enroll_continue_wait(fido_dev_t *dev, const fido_bio_template_t *t,
509
    fido_bio_enroll_t *e, uint32_t timo_ms, int ms)
510
291
{
511
291
        cbor_item_t     *argv[3];
512
291
        const uint8_t    cmd = CMD_ENROLL_NEXT;
513
291
        int              r = FIDO_ERR_INTERNAL;
514
291
515
291
        memset(&argv, 0, sizeof(argv));
516
291
517
291
        if ((argv[0] = fido_blob_encode(&t->id)) == NULL ||
518
291
            (argv[2] = cbor_build_uint32(timo_ms)) == NULL) {
519
23
                fido_log_debug("%s: cbor encode", __func__);
520
23
                goto fail;
521
23
        }
522
268
523
268
        if ((r = bio_tx(dev, cmd, argv, 3, NULL, e->token)) != FIDO_OK ||
524
268
            (r = bio_rx_enroll_continue(dev, e, ms)) != FIDO_OK) {
525
194
                fido_log_debug("%s: tx/rx", __func__);
526
194
                goto fail;
527
194
        }
528
74
529
74
        r = FIDO_OK;
530
291
fail:
531
291
        cbor_vector_free(argv, nitems(argv));
532
291
533
291
        return (r);
534
74
}
535
536
int
537
fido_bio_dev_enroll_continue(fido_dev_t *dev, const fido_bio_template_t *t,
538
    fido_bio_enroll_t *e, uint32_t timo_ms)
539
291
{
540
291
        if (e->token == NULL)
541
291
                return (FIDO_ERR_INVALID_ARGUMENT);
542
291
543
291
        return (bio_enroll_continue_wait(dev, t, e, timo_ms, -1));
544
291
}
545
546
static int
547
bio_enroll_cancel_wait(fido_dev_t *dev, int ms)
548
0
{
549
0
        const uint8_t   cmd = CMD_ENROLL_CANCEL;
550
0
        int             r;
551
0
552
0
        if ((r = bio_tx(dev, cmd, NULL, 0, NULL, NULL)) != FIDO_OK ||
553
0
            (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
554
0
                fido_log_debug("%s: tx/rx", __func__);
555
0
                return (r);
556
0
        }
557
0
558
0
        return (FIDO_OK);
559
0
}
560
561
int
562
fido_bio_dev_enroll_cancel(fido_dev_t *dev)
563
0
{
564
0
        return (bio_enroll_cancel_wait(dev, -1));
565
0
}
566
567
static int
568
bio_enroll_remove_wait(fido_dev_t *dev, const fido_bio_template_t *t,
569
    const char *pin, int ms)
570
326
{
571
326
        cbor_item_t     *argv[1];
572
326
        const uint8_t    cmd = CMD_ENROLL_REMOVE;
573
326
        int              r = FIDO_ERR_INTERNAL;
574
326
575
326
        memset(&argv, 0, sizeof(argv));
576
326
577
326
        if ((argv[0] = fido_blob_encode(&t->id)) == NULL) {
578
6
                fido_log_debug("%s: cbor encode", __func__);
579
6
                goto fail;
580
6
        }
581
320
582
320
        if ((r = bio_tx(dev, cmd, argv, 1, pin, NULL)) != FIDO_OK ||
583
320
            (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
584
319
                fido_log_debug("%s: tx/rx", __func__);
585
319
                goto fail;
586
319
        }
587
1
588
1
        r = FIDO_OK;
589
326
fail:
590
326
        cbor_vector_free(argv, nitems(argv));
591
326
592
326
        return (r);
593
1
}
594
595
int
596
fido_bio_dev_enroll_remove(fido_dev_t *dev, const fido_bio_template_t *t,
597
    const char *pin)
598
326
{
599
326
        return (bio_enroll_remove_wait(dev, t, pin, -1));
600
326
}
601
602
static void
603
bio_reset_info(fido_bio_info_t *i)
604
120
{
605
120
        i->type = 0;
606
120
        i->max_samples = 0;
607
120
}
608
609
static int
610
bio_parse_info(const cbor_item_t *key, const cbor_item_t *val, void *arg)
611
109
{
612
109
        fido_bio_info_t *i = arg;
613
109
        uint64_t         x;
614
109
615
109
        if (cbor_isa_uint(key) == false ||
616
109
            cbor_int_get_width(key) != CBOR_INT_8) {
617
53
                fido_log_debug("%s: cbor type", __func__);
618
53
                return (0); /* ignore */
619
53
        }
620
56
621
56
        switch (cbor_get_uint8(key)) {
622
56
        case 2:
623
12
                if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
624
4
                        fido_log_debug("%s: cbor_decode_uint64", __func__);
625
4
                        return (-1);
626
4
                }
627
8
                i->type = (uint8_t)x;
628
8
                break;
629
9
        case 3:
630
9
                if (cbor_decode_uint64(val, &x) < 0 || x > UINT8_MAX) {
631
3
                        fido_log_debug("%s: cbor_decode_uint64", __func__);
632
3
                        return (-1);
633
3
                }
634
6
                i->max_samples = (uint8_t)x;
635
6
                break;
636
35
        default:
637
35
                return (0); /* ignore */
638
14
        }
639
14
640
14
        return (0);
641
14
}
642
643
static int
644
bio_rx_info(fido_dev_t *dev, fido_bio_info_t *i, int ms)
645
120
{
646
120
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
647
120
        unsigned char   reply[2048];
648
120
        int             reply_len;
649
120
        int             r;
650
120
651
120
        bio_reset_info(i);
652
120
653
120
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
654
51
                fido_log_debug("%s: fido_rx", __func__);
655
51
                return (FIDO_ERR_RX);
656
51
        }
657
69
658
69
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, i,
659
69
            bio_parse_info)) != FIDO_OK) {
660
54
                fido_log_debug("%s: bio_parse_info" , __func__);
661
54
                return (r);
662
54
        }
663
15
664
15
        return (FIDO_OK);
665
15
}
666
667
static int
668
bio_get_info_wait(fido_dev_t *dev, fido_bio_info_t *i, int ms)
669
137
{
670
137
        int r;
671
137
672
137
        if ((r = bio_tx(dev, CMD_GET_INFO, NULL, 0, NULL, NULL)) != FIDO_OK ||
673
137
            (r = bio_rx_info(dev, i, ms)) != FIDO_OK) {
674
122
                fido_log_debug("%s: tx/rx", __func__);
675
122
                return (r);
676
122
        }
677
15
678
15
        return (FIDO_OK);
679
15
}
680
681
int
682
fido_bio_dev_get_info(fido_dev_t *dev, fido_bio_info_t *i)
683
137
{
684
137
        return (bio_get_info_wait(dev, i, -1));
685
137
}
686
687
const char *
688
fido_bio_template_name(const fido_bio_template_t *t)
689
2.91k
{
690
2.91k
        return (t->name);
691
2.91k
}
692
693
const unsigned char *
694
fido_bio_template_id_ptr(const fido_bio_template_t *t)
695
1.45k
{
696
1.45k
        return (t->id.ptr);
697
1.45k
}
698
699
size_t
700
fido_bio_template_id_len(const fido_bio_template_t *t)
701
1.45k
{
702
1.45k
        return (t->id.len);
703
1.45k
}
704
705
size_t
706
fido_bio_template_array_count(const fido_bio_template_array_t *ta)
707
795
{
708
795
        return (ta->n_rx);
709
795
}
710
711
fido_bio_template_array_t *
712
fido_bio_template_array_new(void)
713
339
{
714
339
        return (calloc(1, sizeof(fido_bio_template_array_t)));
715
339
}
716
717
fido_bio_template_t *
718
fido_bio_template_new(void)
719
1.02k
{
720
1.02k
        return (calloc(1, sizeof(fido_bio_template_t)));
721
1.02k
}
722
723
void
724
fido_bio_template_array_free(fido_bio_template_array_t **tap)
725
704
{
726
704
        fido_bio_template_array_t *ta;
727
704
728
704
        if (tap == NULL || (ta = *tap) == NULL)
729
704
                return;
730
338
731
338
        bio_reset_template_array(ta);
732
338
        free(ta);
733
338
        *tap = NULL;
734
338
}
735
736
void
737
fido_bio_template_free(fido_bio_template_t **tp)
738
2.11k
{
739
2.11k
        fido_bio_template_t *t;
740
2.11k
741
2.11k
        if (tp == NULL || (t = *tp) == NULL)
742
2.11k
                return;
743
1.02k
744
1.02k
        bio_reset_template(t);
745
1.02k
        free(t);
746
1.02k
        *tp = NULL;
747
1.02k
}
748
749
int
750
fido_bio_template_set_name(fido_bio_template_t *t, const char *name)
751
317
{
752
317
        free(t->name);
753
317
        t->name = NULL;
754
317
755
317
        if (name && (t->name = strdup(name)) == NULL)
756
317
                return (FIDO_ERR_INTERNAL);
757
316
758
316
        return (FIDO_OK);
759
316
}
760
761
int
762
fido_bio_template_set_id(fido_bio_template_t *t, const unsigned char *ptr,
763
    size_t len)
764
643
{
765
643
        free(t->id.ptr);
766
643
        t->id.ptr = NULL;
767
643
        t->id.len = 0;
768
643
769
643
        if (ptr && fido_blob_set(&t->id, ptr, len) < 0)
770
8
                return (FIDO_ERR_INTERNAL);
771
635
772
635
        return (FIDO_OK);
773
635
}
774
775
const fido_bio_template_t *
776
fido_bio_template(const fido_bio_template_array_t *ta, size_t idx)
777
457
{
778
457
        if (idx >= ta->n_alloc)
779
317
                return (NULL);
780
140
781
140
        return (&ta->ptr[idx]);
782
140
}
783
784
fido_bio_enroll_t *
785
fido_bio_enroll_new(void)
786
383
{
787
383
        return (calloc(1, sizeof(fido_bio_enroll_t)));
788
383
}
789
790
fido_bio_info_t *
791
fido_bio_info_new(void)
792
138
{
793
138
        return (calloc(1, sizeof(fido_bio_info_t)));
794
138
}
795
796
uint8_t
797
fido_bio_info_type(const fido_bio_info_t *i)
798
137
{
799
137
        return (i->type);
800
137
}
801
802
uint8_t
803
fido_bio_info_max_samples(const fido_bio_info_t *i)
804
137
{
805
137
        return (i->max_samples);
806
137
}
807
808
void
809
fido_bio_enroll_free(fido_bio_enroll_t **ep)
810
704
{
811
704
        fido_bio_enroll_t *e;
812
704
813
704
        if (ep == NULL || (e = *ep) == NULL)
814
704
                return;
815
382
816
382
        bio_reset_enroll(e);
817
382
818
382
        free(e);
819
382
        *ep = NULL;
820
382
}
821
822
void
823
fido_bio_info_free(fido_bio_info_t **ip)
824
704
{
825
704
        fido_bio_info_t *i;
826
704
827
704
        if (ip == NULL || (i = *ip) == NULL)
828
704
                return;
829
137
830
137
        free(i);
831
137
        *ip = NULL;
832
137
}
833
834
uint8_t
835
fido_bio_enroll_remaining_samples(const fido_bio_enroll_t *e)
836
1.34k
{
837
1.34k
        return (e->remaining_samples);
838
1.34k
}
839
840
uint8_t
841
fido_bio_enroll_last_status(const fido_bio_enroll_t *e)
842
673
{
843
673
        return (e->last_status);
844
673
}
/home/pedro/projects/libfido2/src/blob.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 <string.h>
8
#include "fido.h"
9
10
fido_blob_t *
11
fido_blob_new(void)
12
13.0k
{
13
13.0k
        return (calloc(1, sizeof(fido_blob_t)));
14
13.0k
}
15
16
int
17
fido_blob_set(fido_blob_t *b, const unsigned char *ptr, size_t len)
18
65.7k
{
19
65.7k
        if (b->ptr != NULL) {
20
0
                explicit_bzero(b->ptr, b->len);
21
0
                free(b->ptr);
22
0
                b->ptr = NULL;
23
0
        }
24
65.7k
25
65.7k
        b->len = 0;
26
65.7k
27
65.7k
        if (ptr == NULL || len == 0) {
28
76
                fido_log_debug("%s: ptr=%p, len=%zu", __func__,
29
76
                    (const void *)ptr, len);
30
76
                return (-1);
31
76
        }
32
65.7k
33
65.7k
        if ((b->ptr = malloc(len)) == NULL) {
34
227
                fido_log_debug("%s: malloc", __func__);
35
227
                return (-1);
36
227
        }
37
65.4k
38
65.4k
        memcpy(b->ptr, ptr, len);
39
65.4k
        b->len = len;
40
65.4k
41
65.4k
        return (0);
42
65.4k
}
43
44
void
45
fido_blob_free(fido_blob_t **bp)
46
18.8k
{
47
18.8k
        fido_blob_t *b;
48
18.8k
49
18.8k
        if (bp == NULL || (b = *bp) == NULL)
50
18.8k
                return;
51
12.9k
52
12.9k
        if (b->ptr) {
53
10.3k
                explicit_bzero(b->ptr, b->len);
54
10.3k
                free(b->ptr);
55
10.3k
        }
56
12.9k
57
12.9k
        explicit_bzero(b, sizeof(*b));
58
12.9k
        free(b);
59
12.9k
60
12.9k
        *bp = NULL;
61
12.9k
}
62
63
void
64
fido_free_blob_array(fido_blob_array_t *array)
65
19.5k
{
66
19.5k
        if (array->ptr == NULL)
67
19.5k
                return;
68
634
69
44.9k
        for (size_t i = 0; i < array->len; i++) {
70
44.3k
                fido_blob_t *b = &array->ptr[i];
71
44.3k
                if (b->ptr != NULL) {
72
44.3k
                        explicit_bzero(b->ptr, b->len);
73
44.3k
                        free(b->ptr);
74
44.3k
                        b->ptr = NULL;
75
44.3k
                }
76
44.3k
        }
77
634
78
634
        free(array->ptr);
79
634
        array->ptr = NULL;
80
634
        array->len = 0;
81
634
}
82
83
cbor_item_t *
84
fido_blob_encode(const fido_blob_t *b)
85
2.00k
{
86
2.00k
        if (b == NULL || b->ptr == NULL)
87
2.00k
                return (NULL);
88
1.98k
89
1.98k
        return (cbor_build_bytestring(b->ptr, b->len));
90
1.98k
}
91
92
int
93
fido_blob_decode(const cbor_item_t *item, fido_blob_t *b)
94
1.15k
{
95
1.15k
        return (cbor_bytestring_copy(item, &b->ptr, &b->len));
96
1.15k
}
97
98
int
99
fido_blob_is_empty(const fido_blob_t *b)
100
125
{
101
125
        return (b->ptr == NULL || b->len == 0);
102
125
}
/home/pedro/projects/libfido2/src/buf.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 <string.h>
8
#include "fido.h"
9
10
int
11
fido_buf_read(const unsigned char **buf, size_t *len, void *dst, size_t count)
12
2.13k
{
13
2.13k
        if (count > *len)
14
29
                return (-1);
15
2.10k
16
2.10k
        memcpy(dst, *buf, count);
17
2.10k
        *buf += count;
18
2.10k
        *len -= count;
19
2.10k
20
2.10k
        return (0);
21
2.10k
}
22
23
int
24
fido_buf_write(unsigned char **buf, size_t *len, const void *src, size_t count)
25
84
{
26
84
        if (count > *len)
27
0
                return (-1);
28
84
29
84
        memcpy(*buf, src, count);
30
84
        *buf += count;
31
84
        *len -= count;
32
84
33
84
        return (0);
34
84
}
/home/pedro/projects/libfido2/src/cbor.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/evp.h>
8
#include <openssl/hmac.h>
9
#include <openssl/sha.h>
10
11
#include <string.h>
12
#include "fido.h"
13
14
static int
15
check_key_type(cbor_item_t *item)
16
45.5k
{
17
45.5k
        if (item->type == CBOR_TYPE_UINT || item->type == CBOR_TYPE_NEGINT ||
18
45.5k
            item->type == CBOR_TYPE_STRING)
19
45.3k
                return (0);
20
116
21
116
        fido_log_debug("%s: invalid type: %d", __func__, item->type);
22
116
23
116
        return (-1);
24
116
}
25
26
/*
27
 * Validate CTAP2 canonical CBOR encoding rules for maps.
28
 */
29
static int
30
ctap_check_cbor(cbor_item_t *prev, cbor_item_t *curr)
31
22.7k
{
32
22.7k
        size_t  curr_len;
33
22.7k
        size_t  prev_len;
34
22.7k
35
22.7k
        if (check_key_type(prev) < 0 || check_key_type(curr) < 0)
36
116
                return (-1);
37
22.6k
38
22.6k
        if (prev->type != curr->type) {
39
4.50k
                if (prev->type < curr->type)
40
4.33k
                        return (0);
41
167
                fido_log_debug("%s: unsorted types", __func__);
42
167
                return (-1);
43
167
        }
44
18.1k
45
18.1k
        if (curr->type == CBOR_TYPE_UINT || curr->type == CBOR_TYPE_NEGINT) {
46
15.8k
                if (cbor_int_get_width(curr) >= cbor_int_get_width(prev) &&
47
15.8k
                    cbor_get_int(curr) > cbor_get_int(prev))
48
15.6k
                        return (0);
49
2.29k
        } else {
50
2.29k
                curr_len = cbor_string_length(curr);
51
2.29k
                prev_len = cbor_string_length(prev);
52
2.29k
53
2.29k
                if (curr_len > prev_len || (curr_len == prev_len &&
54
447
                    memcmp(cbor_string_handle(prev), cbor_string_handle(curr),
55
402
                    curr_len) < 0))
56
2.20k
                        return (0);
57
338
        }
58
338
59
338
        fido_log_debug("%s: invalid cbor", __func__);
60
338
61
338
        return (-1);
62
338
}
63
64
int
65
cbor_map_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
66
    const cbor_item_t *, void *))
67
11.6k
{
68
11.6k
        struct cbor_pair        *v;
69
11.6k
        size_t                   n;
70
11.6k
71
11.6k
        if ((v = cbor_map_handle(item)) == NULL) {
72
36
                fido_log_debug("%s: cbor_map_handle", __func__);
73
36
                return (-1);
74
36
        }
75
11.6k
76
11.6k
        n = cbor_map_size(item);
77
11.6k
78
44.4k
        for (size_t i = 0; i < n; i++) {
79
34.3k
                if (v[i].key == NULL || v[i].value == NULL) {
80
0
                        fido_log_debug("%s: key=%p, value=%p for i=%zu",
81
0
                            __func__, (void *)v[i].key, (void *)v[i].value, i);
82
0
                        return (-1);
83
0
                }
84
34.3k
                if (i && ctap_check_cbor(v[i - 1].key, v[i].key) < 0) {
85
621
                        fido_log_debug("%s: ctap_check_cbor", __func__);
86
621
                        return (-1);
87
621
                }
88
33.7k
                if (f(v[i].key, v[i].value, arg) < 0) {
89
919
                        fido_log_debug("%s: iterator < 0 on i=%zu", __func__,
90
919
                            i);
91
919
                        return (-1);
92
919
                }
93
33.7k
        }
94
11.6k
95
11.6k
        return (0);
96
11.6k
}
97
98
int
99
cbor_array_iter(const cbor_item_t *item, void *arg, int(*f)(const cbor_item_t *,
100
    void *))
101
239
{
102
239
        cbor_item_t     **v;
103
239
        size_t            n;
104
239
105
239
        if ((v = cbor_array_handle(item)) == NULL) {
106
3
                fido_log_debug("%s: cbor_array_handle", __func__);
107
3
                return (-1);
108
3
        }
109
236
110
236
        n = cbor_array_size(item);
111
236
112
1.00k
        for (size_t i = 0; i < n; i++)
113
806
                if (v[i] == NULL || f(v[i], arg) < 0) {
114
41
                        fido_log_debug("%s: iterator < 0 on i=%zu,%p",
115
41
                            __func__, i, (void *)v[i]);
116
41
                        return (-1);
117
41
                }
118
236
119
236
        return (0);
120
236
}
121
122
int
123
cbor_parse_reply(const unsigned char *blob, size_t blob_len, void *arg,
124
    int(*parser)(const cbor_item_t *, const cbor_item_t *, void *))
125
6.40k
{
126
6.40k
        cbor_item_t             *item = NULL;
127
6.40k
        struct cbor_load_result  cbor;
128
6.40k
        int                      r;
129
6.40k
130
6.40k
        if (blob_len < 1) {
131
121
                fido_log_debug("%s: blob_len=%zu", __func__, blob_len);
132
121
                r = FIDO_ERR_RX;
133
121
                goto fail;
134
121
        }
135
6.28k
136
6.28k
        if (blob[0] != FIDO_OK) {
137
73
                fido_log_debug("%s: blob[0]=0x%02x", __func__, blob[0]);
138
73
                r = blob[0];
139
73
                goto fail;
140
73
        }
141
6.20k
142
6.20k
        if ((item = cbor_load(blob + 1, blob_len - 1, &cbor)) == NULL) {
143
86
                fido_log_debug("%s: cbor_load", __func__);
144
86
                r = FIDO_ERR_RX_NOT_CBOR;
145
86
                goto fail;
146
86
        }
147
6.12k
148
6.12k
        if (cbor_isa_map(item) == false ||
149
6.12k
            cbor_map_is_definite(item) == false) {
150
81
                fido_log_debug("%s: cbor type", __func__);
151
81
                r = FIDO_ERR_RX_INVALID_CBOR;
152
81
                goto fail;
153
81
        }
154
6.04k
155
6.04k
        if (cbor_map_iter(item, arg, parser) < 0) {
156
1.05k
                fido_log_debug("%s: cbor_map_iter", __func__);
157
1.05k
                r = FIDO_ERR_RX_INVALID_CBOR;
158
1.05k
                goto fail;
159
1.05k
        }
160
4.98k
161
4.98k
        r = FIDO_OK;
162
6.40k
fail:
163
6.40k
        if (item != NULL)
164
6.40k
                cbor_decref(&item);
165
6.40k
166
6.40k
        return (r);
167
4.98k
}
168
169
void
170
cbor_vector_free(cbor_item_t **item, size_t len)
171
11.9k
{
172
56.4k
        for (size_t i = 0; i < len; i++)
173
44.5k
                if (item[i] != NULL)
174
44.5k
                        cbor_decref(&item[i]);
175
11.9k
}
176
177
int
178
cbor_bytestring_copy(const cbor_item_t *item, unsigned char **buf, size_t *len)
179
1.95k
{
180
1.95k
        if (*buf != NULL || *len != 0) {
181
2
                fido_log_debug("%s: dup", __func__);
182
2
                return (-1);
183
2
        }
184
1.94k
185
1.94k
        if (cbor_isa_bytestring(item) == false ||
186
1.94k
            cbor_bytestring_is_definite(item) == false) {
187
46
                fido_log_debug("%s: cbor type", __func__);
188
46
                return (-1);
189
46
        }
190
1.90k
191
1.90k
        *len = cbor_bytestring_length(item);
192
1.90k
        if ((*buf = malloc(*len)) == NULL) {
193
19
                *len = 0;
194
19
                return (-1);
195
19
        }
196
1.88k
197
1.88k
        memcpy(*buf, cbor_bytestring_handle(item), *len);
198
1.88k
199
1.88k
        return (0);
200
1.88k
}
201
202
int
203
cbor_string_copy(const cbor_item_t *item, char **str)
204
4.38k
{
205
4.38k
        size_t len;
206
4.38k
207
4.38k
        if (*str != NULL) {
208
1
                fido_log_debug("%s: dup", __func__);
209
1
                return (-1);
210
1
        }
211
4.38k
212
4.38k
        if (cbor_isa_string(item) == false ||
213
4.38k
            cbor_string_is_definite(item) == false) {
214
85
                fido_log_debug("%s: cbor type", __func__);
215
85
                return (-1);
216
85
        }
217
4.30k
218
4.30k
        if ((len = cbor_string_length(item)) == SIZE_MAX ||
219
4.30k
            (*str = malloc(len + 1)) == NULL)
220
4.30k
                return (-1);
221
4.26k
222
4.26k
        memcpy(*str, cbor_string_handle(item), len);
223
4.26k
        (*str)[len] = '\0';
224
4.26k
225
4.26k
        return (0);
226
4.26k
}
227
228
int
229
cbor_add_bytestring(cbor_item_t *item, const char *key,
230
    const unsigned char *value, size_t value_len)
231
8.18k
{
232
8.18k
        struct cbor_pair pair;
233
8.18k
        int ok = -1;
234
8.18k
235
8.18k
        memset(&pair, 0, sizeof(pair));
236
8.18k
237
8.18k
        if ((pair.key = cbor_build_string(key)) == NULL ||
238
8.18k
            (pair.value = cbor_build_bytestring(value, value_len)) == NULL) {
239
18
                fido_log_debug("%s: cbor_build", __func__);
240
18
                goto fail;
241
18
        }
242
8.16k
243
8.16k
        if (!cbor_map_add(item, pair)) {
244
6
                fido_log_debug("%s: cbor_map_add", __func__);
245
6
                goto fail;
246
6
        }
247
8.15k
248
8.15k
        ok = 0;
249
8.18k
fail:
250
8.18k
        if (pair.key)
251
8.17k
                cbor_decref(&pair.key);
252
8.18k
        if (pair.value)
253
8.16k
                cbor_decref(&pair.value);
254
8.18k
255
8.18k
        return (ok);
256
8.15k
}
257
258
int
259
cbor_add_string(cbor_item_t *item, const char *key, const char *value)
260
9.96k
{
261
9.96k
        struct cbor_pair pair;
262
9.96k
        int ok = -1;
263
9.96k
264
9.96k
        memset(&pair, 0, sizeof(pair));
265
9.96k
266
9.96k
        if ((pair.key = cbor_build_string(key)) == NULL ||
267
9.96k
            (pair.value = cbor_build_string(value)) == NULL) {
268
13
                fido_log_debug("%s: cbor_build", __func__);
269
13
                goto fail;
270
13
        }
271
9.95k
272
9.95k
        if (!cbor_map_add(item, pair)) {
273
11
                fido_log_debug("%s: cbor_map_add", __func__);
274
11
                goto fail;
275
11
        }
276
9.93k
277
9.93k
        ok = 0;
278
9.96k
fail:
279
9.96k
        if (pair.key)
280
9.95k
                cbor_decref(&pair.key);
281
9.96k
        if (pair.value)
282
9.95k
                cbor_decref(&pair.value);
283
9.96k
284
9.96k
        return (ok);
285
9.93k
}
286
287
int
288
cbor_add_bool(cbor_item_t *item, const char *key, fido_opt_t value)
289
409
{
290
409
        struct cbor_pair pair;
291
409
        int ok = -1;
292
409
293
409
        memset(&pair, 0, sizeof(pair));
294
409
295
409
        if ((pair.key = cbor_build_string(key)) == NULL ||
296
409
            (pair.value = cbor_build_bool(value == FIDO_OPT_TRUE)) == NULL) {
297
3
                fido_log_debug("%s: cbor_build", __func__);
298
3
                goto fail;
299
3
        }
300
406
301
406
        if (!cbor_map_add(item, pair)) {
302
3
                fido_log_debug("%s: cbor_map_add", __func__);
303
3
                goto fail;
304
3
        }
305
403
306
403
        ok = 0;
307
409
fail:
308
409
        if (pair.key)
309
406
                cbor_decref(&pair.key);
310
409
        if (pair.value)
311
406
                cbor_decref(&pair.value);
312
409
313
409
        return (ok);
314
403
}
315
316
static int
317
cbor_add_arg(cbor_item_t *item, uint8_t n, cbor_item_t *arg)
318
28.9k
{
319
28.9k
        struct cbor_pair pair;
320
28.9k
        int ok = -1;
321
28.9k
322
28.9k
        memset(&pair, 0, sizeof(pair));
323
28.9k
324
28.9k
        if (arg == NULL)
325
28.9k
                return (0); /* empty argument */
326
22.0k
327
22.0k
        if ((pair.key = cbor_build_uint8(n)) == NULL) {
328
65
                fido_log_debug("%s: cbor_build", __func__);
329
65
                goto fail;
330
65
        }
331
21.9k
332
21.9k
        pair.value = arg;
333
21.9k
334
21.9k
        if (!cbor_map_add(item, pair)) {
335
85
                fido_log_debug("%s: cbor_map_add", __func__);
336
85
                goto fail;
337
85
        }
338
21.8k
339
21.8k
        ok = 0;
340
22.0k
fail:
341
22.0k
        if (pair.key)
342
21.9k
                cbor_decref(&pair.key);
343
22.0k
344
22.0k
        return (ok);
345
21.8k
}
346
347
cbor_item_t *
348
cbor_flatten_vector(cbor_item_t *argv[], size_t argc)
349
9.61k
{
350
9.61k
        cbor_item_t     *map;
351
9.61k
        uint8_t          i;
352
9.61k
353
9.61k
        if (argc > UINT8_MAX - 1)
354
0
                return (NULL);
355
9.61k
356
9.61k
        if ((map = cbor_new_definite_map(argc)) == NULL)
357
9.61k
                return (NULL);
358
9.57k
359
38.3k
        for (i = 0; i < argc; i++)
360
28.9k
                if (cbor_add_arg(map, i + 1, argv[i]) < 0)
361
150
                        break;
362
9.57k
363
9.57k
        if (i != argc) {
364
150
                cbor_decref(&map);
365
150
                map = NULL;
366
150
        }
367
9.57k
368
9.57k
        return (map);
369
9.57k
}
370
371
int
372
cbor_build_frame(uint8_t cmd, cbor_item_t *argv[], size_t argc, fido_blob_t *f)
373
7.77k
{
374
7.77k
        cbor_item_t     *flat = NULL;
375
7.77k
        unsigned char   *cbor = NULL;
376
7.77k
        size_t           cbor_len;
377
7.77k
        size_t           cbor_alloc_len;
378
7.77k
        int              ok = -1;
379
7.77k
380
7.77k
        if ((flat = cbor_flatten_vector(argv, argc)) == NULL)
381
7.77k
                goto fail;
382
7.61k
383
7.61k
        cbor_len = cbor_serialize_alloc(flat, &cbor, &cbor_alloc_len);
384
7.61k
        if (cbor_len == 0 || cbor_len == SIZE_MAX) {
385
34
                fido_log_debug("%s: cbor_len=%zu", __func__, cbor_len);
386
34
                goto fail;
387
34
        }
388
7.58k
389
7.58k
        if ((f->ptr = malloc(cbor_len + 1)) == NULL)
390
7.58k
                goto fail;
391
7.54k
392
7.54k
        f->len = cbor_len + 1;
393
7.54k
        f->ptr[0] = cmd;
394
7.54k
        memcpy(f->ptr + 1, cbor, f->len - 1);
395
7.54k
396
7.54k
        ok = 0;
397
7.77k
fail:
398
7.77k
        if (flat != NULL)
399
7.77k
                cbor_decref(&flat);
400
7.77k
401
7.77k
        free(cbor);
402
7.77k
403
7.77k
        return (ok);
404
7.54k
}
405
406
cbor_item_t *
407
cbor_encode_rp_entity(const fido_rp_t *rp)
408
375
{
409
375
        cbor_item_t *item = NULL;
410
375
411
375
        if ((item = cbor_new_definite_map(2)) == NULL)
412
375
                return (NULL);
413
374
414
374
        if ((rp->id && cbor_add_string(item, "id", rp->id) < 0) ||
415
374
            (rp->name && cbor_add_string(item, "name", rp->name) < 0)) {
416
6
                cbor_decref(&item);
417
6
                return (NULL);
418
6
        }
419
368
420
368
        return (item);
421
368
}
422
423
cbor_item_t *
424
cbor_encode_user_entity(const fido_user_t *user)
425
368
{
426
368
        cbor_item_t             *item = NULL;
427
368
        const fido_blob_t       *id = &user->id;
428
368
        const char              *display = user->display_name;
429
368
430
368
        if ((item = cbor_new_definite_map(4)) == NULL)
431
368
                return (NULL);
432
367
433
367
        if ((id->ptr && cbor_add_bytestring(item, "id", id->ptr, id->len) < 0) ||
434
367
            (user->icon && cbor_add_string(item, "icon", user->icon) < 0) ||
435
367
            (user->name && cbor_add_string(item, "name", user->name) < 0) ||
436
367
            (display && cbor_add_string(item, "displayName", display) < 0)) {
437
4
                cbor_decref(&item);
438
4
                return (NULL);
439
4
        }
440
363
441
363
        return (item);
442
363
}
443
444
cbor_item_t *
445
cbor_encode_pubkey_param(int cose_alg)
446
363
{
447
363
        cbor_item_t             *item = NULL;
448
363
        cbor_item_t             *body = NULL;
449
363
        struct cbor_pair         alg;
450
363
        int                      ok = -1;
451
363
452
363
        memset(&alg, 0, sizeof(alg));
453
363
454
363
        if ((item = cbor_new_definite_array(1)) == NULL ||
455
363
            (body = cbor_new_definite_map(2)) == NULL ||
456
363
            cose_alg > -1 || cose_alg < INT16_MIN)
457
363
                goto fail;
458
362
459
362
        alg.key = cbor_build_string("alg");
460
362
461
362
        if (-cose_alg - 1 > UINT8_MAX)
462
362
                alg.value = cbor_build_negint16((uint16_t)(-cose_alg - 1));
463
291
        else
464
291
                alg.value = cbor_build_negint8((uint8_t)(-cose_alg - 1));
465
362
466
362
        if (alg.key == NULL || alg.value == NULL) {
467
1
                fido_log_debug("%s: cbor_build", __func__);
468
1
                goto fail;
469
1
        }
470
361
471
361
        if (cbor_map_add(body, alg) == false ||
472
361
            cbor_add_string(body, "type", "public-key") < 0 ||
473
361
            cbor_array_push(item, body) == false)
474
361
                goto fail;
475
359
476
359
        ok  = 0;
477
363
fail:
478
363
        if (ok < 0) {
479
4
                if (item != NULL) {
480
4
                        cbor_decref(&item);
481
4
                        item = NULL;
482
4
                }
483
4
        }
484
363
485
363
        if (body != NULL)
486
363
                cbor_decref(&body);
487
363
        if (alg.key != NULL)
488
363
                cbor_decref(&alg.key);
489
363
        if (alg.value != NULL)
490
363
                cbor_decref(&alg.value);
491
363
492
363
        return (item);
493
359
}
494
495
cbor_item_t *
496
cbor_encode_pubkey(const fido_blob_t *pubkey)
497
7.82k
{
498
7.82k
        cbor_item_t *cbor_key = NULL;
499
7.82k
500
7.82k
        if ((cbor_key = cbor_new_definite_map(2)) == NULL ||
501
7.82k
            cbor_add_bytestring(cbor_key, "id", pubkey->ptr, pubkey->len) < 0 ||
502
7.82k
            cbor_add_string(cbor_key, "type", "public-key") < 0) {
503
41
                if (cbor_key)
504
37
                        cbor_decref(&cbor_key);
505
41
                return (NULL);
506
41
        }
507
7.78k
508
7.78k
        return (cbor_key);
509
7.78k
}
510
511
cbor_item_t *
512
cbor_encode_pubkey_list(const fido_blob_array_t *list)
513
316
{
514
316
        cbor_item_t     *array = NULL;
515
316
        cbor_item_t     *key = NULL;
516
316
517
316
        if ((array = cbor_new_definite_array(list->len)) == NULL)
518
316
                goto fail;
519
316
520
7.79k
        for (size_t i = 0; i < list->len; i++) {
521
7.51k
                if ((key = cbor_encode_pubkey(&list->ptr[i])) == NULL ||
522
7.51k
                    cbor_array_push(array, key) == false)
523
7.51k
                        goto fail;
524
7.48k
                cbor_decref(&key);
525
7.48k
        }
526
316
527
316
        return (array);
528
32
fail:
529
32
        if (key != NULL)
530
32
                cbor_decref(&key);
531
32
        if (array != NULL)
532
32
                cbor_decref(&array);
533
32
534
32
        return (NULL);
535
316
}
536
537
cbor_item_t *
538
cbor_encode_extensions(int ext)
539
14
{
540
14
        cbor_item_t *item = NULL;
541
14
542
14
        if (ext == 0 || ext != FIDO_EXT_HMAC_SECRET)
543
14
                return (NULL);
544
14
545
14
        if ((item = cbor_new_definite_map(1)) == NULL)
546
14
                return (NULL);
547
13
548
13
        if (cbor_add_bool(item, "hmac-secret", FIDO_OPT_TRUE) < 0) {
549
1
                cbor_decref(&item);
550
1
                return (NULL);
551
1
        }
552
12
553
12
        return (item);
554
12
}
555
556
cbor_item_t *
557
cbor_encode_options(fido_opt_t rk, fido_opt_t uv)
558
218
{
559
218
        cbor_item_t *item = NULL;
560
218
561
218
        if ((item = cbor_new_definite_map(2)) == NULL)
562
218
                return (NULL);
563
217
564
217
        if ((rk != FIDO_OPT_OMIT && cbor_add_bool(item, "rk", rk) < 0) ||
565
217
            (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
566
2
                cbor_decref(&item);
567
2
                return (NULL);
568
2
        }
569
215
570
215
        return (item);
571
215
}
572
573
cbor_item_t *
574
cbor_encode_assert_options(fido_opt_t up, fido_opt_t uv)
575
98
{
576
98
        cbor_item_t *item = NULL;
577
98
578
98
        if ((item = cbor_new_definite_map(2)) == NULL)
579
98
                return (NULL);
580
97
581
97
        if ((up != FIDO_OPT_OMIT && cbor_add_bool(item, "up", up) < 0) ||
582
97
            (uv != FIDO_OPT_OMIT && cbor_add_bool(item, "uv", uv) < 0)) {
583
3
                cbor_decref(&item);
584
3
                return (NULL);
585
3
        }
586
94
587
94
        return (item);
588
94
}
589
590
cbor_item_t *
591
cbor_encode_pin_auth(const fido_blob_t *hmac_key, const fido_blob_t *data)
592
1.18k
{
593
1.18k
        const EVP_MD    *md = NULL;
594
1.18k
        unsigned char    dgst[SHA256_DIGEST_LENGTH];
595
1.18k
        unsigned int     dgst_len;
596
1.18k
597
1.18k
        if ((md = EVP_sha256()) == NULL || HMAC(md, hmac_key->ptr,
598
1.16k
            (int)hmac_key->len, data->ptr, (int)data->len, dgst,
599
1.16k
            &dgst_len) == NULL || dgst_len != SHA256_DIGEST_LENGTH)
600
1.18k
                return (NULL);
601
1.15k
602
1.15k
        return (cbor_build_bytestring(dgst, 16));
603
1.15k
}
604
605
cbor_item_t *
606
cbor_encode_pin_opt(void)
607
1.17k
{
608
1.17k
        return (cbor_build_uint8(1));
609
1.17k
}
610
611
cbor_item_t *
612
cbor_encode_pin_enc(const fido_blob_t *key, const fido_blob_t *pin)
613
76
{
614
76
        fido_blob_t      pe;
615
76
        cbor_item_t     *item = NULL;
616
76
617
76
        if (aes256_cbc_enc(key, pin, &pe) < 0)
618
8
                return (NULL);
619
68
620
68
        item = cbor_build_bytestring(pe.ptr, pe.len);
621
68
        free(pe.ptr);
622
68
623
68
        return (item);
624
68
}
625
626
static int
627
sha256(const unsigned char *data, size_t data_len, fido_blob_t *digest)
628
1.41k
{
629
1.41k
        if ((digest->ptr = calloc(1, SHA256_DIGEST_LENGTH)) == NULL)
630
1.41k
                return (-1);
631
1.40k
632
1.40k
        digest->len = SHA256_DIGEST_LENGTH;
633
1.40k
634
1.40k
        if (SHA256(data, data_len, digest->ptr) != digest->ptr) {
635
21
                free(digest->ptr);
636
21
                digest->ptr = NULL;
637
21
                digest->len = 0;
638
21
                return (-1);
639
21
        }
640
1.37k
641
1.37k
        return (0);
642
1.37k
}
643
644
cbor_item_t *
645
cbor_encode_change_pin_auth(const fido_blob_t *key, const fido_blob_t *new_pin,
646
    const fido_blob_t *pin)
647
47
{
648
47
        unsigned char    dgst[SHA256_DIGEST_LENGTH];
649
47
        unsigned int     dgst_len;
650
47
        cbor_item_t     *item = NULL;
651
47
        const EVP_MD    *md = NULL;
652
#if OPENSSL_VERSION_NUMBER < 0x10100000L
653
        HMAC_CTX         ctx;
654
#else
655
        HMAC_CTX        *ctx = NULL;
656
47
#endif
657
47
        fido_blob_t     *npe = NULL; /* new pin, encrypted */
658
47
        fido_blob_t     *ph = NULL;  /* pin hash */
659
47
        fido_blob_t     *phe = NULL; /* pin hash, encrypted */
660
47
        int              ok = -1;
661
47
662
47
        if ((npe = fido_blob_new()) == NULL ||
663
47
            (ph = fido_blob_new()) == NULL ||
664
47
            (phe = fido_blob_new()) == NULL)
665
47
                goto fail;
666
44
667
44
        if (aes256_cbc_enc(key, new_pin, npe) < 0) {
668
4
                fido_log_debug("%s: aes256_cbc_enc 1", __func__);
669
4
                goto fail;
670
4
        }
671
40
672
40
        if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) {
673
2
                fido_log_debug("%s: sha256", __func__);
674
2
                goto fail;
675
2
        }
676
38
677
38
        ph->len = 16; /* first 16 bytes */
678
38
679
38
        if (aes256_cbc_enc(key, ph, phe) < 0) {
680
1
                fido_log_debug("%s: aes256_cbc_enc 2", __func__);
681
1
                goto fail;
682
1
        }
683
37
684
#if OPENSSL_VERSION_NUMBER < 0x10100000L
685
        HMAC_CTX_init(&ctx);
686
687
        if ((md = EVP_sha256()) == NULL ||
688
            HMAC_Init_ex(&ctx, key->ptr, (int)key->len, md, NULL) == 0 ||
689
            HMAC_Update(&ctx, npe->ptr, (int)npe->len) == 0 ||
690
            HMAC_Update(&ctx, phe->ptr, (int)phe->len) == 0 ||
691
            HMAC_Final(&ctx, dgst, &dgst_len) == 0 || dgst_len != 32) {
692
                fido_log_debug("%s: HMAC", __func__);
693
                goto fail;
694
        }
695
#else
696
37
        if ((ctx = HMAC_CTX_new()) == NULL ||
697
37
            (md = EVP_sha256())  == NULL ||
698
37
            HMAC_Init_ex(ctx, key->ptr, (int)key->len, md, NULL) == 0 ||
699
37
            HMAC_Update(ctx, npe->ptr, (int)npe->len) == 0 ||
700
37
            HMAC_Update(ctx, phe->ptr, (int)phe->len) == 0 ||
701
37
            HMAC_Final(ctx, dgst, &dgst_len) == 0 || dgst_len != 32) {
702
7
                fido_log_debug("%s: HMAC", __func__);
703
7
                goto fail;
704
7
        }
705
30
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
706
30
707
30
        if ((item = cbor_build_bytestring(dgst, 16)) == NULL) {
708
2
                fido_log_debug("%s: cbor_build_bytestring", __func__);
709
2
                goto fail;
710
2
        }
711
28
712
28
        ok = 0;
713
47
fail:
714
47
        fido_blob_free(&npe);
715
47
        fido_blob_free(&ph);
716
47
        fido_blob_free(&phe);
717
47
718
47
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
719
47
        if (ctx != NULL)
720
47
                HMAC_CTX_free(ctx);
721
47
#endif
722
47
723
47
        if (ok < 0) {
724
19
                if (item != NULL) {
725
0
                        cbor_decref(&item);
726
0
                        item = NULL;
727
0
                }
728
19
        }
729
47
730
47
        return (item);
731
28
}
732
733
cbor_item_t *
734
cbor_encode_set_pin_auth(const fido_blob_t *key, const fido_blob_t *pin)
735
55
{
736
55
        const EVP_MD    *md = NULL;
737
55
        unsigned char    dgst[SHA256_DIGEST_LENGTH];
738
55
        unsigned int     dgst_len;
739
55
        cbor_item_t     *item = NULL;
740
55
        fido_blob_t     *pe = NULL;
741
55
742
55
        if ((pe = fido_blob_new()) == NULL)
743
55
                goto fail;
744
53
745
53
        if (aes256_cbc_enc(key, pin, pe) < 0) {
746
7
                fido_log_debug("%s: aes256_cbc_enc", __func__);
747
7
                goto fail;
748
7
        }
749
46
750
46
        if ((md = EVP_sha256()) == NULL || key->len != 32 || HMAC(md, key->ptr,
751
43
            (int)key->len, pe->ptr, (int)pe->len, dgst, &dgst_len) == NULL ||
752
46
            dgst_len != SHA256_DIGEST_LENGTH) {
753
5
                fido_log_debug("%s: HMAC", __func__);
754
5
                goto fail;
755
5
        }
756
41
757
41
        item = cbor_build_bytestring(dgst, 16);
758
55
fail:
759
55
        fido_blob_free(&pe);
760
55
761
55
        return (item);
762
41
}
763
764
cbor_item_t *
765
cbor_encode_pin_hash_enc(const fido_blob_t *shared, const fido_blob_t *pin)
766
1.39k
{
767
1.39k
        cbor_item_t     *item = NULL;
768
1.39k
        fido_blob_t     *ph = NULL;
769
1.39k
        fido_blob_t     *phe = NULL;
770
1.39k
771
1.39k
        if ((ph = fido_blob_new()) == NULL || (phe = fido_blob_new()) == NULL)
772
1.39k
                goto fail;
773
1.37k
774
1.37k
        if (sha256(pin->ptr, pin->len, ph) < 0 || ph->len < 16) {
775
31
                fido_log_debug("%s: SHA256", __func__);
776
31
                goto fail;
777
31
        }
778
1.34k
779
1.34k
        ph->len = 16; /* first 16 bytes */
780
1.34k
781
1.34k
        if (aes256_cbc_enc(shared, ph, phe) < 0) {
782
69
                fido_log_debug("%s: aes256_cbc_enc", __func__);
783
69
                goto fail;
784
69
        }
785
1.27k
786
1.27k
        item = cbor_build_bytestring(phe->ptr, phe->len);
787
1.39k
fail:
788
1.39k
        fido_blob_free(&ph);
789
1.39k
        fido_blob_free(&phe);
790
1.39k
791
1.39k
        return (item);
792
1.27k
}
793
794
cbor_item_t *
795
cbor_encode_hmac_secret_param(const fido_blob_t *ecdh, const es256_pk_t *pk,
796
    const fido_blob_t *hmac_salt)
797
25
{
798
25
        cbor_item_t             *item = NULL;
799
25
        cbor_item_t             *param = NULL;
800
25
        cbor_item_t             *argv[3];
801
25
        struct cbor_pair         pair;
802
25
803
25
        memset(argv, 0, sizeof(argv));
804
25
        memset(&pair, 0, sizeof(pair));
805
25
806
25
        if (ecdh == NULL || pk == NULL || hmac_salt->ptr == NULL) {
807
2
                fido_log_debug("%s: ecdh=%p, pk=%p, hmac_salt->ptr=%p",
808
2
                    __func__, (const void *)ecdh, (const void *)pk,
809
2
                    (const void *)hmac_salt->ptr);
810
2
                goto fail;
811
2
        }
812
23
813
23
        if (hmac_salt->len != 32 && hmac_salt->len != 64) {
814
0
                fido_log_debug("%s: hmac_salt->len=%zu", __func__,
815
0
                    hmac_salt->len);
816
0
                goto fail;
817
0
        }
818
23
819
23
        /* XXX not pin, but salt */
820
23
        if ((argv[0] = es256_pk_encode(pk, 1)) == NULL ||
821
23
            (argv[1] = cbor_encode_pin_enc(ecdh, hmac_salt)) == NULL ||
822
23
            (argv[2] = cbor_encode_set_pin_auth(ecdh, hmac_salt)) == NULL) {
823
9
                fido_log_debug("%s: cbor encode", __func__);
824
9
                goto fail;
825
9
        }
826
14
827
14
        if ((param = cbor_flatten_vector(argv, 3)) == NULL) {
828
1
                fido_log_debug("%s: cbor_flatten_vector", __func__);
829
1
                goto fail;
830
1
        }
831
13
832
13
        if ((item = cbor_new_definite_map(1)) == NULL) {
833
1
                fido_log_debug("%s: cbor_new_definite_map", __func__);
834
1
                goto fail;
835
1
        }
836
12
837
12
        if ((pair.key = cbor_build_string("hmac-secret")) == NULL) {
838
1
                fido_log_debug("%s: cbor_build", __func__);
839
1
                goto fail;
840
1
        }
841
11
842
11
        pair.value = param;
843
11
844
11
        if (!cbor_map_add(item, pair)) {
845
1
                fido_log_debug("%s: cbor_map_add", __func__);
846
1
                cbor_decref(&item);
847
1
                item = NULL;
848
1
                goto fail;
849
1
        }
850
25
851
25
fail:
852
100
        for (size_t i = 0; i < 3; i++)
853
75
                if (argv[i] != NULL)
854
75
                        cbor_decref(&argv[i]);
855
25
856
25
        if (param != NULL)
857
25
                cbor_decref(&param);
858
25
        if (pair.key != NULL)
859
25
                cbor_decref(&pair.key);
860
25
861
25
        return (item);
862
11
}
863
864
int
865
cbor_decode_fmt(const cbor_item_t *item, char **fmt)
866
146
{
867
146
        char    *type = NULL;
868
146
869
146
        if (cbor_string_copy(item, &type) < 0) {
870
1
                fido_log_debug("%s: cbor_string_copy", __func__);
871
1
                return (-1);
872
1
        }
873
145
874
145
        if (strcmp(type, "packed") && strcmp(type, "fido-u2f")) {
875
1
                fido_log_debug("%s: type=%s", __func__, type);
876
1
                free(type);
877
1
                return (-1);
878
1
        }
879
144
880
144
        *fmt = type;
881
144
882
144
        return (0);
883
144
}
884
885
struct cose_key {
886
        int kty;
887
        int alg;
888
        int crv;
889
};
890
891
static int
892
find_cose_alg(const cbor_item_t *key, const cbor_item_t *val, void *arg)
893
3.29k
{
894
3.29k
        struct cose_key *cose_key = arg;
895
3.29k
896
3.29k
        if (cbor_isa_uint(key) == true &&
897
3.29k
            cbor_int_get_width(key) == CBOR_INT_8) {
898
1.45k
                switch (cbor_get_uint8(key)) {
899
1.45k
                case 1:
900
727
                        if (cbor_isa_uint(val) == false ||
901
727
                            cbor_get_int(val) > INT_MAX || cose_key->kty != 0) {
902
7
                                fido_log_debug("%s: kty", __func__);
903
7
                                return (-1);
904
7
                        }
905
720
906
720
                        cose_key->kty = (int)cbor_get_int(val);
907
720
908
720
                        break;
909
720
                case 3:
910
697
                        if (cbor_isa_negint(val) == false ||
911
697
                            cbor_get_int(val) > INT_MAX || cose_key->alg != 0) {
912
10
                                fido_log_debug("%s: alg", __func__);
913
10
                                return (-1);
914
10
                        }
915
687
916
687
                        cose_key->alg = -(int)cbor_get_int(val) - 1;
917
687
918
687
                        break;
919
1.83k
                }
920
1.83k
        } else if (cbor_isa_negint(key) == true &&
921
1.83k
            cbor_int_get_width(key) == CBOR_INT_8) {
922
1.69k
                if (cbor_get_uint8(key) == 0) {
923
649
                        /* get crv if not rsa, otherwise ignore */
924
649
                        if (cbor_isa_uint(val) == true &&
925
649
                            cbor_get_int(val) <= INT_MAX &&
926
649
                            cose_key->crv == 0)
927
634
                                cose_key->crv = (int)cbor_get_int(val);
928
649
                }
929
1.69k
        }
930
3.29k
931
3.29k
        return (0);
932
3.29k
}
933
934
static int
935
get_cose_alg(const cbor_item_t *item, int *cose_alg)
936
760
{
937
760
        struct cose_key cose_key;
938
760
939
760
        memset(&cose_key, 0, sizeof(cose_key));
940
760
941
760
        *cose_alg = 0;
942
760
943
760
        if (cbor_isa_map(item) == false ||
944
760
            cbor_map_is_definite(item) == false ||
945
760
            cbor_map_iter(item, &cose_key, find_cose_alg) < 0) {
946
87
                fido_log_debug("%s: cbor type", __func__);
947
87
                return (-1);
948
87
        }
949
673
950
673
        switch (cose_key.alg) {
951
673
        case COSE_ES256:
952
396
                if (cose_key.kty != COSE_KTY_EC2 ||
953
396
                    cose_key.crv != COSE_P256) {
954
15
                        fido_log_debug("%s: invalid kty/crv", __func__);
955
15
                        return (-1);
956
15
                }
957
381
958
381
                break;
959
381
        case COSE_EDDSA:
960
231
                if (cose_key.kty != COSE_KTY_OKP ||
961
231
                    cose_key.crv != COSE_ED25519) {
962
10
                        fido_log_debug("%s: invalid kty/crv", __func__);
963
10
                        return (-1);
964
10
                }
965
221
966
221
                break;
967
221
        case COSE_RS256:
968
25
                if (cose_key.kty != COSE_KTY_RSA) {
969
1
                        fido_log_debug("%s: invalid kty/crv", __func__);
970
1
                        return (-1);
971
1
                }
972
24
973
24
                break;
974
24
        default:
975
21
                fido_log_debug("%s: unknown alg %d", __func__, cose_key.alg);
976
21
977
21
                return (-1);
978
626
        }
979
626
980
626
        *cose_alg = cose_key.alg;
981
626
982
626
        return (0);
983
626
}
984
985
int
986
cbor_decode_pubkey(const cbor_item_t *item, int *type, void *key)
987
760
{
988
760
        if (get_cose_alg(item, type) < 0) {
989
134
                fido_log_debug("%s: get_cose_alg", __func__);
990
134
                return (-1);
991
134
        }
992
626
993
626
        switch (*type) {
994
626
        case COSE_ES256:
995
381
                if (es256_pk_decode(item, key) < 0) {
996
10
                        fido_log_debug("%s: es256_pk_decode", __func__);
997
10
                        return (-1);
998
10
                }
999
371
                break;
1000
371
        case COSE_RS256:
1001
24
                if (rs256_pk_decode(item, key) < 0) {
1002
3
                        fido_log_debug("%s: rs256_pk_decode", __func__);
1003
3
                        return (-1);
1004
3
                }
1005
21
                break;
1006
221
        case COSE_EDDSA:
1007
221
                if (eddsa_pk_decode(item, key) < 0) {
1008
7
                        fido_log_debug("%s: eddsa_pk_decode", __func__);
1009
7
                        return (-1);
1010
7
                }
1011
214
                break;
1012
214
        default:
1013
0
                fido_log_debug("%s: invalid cose_alg %d", __func__, *type);
1014
0
                return (-1);
1015
606
        }
1016
606
1017
606
        return (0);
1018
606
}
1019
1020
static int
1021
decode_attcred(const unsigned char **buf, size_t *len, int cose_alg,
1022
    fido_attcred_t *attcred)
1023
294
{
1024
294
        cbor_item_t             *item = NULL;
1025
294
        struct cbor_load_result  cbor;
1026
294
        uint16_t                 id_len;
1027
294
        int                      ok = -1;
1028
294
1029
294
        fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf,
1030
294
            *len);
1031
294
1032
294
        if (fido_buf_read(buf, len, &attcred->aaguid,
1033
294
            sizeof(attcred->aaguid)) < 0) {
1034
6
                fido_log_debug("%s: fido_buf_read aaguid", __func__);
1035
6
                return (-1);
1036
6
        }
1037
288
1038
288
        if (fido_buf_read(buf, len, &id_len, sizeof(id_len)) < 0) {
1039
3
                fido_log_debug("%s: fido_buf_read id_len", __func__);
1040
3
                return (-1);
1041
3
        }
1042
285
1043
285
        attcred->id.len = (size_t)be16toh(id_len);
1044
285
        if ((attcred->id.ptr = malloc(attcred->id.len)) == NULL)
1045
285
                return (-1);
1046
280
1047
280
        fido_log_debug("%s: attcred->id.len=%zu", __func__, attcred->id.len);
1048
280
1049
280
        if (fido_buf_read(buf, len, attcred->id.ptr, attcred->id.len) < 0) {
1050
9
                fido_log_debug("%s: fido_buf_read id", __func__);
1051
9
                return (-1);
1052
9
        }
1053
271
1054
271
        if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1055
10
                fido_log_debug("%s: cbor_load", __func__);
1056
10
                fido_log_xxd(*buf, *len);
1057
10
                goto fail;
1058
10
        }
1059
261
1060
261
        if (cbor_decode_pubkey(item, &attcred->type, &attcred->pubkey) < 0) {
1061
97
                fido_log_debug("%s: cbor_decode_pubkey", __func__);
1062
97
                goto fail;
1063
97
        }
1064
164
1065
164
        if (attcred->type != cose_alg) {
1066
11
                fido_log_debug("%s: cose_alg mismatch (%d != %d)", __func__,
1067
11
                    attcred->type, cose_alg);
1068
11
                goto fail;
1069
11
        }
1070
153
1071
153
        *buf += cbor.read;
1072
153
        *len -= cbor.read;
1073
153
1074
153
        ok = 0;
1075
271
fail:
1076
271
        if (item != NULL)
1077
271
                cbor_decref(&item);
1078
271
1079
271
        return (ok);
1080
153
}
1081
1082
static int
1083
decode_extension(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1084
0
{
1085
0
        int     *authdata_ext = arg;
1086
0
        char    *type = NULL;
1087
0
        int      ok = -1;
1088
0
1089
0
        if (cbor_string_copy(key, &type) < 0 || strcmp(type, "hmac-secret")) {
1090
0
                fido_log_debug("%s: cbor type", __func__);
1091
0
                ok = 0; /* ignore */
1092
0
                goto out;
1093
0
        }
1094
0
1095
0
        if (cbor_isa_float_ctrl(val) == false ||
1096
0
            cbor_float_get_width(val) != CBOR_FLOAT_0 ||
1097
0
            cbor_is_bool(val) == false || *authdata_ext != 0) {
1098
0
                fido_log_debug("%s: cbor type", __func__);
1099
0
                goto out;
1100
0
        }
1101
0
1102
0
        if (cbor_ctrl_value(val) == CBOR_CTRL_TRUE)
1103
0
                *authdata_ext |= FIDO_EXT_HMAC_SECRET;
1104
0
1105
0
        ok = 0;
1106
0
out:
1107
0
        free(type);
1108
0
1109
0
        return (ok);
1110
0
}
1111
1112
static int
1113
decode_extensions(const unsigned char **buf, size_t *len, int *authdata_ext)
1114
6
{
1115
6
        cbor_item_t             *item = NULL;
1116
6
        struct cbor_load_result  cbor;
1117
6
        int                      ok = -1;
1118
6
1119
6
        fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf,
1120
6
            *len);
1121
6
1122
6
        *authdata_ext = 0;
1123
6
1124
6
        if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1125
3
                fido_log_debug("%s: cbor_load", __func__);
1126
3
                fido_log_xxd(*buf, *len);
1127
3
                goto fail;
1128
3
        }
1129
3
1130
3
        if (cbor_isa_map(item) == false ||
1131
3
            cbor_map_is_definite(item) == false ||
1132
3
            cbor_map_size(item) != 1 ||
1133
3
            cbor_map_iter(item, authdata_ext, decode_extension) < 0) {
1134
3
                fido_log_debug("%s: cbor type", __func__);
1135
3
                goto fail;
1136
3
        }
1137
0
1138
0
        *buf += cbor.read;
1139
0
        *len -= cbor.read;
1140
0
1141
0
        ok = 0;
1142
6
fail:
1143
6
        if (item != NULL)
1144
6
                cbor_decref(&item);
1145
6
1146
6
        return (ok);
1147
0
}
1148
1149
static int
1150
decode_hmac_secret_aux(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1151
7
{
1152
7
        fido_blob_t     *out = arg;
1153
7
        char            *type = NULL;
1154
7
        int              ok = -1;
1155
7
1156
7
        if (cbor_string_copy(key, &type) < 0 || strcmp(type, "hmac-secret")) {
1157
5
                fido_log_debug("%s: cbor type", __func__);
1158
5
                ok = 0; /* ignore */
1159
5
                goto out;
1160
5
        }
1161
2
1162
2
        ok = cbor_bytestring_copy(val, &out->ptr, &out->len);
1163
7
out:
1164
7
        free(type);
1165
7
1166
7
        return (ok);
1167
2
}
1168
1169
static int
1170
decode_hmac_secret(const unsigned char **buf, size_t *len, fido_blob_t *out)
1171
14
{
1172
14
        cbor_item_t             *item = NULL;
1173
14
        struct cbor_load_result  cbor;
1174
14
        int                      ok = -1;
1175
14
1176
14
        fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)*buf,
1177
14
            *len);
1178
14
1179
14
        if ((item = cbor_load(*buf, *len, &cbor)) == NULL) {
1180
3
                fido_log_debug("%s: cbor_load", __func__);
1181
3
                fido_log_xxd(*buf, *len);
1182
3
                goto fail;
1183
3
        }
1184
11
1185
11
        if (cbor_isa_map(item) == false ||
1186
11
            cbor_map_is_definite(item) == false ||
1187
11
            cbor_map_size(item) != 1 ||
1188
11
            cbor_map_iter(item, out, decode_hmac_secret_aux) < 0) {
1189
4
                fido_log_debug("%s: cbor type", __func__);
1190
4
                goto fail;
1191
4
        }
1192
7
1193
7
        *buf += cbor.read;
1194
7
        *len -= cbor.read;
1195
7
1196
7
        ok = 0;
1197
14
fail:
1198
14
        if (item != NULL)
1199
14
                cbor_decref(&item);
1200
14
1201
14
        return (ok);
1202
7
}
1203
1204
int
1205
cbor_decode_cred_authdata(const cbor_item_t *item, int cose_alg,
1206
    fido_blob_t *authdata_cbor, fido_authdata_t *authdata,
1207
    fido_attcred_t *attcred, int *authdata_ext)
1208
382
{
1209
382
        const unsigned char     *buf = NULL;
1210
382
        size_t                   len;
1211
382
        size_t                   alloc_len;
1212
382
1213
382
        if (cbor_isa_bytestring(item) == false ||
1214
382
            cbor_bytestring_is_definite(item) == false) {
1215
1
                fido_log_debug("%s: cbor type", __func__);
1216
1
                return (-1);
1217
1
        }
1218
381
1219
381
        if (authdata_cbor->ptr != NULL ||
1220
381
            (authdata_cbor->len = cbor_serialize_alloc(item,
1221
381
            &authdata_cbor->ptr, &alloc_len)) == 0) {
1222
9
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
1223
9
                return (-1);
1224
9
        }
1225
372
1226
372
        buf = cbor_bytestring_handle(item);
1227
372
        len = cbor_bytestring_length(item);
1228
372
1229
372
        fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len);
1230
372
1231
372
        if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
1232
6
                fido_log_debug("%s: fido_buf_read", __func__);
1233
6
                return (-1);
1234
6
        }
1235
366
1236
366
        authdata->sigcount = be32toh(authdata->sigcount);
1237
366
1238
366
        if (attcred != NULL) {
1239
366
                if ((authdata->flags & CTAP_AUTHDATA_ATT_CRED) == 0 ||
1240
366
                    decode_attcred(&buf, &len, cose_alg, attcred) < 0)
1241
213
                        return (-1);
1242
153
        }
1243
153
1244
153
        if (authdata_ext != NULL) {
1245
153
                if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0 && 
1246
153
                    decode_extensions(&buf, &len, authdata_ext) < 0)
1247
6
                        return (-1);
1248
147
        }
1249
147
1250
147
        /* XXX we should probably ensure that len == 0 at this point */
1251
147
1252
147
        return (FIDO_OK);
1253
147
}
1254
1255
int
1256
cbor_decode_assert_authdata(const cbor_item_t *item, fido_blob_t *authdata_cbor,
1257
    fido_authdata_t *authdata, int *authdata_ext, fido_blob_t *hmac_secret_enc)
1258
340
{
1259
340
        const unsigned char     *buf = NULL;
1260
340
        size_t                   len;
1261
340
        size_t                   alloc_len;
1262
340
1263
340
        if (cbor_isa_bytestring(item) == false ||
1264
340
            cbor_bytestring_is_definite(item) == false) {
1265
1
                fido_log_debug("%s: cbor type", __func__);
1266
1
                return (-1);
1267
1
        }
1268
339
1269
339
        if (authdata_cbor->ptr != NULL ||
1270
339
            (authdata_cbor->len = cbor_serialize_alloc(item,
1271
339
            &authdata_cbor->ptr, &alloc_len)) == 0) {
1272
4
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
1273
4
                return (-1);
1274
4
        }
1275
335
1276
335
        buf = cbor_bytestring_handle(item);
1277
335
        len = cbor_bytestring_length(item);
1278
335
1279
335
        fido_log_debug("%s: buf=%p, len=%zu", __func__, (const void *)buf, len);
1280
335
1281
335
        if (fido_buf_read(&buf, &len, authdata, sizeof(*authdata)) < 0) {
1282
2
                fido_log_debug("%s: fido_buf_read", __func__);
1283
2
                return (-1);
1284
2
        }
1285
333
1286
333
        authdata->sigcount = be32toh(authdata->sigcount);
1287
333
1288
333
        *authdata_ext = 0;
1289
333
        if ((authdata->flags & CTAP_AUTHDATA_EXT_DATA) != 0) {
1290
14
                /* XXX semantic leap: extensions -> hmac_secret */
1291
14
                if (decode_hmac_secret(&buf, &len, hmac_secret_enc) < 0) {
1292
7
                        fido_log_debug("%s: decode_hmac_secret", __func__);
1293
7
                        return (-1);
1294
7
                }
1295
7
                *authdata_ext = FIDO_EXT_HMAC_SECRET;
1296
7
        }
1297
333
1298
333
        /* XXX we should probably ensure that len == 0 at this point */
1299
333
1300
333
        return (FIDO_OK);
1301
333
}
1302
1303
static int
1304
decode_x5c(const cbor_item_t *item, void *arg)
1305
70
{
1306
70
        fido_blob_t *x5c = arg;
1307
70
1308
70
        if (x5c->len)
1309
41
                return (0); /* ignore */
1310
29
1311
29
        return (cbor_bytestring_copy(item, &x5c->ptr, &x5c->len));
1312
29
}
1313
1314
static int
1315
decode_attstmt_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1316
149
{
1317
149
        fido_attstmt_t  *attstmt = arg;
1318
149
        char            *name = NULL;
1319
149
        int              ok = -1;
1320
149
1321
149
        if (cbor_string_copy(key, &name) < 0) {
1322
20
                fido_log_debug("%s: cbor type", __func__);
1323
20
                ok = 0; /* ignore */
1324
20
                goto out;
1325
20
        }
1326
129
1327
129
        if (!strcmp(name, "alg")) {
1328
45
                if (cbor_isa_negint(val) == false ||
1329
45
                    cbor_int_get_width(val) != CBOR_INT_8 ||
1330
45
                    cbor_get_uint8(val) != -COSE_ES256 - 1) {
1331
3
                        fido_log_debug("%s: alg", __func__);
1332
3
                        goto out;
1333
3
                }
1334
84
        } else if (!strcmp(name, "sig")) {
1335
42
                if (cbor_bytestring_copy(val, &attstmt->sig.ptr,
1336
42
                    &attstmt->sig.len) < 0) {
1337
1
                        fido_log_debug("%s: sig", __func__);
1338
1
                        goto out;
1339
1
                }
1340
42
        } else if (!strcmp(name, "x5c")) {
1341
31
                if (cbor_isa_array(val) == false ||
1342
31
                    cbor_array_is_definite(val) == false ||
1343
31
                    cbor_array_iter(val, &attstmt->x5c, decode_x5c) < 0) {
1344
4
                        fido_log_debug("%s: x5c", __func__);
1345
4
                        goto out;
1346
4
                }
1347
121
        }
1348
121
1349
121
        ok = 0;
1350
149
out:
1351
149
        free(name);
1352
149
1353
149
        return (ok);
1354
121
}
1355
1356
int
1357
cbor_decode_attstmt(const cbor_item_t *item, fido_attstmt_t *attstmt)
1358
56
{
1359
56
        if (cbor_isa_map(item) == false ||
1360
56
            cbor_map_is_definite(item) == false ||
1361
56
            cbor_map_iter(item, attstmt, decode_attstmt_entry) < 0) {
1362
20
                fido_log_debug("%s: cbor type", __func__);
1363
20
                return (-1);
1364
20
        }
1365
36
1366
36
        return (0);
1367
36
}
1368
1369
int
1370
cbor_decode_uint64(const cbor_item_t *item, uint64_t *n)
1371
669
{
1372
669
        if (cbor_isa_uint(item) == false) {
1373
14
                fido_log_debug("%s: cbor type", __func__);
1374
14
                return (-1);
1375
14
        }
1376
655
1377
655
        *n = cbor_get_int(item);
1378
655
1379
655
        return (0);
1380
655
}
1381
1382
static int
1383
decode_cred_id_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1384
1.16k
{
1385
1.16k
        fido_blob_t     *id = arg;
1386
1.16k
        char            *name = NULL;
1387
1.16k
        int              ok = -1;
1388
1.16k
1389
1.16k
        if (cbor_string_copy(key, &name) < 0) {
1390
35
                fido_log_debug("%s: cbor type", __func__);
1391
35
                ok = 0; /* ignore */
1392
35
                goto out;
1393
35
        }
1394
1.12k
1395
1.12k
        if (!strcmp(name, "id"))
1396
399
                if (cbor_bytestring_copy(val, &id->ptr, &id->len) < 0) {
1397
3
                        fido_log_debug("%s: cbor_bytestring_copy", __func__);
1398
3
                        goto out;
1399
3
                }
1400
1.12k
1401
1.12k
        ok = 0;
1402
1.16k
out:
1403
1.16k
        free(name);
1404
1.16k
1405
1.16k
        return (ok);
1406
1.12k
}
1407
1408
int
1409
cbor_decode_cred_id(const cbor_item_t *item, fido_blob_t *id)
1410
589
{
1411
589
        if (cbor_isa_map(item) == false ||
1412
589
            cbor_map_is_definite(item) == false ||
1413
589
            cbor_map_iter(item, id, decode_cred_id_entry) < 0) {
1414
13
                fido_log_debug("%s: cbor type", __func__);
1415
13
                return (-1);
1416
13
        }
1417
576
1418
576
        return (0);
1419
576
}
1420
1421
static int
1422
decode_user_entry(const cbor_item_t *key, const cbor_item_t *val, void *arg)
1423
1.60k
{
1424
1.60k
        fido_user_t     *user = arg;
1425
1.60k
        char            *name = NULL;
1426
1.60k
        int              ok = -1;
1427
1.60k
1428
1.60k
        if (cbor_string_copy(key, &name) < 0) {
1429
20
                fido_log_debug("%s: cbor type", __func__);
1430
20
                ok = 0; /* ignore */
1431
20
                goto out;
1432
20
        }
1433
1.58k
1434
1.58k
        if (!strcmp(name, "icon")) {
1435
11
                if (cbor_string_copy(val, &user->icon) < 0) {
1436
1
                        fido_log_debug("%s: icon", __func__);
1437
1
                        goto out;
1438
1
                }
1439
1.57k
        } else if (!strcmp(name, "name")) {
1440
265
                if (cbor_string_copy(val, &user->name) < 0) {
1441
2
                        fido_log_debug("%s: name", __func__);
1442
2
                        goto out;
1443
2
                }
1444
1.30k
        } else if (!strcmp(name, "displayName")) {
1445
74
                if (cbor_string_copy(val, &user->display_name) < 0) {
1446
1
                        fido_log_debug("%s: display_name", __func__);
1447
1
                        goto out;
1448
1
                }
1449
1.23k
        } else if (!strcmp(name, "id")) {
1450
319
                if (cbor_bytestring_copy(val, &user->id.ptr, &user->id.len) < 0) {
1451
2
                        fido_log_debug("%s: id", __func__);
1452
2
                        goto out;
1453
2
                }
1454
1.57k
        }
1455
1.57k
1456
1.57k
        ok = 0;
1457
1.60k
out:
1458
1.60k
        free(name);
1459
1.60k
1460
1.60k
        return (ok);
1461
1.57k
}
1462
1463
int
1464
cbor_decode_user(const cbor_item_t *item, fido_user_t *user)
1465
544
{
1466
544
        if (cbor_isa_map(item) == false ||
1467
544
            cbor_map_is_definite(item) == false ||
1468
544
            cbor_map_iter(item, user, decode_user_entry) < 0) {
1469
19
                fido_log_debug("%s: cbor type", __func__);
1470
19
                return (-1);
1471
19
        }
1472
525
1473
525
        return (0);
1474
525
}
1475
1476
static int
1477
decode_rp_entity_entry(const cbor_item_t *key, const cbor_item_t *val,
1478
    void *arg)
1479
203
{
1480
203
        fido_rp_t       *rp = arg;
1481
203
        char            *name = NULL;
1482
203
        int              ok = -1;
1483
203
1484
203
        if (cbor_string_copy(key, &name) < 0) {
1485
11
                fido_log_debug("%s: cbor type", __func__);
1486
11
                ok = 0; /* ignore */
1487
11
                goto out;
1488
11
        }
1489
192
1490
192
        if (!strcmp(name, "id")) {
1491
97
                if (cbor_string_copy(val, &rp->id) < 0) {
1492
2
                        fido_log_debug("%s: id", __func__);
1493
2
                        goto out;
1494
2
                }
1495
95
        } else if (!strcmp(name, "name")) {
1496
2
                if (cbor_string_copy(val, &rp->name) < 0) {
1497
1
                        fido_log_debug("%s: name", __func__);
1498
1
                        goto out;
1499
1
                }
1500
189
        }
1501
189
1502
189
        ok = 0;
1503
203
out:
1504
203
        free(name);
1505
203
1506
203
        return (ok);
1507
189
}
1508
1509
int
1510
cbor_decode_rp_entity(const cbor_item_t *item, fido_rp_t *rp)
1511
197
{
1512
197
        if (cbor_isa_map(item) == false ||
1513
197
            cbor_map_is_definite(item) == false ||
1514
197
            cbor_map_iter(item, rp, decode_rp_entity_entry) < 0) {
1515
7
                fido_log_debug("%s: cbor type", __func__);
1516
7
                return (-1);
1517
7
        }
1518
190
1519
190
        return (0);
1520
190
}
/home/pedro/projects/libfido2/src/cred.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/ec.h>
8
#include <openssl/evp.h>
9
#include <openssl/sha.h>
10
#include <openssl/x509.h>
11
12
#include <string.h>
13
#include "fido.h"
14
#include "fido/es256.h"
15
16
static int
17
parse_makecred_reply(const cbor_item_t *key, const cbor_item_t *val, void *arg)
18
363
{
19
363
        fido_cred_t *cred = arg;
20
363
21
363
        if (cbor_isa_uint(key) == false ||
22
363
            cbor_int_get_width(key) != CBOR_INT_8) {
23
12
                fido_log_debug("%s: cbor type", __func__);
24
12
                return (0); /* ignore */
25
12
        }
26
351
27
351
        switch (cbor_get_uint8(key)) {
28
351
        case 1: /* fmt */
29
146
                return (cbor_decode_fmt(val, &cred->fmt));
30
351
        case 2: /* authdata */
31
143
                return (cbor_decode_cred_authdata(val, cred->type,
32
143
                    &cred->authdata_cbor, &cred->authdata, &cred->attcred,
33
143
                    &cred->authdata_ext));
34
351
        case 3: /* attestation statement */
35
56
                return (cbor_decode_attstmt(val, &cred->attstmt));
36
351
        default: /* ignore */
37
6
                fido_log_debug("%s: cbor type", __func__);
38
6
                return (0);
39
351
        }
40
351
}
41
42
static int
43
fido_dev_make_cred_tx(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
44
377
{
45
377
        fido_blob_t      f;
46
377
        fido_blob_t     *ecdh = NULL;
47
377
        es256_pk_t      *pk = NULL;
48
377
        cbor_item_t     *argv[9];
49
377
        int              r;
50
377
51
377
        memset(&f, 0, sizeof(f));
52
377
        memset(argv, 0, sizeof(argv));
53
377
54
377
        if (cred->cdh.ptr == NULL || cred->type == 0) {
55
1
                fido_log_debug("%s: cdh=%p, type=%d", __func__,
56
1
                    (void *)cred->cdh.ptr, cred->type);
57
1
                r = FIDO_ERR_INVALID_ARGUMENT;
58
1
                goto fail;
59
1
        }
60
376
61
376
        if ((argv[0] = fido_blob_encode(&cred->cdh)) == NULL ||
62
376
            (argv[1] = cbor_encode_rp_entity(&cred->rp)) == NULL ||
63
376
            (argv[2] = cbor_encode_user_entity(&cred->user)) == NULL ||
64
376
            (argv[3] = cbor_encode_pubkey_param(cred->type)) == NULL) {
65
17
                fido_log_debug("%s: cbor encode", __func__);
66
17
                r = FIDO_ERR_INTERNAL;
67
17
                goto fail;
68
17
        }
69
359
70
359
        /* excluded credentials */
71
359
        if (cred->excl.len)
72
205
                if ((argv[4] = cbor_encode_pubkey_list(&cred->excl)) == NULL) {
73
23
                        fido_log_debug("%s: cbor_encode_pubkey_list", __func__);
74
23
                        r = FIDO_ERR_INTERNAL;
75
23
                        goto fail;
76
23
                }
77
336
78
336
        /* extensions */
79
336
        if (cred->ext)
80
14
                if ((argv[5] = cbor_encode_extensions(cred->ext)) == NULL) {
81
2
                        fido_log_debug("%s: cbor_encode_extensions", __func__);
82
2
                        r = FIDO_ERR_INTERNAL;
83
2
                        goto fail;
84
2
                }
85
334
86
334
        /* options */
87
334
        if (cred->rk != FIDO_OPT_OMIT || cred->uv != FIDO_OPT_OMIT)
88
218
                if ((argv[6] = cbor_encode_options(cred->rk,
89
218
                    cred->uv)) == NULL) {
90
3
                        fido_log_debug("%s: cbor_encode_options", __func__);
91
3
                        r = FIDO_ERR_INTERNAL;
92
3
                        goto fail;
93
3
                }
94
331
95
331
        /* pin authentication */
96
331
        if (pin) {
97
331
                if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
98
107
                        fido_log_debug("%s: fido_do_ecdh", __func__);
99
107
                        goto fail;
100
107
                }
101
224
                if ((r = cbor_add_pin_params(dev, &cred->cdh, pk, ecdh, pin,
102
224
                    &argv[7], &argv[8])) != FIDO_OK) {
103
49
                        fido_log_debug("%s: cbor_add_pin_params", __func__);
104
49
                        goto fail;
105
49
                }
106
175
        }
107
175
108
175
        /* framing and transmission */
109
175
        if (cbor_build_frame(CTAP_CBOR_MAKECRED, argv, 9, &f) < 0 ||
110
175
            fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
111
6
                fido_log_debug("%s: fido_tx", __func__);
112
6
                r = FIDO_ERR_TX;
113
6
                goto fail;
114
6
        }
115
169
116
169
        r = FIDO_OK;
117
377
fail:
118
377
        es256_pk_free(&pk);
119
377
        fido_blob_free(&ecdh);
120
377
        cbor_vector_free(argv, nitems(argv));
121
377
        free(f.ptr);
122
377
123
377
        return (r);
124
169
}
125
126
static int
127
fido_dev_make_cred_rx(fido_dev_t *dev, fido_cred_t *cred, int ms)
128
169
{
129
169
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
130
169
        unsigned char   reply[2048];
131
169
        int             reply_len;
132
169
        int             r;
133
169
134
169
        fido_cred_reset_rx(cred);
135
169
136
169
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
137
12
                fido_log_debug("%s: fido_rx", __func__);
138
12
                return (FIDO_ERR_RX);
139
12
        }
140
157
141
157
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, cred,
142
157
            parse_makecred_reply)) != FIDO_OK) {
143
111
                fido_log_debug("%s: parse_makecred_reply", __func__);
144
111
                return (r);
145
111
        }
146
46
147
46
        if (cred->fmt == NULL || fido_blob_is_empty(&cred->authdata_cbor) ||
148
46
            fido_blob_is_empty(&cred->attcred.id) ||
149
46
            fido_blob_is_empty(&cred->attstmt.sig)) {
150
15
                fido_cred_reset_rx(cred);
151
15
                return (FIDO_ERR_INVALID_CBOR);
152
15
        }
153
31
154
31
        return (FIDO_OK);
155
31
}
156
157
static int
158
fido_dev_make_cred_wait(fido_dev_t *dev, fido_cred_t *cred, const char *pin, int ms)
159
377
{
160
377
        int  r;
161
377
162
377
        if ((r = fido_dev_make_cred_tx(dev, cred, pin)) != FIDO_OK ||
163
377
            (r = fido_dev_make_cred_rx(dev, cred, ms)) != FIDO_OK)
164
377
                return (r);
165
31
166
31
        return (FIDO_OK);
167
31
}
168
169
int
170
fido_dev_make_cred(fido_dev_t *dev, fido_cred_t *cred, const char *pin)
171
481
{
172
481
        if (fido_dev_is_fido2(dev) == false) {
173
104
                if (pin != NULL || cred->rk == FIDO_OPT_TRUE || cred->ext != 0)
174
14
                        return (FIDO_ERR_UNSUPPORTED_OPTION);
175
90
                return (u2f_register(dev, cred, -1));
176
90
        }
177
377
178
377
        return (fido_dev_make_cred_wait(dev, cred, pin, -1));
179
377
}
180
181
static int
182
check_extensions(int authdata_ext, int ext)
183
24
{
184
24
        if (authdata_ext != ext) {
185
2
                fido_log_debug("%s: authdata_ext=0x%x != ext=0x%x", __func__,
186
2
                    authdata_ext, ext);
187
2
                return (-1);
188
2
        }
189
22
190
22
        return (0);
191
22
}
192
193
int
194
fido_check_rp_id(const char *id, const unsigned char *obtained_hash)
195
165
{
196
165
        unsigned char expected_hash[SHA256_DIGEST_LENGTH];
197
165
198
165
        explicit_bzero(expected_hash, sizeof(expected_hash));
199
165
200
165
        if (SHA256((const unsigned char *)id, strlen(id),
201
165
            expected_hash) != expected_hash) {
202
3
                fido_log_debug("%s: sha256", __func__);
203
3
                return (-1);
204
3
        }
205
162
206
162
        return (timingsafe_bcmp(expected_hash, obtained_hash,
207
162
            SHA256_DIGEST_LENGTH));
208
162
}
209
210
static int
211
get_signed_hash_packed(fido_blob_t *dgst, const fido_blob_t *clientdata,
212
    const fido_blob_t *authdata_cbor)
213
10
{
214
10
        cbor_item_t             *item = NULL;
215
10
        unsigned char           *authdata_ptr = NULL;
216
10
        size_t                   authdata_len;
217
10
        struct cbor_load_result  cbor;
218
10
        SHA256_CTX               ctx;
219
10
        int                      ok = -1;
220
10
221
10
        if ((item = cbor_load(authdata_cbor->ptr, authdata_cbor->len,
222
10
            &cbor)) == NULL) {
223
1
                fido_log_debug("%s: cbor_load", __func__);
224
1
                goto fail;
225
1
        }
226
9
227
9
        if (cbor_isa_bytestring(item) == false ||
228
9
            cbor_bytestring_is_definite(item) == false) {
229
0
                fido_log_debug("%s: cbor type", __func__);
230
0
                goto fail;
231
0
        }
232
9
233
9
        authdata_ptr = cbor_bytestring_handle(item);
234
9
        authdata_len = cbor_bytestring_length(item);
235
9
236
9
        if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
237
9
            SHA256_Update(&ctx, authdata_ptr, authdata_len) == 0 ||
238
9
            SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
239
9
            SHA256_Final(dgst->ptr, &ctx) == 0) {
240
5
                fido_log_debug("%s: sha256", __func__);
241
5
                goto fail;
242
5
        }
243
4
244
4
        ok = 0;
245
10
fail:
246
10
        if (item != NULL)
247
10
                cbor_decref(&item);
248
10
249
10
        return (ok);
250
4
}
251
252
static int
253
get_signed_hash_u2f(fido_blob_t *dgst, const unsigned char *rp_id,
254
    size_t rp_id_len, const fido_blob_t *clientdata, const fido_blob_t *id,
255
    const es256_pk_t *pk)
256
12
{
257
12
        const uint8_t           zero = 0;
258
12
        const uint8_t           four = 4; /* uncompressed point */
259
12
        SHA256_CTX              ctx;
260
12
261
12
        if (dgst->len != SHA256_DIGEST_LENGTH || SHA256_Init(&ctx) == 0 ||
262
12
            SHA256_Update(&ctx, &zero, sizeof(zero)) == 0 ||
263
12
            SHA256_Update(&ctx, rp_id, rp_id_len) == 0 ||
264
12
            SHA256_Update(&ctx, clientdata->ptr, clientdata->len) == 0 ||
265
12
            SHA256_Update(&ctx, id->ptr, id->len) == 0 ||
266
12
            SHA256_Update(&ctx, &four, sizeof(four)) == 0 ||
267
12
            SHA256_Update(&ctx, pk->x, sizeof(pk->x)) == 0 ||
268
12
            SHA256_Update(&ctx, pk->y, sizeof(pk->y)) == 0 ||
269
12
            SHA256_Final(dgst->ptr, &ctx) == 0) {
270
9
                fido_log_debug("%s: sha256", __func__);
271
9
                return (-1);
272
9
        }
273
3
274
3
        return (0);
275
3
}
276
277
static int
278
verify_sig(const fido_blob_t *dgst, const fido_blob_t *x5c,
279
    const fido_blob_t *sig)
280
5
{
281
5
        BIO             *rawcert = NULL;
282
5
        X509            *cert = NULL;
283
5
        EVP_PKEY        *pkey = NULL;
284
5
        EC_KEY          *ec;
285
5
        int              ok = -1;
286
5
287
5
        /* openssl needs ints */
288
5
        if (dgst->len > INT_MAX || x5c->len > INT_MAX || sig->len > INT_MAX) {
289
0
                fido_log_debug("%s: dgst->len=%zu, x5c->len=%zu, sig->len=%zu",
290
0
                    __func__, dgst->len, x5c->len, sig->len);
291
0
                return (-1);
292
0
        }
293
5
294
5
        /* fetch key from x509 */
295
5
        if ((rawcert = BIO_new_mem_buf(x5c->ptr, (int)x5c->len)) == NULL ||
296
5
            (cert = d2i_X509_bio(rawcert, NULL)) == NULL ||
297
5
            (pkey = X509_get_pubkey(cert)) == NULL ||
298
5
            (ec = EVP_PKEY_get0_EC_KEY(pkey)) == NULL) {
299
2
                fido_log_debug("%s: x509 key", __func__);
300
2
                goto fail;
301
2
        }
302
3
303
3
        if (ECDSA_verify(0, dgst->ptr, (int)dgst->len, sig->ptr,
304
3
            (int)sig->len, ec) != 1) {
305
2
                fido_log_debug("%s: ECDSA_verify", __func__);
306
2
                goto fail;
307
2
        }
308
1
309
1
        ok = 0;
310
5
fail:
311
5
        if (rawcert != NULL)
312
5
                BIO_free(rawcert);
313
5
        if (cert != NULL)
314
5
                X509_free(cert);
315
5
        if (pkey != NULL)
316
5
                EVP_PKEY_free(pkey);
317
5
318
5
        return (ok);
319
1
}
320
321
int
322
fido_cred_verify(const fido_cred_t *cred)
323
488
{
324
488
        unsigned char   buf[SHA256_DIGEST_LENGTH];
325
488
        fido_blob_t     dgst;
326
488
        int             r;
327
488
328
488
        dgst.ptr = buf;
329
488
        dgst.len = sizeof(buf);
330
488
331
488
        /* do we have everything we need? */
332
488
        if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
333
488
            cred->attstmt.x5c.ptr == NULL || cred->attstmt.sig.ptr == NULL ||
334
488
            cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
335
488
            cred->rp.id == NULL) {
336
458
                fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
337
458
                    "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
338
458
                    (void *)cred->authdata_cbor.ptr,
339
458
                    (void *)cred->attstmt.x5c.ptr,
340
458
                    (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
341
458
                    (void *)cred->attcred.id.ptr, cred->rp.id);
342
458
                r = FIDO_ERR_INVALID_ARGUMENT;
343
458
                goto out;
344
458
        }
345
30
346
30
        if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
347
9
                fido_log_debug("%s: fido_check_rp_id", __func__);
348
9
                r = FIDO_ERR_INVALID_PARAM;
349
9
                goto out;
350
9
        }
351
21
352
21
        if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
353
21
            cred->uv) < 0) {
354
2
                fido_log_debug("%s: fido_check_flags", __func__);
355
2
                r = FIDO_ERR_INVALID_PARAM;
356
2
                goto out;
357
2
        }
358
19
359
19
        if (check_extensions(cred->authdata_ext, cred->ext) < 0) {
360
1
                fido_log_debug("%s: check_extensions", __func__);
361
1
                r = FIDO_ERR_INVALID_PARAM;
362
1
                goto out;
363
1
        }
364
18
365
18
        if (!strcmp(cred->fmt, "packed")) {
366
8
                if (get_signed_hash_packed(&dgst, &cred->cdh,
367
8
                    &cred->authdata_cbor) < 0) {
368
5
                        fido_log_debug("%s: get_signed_hash_packed", __func__);
369
5
                        r = FIDO_ERR_INTERNAL;
370
5
                        goto out;
371
5
                }
372
10
        } else {
373
10
                if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
374
10
                    sizeof(cred->authdata.rp_id_hash), &cred->cdh,
375
10
                    &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
376
8
                        fido_log_debug("%s: get_signed_hash_u2f", __func__);
377
8
                        r = FIDO_ERR_INTERNAL;
378
8
                        goto out;
379
8
                }
380
5
        }
381
5
382
5
        if (verify_sig(&dgst, &cred->attstmt.x5c, &cred->attstmt.sig) < 0) {
383
4
                fido_log_debug("%s: verify_sig", __func__);
384
4
                r = FIDO_ERR_INVALID_SIG;
385
4
                goto out;
386
4
        }
387
1
388
1
        r = FIDO_OK;
389
488
out:
390
488
        explicit_bzero(buf, sizeof(buf));
391
488
392
488
        return (r);
393
1
}
394
395
int
396
fido_cred_verify_self(const fido_cred_t *cred)
397
488
{
398
488
        unsigned char   buf[SHA256_DIGEST_LENGTH];
399
488
        fido_blob_t     dgst;
400
488
        int             ok = -1;
401
488
        int             r;
402
488
403
488
        dgst.ptr = buf;
404
488
        dgst.len = sizeof(buf);
405
488
406
488
        /* do we have everything we need? */
407
488
        if (cred->cdh.ptr == NULL || cred->authdata_cbor.ptr == NULL ||
408
488
            cred->attstmt.x5c.ptr != NULL || cred->attstmt.sig.ptr == NULL ||
409
488
            cred->fmt == NULL || cred->attcred.id.ptr == NULL ||
410
488
            cred->rp.id == NULL) {
411
474
                fido_log_debug("%s: cdh=%p, authdata=%p, x5c=%p, sig=%p, "
412
474
                    "fmt=%p id=%p, rp.id=%s", __func__, (void *)cred->cdh.ptr,
413
474
                    (void *)cred->authdata_cbor.ptr,
414
474
                    (void *)cred->attstmt.x5c.ptr,
415
474
                    (void *)cred->attstmt.sig.ptr, (void *)cred->fmt,
416
474
                    (void *)cred->attcred.id.ptr, cred->rp.id);
417
474
                r = FIDO_ERR_INVALID_ARGUMENT;
418
474
                goto out;
419
474
        }
420
14
421
14
        if (fido_check_rp_id(cred->rp.id, cred->authdata.rp_id_hash) != 0) {
422
9
                fido_log_debug("%s: fido_check_rp_id", __func__);
423
9
                r = FIDO_ERR_INVALID_PARAM;
424
9
                goto out;
425
9
        }
426
5
427
5
        if (fido_check_flags(cred->authdata.flags, FIDO_OPT_TRUE,
428
5
            cred->uv) < 0) {
429
0
                fido_log_debug("%s: fido_check_flags", __func__);
430
0
                r = FIDO_ERR_INVALID_PARAM;
431
0
                goto out;
432
0
        }
433
5
434
5
        if (check_extensions(cred->authdata_ext, cred->ext) < 0) {
435
1
                fido_log_debug("%s: check_extensions", __func__);
436
1
                r = FIDO_ERR_INVALID_PARAM;
437
1
                goto out;
438
1
        }
439
4
440
4
        if (!strcmp(cred->fmt, "packed")) {
441
2
                if (get_signed_hash_packed(&dgst, &cred->cdh,
442
2
                    &cred->authdata_cbor) < 0) {
443
1
                        fido_log_debug("%s: get_signed_hash_packed", __func__);
444
1
                        r = FIDO_ERR_INTERNAL;
445
1
                        goto out;
446
1
                }
447
2
        } else {
448
2
                if (get_signed_hash_u2f(&dgst, cred->authdata.rp_id_hash,
449
2
                    sizeof(cred->authdata.rp_id_hash), &cred->cdh,
450
2
                    &cred->attcred.id, &cred->attcred.pubkey.es256) < 0) {
451
1
                        fido_log_debug("%s: get_signed_hash_u2f", __func__);
452
1
                        r = FIDO_ERR_INTERNAL;
453
1
                        goto out;
454
1
                }
455
2
        }
456
2
457
2
        switch (cred->attcred.type) {
458
2
        case COSE_ES256:
459
2
                ok = fido_verify_sig_es256(&dgst, &cred->attcred.pubkey.es256,
460
2
                    &cred->attstmt.sig);
461
2
                break;
462
2
        case COSE_RS256:
463
0
                ok = fido_verify_sig_rs256(&dgst, &cred->attcred.pubkey.rs256,
464
0
                    &cred->attstmt.sig);
465
0
                break;
466
2
        case COSE_EDDSA:
467
0
                ok = fido_verify_sig_eddsa(&dgst, &cred->attcred.pubkey.eddsa,
468
0
                    &cred->attstmt.sig);
469
0
                break;
470
2
        default:
471
0
                fido_log_debug("%s: unsupported cose_alg %d", __func__,
472
0
                    cred->attcred.type);
473
0
                r = FIDO_ERR_UNSUPPORTED_OPTION;
474
0
                goto out;
475
2
        }
476
2
477
2
        if (ok < 0)
478
2
                r = FIDO_ERR_INVALID_SIG;
479
2
        else
480
2
                r = FIDO_OK;
481
2
482
488
out:
483
488
        explicit_bzero(buf, sizeof(buf));
484
488
485
488
        return (r);
486
2
}
487
488
fido_cred_t *
489
fido_cred_new(void)
490
999
{
491
999
        return (calloc(1, sizeof(fido_cred_t)));
492
999
}
493
494
static void
495
fido_cred_clean_authdata(fido_cred_t *cred)
496
5.20k
{
497
5.20k
        free(cred->authdata_cbor.ptr);
498
5.20k
        free(cred->attcred.id.ptr);
499
5.20k
500
5.20k
        memset(&cred->authdata_ext, 0, sizeof(cred->authdata_ext));
501
5.20k
        memset(&cred->authdata_cbor, 0, sizeof(cred->authdata_cbor));
502
5.20k
        memset(&cred->authdata, 0, sizeof(cred->authdata));
503
5.20k
        memset(&cred->attcred, 0, sizeof(cred->attcred));
504
5.20k
}
505
506
void
507
fido_cred_reset_tx(fido_cred_t *cred)
508
3.25k
{
509
3.25k
        free(cred->cdh.ptr);
510
3.25k
        free(cred->rp.id);
511
3.25k
        free(cred->rp.name);
512
3.25k
        free(cred->user.id.ptr);
513
3.25k
        free(cred->user.icon);
514
3.25k
        free(cred->user.name);
515
3.25k
        free(cred->user.display_name);
516
3.25k
        fido_free_blob_array(&cred->excl);
517
3.25k
518
3.25k
        memset(&cred->cdh, 0, sizeof(cred->cdh));
519
3.25k
        memset(&cred->rp, 0, sizeof(cred->rp));
520
3.25k
        memset(&cred->user, 0, sizeof(cred->user));
521
3.25k
        memset(&cred->excl, 0, sizeof(cred->excl));
522
3.25k
523
3.25k
        cred->type = 0;
524
3.25k
        cred->ext = 0;
525
3.25k
        cred->rk = FIDO_OPT_OMIT;
526
3.25k
        cred->uv = FIDO_OPT_OMIT;
527
3.25k
}
528
529
static void
530
fido_cred_clean_x509(fido_cred_t *cred)
531
3.94k
{
532
3.94k
        free(cred->attstmt.x5c.ptr);
533
3.94k
        cred->attstmt.x5c.ptr = NULL;
534
3.94k
        cred->attstmt.x5c.len = 0;
535
3.94k
}
536
537
static void
538
fido_cred_clean_sig(fido_cred_t *cred)
539
3.94k
{
540
3.94k
        free(cred->attstmt.sig.ptr);
541
3.94k
        cred->attstmt.sig.ptr = NULL;
542
3.94k
        cred->attstmt.sig.len = 0;
543
3.94k
}
544
545
void
546
fido_cred_reset_rx(fido_cred_t *cred)
547
3.44k
{
548
3.44k
        free(cred->fmt);
549
3.44k
        cred->fmt = NULL;
550
3.44k
551
3.44k
        fido_cred_clean_authdata(cred);
552
3.44k
        fido_cred_clean_x509(cred);
553
3.44k
        fido_cred_clean_sig(cred);
554
3.44k
}
555
556
void
557
fido_cred_free(fido_cred_t **cred_p)
558
987
{
559
987
        fido_cred_t *cred;
560
987
561
987
        if (cred_p == NULL || (cred = *cred_p) == NULL)
562
987
                return;
563
987
564
987
        fido_cred_reset_tx(cred);
565
987
        fido_cred_reset_rx(cred);
566
987
567
987
        free(cred);
568
987
569
987
        *cred_p = NULL;
570
987
}
571
572
int
573
fido_cred_set_authdata(fido_cred_t *cred, const unsigned char *ptr, size_t len)
574
506
{
575
506
        cbor_item_t             *item = NULL;
576
506
        struct cbor_load_result  cbor;
577
506
        int                      r;
578
506
579
506
        fido_cred_clean_authdata(cred);
580
506
581
506
        if (ptr == NULL || len == 0) {
582
341
                r = FIDO_ERR_INVALID_ARGUMENT;
583
341
                goto fail;
584
341
        }
585
165
586
165
        if ((item = cbor_load(ptr, len, &cbor)) == NULL) {
587
3
                fido_log_debug("%s: cbor_load", __func__);
588
3
                r = FIDO_ERR_INVALID_ARGUMENT;
589
3
                goto fail;
590
3
        }
591
162
592
162
        if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
593
162
            &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
594
78
                fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
595
78
                r = FIDO_ERR_INVALID_ARGUMENT;
596
78
                goto fail;
597
78
        }
598
84
599
84
        r = FIDO_OK;
600
506
fail:
601
506
        if (item != NULL)
602
506
                cbor_decref(&item);
603
506
604
506
        if (r != FIDO_OK)
605
506
                fido_cred_clean_authdata(cred);
606
506
607
506
        return (r);
608
84
609
84
}
610
611
int
612
fido_cred_set_authdata_raw(fido_cred_t *cred, const unsigned char *ptr,
613
    size_t len)
614
420
{
615
420
        cbor_item_t             *item = NULL;
616
420
        int                      r;
617
420
618
420
        fido_cred_clean_authdata(cred);
619
420
620
420
        if (ptr == NULL || len == 0) {
621
341
                r = FIDO_ERR_INVALID_ARGUMENT;
622
341
                goto fail;
623
341
        }
624
79
625
79
        if ((item = cbor_build_bytestring(ptr, len)) == NULL) {
626
2
                fido_log_debug("%s: cbor_build_bytestring", __func__);
627
2
                r = FIDO_ERR_INTERNAL;
628
2
                goto fail;
629
2
        }
630
77
631
77
        if (cbor_decode_cred_authdata(item, cred->type, &cred->authdata_cbor,
632
77
            &cred->authdata, &cred->attcred, &cred->authdata_ext) < 0) {
633
77
                fido_log_debug("%s: cbor_decode_cred_authdata", __func__);
634
77
                r = FIDO_ERR_INVALID_ARGUMENT;
635
77
                goto fail;
636
77
        }
637
0
638
0
        r = FIDO_OK;
639
420
fail:
640
420
        if (item != NULL)
641
420
                cbor_decref(&item);
642
420
643
420
        if (r != FIDO_OK)
644
420
                fido_cred_clean_authdata(cred);
645
420
646
420
        return (r);
647
0
648
0
}
649
650
int
651
fido_cred_set_x509(fido_cred_t *cred, const unsigned char *ptr, size_t len)
652
504
{
653
504
        unsigned char *x509;
654
504
655
504
        fido_cred_clean_x509(cred);
656
504
657
504
        if (ptr == NULL || len == 0)
658
448
                return (FIDO_ERR_INVALID_ARGUMENT);
659
56
        if ((x509 = malloc(len)) == NULL)
660
56
                return (FIDO_ERR_INTERNAL);
661
53
662
53
        memcpy(x509, ptr, len);
663
53
        cred->attstmt.x5c.ptr = x509;
664
53
        cred->attstmt.x5c.len = len;
665
53
666
53
        return (FIDO_OK);
667
53
}
668
669
int
670
fido_cred_set_sig(fido_cred_t *cred, const unsigned char *ptr, size_t len)
671
503
{
672
503
        unsigned char *sig;
673
503
674
503
        fido_cred_clean_sig(cred);
675
503
676
503
        if (ptr == NULL || len == 0)
677
436
                return (FIDO_ERR_INVALID_ARGUMENT);
678
67
        if ((sig = malloc(len)) == NULL)
679
67
                return (FIDO_ERR_INTERNAL);
680
65
681
65
        memcpy(sig, ptr, len);
682
65
        cred->attstmt.sig.ptr = sig;
683
65
        cred->attstmt.sig.len = len;
684
65
685
65
        return (FIDO_OK);
686
65
}
687
688
int
689
fido_cred_exclude(fido_cred_t *cred, const unsigned char *id_ptr, size_t id_len)
690
13.1k
{
691
13.1k
        fido_blob_t id_blob;
692
13.1k
        fido_blob_t *list_ptr;
693
13.1k
694
13.1k
        memset(&id_blob, 0, sizeof(id_blob));
695
13.1k
696
13.1k
        if (fido_blob_set(&id_blob, id_ptr, id_len) < 0)
697
50
                return (FIDO_ERR_INVALID_ARGUMENT);
698
13.1k
699
13.1k
        if (cred->excl.len == SIZE_MAX) {
700
0
                free(id_blob.ptr);
701
0
                return (FIDO_ERR_INVALID_ARGUMENT);
702
0
        }
703
13.1k
704
13.1k
        if ((list_ptr = recallocarray(cred->excl.ptr, cred->excl.len,
705
13.1k
            cred->excl.len + 1, sizeof(fido_blob_t))) == NULL) {
706
61
                free(id_blob.ptr);
707
61
                return (FIDO_ERR_INTERNAL);
708
61
        }
709
13.0k
710
13.0k
        list_ptr[cred->excl.len++] = id_blob;
711
13.0k
        cred->excl.ptr = list_ptr;
712
13.0k
713
13.0k
        return (FIDO_OK);
714
13.0k
}
715
716
int
717
fido_cred_set_clientdata_hash(fido_cred_t *cred, const unsigned char *hash,
718
    size_t hash_len)
719
969
{
720
969
        if (fido_blob_set(&cred->cdh, hash, hash_len) < 0)
721
24
                return (FIDO_ERR_INVALID_ARGUMENT);
722
945
723
945
        return (FIDO_OK);
724
945
}
725
726
int
727
fido_cred_set_rp(fido_cred_t *cred, const char *id, const char *name)
728
969
{
729
969
        fido_rp_t *rp = &cred->rp;
730
969
731
969
        if (rp->id != NULL) {
732
0
                free(rp->id);
733
0
                rp->id = NULL;
734
0
        }
735
969
        if (rp->name != NULL) {
736
0
                free(rp->name);
737
0
                rp->name = NULL;
738
0
        }
739
969
740
969
        if (id != NULL && (rp->id = strdup(id)) == NULL)
741
969
                goto fail;
742
961
        if (name != NULL && (rp->name = strdup(name)) == NULL)
743
961
                goto fail;
744
955
745
955
        return (FIDO_OK);
746
14
fail:
747
14
        free(rp->id);
748
14
        free(rp->name);
749
14
        rp->id = NULL;
750
14
        rp->name = NULL;
751
14
752
14
        return (FIDO_ERR_INTERNAL);
753
955
}
754
755
int
756
fido_cred_set_user(fido_cred_t *cred, const unsigned char *user_id,
757
    size_t user_id_len, const char *name, const char *display_name,
758
    const char *icon)
759
481
{
760
481
        fido_user_t *up = &cred->user;
761
481
762
481
        if (up->id.ptr != NULL) {
763
0
                free(up->id.ptr);
764
0
                up->id.ptr = NULL;
765
0
                up->id.len = 0;
766
0
        }
767
481
        if (up->name != NULL) {
768
0
                free(up->name);
769
0
                up->name = NULL;
770
0
        }
771
481
        if (up->display_name != NULL) {
772
0
                free(up->display_name);
773
0
                up->display_name = NULL;
774
0
        }
775
481
        if (up->icon != NULL) {
776
0
                free(up->icon);
777
0
                up->icon = NULL;
778
0
        }
779
481
780
481
        if (user_id != NULL) {
781
481
                if ((up->id.ptr = malloc(user_id_len)) == NULL)
782
481
                        goto fail;
783
478
                memcpy(up->id.ptr, user_id, user_id_len);
784
478
                up->id.len = user_id_len;
785
478
        }
786
481
        if (name != NULL && (up->name = strdup(name)) == NULL)
787
478
                goto fail;
788
475
        if (display_name != NULL &&
789
475
            (up->display_name = strdup(display_name)) == NULL)
790
475
                goto fail;
791
471
        if (icon != NULL && (up->icon = strdup(icon)) == NULL)
792
471
                goto fail;
793
470
794
470
        return (FIDO_OK);
795
11
fail:
796
11
        free(up->id.ptr);
797
11
        free(up->name);
798
11
        free(up->display_name);
799
11
        free(up->icon);
800
11
801
11
        up->id.ptr = NULL;
802
11
        up->id.len = 0;
803
11
        up->name = NULL;
804
11
        up->display_name = NULL;
805
11
        up->icon = NULL;
806
11
807
11
        return (FIDO_ERR_INTERNAL);
808
470
}
809
810
int
811
fido_cred_set_extensions(fido_cred_t *cred, int ext)
812
969
{
813
969
        if (ext != 0 && ext != FIDO_EXT_HMAC_SECRET)
814
969
                return (FIDO_ERR_INVALID_ARGUMENT);
815
120
816
120
        cred->ext = ext;
817
120
818
120
        return (FIDO_OK);
819
120
}
820
821
int
822
fido_cred_set_options(fido_cred_t *cred, bool rk, bool uv)
823
0
{
824
0
        cred->rk = rk ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
825
0
        cred->uv = uv ? FIDO_OPT_TRUE : FIDO_OPT_FALSE;
826
0
827
0
        return (FIDO_OK);
828
0
}
829
830
int
831
fido_cred_set_rk(fido_cred_t *cred, fido_opt_t rk)
832
334
{
833
334
        cred->rk = rk;
834
334
835
334
        return (FIDO_OK);
836
334
}
837
838
int
839
fido_cred_set_uv(fido_cred_t *cred, fido_opt_t uv)
840
304
{
841
304
        cred->uv = uv;
842
304
843
304
        return (FIDO_OK);
844
304
}
845
846
int
847
fido_cred_set_fmt(fido_cred_t *cred, const char *fmt)
848
168
{
849
168
        free(cred->fmt);
850
168
        cred->fmt = NULL;
851
168
852
168
        if (fmt == NULL)
853
168
                return (FIDO_ERR_INVALID_ARGUMENT);
854
168
855
168
        if (strcmp(fmt, "packed") && strcmp(fmt, "fido-u2f"))
856
0
                return (FIDO_ERR_INVALID_ARGUMENT);
857
168
858
168
        if ((cred->fmt = strdup(fmt)) == NULL)
859
168
                return (FIDO_ERR_INTERNAL);
860
164
861
164
        return (FIDO_OK);
862
164
}
863
864
int
865
fido_cred_set_type(fido_cred_t *cred, int cose_alg)
866
969
{
867
969
        if ((cose_alg != COSE_ES256 && cose_alg != COSE_RS256 &&
868
969
            cose_alg != COSE_EDDSA) || cred->type != 0)
869
0
                return (FIDO_ERR_INVALID_ARGUMENT);
870
969
871
969
        cred->type = cose_alg;
872
969
873
969
        return (FIDO_OK);
874
969
}
875
876
int
877
fido_cred_type(const fido_cred_t *cred)
878
1.14k
{
879
1.14k
        return (cred->type);
880
1.14k
}
881
882
uint8_t
883
fido_cred_flags(const fido_cred_t *cred)
884
488
{
885
488
        return (cred->authdata.flags);
886
488
}
887
888
const unsigned char *
889
fido_cred_clientdata_hash_ptr(const fido_cred_t *cred)
890
499
{
891
499
        return (cred->cdh.ptr);
892
499
}
893
894
size_t
895
fido_cred_clientdata_hash_len(const fido_cred_t *cred)
896
499
{
897
499
        return (cred->cdh.len);
898
499
}
899
900
const unsigned char *
901
fido_cred_x5c_ptr(const fido_cred_t *cred)
902
499
{
903
499
        return (cred->attstmt.x5c.ptr);
904
499
}
905
906
size_t
907
fido_cred_x5c_len(const fido_cred_t *cred)
908
499
{
909
499
        return (cred->attstmt.x5c.len);
910
499
}
911
912
const unsigned char *
913
fido_cred_sig_ptr(const fido_cred_t *cred)
914
499
{
915
499
        return (cred->attstmt.sig.ptr);
916
499
}
917
918
size_t
919
fido_cred_sig_len(const fido_cred_t *cred)
920
499
{
921
499
        return (cred->attstmt.sig.len);
922
499
}
923
924
const unsigned char *
925
fido_cred_authdata_ptr(const fido_cred_t *cred)
926
499
{
927
499
        return (cred->authdata_cbor.ptr);
928
499
}
929
930
size_t
931
fido_cred_authdata_len(const fido_cred_t *cred)
932
499
{
933
499
        return (cred->authdata_cbor.len);
934
499
}
935
936
const unsigned char *
937
fido_cred_pubkey_ptr(const fido_cred_t *cred)
938
1.14k
{
939
1.14k
        const void *ptr;
940
1.14k
941
1.14k
        switch (cred->attcred.type) {
942
1.14k
        case COSE_ES256:
943
280
                ptr = &cred->attcred.pubkey.es256;
944
280
                break;
945
1.14k
        case COSE_RS256:
946
24
                ptr = &cred->attcred.pubkey.rs256;
947
24
                break;
948
1.14k
        case COSE_EDDSA:
949
213
                ptr = &cred->attcred.pubkey.eddsa;
950
213
                break;
951
1.14k
        default:
952
623
                ptr = NULL;
953
623
                break;
954
1.14k
        }
955
1.14k
956
1.14k
        return (ptr);
957
1.14k
}
958
959
size_t
960
fido_cred_pubkey_len(const fido_cred_t *cred)
961
1.14k
{
962
1.14k
        size_t len;
963
1.14k
964
1.14k
        switch (cred->attcred.type) {
965
1.14k
        case COSE_ES256:
966
280
                len = sizeof(cred->attcred.pubkey.es256);
967
280
                break;
968
1.14k
        case COSE_RS256:
969
24
                len = sizeof(cred->attcred.pubkey.rs256);
970
24
                break;
971
1.14k
        case COSE_EDDSA:
972
213
                len = sizeof(cred->attcred.pubkey.eddsa);
973
213
                break;
974
1.14k
        default:
975
623
                len = 0;
976
623
                break;
977
1.14k
        }
978
1.14k
979
1.14k
        return (len);
980
1.14k
}
981
982
const unsigned char *
983
fido_cred_id_ptr(const fido_cred_t *cred)
984
1.14k
{
985
1.14k
        return (cred->attcred.id.ptr);
986
1.14k
}
987
988
size_t
989
fido_cred_id_len(const fido_cred_t *cred)
990
1.14k
{
991
1.14k
        return (cred->attcred.id.len);
992
1.14k
}
993
994
const char *
995
fido_cred_fmt(const fido_cred_t *cred)
996
499
{
997
499
        return (cred->fmt);
998
499
}
999
1000
const char *
1001
fido_cred_rp_id(const fido_cred_t *cred)
1002
499
{
1003
499
        return (cred->rp.id);
1004
499
}
1005
1006
const char *
1007
fido_cred_rp_name(const fido_cred_t *cred)
1008
499
{
1009
499
        return (cred->rp.name);
1010
499
}
1011
1012
const char *
1013
fido_cred_user_name(const fido_cred_t *cred)
1014
2.28k
{
1015
2.28k
        return (cred->user.name);
1016
2.28k
}
1017
1018
const char *
1019
fido_cred_display_name(const fido_cred_t *cred)
1020
2.28k
{
1021
2.28k
        return (cred->user.display_name);
1022
2.28k
}
1023
1024
const unsigned char *
1025
fido_cred_user_id_ptr(const fido_cred_t *cred)
1026
1.14k
{
1027
1.14k
        return (cred->user.id.ptr);
1028
1.14k
}
1029
1030
size_t
1031
fido_cred_user_id_len(const fido_cred_t *cred)
1032
1.14k
{
1033
1.14k
        return (cred->user.id.len);
1034
1.14k
}
/home/pedro/projects/libfido2/src/credman.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2019 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/sha.h>
8
9
#include <string.h>
10
11
#include "fido.h"
12
#include "fido/credman.h"
13
#include "fido/es256.h"
14
15
284
#define CMD_CRED_METADATA       0x01
16
396
#define CMD_RP_BEGIN            0x02
17
286
#define CMD_RP_NEXT             0x03
18
1.02k
#define CMD_RK_BEGIN            0x04
19
482
#define CMD_RK_NEXT             0x05
20
626
#define CMD_DELETE_CRED         0x06
21
22
static int
23
credman_grow_array(void **ptr, size_t *n_alloc, size_t *n_rx, size_t n,
24
    size_t size)
25
253
{
26
253
        void *new_ptr;
27
253
28
253
#ifdef FIDO_FUZZ
29
253
        if (n > UINT8_MAX) {
30
5
                fido_log_debug("%s: n > UINT8_MAX", __func__);
31
5
                return (-1);
32
5
        }
33
248
#endif
34
248
35
248
        if (n < *n_alloc)
36
0
                return (0);
37
248
38
248
        /* sanity check */
39
248
        if (*n_rx > 0 || *n_rx > *n_alloc || n < *n_alloc) {
40
0
                fido_log_debug("%s: n=%zu, n_rx=%zu, n_alloc=%zu", __func__, n,
41
0
                    *n_rx, *n_alloc);
42
0
                return (-1);
43
0
        }
44
248
45
248
        if ((new_ptr = recallocarray(*ptr, *n_alloc, n, size)) == NULL)
46
248
                return (-1);
47
244
48
244
        *ptr = new_ptr;
49
244
        *n_alloc = n;
50
244
51
244
        return (0);
52
244
}
53
54
static int
55
credman_prepare_hmac(uint8_t cmd, const fido_blob_t *body, cbor_item_t **param,
56
    fido_blob_t *hmac_data)
57
1.50k
{
58
1.50k
        cbor_item_t *param_cbor[2];
59
1.50k
        size_t n;
60
1.50k
        int ok = -1;
61
1.50k
62
1.50k
        memset(&param_cbor, 0, sizeof(param_cbor));
63
1.50k
64
1.50k
        if (body == NULL)
65
1.50k
                return (fido_blob_set(hmac_data, &cmd, sizeof(cmd)));
66
825
67
825
        switch (cmd) {
68
825
        case CMD_RK_BEGIN:
69
513
                n = 1;
70
513
                param_cbor[n - 1] = fido_blob_encode(body);
71
513
                break;
72
825
        case CMD_DELETE_CRED:
73
312
                n = 2;
74
312
                param_cbor[n - 1] = cbor_encode_pubkey(body);
75
312
                break;
76
825
        default:
77
0
                fido_log_debug("%s: unknown cmd=0x%02x", __func__, cmd);
78
0
                return (-1);
79
825
        }
80
825
81
825
        if (param_cbor[n - 1] == NULL) {
82
12
                fido_log_debug("%s: cbor encode", __func__);
83
12
                return (-1);
84
12
        }
85
813
        if ((*param = cbor_flatten_vector(param_cbor, n)) == NULL) {
86
10
                fido_log_debug("%s: cbor_flatten_vector", __func__);
87
10
                goto fail;
88
10
        }
89
803
        if (cbor_build_frame(cmd, param_cbor, n, hmac_data) < 0) {
90
14
                fido_log_debug("%s: cbor_build_frame", __func__);
91
14
                goto fail;
92
14
        }
93
789
94
789
        ok = 0;
95
813
fail:
96
813
        cbor_vector_free(param_cbor, nitems(param_cbor));
97
813
98
813
        return (ok);
99
789
}
100
101
static int
102
credman_tx(fido_dev_t *dev, uint8_t cmd, const fido_blob_t *param,
103
    const char *pin)
104
2.27k
{
105
2.27k
        fido_blob_t      f;
106
2.27k
        fido_blob_t     *ecdh = NULL;
107
2.27k
        fido_blob_t      hmac;
108
2.27k
        es256_pk_t      *pk = NULL;
109
2.27k
        cbor_item_t     *argv[4];
110
2.27k
        int              r = FIDO_ERR_INTERNAL;
111
2.27k
112
2.27k
        memset(&f, 0, sizeof(f));
113
2.27k
        memset(&hmac, 0, sizeof(hmac));
114
2.27k
        memset(&argv, 0, sizeof(argv));
115
2.27k
116
2.27k
        /* subCommand */
117
2.27k
        if ((argv[0] = cbor_build_uint8(cmd)) == NULL) {
118
6
                fido_log_debug("%s: cbor encode", __func__);
119
6
                goto fail;
120
6
        }
121
2.26k
122
2.26k
        /* pinProtocol, pinAuth */
123
2.26k
        if (pin != NULL) {
124
1.50k
                if (credman_prepare_hmac(cmd, param, &argv[1], &hmac) < 0) {
125
43
                        fido_log_debug("%s: credman_prepare_hmac", __func__);
126
43
                        goto fail;
127
43
                }
128
1.45k
                if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
129
772
                        fido_log_debug("%s: fido_do_ecdh", __func__);
130
772
                        goto fail;
131
772
                }
132
686
                if ((r = cbor_add_pin_params(dev, &hmac, pk, ecdh, pin,
133
686
                    &argv[3], &argv[2])) != FIDO_OK) {
134
295
                        fido_log_debug("%s: cbor_add_pin_params", __func__);
135
295
                        goto fail;
136
295
                }
137
1.15k
        }
138
1.15k
139
1.15k
        /* framing and transmission */
140
1.15k
        if (cbor_build_frame(CTAP_CBOR_CRED_MGMT_PRE, argv, 4, &f) < 0 ||
141
1.15k
            fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
142
25
                fido_log_debug("%s: fido_tx", __func__);
143
25
                r = FIDO_ERR_TX;
144
25
                goto fail;
145
25
        }
146
1.13k
147
1.13k
        r = FIDO_OK;
148
2.27k
fail:
149
2.27k
        es256_pk_free(&pk);
150
2.27k
        fido_blob_free(&ecdh);
151
2.27k
        cbor_vector_free(argv, nitems(argv));
152
2.27k
        free(f.ptr);
153
2.27k
        free(hmac.ptr);
154
2.27k
155
2.27k
        return (r);
156
1.13k
}
157
158
static int
159
credman_parse_metadata(const cbor_item_t *key, const cbor_item_t *val,
160
    void *arg)
161
46
{
162
46
        fido_credman_metadata_t *metadata = arg;
163
46
164
46
        if (cbor_isa_uint(key) == false ||
165
46
            cbor_int_get_width(key) != CBOR_INT_8) {
166
20
                fido_log_debug("%s: cbor type", __func__);
167
20
                return (0); /* ignore */
168
20
        }
169
26
170
26
        switch (cbor_get_uint8(key)) {
171
26
        case 1:
172
3
                return (cbor_decode_uint64(val, &metadata->rk_existing));
173
26
        case 2:
174
4
                return (cbor_decode_uint64(val, &metadata->rk_remaining));
175
26
        default:
176
19
                fido_log_debug("%s: cbor type", __func__);
177
19
                return (0); /* ignore */
178
26
        }
179
26
}
180
181
static int
182
credman_rx_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata, int ms)
183
37
{
184
37
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
185
37
        unsigned char   reply[512];
186
37
        int             reply_len;
187
37
        int             r;
188
37
189
37
        memset(metadata, 0, sizeof(*metadata));
190
37
191
37
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
192
19
                fido_log_debug("%s: fido_rx", __func__);
193
19
                return (FIDO_ERR_RX);
194
19
        }
195
18
196
18
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, metadata,
197
18
            credman_parse_metadata)) != FIDO_OK) {
198
12
                fido_log_debug("%s: credman_parse_metadata", __func__);
199
12
                return (r);
200
12
        }
201
6
202
6
        return (FIDO_OK);
203
6
}
204
205
static int
206
credman_get_metadata_wait(fido_dev_t *dev, fido_credman_metadata_t *metadata,
207
    const char *pin, int ms)
208
284
{
209
284
        int r;
210
284
211
284
        if ((r = credman_tx(dev, CMD_CRED_METADATA, NULL, pin)) != FIDO_OK ||
212
284
            (r = credman_rx_metadata(dev, metadata, ms)) != FIDO_OK)
213
284
                return (r);
214
6
215
6
        return (FIDO_OK);
216
6
}
217
218
int
219
fido_credman_get_dev_metadata(fido_dev_t *dev, fido_credman_metadata_t *metadata,
220
    const char *pin)
221
291
{
222
291
        if (fido_dev_is_fido2(dev) == false)
223
291
                return (FIDO_ERR_INVALID_COMMAND);
224
284
        if (pin == NULL)
225
284
                return (FIDO_ERR_INVALID_ARGUMENT);
226
284
227
284
        return (credman_get_metadata_wait(dev, metadata, pin, -1));
228
284
}
229
230
static int
231
credman_parse_rk(const cbor_item_t *key, const cbor_item_t *val, void *arg)
232
2.23k
{
233
2.23k
        fido_cred_t *cred = arg;
234
2.23k
235
2.23k
        if (cbor_isa_uint(key) == false ||
236
2.23k
            cbor_int_get_width(key) != CBOR_INT_8) {
237
150
                fido_log_debug("%s: cbor type", __func__);
238
150
                return (0); /* ignore */
239
150
        }
240
2.08k
241
2.08k
        switch (cbor_get_uint8(key)) {
242
2.08k
        case 6: /* user entity */
243
538
                return (cbor_decode_user(val, &cred->user));
244
2.08k
        case 7:
245
510
                return (cbor_decode_cred_id(val, &cred->attcred.id));
246
2.08k
        case 8:
247
499
                if (cbor_decode_pubkey(val, &cred->attcred.type,
248
499
                    &cred->attcred.pubkey) < 0)
249
57
                        return (-1);
250
442
                cred->type = cred->attcred.type; /* XXX */
251
442
                return (0);
252
537
        default:
253
537
                fido_log_debug("%s: cbor type", __func__);
254
537
                return (0); /* ignore */
255
2.08k
        }
256
2.08k
}
257
258
static void
259
credman_reset_rk(fido_credman_rk_t *rk)
260
719
{
261
2.98k
        for (size_t i = 0; i < rk->n_alloc; i++) {
262
2.27k
                fido_cred_reset_tx(&rk->ptr[i]);
263
2.27k
                fido_cred_reset_rx(&rk->ptr[i]);
264
2.27k
        }
265
719
266
719
        free(rk->ptr);
267
719
        rk->ptr = NULL;
268
719
        memset(rk, 0, sizeof(*rk));
269
719
}
270
271
static int
272
credman_parse_rk_count(const cbor_item_t *key, const cbor_item_t *val,
273
    void *arg)
274
872
{
275
872
        fido_credman_rk_t *rk = arg;
276
872
        uint64_t n;
277
872
278
872
        /* totalCredentials */
279
872
        if (cbor_isa_uint(key) == false ||
280
872
            cbor_int_get_width(key) != CBOR_INT_8 ||
281
872
            cbor_get_uint8(key) != 9) {
282
697
                fido_log_debug("%s: cbor_type", __func__);
283
697
                return (0); /* ignore */
284
697
        }
285
175
286
175
        if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
287
1
                fido_log_debug("%s: cbor_decode_uint64", __func__);
288
1
                return (-1);
289
1
        }
290
174
291
174
        if (credman_grow_array((void **)&rk->ptr, &rk->n_alloc, &rk->n_rx,
292
174
            (size_t)n, sizeof(*rk->ptr)) < 0) {
293
4
                fido_log_debug("%s: credman_grow_array", __func__);
294
4
                return (-1);
295
4
        }
296
170
297
170
        return (0);
298
170
}
299
300
static int
301
credman_rx_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms)
302
202
{
303
202
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
304
202
        unsigned char   reply[2048];
305
202
        int             reply_len;
306
202
        int             r;
307
202
308
202
        credman_reset_rk(rk);
309
202
310
202
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
311
15
                fido_log_debug("%s: fido_rx", __func__);
312
15
                return (FIDO_ERR_RX);
313
15
        }
314
187
315
187
        /* adjust as needed */
316
187
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, rk,
317
187
            credman_parse_rk_count)) != FIDO_OK) {
318
13
                fido_log_debug("%s: credman_parse_rk_count", __func__);
319
13
                return (r);
320
13
        }
321
174
322
174
        if (rk->n_alloc == 0) {
323
5
                fido_log_debug("%s: n_alloc=0", __func__);
324
5
                return (FIDO_OK);
325
5
        }
326
169
327
169
        /* parse the first rk */
328
169
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[0],
329
169
            credman_parse_rk)) != FIDO_OK) {
330
31
                fido_log_debug("%s: credman_parse_rk", __func__);
331
31
                return (r);
332
31
        }
333
138
334
138
        rk->n_rx++;
335
138
336
138
        return (FIDO_OK);
337
138
}
338
339
static int
340
credman_rx_next_rk(fido_dev_t *dev, fido_credman_rk_t *rk, int ms)
341
479
{
342
479
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
343
479
        unsigned char   reply[2048];
344
479
        int             reply_len;
345
479
        int             r;
346
479
347
479
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
348
53
                fido_log_debug("%s: fido_rx", __func__);
349
53
                return (FIDO_ERR_RX);
350
53
        }
351
426
352
426
        /* sanity check */
353
426
        if (rk->n_rx >= rk->n_alloc) {
354
0
                fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rk->n_rx,
355
0
                    rk->n_alloc);
356
0
                return (FIDO_ERR_INTERNAL);
357
0
        }
358
426
359
426
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rk->ptr[rk->n_rx],
360
426
            credman_parse_rk)) != FIDO_OK) {
361
75
                fido_log_debug("%s: credman_parse_rk", __func__);
362
75
                return (r);
363
75
        }
364
351
365
351
        return (FIDO_OK);
366
351
}
367
368
static int
369
credman_get_rk_wait(fido_dev_t *dev, const char *rp_id, fido_credman_rk_t *rk,
370
    const char *pin, int ms)
371
514
{
372
514
        fido_blob_t     rp_dgst;
373
514
        uint8_t         dgst[SHA256_DIGEST_LENGTH];
374
514
        int             r;
375
514
376
514
        if (SHA256((const unsigned char *)rp_id, strlen(rp_id), dgst) != dgst) {
377
1
                fido_log_debug("%s: sha256", __func__);
378
1
                return (FIDO_ERR_INTERNAL);
379
1
        }
380
513
381
513
        rp_dgst.ptr = dgst;
382
513
        rp_dgst.len = sizeof(dgst);
383
513
384
513
        if ((r = credman_tx(dev, CMD_RK_BEGIN, &rp_dgst, pin)) != FIDO_OK ||
385
513
            (r = credman_rx_rk(dev, rk, ms)) != FIDO_OK)
386
513
                return (r);
387
143
388
494
        while (rk->n_rx < rk->n_alloc) {
389
482
                if ((r = credman_tx(dev, CMD_RK_NEXT, NULL, NULL)) != FIDO_OK ||
390
482
                    (r = credman_rx_next_rk(dev, rk, ms)) != FIDO_OK)
391
482
                        return (r);
392
351
                rk->n_rx++;
393
351
        }
394
143
395
143
        return (FIDO_OK);
396
143
}
397
398
int
399
fido_credman_get_dev_rk(fido_dev_t *dev, const char *rp_id,
400
    fido_credman_rk_t *rk, const char *pin)
401
517
{
402
517
        if (fido_dev_is_fido2(dev) == false)
403
517
                return (FIDO_ERR_INVALID_COMMAND);
404
514
        if (pin == NULL)
405
514
                return (FIDO_ERR_INVALID_ARGUMENT);
406
514
407
514
        return (credman_get_rk_wait(dev, rp_id, rk, pin, -1));
408
514
}
409
410
static int
411
credman_del_rk_wait(fido_dev_t *dev, const unsigned char *cred_id,
412
    size_t cred_id_len, const char *pin, int ms)
413
315
{
414
315
        fido_blob_t cred;
415
315
        int r;
416
315
417
315
        memset(&cred, 0, sizeof(cred));
418
315
419
315
        if (fido_blob_set(&cred, cred_id, cred_id_len) < 0)
420
1
                return (FIDO_ERR_INVALID_ARGUMENT);
421
314
422
314
        if ((r = credman_tx(dev, CMD_DELETE_CRED, &cred, pin)) != FIDO_OK ||
423
314
            (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
424
314
                goto fail;
425
3
426
3
        r = FIDO_OK;
427
314
fail:
428
314
        free(cred.ptr);
429
314
430
314
        return (r);
431
3
}
432
433
int
434
fido_credman_del_dev_rk(fido_dev_t *dev, const unsigned char *cred_id,
435
    size_t cred_id_len, const char *pin)
436
323
{
437
323
        if (fido_dev_is_fido2(dev) == false)
438
323
                return (FIDO_ERR_INVALID_COMMAND);
439
315
        if (pin == NULL)
440
315
                return (FIDO_ERR_INVALID_ARGUMENT);
441
315
442
315
        return (credman_del_rk_wait(dev, cred_id, cred_id_len, pin, -1));
443
315
}
444
445
static int
446
credman_parse_rp(const cbor_item_t *key, const cbor_item_t *val, void *arg)
447
657
{
448
657
        struct fido_credman_single_rp *rp = arg;
449
657
450
657
        if (cbor_isa_uint(key) == false ||
451
657
            cbor_int_get_width(key) != CBOR_INT_8) {
452
83
                fido_log_debug("%s: cbor type", __func__);
453
83
                return (0); /* ignore */
454
83
        }
455
574
456
574
        switch (cbor_get_uint8(key)) {
457
574
        case 3:
458
197
                return (cbor_decode_rp_entity(val, &rp->rp_entity));
459
574
        case 4:
460
123
                return (fido_blob_decode(val, &rp->rp_id_hash));
461
574
        default:
462
254
                fido_log_debug("%s: cbor type", __func__);
463
254
                return (0); /* ignore */
464
574
        }
465
574
}
466
467
static void
468
credman_reset_rp(fido_credman_rp_t *rp)
469
505
{
470
2.55k
        for (size_t i = 0; i < rp->n_alloc; i++) {
471
2.05k
                free(rp->ptr[i].rp_entity.id);
472
2.05k
                free(rp->ptr[i].rp_entity.name);
473
2.05k
                rp->ptr[i].rp_entity.id = NULL;
474
2.05k
                rp->ptr[i].rp_entity.name = NULL;
475
2.05k
                free(rp->ptr[i].rp_id_hash.ptr);
476
2.05k
                memset(&rp->ptr[i].rp_id_hash, 0,
477
2.05k
                    sizeof(rp->ptr[i].rp_id_hash));
478
2.05k
        }
479
505
480
505
        free(rp->ptr);
481
505
        rp->ptr = NULL;
482
505
        memset(rp, 0, sizeof(*rp));
483
505
}
484
485
static int
486
credman_parse_rp_count(const cbor_item_t *key, const cbor_item_t *val,
487
    void *arg)
488
272
{
489
272
        fido_credman_rp_t *rp = arg;
490
272
        uint64_t n;
491
272
492
272
        /* totalRPs */
493
272
        if (cbor_isa_uint(key) == false ||
494
272
            cbor_int_get_width(key) != CBOR_INT_8 ||
495
272
            cbor_get_uint8(key) != 5) {
496
191
                fido_log_debug("%s: cbor_type", __func__);
497
191
                return (0); /* ignore */
498
191
        }
499
81
500
81
        if (cbor_decode_uint64(val, &n) < 0 || n > SIZE_MAX) {
501
2
                fido_log_debug("%s: cbor_decode_uint64", __func__);
502
2
                return (-1);
503
2
        }
504
79
505
79
        if (credman_grow_array((void **)&rp->ptr, &rp->n_alloc, &rp->n_rx,
506
79
            (size_t)n, sizeof(*rp->ptr)) < 0) {
507
5
                fido_log_debug("%s: credman_grow_array", __func__);
508
5
                return (-1);
509
5
        }
510
74
511
74
        return (0);
512
74
}
513
514
static int
515
credman_rx_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms)
516
103
{
517
103
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
518
103
        unsigned char   reply[2048];
519
103
        int             reply_len;
520
103
        int             r;
521
103
522
103
        credman_reset_rp(rp);
523
103
524
103
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
525
12
                fido_log_debug("%s: fido_rx", __func__);
526
12
                return (FIDO_ERR_RX);
527
12
        }
528
91
529
91
        /* adjust as needed */
530
91
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, rp,
531
91
            credman_parse_rp_count)) != FIDO_OK) {
532
11
                fido_log_debug("%s: credman_parse_rp_count", __func__);
533
11
                return (r);
534
11
        }
535
80
536
80
        if (rp->n_alloc == 0) {
537
7
                fido_log_debug("%s: n_alloc=0", __func__);
538
7
                return (FIDO_OK);
539
7
        }
540
73
541
73
        /* parse the first rp */
542
73
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[0],
543
73
            credman_parse_rp)) != FIDO_OK) {
544
3
                fido_log_debug("%s: credman_parse_rp", __func__);
545
3
                return (r);
546
3
        }
547
70
548
70
        rp->n_rx++;
549
70
550
70
        return (FIDO_OK);
551
70
}
552
553
static int
554
credman_rx_next_rp(fido_dev_t *dev, fido_credman_rp_t *rp, int ms)
555
282
{
556
282
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
557
282
        unsigned char   reply[2048];
558
282
        int             reply_len;
559
282
        int             r;
560
282
561
282
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
562
42
                fido_log_debug("%s: fido_rx", __func__);
563
42
                return (FIDO_ERR_RX);
564
42
        }
565
240
566
240
        /* sanity check */
567
240
        if (rp->n_rx >= rp->n_alloc) {
568
0
                fido_log_debug("%s: n_rx=%zu, n_alloc=%zu", __func__, rp->n_rx,
569
0
                    rp->n_alloc);
570
0
                return (FIDO_ERR_INTERNAL);
571
0
        }
572
240
573
240
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, &rp->ptr[rp->n_rx],
574
240
            credman_parse_rp)) != FIDO_OK) {
575
14
                fido_log_debug("%s: credman_parse_rp", __func__);
576
14
                return (r);
577
14
        }
578
226
579
226
        return (FIDO_OK);
580
226
}
581
582
static int
583
credman_get_rp_wait(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin,
584
    int ms)
585
396
{
586
396
        int r;
587
396
588
396
        if ((r = credman_tx(dev, CMD_RP_BEGIN, NULL, pin)) != FIDO_OK ||
589
396
            (r = credman_rx_rp(dev, rp, ms)) != FIDO_OK)
590
396
                return (r);
591
77
592
303
        while (rp->n_rx < rp->n_alloc) {
593
286
                if ((r = credman_tx(dev, CMD_RP_NEXT, NULL, NULL)) != FIDO_OK ||
594
286
                    (r = credman_rx_next_rp(dev, rp, ms)) != FIDO_OK)
595
286
                        return (r);
596
226
                rp->n_rx++;
597
226
        }
598
77
599
77
        return (FIDO_OK);
600
77
}
601
602
int
603
fido_credman_get_dev_rp(fido_dev_t *dev, fido_credman_rp_t *rp, const char *pin)
604
402
{
605
402
        if (fido_dev_is_fido2(dev) == false)
606
402
                return (FIDO_ERR_INVALID_COMMAND);
607
396
        if (pin == NULL)
608
396
                return (FIDO_ERR_INVALID_ARGUMENT);
609
396
610
396
        return (credman_get_rp_wait(dev, rp, pin, -1));
611
396
}
612
613
fido_credman_rk_t *
614
fido_credman_rk_new(void)
615
518
{
616
518
        return (calloc(1, sizeof(fido_credman_rk_t)));
617
518
}
618
619
void
620
fido_credman_rk_free(fido_credman_rk_t **rk_p)
621
517
{
622
517
        fido_credman_rk_t *rk;
623
517
624
517
        if (rk_p == NULL || (rk = *rk_p) == NULL)
625
517
                return;
626
517
627
517
        credman_reset_rk(rk);
628
517
        free(rk);
629
517
        *rk_p = NULL;
630
517
}
631
632
size_t
633
fido_credman_rk_count(const fido_credman_rk_t *rk)
634
1.87k
{
635
1.87k
        return (rk->n_rx);
636
1.87k
}
637
638
const fido_cred_t *
639
fido_credman_rk(const fido_credman_rk_t *rk, size_t idx)
640
1.00k
{
641
1.00k
        if (idx >= rk->n_alloc)
642
354
                return (NULL);
643
652
644
652
        return (&rk->ptr[idx]);
645
652
}
646
647
fido_credman_metadata_t *
648
fido_credman_metadata_new(void)
649
292
{
650
292
        return (calloc(1, sizeof(fido_credman_metadata_t)));
651
292
}
652
653
void
654
fido_credman_metadata_free(fido_credman_metadata_t **metadata_p)
655
291
{
656
291
        fido_credman_metadata_t *metadata;
657
291
658
291
        if (metadata_p == NULL || (metadata = *metadata_p) == NULL)
659
291
                return;
660
291
661
291
        free(metadata);
662
291
        *metadata_p = NULL;
663
291
}
664
665
uint64_t
666
fido_credman_rk_existing(const fido_credman_metadata_t *metadata)
667
291
{
668
291
        return (metadata->rk_existing);
669
291
}
670
671
uint64_t
672
fido_credman_rk_remaining(const fido_credman_metadata_t *metadata)
673
291
{
674
291
        return (metadata->rk_remaining);
675
291
}
676
677
fido_credman_rp_t *
678
fido_credman_rp_new(void)
679
403
{
680
403
        return (calloc(1, sizeof(fido_credman_rp_t)));
681
403
}
682
683
void
684
fido_credman_rp_free(fido_credman_rp_t **rp_p)
685
402
{
686
402
        fido_credman_rp_t *rp;
687
402
688
402
        if (rp_p == NULL || (rp = *rp_p) == NULL)
689
402
                return;
690
402
691
402
        credman_reset_rp(rp);
692
402
        free(rp);
693
402
        *rp_p = NULL;
694
402
}
695
696
size_t
697
fido_credman_rp_count(const fido_credman_rp_t *rp)
698
1.10k
{
699
1.10k
        return (rp->n_rx);
700
1.10k
}
701
702
const char *
703
fido_credman_rp_id(const fido_credman_rp_t *rp, size_t idx)
704
1.39k
{
705
1.39k
        if (idx >= rp->n_alloc)
706
676
                return (NULL);
707
720
708
720
        return (rp->ptr[idx].rp_entity.id);
709
720
}
710
711
const char *
712
fido_credman_rp_name(const fido_credman_rp_t *rp, size_t idx)
713
1.39k
{
714
1.39k
        if (idx >= rp->n_alloc)
715
676
                return (NULL);
716
720
717
720
        return (rp->ptr[idx].rp_entity.name);
718
720
}
719
720
size_t
721
fido_credman_rp_id_hash_len(const fido_credman_rp_t *rp, size_t idx)
722
698
{
723
698
        if (idx >= rp->n_alloc)
724
338
                return (0);
725
360
726
360
        return (rp->ptr[idx].rp_id_hash.len);
727
360
}
728
729
const unsigned char *
730
fido_credman_rp_id_hash_ptr(const fido_credman_rp_t *rp, size_t idx)
731
698
{
732
698
        if (idx >= rp->n_alloc)
733
338
                return (NULL);
734
360
735
360
        return (rp->ptr[idx].rp_id_hash.ptr);
736
360
}
/home/pedro/projects/libfido2/src/dev.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 <sys/types.h>
8
#include <sys/stat.h>
9
10
#include <fcntl.h>
11
#include <stdint.h>
12
#include <stdlib.h>
13
#include <string.h>
14
#ifdef HAVE_UNISTD_H
15
#include <unistd.h>
16
#endif
17
18
#include "fido.h"
19
20
#if defined(_WIN32)
21
#include <windows.h>
22
23
#include <winternl.h>
24
#include <winerror.h>
25
#include <stdio.h>
26
#include <bcrypt.h>
27
#include <sal.h>
28
29
static int
30
obtain_nonce(uint64_t *nonce)
31
{
32
        NTSTATUS status;
33
34
        status = BCryptGenRandom(NULL, (unsigned char *)nonce, sizeof(*nonce),
35
            BCRYPT_USE_SYSTEM_PREFERRED_RNG);
36
37
        if (!NT_SUCCESS(status))
38
                return (-1);
39
40
        return (0);
41
}
42
#elif defined(HAS_DEV_URANDOM)
43
static int
44
obtain_nonce(uint64_t *nonce)
45
9.99k
{
46
9.99k
        int     fd = -1;
47
9.99k
        int     ok = -1;
48
9.99k
        ssize_t r;
49
9.99k
50
9.99k
        if ((fd = open(FIDO_RANDOM_DEV, O_RDONLY)) < 0)
51
0
                goto fail;
52
9.99k
        if ((r = read(fd, nonce, sizeof(*nonce))) < 0 ||
53
9.99k
            (size_t)r != sizeof(*nonce))
54
0
                goto fail;
55
9.99k
56
9.99k
        ok = 0;
57
9.99k
fail:
58
9.99k
        if (fd != -1)
59
9.99k
                close(fd);
60
9.99k
61
9.99k
        return (ok);
62
9.99k
}
63
#else
64
#error "please provide an implementation of obtain_nonce() for your platform"
65
#endif /* _WIN32 */
66
67
static int
68
fido_dev_open_tx(fido_dev_t *dev, const char *path)
69
9.99k
{
70
9.99k
        const uint8_t cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT;
71
9.99k
72
9.99k
        if (dev->io_handle != NULL) {
73
0
                fido_log_debug("%s: handle=%p", __func__, dev->io_handle);
74
0
                return (FIDO_ERR_INVALID_ARGUMENT);
75
0
        }
76
9.99k
77
9.99k
        if (dev->io.open == NULL || dev->io.close == NULL) {
78
0
                fido_log_debug("%s: NULL open/close", __func__);
79
0
                return (FIDO_ERR_INVALID_ARGUMENT);
80
0
        }
81
9.99k
82
9.99k
        if (obtain_nonce(&dev->nonce) < 0) {
83
0
                fido_log_debug("%s: obtain_nonce", __func__);
84
0
                return (FIDO_ERR_INTERNAL);
85
0
        }
86
9.99k
87
9.99k
        if ((dev->io_handle = dev->io.open(path)) == NULL) {
88
0
                fido_log_debug("%s: dev->io.open", __func__);
89
0
                return (FIDO_ERR_INTERNAL);
90
0
        }
91
9.99k
92
9.99k
        if (fido_tx(dev, cmd, &dev->nonce, sizeof(dev->nonce)) < 0) {
93
103
                fido_log_debug("%s: fido_tx", __func__);
94
103
                dev->io.close(dev->io_handle);
95
103
                dev->io_handle = NULL;
96
103
                return (FIDO_ERR_TX);
97
103
        }
98
9.89k
99
9.89k
        return (FIDO_OK);
100
9.89k
}
101
102
static int
103
fido_dev_open_rx(fido_dev_t *dev, int ms)
104
9.89k
{
105
9.89k
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_INIT;
106
9.89k
        int             n;
107
9.89k
108
9.89k
        if ((n = fido_rx(dev, cmd, &dev->attr, sizeof(dev->attr), ms)) < 0) {
109
4.96k
                fido_log_debug("%s: fido_rx", __func__);
110
4.96k
                goto fail;
111
4.96k
        }
112
4.92k
113
4.92k
#ifdef FIDO_FUZZ
114
4.92k
        dev->attr.nonce = dev->nonce;
115
4.92k
#endif
116
4.92k
117
4.92k
        if ((size_t)n != sizeof(dev->attr) || dev->attr.nonce != dev->nonce) {
118
193
                fido_log_debug("%s: invalid nonce", __func__);
119
193
                goto fail;
120
193
        }
121
4.73k
122
4.73k
        dev->cid = dev->attr.cid;
123
4.73k
124
4.73k
        return (FIDO_OK);
125
5.16k
fail:
126
5.16k
        dev->io.close(dev->io_handle);
127
5.16k
        dev->io_handle = NULL;
128
5.16k
129
5.16k
        return (FIDO_ERR_RX);
130
4.73k
}
131
132
static int
133
fido_dev_open_wait(fido_dev_t *dev, const char *path, int ms)
134
9.99k
{
135
9.99k
        int r;
136
9.99k
137
9.99k
        if ((r = fido_dev_open_tx(dev, path)) != FIDO_OK ||
138
9.99k
            (r = fido_dev_open_rx(dev, ms)) != FIDO_OK)
139
9.99k
                return (r);
140
4.73k
141
4.73k
        return (FIDO_OK);
142
4.73k
}
143
144
int
145
fido_dev_open(fido_dev_t *dev, const char *path)
146
9.99k
{
147
9.99k
        return (fido_dev_open_wait(dev, path, -1));
148
9.99k
}
149
150
int
151
fido_dev_close(fido_dev_t *dev)
152
4.73k
{
153
4.73k
        if (dev->io_handle == NULL || dev->io.close == NULL)
154
4.73k
                return (FIDO_ERR_INVALID_ARGUMENT);
155
4.73k
156
4.73k
        dev->io.close(dev->io_handle);
157
4.73k
        dev->io_handle = NULL;
158
4.73k
159
4.73k
        return (FIDO_OK);
160
4.73k
}
161
162
int
163
fido_dev_cancel(fido_dev_t *dev)
164
915
{
165
915
        if (fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CANCEL, NULL, 0) < 0)
166
915
                return (FIDO_ERR_TX);
167
0
168
0
        return (FIDO_OK);
169
0
}
170
171
int
172
fido_dev_set_io_functions(fido_dev_t *dev, const fido_dev_io_t *io)
173
19.9k
{
174
19.9k
        if (dev->io_handle != NULL) {
175
0
                fido_log_debug("%s: NULL handle", __func__);
176
0
                return (FIDO_ERR_INVALID_ARGUMENT);
177
0
        }
178
19.9k
179
19.9k
        if (io == NULL || io->open == NULL || io->close == NULL ||
180
19.9k
            io->read == NULL || io->write == NULL) {
181
0
                fido_log_debug("%s: NULL function", __func__);
182
0
                return (FIDO_ERR_INVALID_ARGUMENT);
183
0
        }
184
19.9k
185
19.9k
        dev->io.open = io->open;
186
19.9k
        dev->io.close = io->close;
187
19.9k
        dev->io.read = io->read;
188
19.9k
        dev->io.write = io->write;
189
19.9k
190
19.9k
        return (FIDO_OK);
191
19.9k
}
192
193
void
194
fido_init(int flags)
195
2.94k
{
196
2.94k
        if (flags & FIDO_DEBUG || getenv("FIDO_DEBUG") != NULL)
197
2.94k
                fido_log_init();
198
2.94k
}
199
200
fido_dev_t *
201
fido_dev_new(void)
202
10.0k
{
203
10.0k
        fido_dev_t      *dev;
204
10.0k
        fido_dev_io_t    io;
205
10.0k
206
10.0k
        if ((dev = calloc(1, sizeof(*dev))) == NULL)
207
10.0k
                return (NULL);
208
9.99k
209
9.99k
        dev->cid = CTAP_CID_BROADCAST;
210
9.99k
211
9.99k
        io.open = fido_hid_open;
212
9.99k
        io.close = fido_hid_close;
213
9.99k
        io.read = fido_hid_read;
214
9.99k
        io.write = fido_hid_write;
215
9.99k
216
9.99k
        if (fido_dev_set_io_functions(dev, &io) != FIDO_OK) {
217
0
                fido_log_debug("%s: fido_dev_set_io_functions", __func__);
218
0
                fido_dev_free(&dev);
219
0
                return (NULL);
220
0
        }
221
9.99k
222
9.99k
        return (dev);
223
9.99k
}
224
225
void
226
fido_dev_free(fido_dev_t **dev_p)
227
12.0k
{
228
12.0k
        fido_dev_t *dev;
229
12.0k
230
12.0k
        if (dev_p == NULL || (dev = *dev_p) == NULL)
231
12.0k
                return;
232
9.99k
233
9.99k
        free(dev);
234
9.99k
235
9.99k
        *dev_p = NULL;
236
9.99k
}
237
238
uint8_t
239
fido_dev_protocol(const fido_dev_t *dev)
240
164
{
241
164
        return (dev->attr.protocol);
242
164
}
243
244
uint8_t
245
fido_dev_major(const fido_dev_t *dev)
246
164
{
247
164
        return (dev->attr.major);
248
164
}
249
250
uint8_t
251
fido_dev_minor(const fido_dev_t *dev)
252
164
{
253
164
        return (dev->attr.minor);
254
164
}
255
256
uint8_t
257
fido_dev_build(const fido_dev_t *dev)
258
164
{
259
164
        return (dev->attr.build);
260
164
}
261
262
uint8_t
263
fido_dev_flags(const fido_dev_t *dev)
264
164
{
265
164
        return (dev->attr.flags);
266
164
}
267
268
bool
269
fido_dev_is_fido2(const fido_dev_t *dev)
270
2.44k
{
271
2.44k
        return (dev->attr.flags & FIDO_CAP_CBOR);
272
2.44k
}
273
274
void
275
fido_dev_force_u2f(fido_dev_t *dev)
276
238
{
277
238
        dev->attr.flags &= ~FIDO_CAP_CBOR;
278
238
}
279
280
void
281
fido_dev_force_fido2(fido_dev_t *dev)
282
0
{
283
0
        dev->attr.flags |= FIDO_CAP_CBOR;
284
0
}
/home/pedro/projects/libfido2/src/ecdh.c
Line
Count
Source
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/evp.h>
8
#include <openssl/sha.h>
9
10
#include "fido.h"
11
#include "fido/es256.h"
12
13
static int
14
do_ecdh(const es256_sk_t *sk, const es256_pk_t *pk, fido_blob_t **ecdh)
15
2.41k
{
16
2.41k
        EVP_PKEY        *pk_evp = NULL;
17
2.41k
        EVP_PKEY        *sk_evp = NULL;
18
2.41k
        EVP_PKEY_CTX    *ctx = NULL;
19
2.41k
        fido_blob_t     *secret = NULL;
20
2.41k
        int              ok = -1;
21
2.41k
22
2.41k
        *ecdh = NULL;
23
2.41k
24
2.41k
        /* allocate blobs for secret & ecdh */
25
2.41k
        if ((secret = fido_blob_new()) == NULL ||
26
2.41k
            (*ecdh = fido_blob_new()) == NULL)
27
2.41k
                goto fail;
28
2.38k
29
2.38k
        /* wrap the keys as openssl objects */
30
2.38k
        if ((pk_evp = es256_pk_to_EVP_PKEY(pk)) == NULL ||
31
2.38k
            (sk_evp = es256_sk_to_EVP_PKEY(sk)) == NULL) {
32
507
                fido_log_debug("%s: es256_to_EVP_PKEY", __func__);
33
507
                goto fail;
34
507
        }
35
1.87k
36
1.87k
        /* set ecdh parameters */
37
1.87k
        if ((ctx = EVP_PKEY_CTX_new(sk_evp, NULL)) == NULL ||
38
1.87k
            EVP_PKEY_derive_init(ctx) <= 0 ||
39
1.87k
            EVP_PKEY_derive_set_peer(ctx, pk_evp) <= 0) {
40
50
                fido_log_debug("%s: EVP_PKEY_derive_init", __func__);
41
50
                goto fail;
42
50
        }
43
1.82k
44
1.82k
        /* perform ecdh */
45
1.82k
        if (EVP_PKEY_derive(ctx, NULL, &secret->len) <= 0 ||
46
1.82k
            (secret->ptr = calloc(1, secret->len)) == NULL ||
47
1.82k
            EVP_PKEY_derive(ctx, secret->ptr, &secret->len) <= 0) {
48
15
                fido_log_debug("%s: EVP_PKEY_derive", __func__);
49
15
                goto fail;
50
15
        }
51
1.80k
52
1.80k
        /* use sha256 as a kdf on the resulting secret */
53
1.80k
        (*ecdh)->len = SHA256_DIGEST_LENGTH;
54
1.80k
        if (((*ecdh)->ptr = calloc(1, (*ecdh)->len)) == NULL ||
55
1.80k
            SHA256(secret->ptr, secret->len, (*ecdh)->ptr) != (*ecdh)->ptr) {
56
39
                fido_log_debug("%s: sha256", __func__);
57
39
                goto fail;
58
39
        }
59
1.77k
60
1.77k
        ok = 0;
61
2.41k
fail:
62
2.41k
        if (pk_evp != NULL)
63
2.41k
                EVP_PKEY_free(pk_evp);
64
2.41k
        if (sk_evp != NULL)
65
2.41k
                EVP_PKEY_free(sk_evp);
66
2.41k
        if (ctx != NULL)
67
2.41k
                EVP_PKEY_CTX_free(ctx);
68
2.41k
        if (ok < 0)
69
648
                fido_blob_free(ecdh);
70
2.41k
71
2.41k
        fido_blob_free(&secret);
72
2.41k
73
2.41k
        return (ok);
74
1.77k
}
75
76
int
77
fido_do_ecdh(fido_dev_t *dev, es256_pk_t **pk, fido_blob_t **ecdh)
78
3.83k
{
79
3.83k
        es256_sk_t      *sk = NULL; /* our private key */
80
3.83k
        es256_pk_t      *ak = NULL; /* authenticator's public key */
81
3.83k
        int              r;
82
3.83k
83
3.83k
        *pk = NULL; /* our public key; returned */
84
3.83k
        *ecdh = NULL; /* shared ecdh secret; returned */
85
3.83k
86
3.83k
        if ((sk = es256_sk_new()) == NULL || (*pk = es256_pk_new()) == NULL) {
87
40
                r = FIDO_ERR_INTERNAL;
88
40
                goto fail;
89
40
        }
90
3.79k
91
3.79k
        if (es256_sk_create(sk) < 0 || es256_derive_pk(sk, *pk) < 0) {
92
208
                fido_log_debug("%s: es256_derive_pk", __func__);
93
208
                r = FIDO_ERR_INTERNAL;
94
208
                goto fail;
95
208
        }
96
3.58k
97
3.58k
        if ((ak = es256_pk_new()) == NULL ||
98
3.58k
            fido_dev_authkey(dev, ak) != FIDO_OK) {
99
1.17k
                fido_log_debug("%s: fido_dev_authkey", __func__);
100
1.17k
                r = FIDO_ERR_INTERNAL;
101
1.17k
                goto fail;
102
1.17k
        }
103
2.41k
104
2.41k
        if (do_ecdh(sk, ak, ecdh) < 0) {
105
648
                fido_log_debug("%s: do_ecdh", __func__);
106
648
                r = FIDO_ERR_INTERNAL;
107
648
                goto fail;
108
648
        }
109
1.77k
110
1.77k
        r = FIDO_OK;
111
3.83k
fail:
112
3.83k
        es256_sk_free(&sk);
113
3.83k
        es256_pk_free(&ak);
114
3.83k
115
3.83k
        if (r != FIDO_OK) {
116
2.06k
                es256_pk_free(pk);
117
2.06k
                fido_blob_free(ecdh);
118
2.06k
        }
119
3.83k
120
3.83k
        return (r);
121
1.77k
}
/home/pedro/projects/libfido2/src/eddsa.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2019 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/ec.h>
9
#include <openssl/evp.h>
10
#include <openssl/obj_mac.h>
11
12
#include <string.h>
13
#include "fido.h"
14
#include "fido/eddsa.h"
15
16
#if defined(LIBRESSL_VERSION_NUMBER) || OPENSSL_VERSION_NUMBER < 0x10101000L
17
EVP_PKEY *
18
EVP_PKEY_new_raw_public_key(int type, ENGINE *e, const unsigned char *key,
19
    size_t keylen)
20
{
21
        (void)type;
22
        (void)e;
23
        (void)key;
24
        (void)keylen;
25
26
        return (NULL);
27
}
28
29
int
30
EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub,
31
    size_t *len)
32
{
33
        (void)pkey;
34
        (void)pub;
35
        (void)len;
36
37
        return (0);
38
}
39
40
int
41
EVP_DigestVerify(EVP_MD_CTX *ctx, const unsigned char *sigret, size_t siglen,
42
    const unsigned char *tbs, size_t tbslen)
43
{
44
        (void)ctx;
45
        (void)sigret;
46
        (void)siglen;
47
        (void)tbs;
48
        (void)tbslen;
49
50
        return (0);
51
}
52
#endif /* LIBRESSL_VERSION_NUMBER || OPENSSL_VERSION_NUMBER < 0x10101000L */
53
54
#if OPENSSL_VERSION_NUMBER < 0x10100000L
55
EVP_MD_CTX *
56
EVP_MD_CTX_new(void)
57
{
58
        return (NULL);
59
}
60
61
void
62
EVP_MD_CTX_free(EVP_MD_CTX *ctx)
63
{
64
        (void)ctx;
65
}
66
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
67
68
static int
69
decode_coord(const cbor_item_t *item, void *xy, size_t xy_len)
70
189
{
71
189
        if (cbor_isa_bytestring(item) == false ||
72
189
            cbor_bytestring_is_definite(item) == false ||
73
189
            cbor_bytestring_length(item) != xy_len) {
74
7
                fido_log_debug("%s: cbor type", __func__);
75
7
                return (-1);
76
7
        }
77
182
78
182
        memcpy(xy, cbor_bytestring_handle(item), xy_len);
79
182
80
182
        return (0);
81
182
}
82
83
static int
84
decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg)
85
888
{
86
888
        eddsa_pk_t *k = arg;
87
888
88
888
        if (cbor_isa_negint(key) == false ||
89
888
            cbor_int_get_width(key) != CBOR_INT_8)
90
468
                return (0); /* ignore */
91
420
92
420
        switch (cbor_get_uint8(key)) {
93
420
        case 1: /* x coordinate */
94
189
                return (decode_coord(val, &k->x, sizeof(k->x)));
95
231
        }
96
231
97
231
        return (0); /* ignore */
98
231
}
99
100
int
101
eddsa_pk_decode(const cbor_item_t *item, eddsa_pk_t *k)
102
221
{
103
221
        if (cbor_isa_map(item) == false ||
104
221
            cbor_map_is_definite(item) == false ||
105
221
            cbor_map_iter(item, k, decode_pubkey_point) < 0) {
106
7
                fido_log_debug("%s: cbor type", __func__);
107
7
                return (-1);
108
7
        }
109
214
110
214
        return (0);
111
214
}
112
113
eddsa_pk_t *
114
eddsa_pk_new(void)
115
299
{
116
299
        return (calloc(1, sizeof(eddsa_pk_t)));
117
299
}
118
119
void
120
eddsa_pk_free(eddsa_pk_t **pkp)
121
606
{
122
606
        eddsa_pk_t *pk;
123
606
124
606
        if (pkp == NULL || (pk = *pkp) == NULL)
125
606
                return;
126
297
127
297
        explicit_bzero(pk, sizeof(*pk));
128
297
        free(pk);
129
297
130
297
        *pkp = NULL;
131
297
}
132
133
int
134
eddsa_pk_from_ptr(eddsa_pk_t *pk, const void *ptr, size_t len)
135
150
{
136
150
        if (len < sizeof(*pk))
137
130
                return (FIDO_ERR_INVALID_ARGUMENT);
138
20
139
20
        memcpy(pk, ptr, sizeof(*pk));
140
20
141
20
        return (FIDO_OK);
142
20
}
143
144
EVP_PKEY *
145
eddsa_pk_to_EVP_PKEY(const eddsa_pk_t *k)
146
166
{
147
166
        EVP_PKEY *pkey = NULL;
148
166
149
166
        if ((pkey = EVP_PKEY_new_raw_public_key(EVP_PKEY_ED25519, NULL, k->x,
150
166
            sizeof(k->x))) == NULL)
151
166
                fido_log_debug("%s: EVP_PKEY_new_raw_public_key", __func__);
152
166
153
166
        return (pkey);
154
166
}
155
156
int
157
eddsa_pk_from_EVP_PKEY(eddsa_pk_t *pk, const EVP_PKEY *pkey)
158
147
{
159
147
        size_t len = 0;
160
147
161
147
        if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1 ||
162
147
            len != sizeof(pk->x))
163
0
                return (FIDO_ERR_INTERNAL);
164
147
        if (EVP_PKEY_get_raw_public_key(pkey, pk->x, &len) != 1 ||
165
147
            len != sizeof(pk->x))
166
0
                return (FIDO_ERR_INTERNAL);
167
147
168
147
        return (FIDO_OK);
169
147
}
/home/pedro/projects/libfido2/src/err.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 "fido/err.h"
8
9
const char *
10
fido_strerr(int n)
11
0
{
12
0
        switch (n) {
13
0
        case FIDO_ERR_SUCCESS:
14
0
                return "FIDO_ERR_SUCCESS";
15
0
        case FIDO_ERR_INVALID_COMMAND:
16
0
                return "FIDO_ERR_INVALID_COMMAND";
17
0
        case FIDO_ERR_INVALID_PARAMETER:
18
0
                return "FIDO_ERR_INVALID_PARAMETER";
19
0
        case FIDO_ERR_INVALID_LENGTH:
20
0
                return "FIDO_ERR_INVALID_LENGTH";
21
0
        case FIDO_ERR_INVALID_SEQ:
22
0
                return "FIDO_ERR_INVALID_SEQ";
23
0
        case FIDO_ERR_TIMEOUT:
24
0
                return "FIDO_ERR_TIMEOUT";
25
0
        case FIDO_ERR_CHANNEL_BUSY:
26
0
                return "FIDO_ERR_CHANNEL_BUSY";
27
0
        case FIDO_ERR_LOCK_REQUIRED:
28
0
                return "FIDO_ERR_LOCK_REQUIRED";
29
0
        case FIDO_ERR_INVALID_CHANNEL:
30
0
                return "FIDO_ERR_INVALID_CHANNEL";
31
0
        case FIDO_ERR_CBOR_UNEXPECTED_TYPE:
32
0
                return "FIDO_ERR_UNEXPECTED_TYPE";
33
0
        case FIDO_ERR_INVALID_CBOR:
34
0
                return "FIDO_ERR_INVALID_CBOR";
35
0
        case FIDO_ERR_MISSING_PARAMETER:
36
0
                return "FIDO_ERR_MISSING_PARAMETER";
37
0
        case FIDO_ERR_LIMIT_EXCEEDED:
38
0
                return "FIDO_ERR_LIMIT_EXCEEDED";
39
0
        case FIDO_ERR_UNSUPPORTED_EXTENSION:
40
0
                return "FIDO_ERR_UNSUPPORTED_EXTENSION";
41
0
        case FIDO_ERR_CREDENTIAL_EXCLUDED:
42
0
                return "FIDO_ERR_CREDENTIAL_EXCLUDED";
43
0
        case FIDO_ERR_PROCESSING:
44
0
                return "FIDO_ERR_PROCESSING";
45
0
        case FIDO_ERR_INVALID_CREDENTIAL:
46
0
                return "FIDO_ERR_INVALID_CREDENTIAL";
47
0
        case FIDO_ERR_USER_ACTION_PENDING:
48
0
                return "FIDO_ERR_ACTION_PENDING";
49
0
        case FIDO_ERR_OPERATION_PENDING:
50
0
                return "FIDO_ERR_OPERATION_PENDING";
51
0
        case FIDO_ERR_NO_OPERATIONS:
52
0
                return "FIDO_ERR_NO_OPERATIONS";
53
0
        case FIDO_ERR_UNSUPPORTED_ALGORITHM:
54
0
                return "FIDO_ERR_UNSUPPORTED_ALGORITHM";
55
0
        case FIDO_ERR_OPERATION_DENIED:
56
0
                return "FIDO_ERR_OPERATION_DENIED";
57
0
        case FIDO_ERR_KEY_STORE_FULL:
58
0
                return "FIDO_ERR_STORE_FULL";
59
0
        case FIDO_ERR_NOT_BUSY:
60
0
                return "FIDO_ERR_NOT_BUSY";
61
0
        case FIDO_ERR_NO_OPERATION_PENDING:
62
0
                return "FIDO_ERR_OPERATION_PENDING";
63
0
        case FIDO_ERR_UNSUPPORTED_OPTION:
64
0
                return "FIDO_ERR_UNSUPPORTED_OPTION";
65
0
        case FIDO_ERR_INVALID_OPTION:
66
0
                return "FIDO_ERR_INVALID_OPTION";
67
0
        case FIDO_ERR_KEEPALIVE_CANCEL:
68
0
                return "FIDO_ERR_KEEPALIVE_CANCEL";
69
0
        case FIDO_ERR_NO_CREDENTIALS:
70
0
                return "FIDO_ERR_NO_CREDENTIALS";
71
0
        case FIDO_ERR_USER_ACTION_TIMEOUT:
72
0
                return "FIDO_ERR_ACTION_TIMEOUT";
73
0
        case FIDO_ERR_NOT_ALLOWED:
74
0
                return "FIDO_ERR_NOT_ALLOWED";
75
0
        case FIDO_ERR_PIN_INVALID:
76
0
                return "FIDO_ERR_PIN_INVALID";
77
0
        case FIDO_ERR_PIN_BLOCKED:
78
0
                return "FIDO_ERR_PIN_BLOCKED";
79
0
        case FIDO_ERR_PIN_AUTH_INVALID:
80
0
                return "FIDO_ERR_AUTH_INVALID";
81
0
        case FIDO_ERR_PIN_AUTH_BLOCKED:
82
0
                return "FIDO_ERR_AUTH_BLOCKED";
83
0
        case FIDO_ERR_PIN_NOT_SET:
84
0
                return "FIDO_ERR_NOT_SET";
85
0
        case FIDO_ERR_PIN_REQUIRED:
86
0
                return "FIDO_ERR_PIN_REQUIRED";
87
0
        case FIDO_ERR_PIN_POLICY_VIOLATION:
88
0
                return "FIDO_ERR_POLICY_VIOLATION";
89
0
        case FIDO_ERR_PIN_TOKEN_EXPIRED:
90
0
                return "FIDO_ERR_TOKEN_EXPIRED";
91
0
        case FIDO_ERR_REQUEST_TOO_LARGE:
92
0
                return "FIDO_ERR_TOO_LARGE";
93
0
        case FIDO_ERR_ACTION_TIMEOUT:
94
0
                return "FIDO_ERR_ACTION_TIMEOUT";
95
0
        case FIDO_ERR_UP_REQUIRED:
96
0
                return "FIDO_ERR_UP_REQUIRED";
97
0
        case FIDO_ERR_ERR_OTHER:
98
0
                return "FIDO_ERR_OTHER";
99
0
        case FIDO_ERR_SPEC_LAST:
100
0
                return "FIDO_ERR_SPEC_LAST";
101
0
        case FIDO_ERR_TX:
102
0
                return "FIDO_ERR_TX";
103
0
        case FIDO_ERR_RX:
104
0
                return "FIDO_ERR_RX";
105
0
        case FIDO_ERR_RX_NOT_CBOR:
106
0
                return "FIDO_ERR_RX_NOT_CBOR";
107
0
        case FIDO_ERR_RX_INVALID_CBOR:
108
0
                return "FIDO_ERR_RX_INVALID_CBOR";
109
0
        case FIDO_ERR_INVALID_PARAM:
110
0
                return "FIDO_ERR_INVALID_PARAM";
111
0
        case FIDO_ERR_INVALID_SIG:
112
0
                return "FIDO_ERR_INVALID_SIG";
113
0
        case FIDO_ERR_INVALID_ARGUMENT:
114
0
                return "FIDO_ERR_INVALID_ARGUMENT";
115
0
        case FIDO_ERR_USER_PRESENCE_REQUIRED:
116
0
                return "FIDO_ERR_USER_PRESENCE_REQUIRED";
117
0
        case FIDO_ERR_INTERNAL:
118
0
                return "FIDO_ERR_INTERNAL";
119
0
        default:
120
0
                return "FIDO_ERR_UNKNOWN";
121
0
        }
122
0
}
/home/pedro/projects/libfido2/src/es256.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/ec.h>
9
#include <openssl/evp.h>
10
#include <openssl/obj_mac.h>
11
12
#include <string.h>
13
#include "fido.h"
14
#include "fido/es256.h"
15
16
static int
17
decode_coord(const cbor_item_t *item, void *xy, size_t xy_len)
18
5.42k
{
19
5.42k
        if (cbor_isa_bytestring(item) == false ||
20
5.42k
            cbor_bytestring_is_definite(item) == false ||
21
5.42k
            cbor_bytestring_length(item) != xy_len) {
22
93
                fido_log_debug("%s: cbor type", __func__);
23
93
                return (-1);
24
93
        }
25
5.32k
26
5.32k
        memcpy(xy, cbor_bytestring_handle(item), xy_len);
27
5.32k
28
5.32k
        return (0);
29
5.32k
}
30
31
static int
32
decode_pubkey_point(const cbor_item_t *key, const cbor_item_t *val, void *arg)
33
14.7k
{
34
14.7k
        es256_pk_t *k = arg;
35
14.7k
36
14.7k
        if (cbor_isa_negint(key) == false ||
37
14.7k
            cbor_int_get_width(key) != CBOR_INT_8)
38
7.90k
                return (0); /* ignore */
39
6.87k
40
6.87k
        switch (cbor_get_uint8(key)) {
41
6.87k
        case 1: /* x coordinate */
42
2.79k
                return (decode_coord(val, &k->x, sizeof(k->x)));
43
6.87k
        case 2: /* y coordinate */
44
2.63k
                return (decode_coord(val, &k->y, sizeof(k->y)));
45
1.45k
        }
46
1.45k
47
1.45k
        return (0); /* ignore */
48
1.45k
}
49
50
int
51
es256_pk_decode(const cbor_item_t *item, es256_pk_t *k)
52
3.15k
{
53
3.15k
        if (cbor_isa_map(item) == false ||
54
3.15k
            cbor_map_is_definite(item) == false ||
55
3.15k
            cbor_map_iter(item, k, decode_pubkey_point) < 0) {
56
418
                fido_log_debug("%s: cbor type", __func__);
57
418
                return (-1);
58
418
        }
59
2.74k
60
2.74k
        return (0);
61
2.74k
}
62
63
cbor_item_t *
64
es256_pk_encode(const es256_pk_t *pk, int ecdh)
65
1.70k
{
66
1.70k
        cbor_item_t             *item = NULL;
67
1.70k
        struct cbor_pair         argv[5];
68
1.70k
        int                      alg;
69
1.70k
        int                      ok = -1;
70
1.70k
71
1.70k
        memset(argv, 0, sizeof(argv));
72
1.70k
73
1.70k
        if ((item = cbor_new_definite_map(5)) == NULL)
74
1.70k
                goto fail;
75
1.68k
76
1.68k
        /* kty */
77
1.68k
        if ((argv[0].key = cbor_build_uint8(1)) == NULL ||
78
1.68k
            (argv[0].value = cbor_build_uint8(2)) == NULL ||
79
1.68k
            !cbor_map_add(item, argv[0]))
80
50
                goto fail;
81
1.63k
82
1.63k
        /*
83
1.63k
         * "The COSEAlgorithmIdentifier used is -25 (ECDH-ES +
84
1.63k
         * HKDF-256) although this is NOT the algorithm actually
85
1.63k
         * used. Setting this to a different value may result in
86
1.63k
         * compatibility issues."
87
1.63k
         */
88
1.63k
        if (ecdh)
89
23
                alg = COSE_ECDH_ES256;
90
1.63k
        else
91
1.63k
                alg = COSE_ES256;
92
1.63k
93
1.63k
        /* alg */
94
1.63k
        if ((argv[1].key = cbor_build_uint8(3)) == NULL ||
95
1.63k
            (argv[1].value = cbor_build_negint8(-alg - 1)) == NULL ||
96
1.63k
            !cbor_map_add(item, argv[1]))
97
37
                goto fail;
98
1.60k
99
1.60k
        /* crv */
100
1.60k
        if ((argv[2].key = cbor_build_negint8(0)) == NULL ||
101
1.60k
            (argv[2].value = cbor_build_uint8(1)) == NULL ||
102
1.60k
            !cbor_map_add(item, argv[2]))
103
31
                goto fail;
104
1.57k
105
1.57k
        /* x */
106
1.57k
        if ((argv[3].key = cbor_build_negint8(1)) == NULL ||
107
1.57k
            (argv[3].value = cbor_build_bytestring(pk->x,
108
1.57k
            sizeof(pk->x))) == NULL || !cbor_map_add(item, argv[3]))
109
34
                goto fail;
110
1.53k
111
1.53k
        /* y */
112
1.53k
        if ((argv[4].key = cbor_build_negint8(2)) == NULL ||
113
1.53k
            (argv[4].value = cbor_build_bytestring(pk->y,
114
1.53k
            sizeof(pk->y))) == NULL || !cbor_map_add(item, argv[4]))
115
34
                goto fail;
116
1.50k
117
1.50k
        ok = 0;
118
1.70k
fail:
119
1.70k
        if (ok < 0) {
120
201
                if (item != NULL) {
121
186
                        cbor_decref(&item);
122
186
                        item = NULL;
123
186
                }
124
201
        }
125
1.70k
126
10.2k
        for (size_t i = 0; i < 5; i++) {
127
8.51k
                if (argv[i].key)
128
8.00k
                        cbor_decref(&argv[i].key);
129
8.51k
                if (argv[i].value)
130
7.93k
                        cbor_decref(&argv[i].value);
131
8.51k
        }
132
1.70k
133
1.70k
        return (item);
134
1.50k
}
135
136
es256_sk_t *
137
es256_sk_new(void)
138
3.83k
{
139
3.83k
        return (calloc(1, sizeof(es256_sk_t)));
140
3.83k
}
141
142
void
143
es256_sk_free(es256_sk_t **skp)
144
3.83k
{
145
3.83k
        es256_sk_t *sk;
146
3.83k
147
3.83k
        if (skp == NULL || (sk = *skp) == NULL)
148
3.83k
                return;
149
3.81k
150
3.81k
        explicit_bzero(sk, sizeof(*sk));
151
3.81k
        free(sk);
152
3.81k
153
3.81k
        *skp = NULL;
154
3.81k
}
155
156
es256_pk_t *
157
es256_pk_new(void)
158
7.60k
{
159
7.60k
        return (calloc(1, sizeof(es256_pk_t)));
160
7.60k
}
161
162
void
163
es256_pk_free(es256_pk_t **pkp)
164
11.6k
{
165
11.6k
        es256_pk_t *pk;
166
11.6k
167
11.6k
        if (pkp == NULL || (pk = *pkp) == NULL)
168
11.6k
                return;
169
7.56k
170
7.56k
        explicit_bzero(pk, sizeof(*pk));
171
7.56k
        free(pk);
172
7.56k
173
7.56k
        *pkp = NULL;
174
7.56k
}
175
176
int
177
es256_pk_from_ptr(es256_pk_t *pk, const void *ptr, size_t len)
178
175
{
179
175
        if (len < sizeof(*pk))
180
156
                return (FIDO_ERR_INVALID_ARGUMENT);
181
19
182
19
        memcpy(pk, ptr, sizeof(*pk));
183
19
184
19
        return (FIDO_OK);
185
19
}
186
187
int
188
es256_pk_set_x(es256_pk_t *pk, const unsigned char *x)
189
25
{
190
25
        memcpy(pk->x, x, sizeof(pk->x));
191
25
192
25
        return (0);
193
25
}
194
195
int
196
es256_pk_set_y(es256_pk_t *pk, const unsigned char *y)
197
25
{
198
25
        memcpy(pk->y, y, sizeof(pk->y));
199
25
200
25
        return (0);
201
25
}
202
203
int
204
es256_sk_create(es256_sk_t *key)
205
3.79k
{
206
3.79k
        EVP_PKEY_CTX    *pctx = NULL;
207
3.79k
        EVP_PKEY_CTX    *kctx = NULL;
208
3.79k
        EVP_PKEY        *p = NULL;
209
3.79k
        EVP_PKEY        *k = NULL;
210
3.79k
        const EC_KEY    *ec;
211
3.79k
        const BIGNUM    *d;
212
3.79k
        const int        nid = NID_X9_62_prime256v1;
213
3.79k
        int              n;
214
3.79k
        int              ok = -1;
215
3.79k
216
3.79k
        if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL)) == NULL ||
217
3.79k
            EVP_PKEY_paramgen_init(pctx) <= 0 ||
218
3.79k
            EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) <= 0 ||
219
3.79k
            EVP_PKEY_paramgen(pctx, &p) <= 0) {
220
0
                fido_log_debug("%s: EVP_PKEY_paramgen", __func__);
221
0
                goto fail;
222
0
        }
223
3.79k
224
3.79k
        if ((kctx = EVP_PKEY_CTX_new(p, NULL)) == NULL ||
225
3.79k
            EVP_PKEY_keygen_init(kctx) <= 0 || EVP_PKEY_keygen(kctx, &k) <= 0) {
226
19
                fido_log_debug("%s: EVP_PKEY_keygen", __func__);
227
19
                goto fail;
228
19
        }
229
3.77k
230
3.77k
        if ((ec = EVP_PKEY_get0_EC_KEY(k)) == NULL ||
231
3.77k
            (d = EC_KEY_get0_private_key(ec)) == NULL ||
232
3.77k
            (n = BN_num_bytes(d)) < 0 || (size_t)n > sizeof(key->d) ||
233
3.77k
            (n = BN_bn2bin(d, key->d)) < 0 || (size_t)n > sizeof(key->d)) {
234
0
                fido_log_debug("%s: EC_KEY_get0_private_key", __func__);
235
0
                goto fail;
236
0
        }
237
3.77k
238
3.77k
        ok = 0;
239
3.79k
fail:
240
3.79k
        if (p != NULL)
241
3.79k
                EVP_PKEY_free(p);
242
3.79k
        if (k != NULL)
243
3.79k
                EVP_PKEY_free(k);
244
3.79k
        if (pctx != NULL)
245
3.79k
                EVP_PKEY_CTX_free(pctx);
246
3.79k
        if (kctx != NULL)
247
3.79k
                EVP_PKEY_CTX_free(kctx);
248
3.79k
249
3.79k
        return (ok);
250
3.77k
}
251
252
EVP_PKEY *
253
es256_pk_to_EVP_PKEY(const es256_pk_t *k)
254
2.43k
{
255
2.43k
        BN_CTX          *bnctx = NULL;
256
2.43k
        EC_KEY          *ec = NULL;
257
2.43k
        EC_POINT        *q = NULL;
258
2.43k
        EVP_PKEY        *pkey = NULL;
259
2.43k
        BIGNUM          *x = NULL;
260
2.43k
        BIGNUM          *y = NULL;
261
2.43k
        const EC_GROUP  *g = NULL;
262
2.43k
        const int        nid = NID_X9_62_prime256v1;
263
2.43k
        int              ok = -1;
264
2.43k
265
2.43k
        if ((bnctx = BN_CTX_new()) == NULL ||
266
2.43k
            (x = BN_CTX_get(bnctx)) == NULL ||
267
2.43k
            (y = BN_CTX_get(bnctx)) == NULL)
268
2.43k
                goto fail;
269
2.37k
270
2.37k
        if (BN_bin2bn(k->x, sizeof(k->x), x) == NULL ||
271
2.37k
            BN_bin2bn(k->y, sizeof(k->y), y) == NULL) {
272
42
                fido_log_debug("%s: BN_bin2bn", __func__);
273
42
                goto fail;
274
42
        }
275
2.32k
276
2.32k
        if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL ||
277
2.32k
            (g = EC_KEY_get0_group(ec)) == NULL) {
278
40
                fido_log_debug("%s: EC_KEY init", __func__);
279
40
                goto fail;
280
40
        }
281
2.28k
282
2.28k
        if ((q = EC_POINT_new(g)) == NULL ||
283
2.28k
            EC_POINT_set_affine_coordinates_GFp(g, q, x, y, bnctx) == 0 ||
284
2.28k
            EC_KEY_set_public_key(ec, q) == 0) {
285
259
                fido_log_debug("%s: EC_KEY_set_public_key", __func__);
286
259
                goto fail;
287
259
        }
288
2.03k
289
2.03k
        if ((pkey = EVP_PKEY_new()) == NULL ||
290
2.03k
            EVP_PKEY_assign_EC_KEY(pkey, ec) == 0) {
291
34
                fido_log_debug("%s: EVP_PKEY_assign_EC_KEY", __func__);
292
34
                goto fail;
293
34
        }
294
1.99k
295
1.99k
        ec = NULL; /* at this point, ec belongs to evp */
296
1.99k
297
1.99k
        ok = 0;
298
2.43k
fail:
299
2.43k
        if (bnctx != NULL)
300
2.43k
                BN_CTX_free(bnctx);
301
2.43k
        if (ec != NULL)
302
2.43k
                EC_KEY_free(ec);
303
2.43k
        if (q != NULL)
304
2.43k
                EC_POINT_free(q);
305
2.43k
        if (ok < 0 && pkey != NULL) {
306
18
                EVP_PKEY_free(pkey);
307
18
                pkey = NULL;
308
18
        }
309
2.43k
310
2.43k
        return (pkey);
311
1.99k
}
312
313
int
314
es256_pk_from_EC_KEY(es256_pk_t *pk, const EC_KEY *ec)
315
3.68k
{
316
3.68k
        BN_CTX          *ctx = NULL;
317
3.68k
        BIGNUM          *x = NULL;
318
3.68k
        BIGNUM          *y = NULL;
319
3.68k
        const EC_POINT  *q = NULL;
320
3.68k
        const EC_GROUP  *g = NULL;
321
3.68k
        int              ok = FIDO_ERR_INTERNAL;
322
3.68k
        int              n;
323
3.68k
324
3.68k
        if ((q = EC_KEY_get0_public_key(ec)) == NULL ||
325
3.68k
            (g = EC_KEY_get0_group(ec)) == NULL)
326
3.68k
                goto fail;
327
3.66k
328
3.66k
        if ((ctx = BN_CTX_new()) == NULL ||
329
3.66k
            (x = BN_CTX_get(ctx)) == NULL ||
330
3.66k
            (y = BN_CTX_get(ctx)) == NULL)
331
3.66k
                goto fail;
332
3.58k
333
3.58k
        if (EC_POINT_get_affine_coordinates_GFp(g, q, x, y, ctx) == 0 ||
334
3.58k
            (n = BN_num_bytes(x)) < 0 || (size_t)n > sizeof(pk->x) ||
335
3.58k
            (n = BN_num_bytes(y)) < 0 || (size_t)n > sizeof(pk->y)) {
336
0
                fido_log_debug("%s: EC_POINT_get_affine_coordinates_GFp",
337
0
                    __func__);
338
0
                goto fail;
339
0
        }
340
3.58k
341
3.58k
        if ((n = BN_bn2bin(x, pk->x)) < 0 || (size_t)n > sizeof(pk->x) ||
342
3.58k
            (n = BN_bn2bin(y, pk->y)) < 0 || (size_t)n > sizeof(pk->y)) {
343
0
                fido_log_debug("%s: BN_bn2bin", __func__);
344
0
                goto fail;
345
0
        }
346
3.58k
347
3.58k
        ok = FIDO_OK;
348
3.68k
fail:
349
3.68k
        if (ctx != NULL)
350
3.68k
                BN_CTX_free(ctx);
351
3.68k
352
3.68k
        return (ok);
353
3.58k
}
354
355
EVP_PKEY *
356
es256_sk_to_EVP_PKEY(const es256_sk_t *k)
357
1.99k
{
358
1.99k
        BN_CTX          *bnctx = NULL;
359
1.99k
        EC_KEY          *ec = NULL;
360
1.99k
        EVP_PKEY        *pkey = NULL;
361
1.99k
        BIGNUM          *d = NULL;
362
1.99k
        const int        nid = NID_X9_62_prime256v1;
363
1.99k
        int              ok = -1;
364
1.99k
365
1.99k
        if ((bnctx = BN_CTX_new()) == NULL || (d = BN_CTX_get(bnctx)) == NULL ||
366
1.99k
            BN_bin2bn(k->d, sizeof(k->d), d) == NULL) {
367
59
                fido_log_debug("%s: BN_bin2bn", __func__);
368
59
                goto fail;
369
59
        }
370
1.93k
371
1.93k
        if ((ec = EC_KEY_new_by_curve_name(nid)) == NULL ||
372
1.93k
            EC_KEY_set_private_key(ec, d) == 0) {
373
20
                fido_log_debug("%s: EC_KEY_set_private_key", __func__);
374
20
                goto fail;
375
20
        }
376
1.91k
377
1.91k
        if ((pkey = EVP_PKEY_new()) == NULL ||
378
1.91k
            EVP_PKEY_assign_EC_KEY(pkey, ec) == 0) {
379
38
                fido_log_debug("%s: EVP_PKEY_assign_EC_KEY", __func__);
380
38
                goto fail;
381
38
        }
382
1.87k
383
1.87k
        ec = NULL; /* at this point, ec belongs to evp */
384
1.87k
385
1.87k
        ok = 0;
386
1.99k
fail:
387
1.99k
        if (bnctx != NULL)
388
1.99k
                BN_CTX_free(bnctx);
389
1.99k
        if (ec != NULL)
390
1.99k
                EC_KEY_free(ec);
391
1.99k
        if (ok < 0 && pkey != NULL) {
392
21
                EVP_PKEY_free(pkey);
393
21
                pkey = NULL;
394
21
        }
395
1.99k
396
1.99k
        return (pkey);
397
1.87k
}
398
399
int
400
es256_derive_pk(const es256_sk_t *sk, es256_pk_t *pk)
401
3.77k
{
402
3.77k
        BIGNUM          *d = NULL;
403
3.77k
        EC_KEY          *ec = NULL;
404
3.77k
        EC_POINT        *q = NULL;
405
3.77k
        const EC_GROUP  *g = NULL;
406
3.77k
        const int        nid = NID_X9_62_prime256v1;
407
3.77k
        int              ok = -1;
408
3.77k
409
3.77k
        if ((d = BN_bin2bn(sk->d, (int)sizeof(sk->d), NULL)) == NULL ||
410
3.77k
            (ec = EC_KEY_new_by_curve_name(nid)) == NULL ||
411
3.77k
            (g = EC_KEY_get0_group(ec)) == NULL ||
412
3.77k
            (q = EC_POINT_new(g)) == NULL) {
413
90
                fido_log_debug("%s: get", __func__);
414
90
                goto fail;
415
90
        }
416
3.68k
417
3.68k
        if (EC_POINT_mul(g, q, d, NULL, NULL, NULL) == 0 ||
418
3.68k
            EC_KEY_set_public_key(ec, q) == 0 ||
419
3.68k
            es256_pk_from_EC_KEY(pk, ec) != FIDO_OK) {
420
99
                fido_log_debug("%s: set", __func__);
421
99
                goto fail;
422
99
        }
423
3.58k
424
3.58k
        ok = 0;
425
3.77k
fail:
426
3.77k
        if (d != NULL)
427
3.77k
                BN_clear_free(d);
428
3.77k
        if (q != NULL)
429
3.77k
                EC_POINT_free(q);
430
3.77k
        if (ec != NULL)
431
3.77k
                EC_KEY_free(ec);
432
3.77k
433
3.77k
        return (ok);
434
3.58k
}
/home/pedro/projects/libfido2/src/extern.h
Line
Count
Source
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
#ifndef _EXTERN_H
8
#define _EXTERN_H
9
10
/* aes256 */
11
int aes256_cbc_dec(const fido_blob_t *, const fido_blob_t *, fido_blob_t *);
12
int aes256_cbc_enc(const fido_blob_t *, const fido_blob_t *, fido_blob_t *);
13
14
/* cbor encoding functions */
15
cbor_item_t *cbor_flatten_vector(cbor_item_t **, size_t);
16
cbor_item_t *cbor_encode_assert_options(fido_opt_t, fido_opt_t);
17
cbor_item_t *cbor_encode_change_pin_auth(const fido_blob_t *,
18
    const fido_blob_t *, const fido_blob_t *);
19
cbor_item_t *cbor_encode_extensions(int);
20
cbor_item_t *cbor_encode_hmac_secret_param(const fido_blob_t *,
21
    const es256_pk_t *, const fido_blob_t *);
22
cbor_item_t *cbor_encode_options(fido_opt_t, fido_opt_t);
23
cbor_item_t *cbor_encode_pin_auth(const fido_blob_t *, const fido_blob_t *);
24
cbor_item_t *cbor_encode_pin_enc(const fido_blob_t *, const fido_blob_t *);
25
cbor_item_t *cbor_encode_pin_hash_enc(const fido_blob_t *, const fido_blob_t *);
26
cbor_item_t *cbor_encode_pin_opt(void);
27
cbor_item_t *cbor_encode_pubkey(const fido_blob_t *);
28
cbor_item_t *cbor_encode_pubkey_list(const fido_blob_array_t *);
29
cbor_item_t *cbor_encode_pubkey_param(int);
30
cbor_item_t *cbor_encode_rp_entity(const fido_rp_t *);
31
cbor_item_t *cbor_encode_set_pin_auth(const fido_blob_t *, const fido_blob_t *);
32
cbor_item_t *cbor_encode_user_entity(const fido_user_t *);
33
cbor_item_t *es256_pk_encode(const es256_pk_t *, int);
34
35
/* cbor decoding functions */
36
int cbor_decode_attstmt(const cbor_item_t *, fido_attstmt_t *);
37
int cbor_decode_cred_authdata(const cbor_item_t *, int, fido_blob_t *,
38
    fido_authdata_t *, fido_attcred_t *, int *);
39
int cbor_decode_assert_authdata(const cbor_item_t *, fido_blob_t *,
40
    fido_authdata_t *, int *, fido_blob_t *);
41
int cbor_decode_cred_id(const cbor_item_t *, fido_blob_t *);
42
int cbor_decode_fmt(const cbor_item_t *, char **);
43
int cbor_decode_pubkey(const cbor_item_t *, int *, void *);
44
int cbor_decode_rp_entity(const cbor_item_t *, fido_rp_t *);
45
int cbor_decode_uint64(const cbor_item_t *, uint64_t *);
46
int cbor_decode_user(const cbor_item_t *, fido_user_t *);
47
int es256_pk_decode(const cbor_item_t *, es256_pk_t *);
48
int rs256_pk_decode(const cbor_item_t *, rs256_pk_t *);
49
int eddsa_pk_decode(const cbor_item_t *, eddsa_pk_t *);
50
51
/* auxiliary cbor routines */
52
int cbor_add_bool(cbor_item_t *, const char *, fido_opt_t);
53
int cbor_add_bytestring(cbor_item_t *, const char *, const unsigned char *,
54
    size_t);
55
int cbor_add_string(cbor_item_t *, const char *, const char *);
56
int cbor_array_iter(const cbor_item_t *, void *, int(*)(const cbor_item_t *,
57
    void *));
58
int cbor_build_frame(uint8_t, cbor_item_t *[], size_t, fido_blob_t *);
59
int cbor_bytestring_copy(const cbor_item_t *, unsigned char **, size_t *);
60
int cbor_map_iter(const cbor_item_t *, void *, int(*)(const cbor_item_t *,
61
    const cbor_item_t *, void *));
62
int cbor_string_copy(const cbor_item_t *, char **);
63
int cbor_parse_reply(const unsigned char *, size_t, void *,
64
    int(*)(const cbor_item_t *, const cbor_item_t *, void *));
65
int cbor_add_pin_params(fido_dev_t *, const fido_blob_t *, const es256_pk_t *,
66
    const fido_blob_t *,const char *, cbor_item_t **, cbor_item_t **);
67
void cbor_vector_free(cbor_item_t **, size_t);
68
69
#ifndef nitems
70
11.9k
#define nitems(_a)      (sizeof((_a)) / sizeof((_a)[0]))
71
#endif
72
73
/* buf */
74
int fido_buf_read(const unsigned char **, size_t *, void *, size_t);
75
int fido_buf_write(unsigned char **, size_t *, const void *, size_t);
76
77
/* hid i/o */
78
void *fido_hid_open(const char *);
79
void  fido_hid_close(void *);
80
int   fido_hid_read(void *, unsigned char *, size_t, int);
81
int   fido_hid_write(void *, const unsigned char *, size_t);
82
83
/* generic i/o */
84
int fido_rx_cbor_status(fido_dev_t *, int);
85
int fido_rx(fido_dev_t *, uint8_t, void *, size_t, int);
86
int fido_tx(fido_dev_t *, uint8_t, const void *, size_t);
87
88
/* log */
89
#ifdef FIDO_NO_DIAGNOSTIC
90
#define fido_log_init(...)      do { /* nothing */ } while (0)
91
#define fido_log_debug(...)     do { /* nothing */ } while (0)
92
#define fido_log_xxd(...)       do { /* nothing */ } while (0)
93
#else
94
#ifdef __GNUC__
95
void fido_log_init(void);
96
void fido_log_debug(const char *, ...)
97
    __attribute__((__format__ (printf, 1, 2)));
98
void fido_log_xxd(const void *, size_t);
99
#else
100
void fido_log_init(void);
101
void fido_log_debug(const char *, ...);
102
void fido_log_xxd(const void *, size_t);
103
#endif /* __GNUC__ */
104
#endif /* FIDO_NO_DIAGNOSTIC */
105
106
/* u2f */
107
int u2f_register(fido_dev_t *, fido_cred_t *, int);
108
int u2f_authenticate(fido_dev_t *, fido_assert_t *, int);
109
110
/* unexposed fido ops */
111
int fido_dev_authkey(fido_dev_t *, es256_pk_t *);
112
int fido_dev_get_pin_token(fido_dev_t *, const char *, const fido_blob_t *,
113
    const es256_pk_t *, fido_blob_t *);
114
int fido_do_ecdh(fido_dev_t *, es256_pk_t **, fido_blob_t **);
115
116
/* misc */
117
void fido_assert_reset_rx(fido_assert_t *);
118
void fido_assert_reset_tx(fido_assert_t *);
119
void fido_cred_reset_rx(fido_cred_t *);
120
void fido_cred_reset_tx(fido_cred_t *);
121
int fido_check_rp_id(const char *, const unsigned char *);
122
int fido_check_flags(uint8_t, fido_opt_t, fido_opt_t);
123
124
/* crypto */
125
int fido_verify_sig_es256(const fido_blob_t *, const es256_pk_t *,
126
    const fido_blob_t *);
127
int fido_verify_sig_rs256(const fido_blob_t *, const rs256_pk_t *,
128
    const fido_blob_t *);
129
int fido_verify_sig_eddsa(const fido_blob_t *, const eddsa_pk_t *,
130
    const fido_blob_t *);
131
132
#endif /* !_EXTERN_H */
/home/pedro/projects/libfido2/src/fido.h
Line
Count
Source
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
#ifndef _FIDO_H
8
#define _FIDO_H
9
10
#include <openssl/ec.h>
11
#include <openssl/evp.h>
12
13
#include <stdbool.h>
14
#include <stdint.h>
15
#include <stdlib.h>
16
17
typedef void *fido_dev_io_open_t(const char *);
18
typedef void  fido_dev_io_close_t(void *);
19
typedef int   fido_dev_io_read_t(void *, unsigned char *, size_t, int);
20
typedef int   fido_dev_io_write_t(void *, const unsigned char *, size_t);
21
22
typedef struct fido_dev_io {
23
        fido_dev_io_open_t  *open;
24
        fido_dev_io_close_t *close;
25
        fido_dev_io_read_t  *read;
26
        fido_dev_io_write_t *write;
27
} fido_dev_io_t;
28
29
typedef enum {
30
        FIDO_OPT_OMIT = 0, /* use authenticator's default */
31
        FIDO_OPT_FALSE,    /* explicitly set option to false */
32
        FIDO_OPT_TRUE,     /* explicitly set option to true */
33
} fido_opt_t;
34
35
#ifdef _FIDO_INTERNAL
36
#include <cbor.h>
37
#include <limits.h>
38
39
#include "blob.h"
40
#include "../openbsd-compat/openbsd-compat.h"
41
#include "iso7816.h"
42
#include "types.h"
43
#include "extern.h"
44
#endif
45
46
#include "fido/err.h"
47
#include "fido/param.h"
48
49
#ifndef _FIDO_INTERNAL
50
typedef struct fido_assert fido_assert_t;
51
typedef struct fido_cbor_info fido_cbor_info_t;
52
typedef struct fido_cred fido_cred_t;
53
typedef struct fido_dev fido_dev_t;
54
typedef struct fido_dev_info fido_dev_info_t;
55
typedef struct es256_pk es256_pk_t;
56
typedef struct es256_sk es256_sk_t;
57
typedef struct rs256_pk rs256_pk_t;
58
typedef struct eddsa_pk eddsa_pk_t;
59
#endif
60
61
fido_assert_t *fido_assert_new(void);
62
fido_cred_t *fido_cred_new(void);
63
fido_dev_t *fido_dev_new(void);
64
fido_dev_info_t *fido_dev_info_new(size_t);
65
fido_cbor_info_t *fido_cbor_info_new(void);
66
67
void fido_assert_free(fido_assert_t **);
68
void fido_cbor_info_free(fido_cbor_info_t **);
69
void fido_cred_free(fido_cred_t **);
70
void fido_dev_force_fido2(fido_dev_t *);
71
void fido_dev_force_u2f(fido_dev_t *);
72
void fido_dev_free(fido_dev_t **);
73
void fido_dev_info_free(fido_dev_info_t **, size_t);
74
75
/* fido_init() flags. */
76
5.89k
#define FIDO_DEBUG      0x01
77
78
void fido_init(int);
79
80
const unsigned char *fido_assert_authdata_ptr(const fido_assert_t *, size_t);
81
const unsigned char *fido_assert_clientdata_hash_ptr(const fido_assert_t *);
82
const unsigned char *fido_assert_hmac_secret_ptr(const fido_assert_t *, size_t);
83
const unsigned char *fido_assert_id_ptr(const fido_assert_t *, size_t);
84
const unsigned char *fido_assert_sig_ptr(const fido_assert_t *, size_t);
85
const unsigned char *fido_assert_user_id_ptr(const fido_assert_t *, size_t);
86
87
char **fido_cbor_info_extensions_ptr(const fido_cbor_info_t *);
88
char **fido_cbor_info_options_name_ptr(const fido_cbor_info_t *);
89
char **fido_cbor_info_versions_ptr(const fido_cbor_info_t *);
90
const bool *fido_cbor_info_options_value_ptr(const fido_cbor_info_t *);
91
const char *fido_assert_rp_id(const fido_assert_t *);
92
const char *fido_assert_user_display_name(const fido_assert_t *, size_t);
93
const char *fido_assert_user_icon(const fido_assert_t *, size_t);
94
const char *fido_assert_user_name(const fido_assert_t *, size_t);
95
const char *fido_cred_display_name(const fido_cred_t *);
96
const char *fido_cred_fmt(const fido_cred_t *);
97
const char *fido_cred_rp_id(const fido_cred_t *);
98
const char *fido_cred_rp_name(const fido_cred_t *);
99
const char *fido_cred_user_name(const fido_cred_t *);
100
const char *fido_dev_info_manufacturer_string(const fido_dev_info_t *);
101
const char *fido_dev_info_path(const fido_dev_info_t *);
102
const char *fido_dev_info_product_string(const fido_dev_info_t *);
103
const fido_dev_info_t *fido_dev_info_ptr(const fido_dev_info_t *, size_t);
104
const uint8_t *fido_cbor_info_protocols_ptr(const fido_cbor_info_t *);
105
const unsigned char *fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *);
106
const unsigned char *fido_cred_authdata_ptr(const fido_cred_t *);
107
const unsigned char *fido_cred_clientdata_hash_ptr(const fido_cred_t *);
108
const unsigned char *fido_cred_id_ptr(const fido_cred_t *);
109
const unsigned char *fido_cred_user_id_ptr(const fido_cred_t *);
110
const unsigned char *fido_cred_pubkey_ptr(const fido_cred_t *);
111
const unsigned char *fido_cred_sig_ptr(const fido_cred_t *);
112
const unsigned char *fido_cred_x5c_ptr(const fido_cred_t *);
113
114
int fido_assert_allow_cred(fido_assert_t *, const unsigned char *, size_t);
115
int fido_assert_set_authdata(fido_assert_t *, size_t, const unsigned char *,
116
    size_t);
117
int fido_assert_set_authdata_raw(fido_assert_t *, size_t, const unsigned char *,
118
    size_t);
119
int fido_assert_set_clientdata_hash(fido_assert_t *, const unsigned char *,
120
    size_t);
121
int fido_assert_set_count(fido_assert_t *, size_t);
122
int fido_assert_set_extensions(fido_assert_t *, int);
123
int fido_assert_set_hmac_salt(fido_assert_t *, const unsigned char *, size_t);
124
int fido_assert_set_options(fido_assert_t *, bool, bool) __attribute__((__deprecated__));
125
int fido_assert_set_rp(fido_assert_t *, const char *);
126
int fido_assert_set_up(fido_assert_t *, fido_opt_t);
127
int fido_assert_set_uv(fido_assert_t *, fido_opt_t);
128
int fido_assert_set_sig(fido_assert_t *, size_t, const unsigned char *, size_t);
129
int fido_assert_verify(const fido_assert_t *, size_t, int, const void *);
130
int fido_cred_exclude(fido_cred_t *, const unsigned char *, size_t);
131
int fido_cred_set_authdata(fido_cred_t *, const unsigned char *, size_t);
132
int fido_cred_set_authdata_raw(fido_cred_t *, const unsigned char *, size_t);
133
int fido_cred_set_clientdata_hash(fido_cred_t *, const unsigned char *, size_t);
134
int fido_cred_set_extensions(fido_cred_t *, int);
135
int fido_cred_set_fmt(fido_cred_t *, const char *);
136
int fido_cred_set_options(fido_cred_t *, bool, bool) __attribute__((__deprecated__));
137
int fido_cred_set_rk(fido_cred_t *, fido_opt_t);
138
int fido_cred_set_rp(fido_cred_t *, const char *, const char *);
139
int fido_cred_set_sig(fido_cred_t *, const unsigned char *, size_t);
140
int fido_cred_set_type(fido_cred_t *, int);
141
int fido_cred_set_uv(fido_cred_t *, fido_opt_t);
142
int fido_cred_type(const fido_cred_t *);
143
int fido_cred_set_user(fido_cred_t *, const unsigned char *, size_t,
144
    const char *, const char *, const char *);
145
int fido_cred_set_x509(fido_cred_t *, const unsigned char *, size_t);
146
int fido_cred_verify(const fido_cred_t *);
147
int fido_cred_verify_self(const fido_cred_t *);
148
int fido_dev_cancel(fido_dev_t *);
149
int fido_dev_close(fido_dev_t *);
150
int fido_dev_get_assert(fido_dev_t *, fido_assert_t *, const char *);
151
int fido_dev_get_cbor_info(fido_dev_t *, fido_cbor_info_t *);
152
int fido_dev_get_retry_count(fido_dev_t *, int *);
153
int fido_dev_info_manifest(fido_dev_info_t *, size_t, size_t *);
154
int fido_dev_make_cred(fido_dev_t *, fido_cred_t *, const char *);
155
int fido_dev_open(fido_dev_t *, const char *);
156
int fido_dev_reset(fido_dev_t *);
157
int fido_dev_set_io_functions(fido_dev_t *, const fido_dev_io_t *);
158
int fido_dev_set_pin(fido_dev_t *, const char *, const char *);
159
160
size_t fido_assert_authdata_len(const fido_assert_t *, size_t);
161
size_t fido_assert_clientdata_hash_len(const fido_assert_t *);
162
size_t fido_assert_count(const fido_assert_t *);
163
size_t fido_assert_hmac_secret_len(const fido_assert_t *, size_t);
164
size_t fido_assert_id_len(const fido_assert_t *, size_t);
165
size_t fido_assert_sig_len(const fido_assert_t *, size_t);
166
size_t fido_assert_user_id_len(const fido_assert_t *, size_t);
167
size_t fido_cbor_info_aaguid_len(const fido_cbor_info_t *);
168
size_t fido_cbor_info_extensions_len(const fido_cbor_info_t *);
169
size_t fido_cbor_info_options_len(const fido_cbor_info_t *);
170
size_t fido_cbor_info_protocols_len(const fido_cbor_info_t *);
171
size_t fido_cbor_info_versions_len(const fido_cbor_info_t *);
172
size_t fido_cred_authdata_len(const fido_cred_t *);
173
size_t fido_cred_clientdata_hash_len(const fido_cred_t *);
174
size_t fido_cred_id_len(const fido_cred_t *);
175
size_t fido_cred_user_id_len(const fido_cred_t *);
176
size_t fido_cred_pubkey_len(const fido_cred_t *);
177
size_t fido_cred_sig_len(const fido_cred_t *);
178
size_t fido_cred_x5c_len(const fido_cred_t *);
179
180
uint8_t  fido_assert_flags(const fido_assert_t *, size_t);
181
uint32_t  fido_assert_sigcount(const fido_assert_t *, size_t);
182
uint8_t  fido_cred_flags(const fido_cred_t *);
183
uint8_t  fido_dev_protocol(const fido_dev_t *);
184
uint8_t  fido_dev_major(const fido_dev_t *);
185
uint8_t  fido_dev_minor(const fido_dev_t *);
186
uint8_t  fido_dev_build(const fido_dev_t *);
187
uint8_t  fido_dev_flags(const fido_dev_t *);
188
int16_t  fido_dev_info_vendor(const fido_dev_info_t *);
189
int16_t  fido_dev_info_product(const fido_dev_info_t *);
190
uint64_t fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *);
191
192
bool fido_dev_is_fido2(const fido_dev_t *);
193
194
#endif /* !_FIDO_H */
/home/pedro/projects/libfido2/src/fido/err.h
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
#ifndef _FIDO_ERR_H
8
#define _FIDO_ERR_H
9
10
274k
#define FIDO_ERR_SUCCESS                0x00
11
24
#define FIDO_ERR_INVALID_COMMAND        0x01
12
0
#define FIDO_ERR_INVALID_PARAMETER      0x02
13
0
#define FIDO_ERR_INVALID_LENGTH         0x03
14
0
#define FIDO_ERR_INVALID_SEQ            0x04
15
0
#define FIDO_ERR_TIMEOUT                0x05
16
0
#define FIDO_ERR_CHANNEL_BUSY           0x06
17
0
#define FIDO_ERR_LOCK_REQUIRED          0x0a
18
0
#define FIDO_ERR_INVALID_CHANNEL        0x0b
19
0
#define FIDO_ERR_CBOR_UNEXPECTED_TYPE   0x11
20
15
#define FIDO_ERR_INVALID_CBOR           0x12
21
0
#define FIDO_ERR_MISSING_PARAMETER      0x14
22
0
#define FIDO_ERR_LIMIT_EXCEEDED         0x15
23
0
#define FIDO_ERR_UNSUPPORTED_EXTENSION  0x16
24
253
#define FIDO_ERR_CREDENTIAL_EXCLUDED    0x19
25
0
#define FIDO_ERR_PROCESSING             0x21
26
0
#define FIDO_ERR_INVALID_CREDENTIAL     0x22
27
0
#define FIDO_ERR_USER_ACTION_PENDING    0x23
28
0
#define FIDO_ERR_OPERATION_PENDING      0x24
29
0
#define FIDO_ERR_NO_OPERATIONS          0x25
30
0
#define FIDO_ERR_UNSUPPORTED_ALGORITHM  0x26
31
0
#define FIDO_ERR_OPERATION_DENIED       0x27
32
0
#define FIDO_ERR_KEY_STORE_FULL         0x28
33
0
#define FIDO_ERR_NOT_BUSY               0x29
34
0
#define FIDO_ERR_NO_OPERATION_PENDING   0x2a
35
33
#define FIDO_ERR_UNSUPPORTED_OPTION     0x2b
36
0
#define FIDO_ERR_INVALID_OPTION         0x2c
37
0
#define FIDO_ERR_KEEPALIVE_CANCEL       0x2d
38
1
#define FIDO_ERR_NO_CREDENTIALS         0x2e
39
0
#define FIDO_ERR_USER_ACTION_TIMEOUT    0x2f
40
0
#define FIDO_ERR_NOT_ALLOWED            0x30
41
0
#define FIDO_ERR_PIN_INVALID            0x31
42
0
#define FIDO_ERR_PIN_BLOCKED            0x32
43
0
#define FIDO_ERR_PIN_AUTH_INVALID       0x33
44
0
#define FIDO_ERR_PIN_AUTH_BLOCKED       0x34
45
0
#define FIDO_ERR_PIN_NOT_SET            0x35
46
0
#define FIDO_ERR_PIN_REQUIRED           0x36
47
9
#define FIDO_ERR_PIN_POLICY_VIOLATION   0x37
48
0
#define FIDO_ERR_PIN_TOKEN_EXPIRED      0x38
49
0
#define FIDO_ERR_REQUEST_TOO_LARGE      0x39
50
0
#define FIDO_ERR_ACTION_TIMEOUT         0x3a
51
0
#define FIDO_ERR_UP_REQUIRED            0x3b
52
0
#define FIDO_ERR_ERR_OTHER              0x7f
53
0
#define FIDO_ERR_SPEC_LAST              0xdf
54
55
/* defined internally */
56
254k
#define FIDO_OK                         FIDO_ERR_SUCCESS
57
1.33k
#define FIDO_ERR_TX                     -1
58
6.37k
#define FIDO_ERR_RX                     -2
59
86
#define FIDO_ERR_RX_NOT_CBOR            -3
60
1.13k
#define FIDO_ERR_RX_INVALID_CBOR        -4
61
40
#define FIDO_ERR_INVALID_PARAM          -5
62
114
#define FIDO_ERR_INVALID_SIG            -6
63
81.9k
#define FIDO_ERR_INVALID_ARGUMENT       -7
64
0
#define FIDO_ERR_USER_PRESENCE_REQUIRED -8
65
11.4k
#define FIDO_ERR_INTERNAL               -9
66
67
const char *fido_strerr(int);
68
69
#endif /* _FIDO_ERR_H */
/home/pedro/projects/libfido2/src/fido/param.h
Line
Count
Source
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
#ifndef _FIDO_PARAM_H
8
#define _FIDO_PARAM_H
9
10
/* Authentication data flags. */
11
150
#define CTAP_AUTHDATA_USER_PRESENT      0x01
12
14
#define CTAP_AUTHDATA_USER_VERIFIED     0x04
13
388
#define CTAP_AUTHDATA_ATT_CRED          0x40
14
486
#define CTAP_AUTHDATA_EXT_DATA          0x80
15
16
/* CTAPHID command opcodes. */
17
#define CTAP_CMD_PING                   0x01
18
630
#define CTAP_CMD_MSG                    0x03
19
#define CTAP_CMD_LOCK                   0x04
20
19.8k
#define CTAP_CMD_INIT                   0x06
21
#define CTAP_CMD_WINK                   0x08
22
13.8k
#define CTAP_CMD_CBOR                   0x10
23
915
#define CTAP_CMD_CANCEL                 0x11
24
14.2k
#define CTAP_KEEPALIVE                  0x3b
25
49.5k
#define CTAP_FRAME_INIT                 0x80
26
27
/* CTAPHID CBOR command opcodes. */
28
175
#define CTAP_CBOR_MAKECRED              0x01
29
85
#define CTAP_CBOR_ASSERT                0x02
30
163
#define CTAP_CBOR_GETINFO               0x04
31
4.93k
#define CTAP_CBOR_CLIENT_PIN            0x06
32
38
#define CTAP_CBOR_RESET                 0x07
33
35
#define CTAP_CBOR_NEXT_ASSERT           0x08
34
616
#define CTAP_CBOR_BIO_ENROLL_PRE        0x40
35
1.15k
#define CTAP_CBOR_CRED_MGMT_PRE         0x41
36
37
/* U2F command opcodes. */
38
64
#define U2F_CMD_REGISTER                0x01
39
507
#define U2F_CMD_AUTH                    0x02
40
41
/* U2F command flags. */
42
151
#define U2F_AUTH_SIGN                   0x03
43
356
#define U2F_AUTH_CHECK                  0x07
44
45
/* ISO7816-4 status words. */
46
1.30k
#define SW_CONDITIONS_NOT_SATISFIED     0x6985
47
80
#define SW_WRONG_DATA                   0x6a80
48
168
#define SW_NO_ERROR                     0x9000
49
50
/* HID Broadcast channel ID. */
51
9.99k
#define CTAP_CID_BROADCAST              0xffffffff
52
53
/* Expected size of a HID report in bytes. */
54
#define CTAP_RPT_SIZE                   64
55
56
/* Randomness device on UNIX-like platforms. */
57
#ifndef FIDO_RANDOM_DEV
58
9.99k
#define FIDO_RANDOM_DEV                 "/dev/urandom"
59
#endif
60
61
/* CTAP capability bits. */
62
#define FIDO_CAP_WINK   0x01 /* if set, device supports CTAP_CMD_WINK */
63
2.68k
#define FIDO_CAP_CBOR   0x04 /* if set, device supports CTAP_CMD_CBOR */
64
#define FIDO_CAP_NMSG   0x08 /* if set, device doesn't support CTAP_CMD_MSG */
65
66
/* Supported COSE algorithms. */
67
5.16k
#define COSE_ES256      -7
68
1.29k
#define COSE_EDDSA      -8
69
23
#define COSE_ECDH_ES256 -25
70
1.54k
#define COSE_RS256      -257
71
72
/* Supported COSE types. */
73
462
#define COSE_KTY_OKP    1
74
792
#define COSE_KTY_EC2    2
75
25
#define COSE_KTY_RSA    3
76
77
/* Supported curves. */
78
389
#define COSE_P256       1
79
226
#define COSE_ED25519    6
80
81
/* Supported extensions. */
82
15.6k
#define FIDO_EXT_HMAC_SECRET    0x01
83
84
#endif /* !_FIDO_PARAM_H */
/home/pedro/projects/libfido2/src/hid.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 <string.h>
8
#include "fido.h"
9
10
fido_dev_info_t *
11
fido_dev_info_new(size_t n)
12
0
{
13
0
        return (calloc(n, sizeof(fido_dev_info_t)));
14
0
}
15
16
void
17
fido_dev_info_free(fido_dev_info_t **devlist_p, size_t n)
18
0
{
19
0
        fido_dev_info_t *devlist;
20
0
21
0
        if (devlist_p == NULL || (devlist = *devlist_p) == NULL)
22
0
                return;
23
0
24
0
        for (size_t i = 0; i < n; i++) {
25
0
                const fido_dev_info_t *di = &devlist[i];
26
0
                free(di->path);
27
0
                free(di->manufacturer);
28
0
                free(di->product);
29
0
        }
30
0
31
0
        free(devlist);
32
0
33
0
        *devlist_p = NULL;
34
0
}
35
36
const fido_dev_info_t *
37
fido_dev_info_ptr(const fido_dev_info_t *devlist, size_t i)
38
0
{
39
0
        return (&devlist[i]);
40
0
}
41
42
const char *
43
fido_dev_info_path(const fido_dev_info_t *di)
44
0
{
45
0
        return (di->path);
46
0
}
47
48
int16_t
49
fido_dev_info_vendor(const fido_dev_info_t *di)
50
0
{
51
0
        return (di->vendor_id);
52
0
}
53
54
int16_t
55
fido_dev_info_product(const fido_dev_info_t *di)
56
0
{
57
0
        return (di->product_id);
58
0
}
59
60
const char *
61
fido_dev_info_manufacturer_string(const fido_dev_info_t *di)
62
0
{
63
0
        return (di->manufacturer);
64
0
}
65
66
const char *
67
fido_dev_info_product_string(const fido_dev_info_t *di)
68
0
{
69
0
        return (di->product);
70
0
}
/home/pedro/projects/libfido2/src/hid_linux.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2019 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 <sys/types.h>
8
9
#include <sys/ioctl.h>
10
#include <linux/hidraw.h>
11
12
#include <fcntl.h>
13
#include <libudev.h>
14
#include <string.h>
15
#include <unistd.h>
16
17
#include "fido.h"
18
19
0
#define REPORT_LEN      65
20
21
static int
22
get_key_len(uint8_t tag, uint8_t *key, size_t *key_len)
23
0
{
24
0
        *key = tag & 0xfc;
25
0
        if ((*key & 0xf0) == 0xf0) {
26
0
                fido_log_debug("%s: *key=0x%02x", __func__, *key);
27
0
                return (-1);
28
0
        }
29
0
30
0
        *key_len = tag & 0x3;
31
0
        if (*key_len == 3) {
32
0
                *key_len = 4;
33
0
        }
34
0
35
0
        return (0);
36
0
}
37
38
static int
39
get_key_val(const void *body, size_t key_len, uint32_t *val)
40
0
{
41
0
        const uint8_t *ptr = body;
42
0
43
0
        switch (key_len) {
44
0
        case 0:
45
0
                *val = 0;
46
0
                break;
47
0
        case 1:
48
0
                *val = ptr[0];
49
0
                break;
50
0
        case 2:
51
0
                *val = (uint32_t)((ptr[1] << 8) | ptr[0]);
52
0
                break;
53
0
        default:
54
0
                fido_log_debug("%s: key_len=%zu", __func__, key_len);
55
0
                return (-1);
56
0
        }
57
0
58
0
        return (0);
59
0
}
60
61
static int
62
get_usage_info(const struct hidraw_report_descriptor *hrd, uint32_t *usage_page,
63
    uint32_t *usage)
64
0
{
65
0
        const uint8_t   *ptr;
66
0
        size_t           len;
67
0
68
0
        ptr = hrd->value;
69
0
        len = hrd->size;
70
0
71
0
        while (len > 0) {
72
0
                const uint8_t tag = ptr[0];
73
0
                ptr++;
74
0
                len--;
75
0
76
0
                uint8_t  key;
77
0
                size_t   key_len;
78
0
                uint32_t key_val;
79
0
80
0
                if (get_key_len(tag, &key, &key_len) < 0 || key_len > len ||
81
0
                    get_key_val(ptr, key_len, &key_val) < 0) {
82
0
                        return (-1);
83
0
                }
84
0
85
0
                if (key == 0x4) {
86
0
                        *usage_page = key_val;
87
0
                } else if (key == 0x8) {
88
0
                        *usage = key_val;
89
0
                }
90
0
91
0
                ptr += key_len;
92
0
                len -= key_len;
93
0
        }
94
0
95
0
        return (0);
96
0
}
97
98
static int
99
get_report_descriptor(const char *path, struct hidraw_report_descriptor *hrd)
100
0
{
101
0
        int     r;
102
0
        int     s = -1;
103
0
        int     fd;
104
0
        int     ok = -1;
105
0
106
0
        if ((fd = open(path, O_RDONLY)) < 0) {
107
0
                fido_log_debug("%s: open", __func__);
108
0
                return (-1);
109
0
        }
110
0
111
0
        if ((r = ioctl(fd, HIDIOCGRDESCSIZE, &s)) < 0 || s < 0 ||
112
0
            (unsigned)s > HID_MAX_DESCRIPTOR_SIZE) {
113
0
                fido_log_debug("%s: ioctl HIDIOCGRDESCSIZE", __func__);
114
0
                goto fail;
115
0
        }
116
0
117
0
        hrd->size = s;
118
0
119
0
        if ((r = ioctl(fd, HIDIOCGRDESC, hrd)) < 0) {
120
0
                fido_log_debug("%s: ioctl HIDIOCGRDESC", __func__);
121
0
                goto fail;
122
0
        }
123
0
124
0
        ok = 0;
125
0
fail:
126
0
        if (fd != -1)
127
0
                close(fd);
128
0
129
0
        return (ok);
130
0
}
131
132
static bool
133
is_fido(const char *path)
134
0
{
135
0
        uint32_t                        usage = 0;
136
0
        uint32_t                        usage_page = 0;
137
0
        struct hidraw_report_descriptor hrd;
138
0
139
0
        memset(&hrd, 0, sizeof(hrd));
140
0
141
0
        if (get_report_descriptor(path, &hrd) < 0 ||
142
0
            get_usage_info(&hrd, &usage_page, &usage) < 0) {
143
0
                return (false);
144
0
        }
145
0
146
0
        return (usage_page == 0xf1d0);
147
0
}
148
149
static int
150
parse_uevent(struct udev_device *dev, int16_t *vendor_id, int16_t *product_id)
151
0
{
152
0
        const char              *uevent;
153
0
        char                    *cp;
154
0
        char                    *p;
155
0
        char                    *s;
156
0
        int                      ok = -1;
157
0
        short unsigned int       x;
158
0
        short unsigned int       y;
159
0
160
0
        if ((uevent = udev_device_get_sysattr_value(dev, "uevent")) == NULL)
161
0
                return (-1);
162
0
163
0
        if ((s = cp = strdup(uevent)) == NULL)
164
0
                return (-1);
165
0
166
0
        for ((p = strsep(&cp, "\n")); p && *p != '\0'; (p = strsep(&cp, "\n"))) {
167
0
                if (strncmp(p, "HID_ID=", 7) == 0) {
168
0
                        if (sscanf(p + 7, "%*x:%hx:%hx", &x, &y) == 2) {
169
0
                                *vendor_id = (int16_t)x;
170
0
                                *product_id = (int16_t)y;
171
0
                                ok = 0;
172
0
                        }
173
0
                        break;
174
0
                }
175
0
        }
176
0
177
0
        free(s);
178
0
179
0
        return (ok);
180
0
}
181
182
static int
183
copy_info(fido_dev_info_t *di, struct udev *udev,
184
    struct udev_list_entry *udev_entry)
185
0
{
186
0
        const char              *name;
187
0
        const char              *path;
188
0
        const char              *manufacturer;
189
0
        const char              *product;
190
0
        struct udev_device      *dev = NULL;
191
0
        struct udev_device      *hid_parent;
192
0
        struct udev_device      *usb_parent;
193
0
        int                      ok = -1;
194
0
195
0
        memset(di, 0, sizeof(*di));
196
0
197
0
        if ((name = udev_list_entry_get_name(udev_entry)) == NULL ||
198
0
            (dev = udev_device_new_from_syspath(udev, name)) == NULL ||
199
0
            (path = udev_device_get_devnode(dev)) == NULL ||
200
0
            is_fido(path) == 0)
201
0
                goto fail;
202
0
203
0
        if ((hid_parent = udev_device_get_parent_with_subsystem_devtype(dev,
204
0
            "hid", NULL)) == NULL)
205
0
                goto fail;
206
0
207
0
        if ((usb_parent = udev_device_get_parent_with_subsystem_devtype(dev,
208
0
            "usb", "usb_device")) == NULL)
209
0
                goto fail;
210
0
211
0
        if (parse_uevent(hid_parent, &di->vendor_id, &di->product_id) < 0 ||
212
0
            (manufacturer = udev_device_get_sysattr_value(usb_parent,
213
0
            "manufacturer")) == NULL ||
214
0
            (product = udev_device_get_sysattr_value(usb_parent,
215
0
            "product")) == NULL)
216
0
                goto fail;
217
0
218
0
        di->path = strdup(path);
219
0
        di->manufacturer = strdup(manufacturer);
220
0
        di->product = strdup(product);
221
0
222
0
        if (di->path == NULL ||
223
0
            di->manufacturer == NULL ||
224
0
            di->product == NULL)
225
0
                goto fail;
226
0
227
0
        ok = 0;
228
0
fail:
229
0
        if (dev != NULL)
230
0
                udev_device_unref(dev);
231
0
232
0
        if (ok < 0) {
233
0
                free(di->path);
234
0
                free(di->manufacturer);
235
0
                free(di->product);
236
0
                explicit_bzero(di, sizeof(*di));
237
0
        }
238
0
239
0
        return (ok);
240
0
}
241
242
int
243
fido_dev_info_manifest(fido_dev_info_t *devlist, size_t ilen, size_t *olen)
244
0
{
245
0
        struct udev             *udev = NULL;
246
0
        struct udev_enumerate   *udev_enum = NULL;
247
0
        struct udev_list_entry  *udev_list;
248
0
        struct udev_list_entry  *udev_entry;
249
0
        int                      r = FIDO_ERR_INTERNAL;
250
0
251
0
        *olen = 0;
252
0
253
0
        if (ilen == 0)
254
0
                return (FIDO_OK); /* nothing to do */
255
0
256
0
        if (devlist == NULL)
257
0
                return (FIDO_ERR_INVALID_ARGUMENT);
258
0
259
0
        if ((udev = udev_new()) == NULL ||
260
0
            (udev_enum = udev_enumerate_new(udev)) == NULL)
261
0
                goto fail;
262
0
263
0
        if (udev_enumerate_add_match_subsystem(udev_enum, "hidraw") < 0 ||
264
0
            udev_enumerate_scan_devices(udev_enum) < 0 ||
265
0
            (udev_list = udev_enumerate_get_list_entry(udev_enum)) == NULL)
266
0
                goto fail;
267
0
268
0
        udev_list_entry_foreach(udev_entry, udev_list) {
269
0
                if (copy_info(&devlist[*olen], udev, udev_entry) == 0) {
270
0
                        if (++(*olen) == ilen)
271
0
                                break;
272
0
                }
273
0
        }
274
0
275
0
        r = FIDO_OK;
276
0
fail:
277
0
        if (udev_enum != NULL)
278
0
                udev_enumerate_unref(udev_enum);
279
0
        if (udev != NULL)
280
0
                udev_unref(udev);
281
0
282
0
        return (r);
283
0
}
284
285
void *
286
fido_hid_open(const char *path)
287
0
{
288
0
        int *fd;
289
0
290
0
        if ((fd = malloc(sizeof(*fd))) == NULL ||
291
0
            (*fd = open(path, O_RDWR)) < 0) {
292
0
                free(fd);
293
0
                return (NULL);
294
0
        }
295
0
296
0
        return (fd);
297
0
}
298
299
void
300
fido_hid_close(void *handle)
301
0
{
302
0
        int *fd = handle;
303
0
304
0
        close(*fd);
305
0
        free(fd);
306
0
}
307
308
int
309
fido_hid_read(void *handle, unsigned char *buf, size_t len, int ms)
310
0
{
311
0
        int     *fd = handle;
312
0
        ssize_t  r;
313
0
314
0
        (void)ms; /* XXX */
315
0
316
0
        if (len != REPORT_LEN - 1) {
317
0
                fido_log_debug("%s: invalid len", __func__);
318
0
                return (-1);
319
0
        }
320
0
321
0
        if ((r = read(*fd, buf, len)) < 0 || r != REPORT_LEN - 1)
322
0
                return (-1);
323
0
324
0
        return (REPORT_LEN - 1);
325
0
}
326
327
int
328
fido_hid_write(void *handle, const unsigned char *buf, size_t len)
329
0
{
330
0
        int     *fd = handle;
331
0
        ssize_t  r;
332
0
333
0
        if (len != REPORT_LEN) {
334
0
                fido_log_debug("%s: invalid len", __func__);
335
0
                return (-1);
336
0
        }
337
0
338
0
        if ((r = write(*fd, buf, len)) < 0 || r != REPORT_LEN) {
339
0
                fido_log_debug("%s: write", __func__);
340
0
                return (-1);
341
0
        }
342
0
343
0
        return (REPORT_LEN);
344
0
}
/home/pedro/projects/libfido2/src/info.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 <string.h>
8
#include "fido.h"
9
10
static int
11
decode_version(const cbor_item_t *item, void *arg)
12
285
{
13
285
        fido_str_array_t        *v = arg;
14
285
        const size_t             i = v->len;
15
285
16
285
        /* keep ptr[x] and len consistent */
17
285
        if (cbor_string_copy(item, &v->ptr[i]) < 0) {
18
9
                fido_log_debug("%s: cbor_string_copy", __func__);
19
9
                return (-1);
20
9
        }
21
276
22
276
        v->len++;
23
276
24
276
        return (0);
25
276
}
26
27
static int
28
decode_versions(const cbor_item_t *item, fido_str_array_t *v)
29
89
{
30
89
        v->ptr = NULL;
31
89
        v->len = 0;
32
89
33
89
        if (cbor_isa_array(item) == false ||
34
89
            cbor_array_is_definite(item) == false) {
35
2
                fido_log_debug("%s: cbor type", __func__);
36
2
                return (-1);
37
2
        }
38
87
39
87
        v->ptr = calloc(cbor_array_size(item), sizeof(char *));
40
87
        if (v->ptr == NULL)
41
87
                return (-1);
42
86
43
86
        if (cbor_array_iter(item, v, decode_version) < 0) {
44
9
                fido_log_debug("%s: decode_version", __func__);
45
9
                return (-1);
46
9
        }
47
77
48
77
        return (0);
49
77
}
50
51
static int
52
decode_extension(const cbor_item_t *item, void *arg)
53
199
{
54
199
        fido_str_array_t        *e = arg;
55
199
        const size_t             i = e->len;
56
199
57
199
        /* keep ptr[x] and len consistent */
58
199
        if (cbor_string_copy(item, &e->ptr[i]) < 0) {
59
4
                fido_log_debug("%s: cbor_string_copy", __func__);
60
4
                return (-1);
61
4
        }
62
195
63
195
        e->len++;
64
195
65
195
        return (0);
66
195
}
67
68
static int
69
decode_extensions(const cbor_item_t *item, fido_str_array_t *e)
70
71
{
71
71
        e->ptr = NULL;
72
71
        e->len = 0;
73
71
74
71
        if (cbor_isa_array(item) == false ||
75
71
            cbor_array_is_definite(item) == false) {
76
2
                fido_log_debug("%s: cbor type", __func__);
77
2
                return (-1);
78
2
        }
79
69
80
69
        e->ptr = calloc(cbor_array_size(item), sizeof(char *));
81
69
        if (e->ptr == NULL)
82
69
                return (-1);
83
68
84
68
        if (cbor_array_iter(item, e, decode_extension) < 0) {
85
5
                fido_log_debug("%s: decode_extension", __func__);
86
5
                return (-1);
87
5
        }
88
63
89
63
        return (0);
90
63
}
91
92
static int
93
decode_aaguid(const cbor_item_t *item, unsigned char *aaguid, size_t aaguid_len)
94
53
{
95
53
        if (cbor_isa_bytestring(item) == false ||
96
53
            cbor_bytestring_is_definite(item) == false ||
97
53
            cbor_bytestring_length(item) != aaguid_len) {
98
3
                fido_log_debug("%s: cbor type", __func__);
99
3
                return (-1);
100
3
        }
101
50
102
50
        memcpy(aaguid, cbor_bytestring_handle(item), aaguid_len);
103
50
104
50
        return (0);
105
50
}
106
107
static int
108
decode_option(const cbor_item_t *key, const cbor_item_t *val, void *arg)
109
184
{
110
184
        fido_opt_array_t        *o = arg;
111
184
        const size_t             i = o->len;
112
184
113
184
        if (cbor_isa_float_ctrl(val) == false ||
114
184
            cbor_float_get_width(val) != CBOR_FLOAT_0 ||
115
184
            cbor_is_bool(val) == false) {
116
39
                fido_log_debug("%s: cbor type", __func__);
117
39
                return (0); /* ignore */
118
39
        }
119
145
120
145
        if (cbor_string_copy(key, &o->name[i]) < 0) {
121
15
                fido_log_debug("%s: cbor_string_copy", __func__);
122
15
                return (0); /* ignore */
123
15
        }
124
130
125
130
        /* keep name/value and len consistent */
126
130
        o->value[i] = cbor_ctrl_value(val) == CBOR_CTRL_TRUE;
127
130
        o->len++;
128
130
129
130
        return (0);
130
130
}
131
132
static int
133
decode_options(const cbor_item_t *item, fido_opt_array_t *o)
134
47
{
135
47
        o->name = NULL;
136
47
        o->value = NULL;
137
47
        o->len = 0;
138
47
139
47
        if (cbor_isa_map(item) == false ||
140
47
            cbor_map_is_definite(item) == false) {
141
2
                fido_log_debug("%s: cbor type", __func__);
142
2
                return (-1);
143
2
        }
144
45
145
45
        o->name = calloc(cbor_map_size(item), sizeof(char *));
146
45
        o->value = calloc(cbor_map_size(item), sizeof(bool));
147
45
        if (o->name == NULL || o->value == NULL)
148
45
                return (-1);
149
43
150
43
        return (cbor_map_iter(item, o, decode_option));
151
43
}
152
153
static int
154
decode_protocol(const cbor_item_t *item, void *arg)
155
113
{
156
113
        fido_byte_array_t       *p = arg;
157
113
        const size_t             i = p->len;
158
113
159
113
        if (cbor_isa_uint(item) == false ||
160
113
            cbor_int_get_width(item) != CBOR_INT_8) {
161
7
                fido_log_debug("%s: cbor type", __func__);
162
7
                return (-1);
163
7
        }
164
106
165
106
        /* keep ptr[x] and len consistent */
166
106
        p->ptr[i] = cbor_get_uint8(item);
167
106
        p->len++;
168
106
169
106
        return (0);
170
106
}
171
172
static int
173
decode_protocols(const cbor_item_t *item, fido_byte_array_t *p)
174
26
{
175
26
        p->ptr = NULL;
176
26
        p->len = 0;
177
26
178
26
        if (cbor_isa_array(item) == false ||
179
26
            cbor_array_is_definite(item) == false) {
180
2
                fido_log_debug("%s: cbor type", __func__);
181
2
                return (-1);
182
2
        }
183
24
184
24
        p->ptr = calloc(cbor_array_size(item), sizeof(uint8_t));
185
24
        if (p->ptr == NULL)
186
24
                return (-1);
187
23
188
23
        if (cbor_array_iter(item, p, decode_protocol) < 0) {
189
7
                fido_log_debug("%s: decode_protocol", __func__);
190
7
                return (-1);
191
7
        }
192
16
193
16
        return (0);
194
16
}
195
196
static int
197
parse_reply_element(const cbor_item_t *key, const cbor_item_t *val, void *arg)
198
455
{
199
455
        fido_cbor_info_t *ci = arg;
200
455
201
455
        if (cbor_isa_uint(key) == false ||
202
455
            cbor_int_get_width(key) != CBOR_INT_8) {
203
93
                fido_log_debug("%s: cbor type", __func__);
204
93
                return (0); /* ignore */
205
93
        }
206
362
207
362
        switch (cbor_get_uint8(key)) {
208
362
        case 1: /* versions */
209
89
                return (decode_versions(val, &ci->versions));
210
362
        case 2: /* extensions */
211
71
                return (decode_extensions(val, &ci->extensions));
212
362
        case 3: /* aaguid */
213
53
                return (decode_aaguid(val, ci->aaguid, sizeof(ci->aaguid)));
214
362
        case 4: /* options */
215
47
                return (decode_options(val, &ci->options));
216
362
        case 5: /* maxMsgSize */
217
26
                return (cbor_decode_uint64(val, &ci->maxmsgsiz));
218
362
        case 6: /* pinProtocols */
219
26
                return (decode_protocols(val, &ci->protocols));
220
362
        default: /* ignore */
221
50
                fido_log_debug("%s: cbor type", __func__);
222
50
                return (0);
223
362
        }
224
362
}
225
226
static int
227
fido_dev_get_cbor_info_tx(fido_dev_t *dev)
228
163
{
229
163
        const unsigned char     cbor[] = { CTAP_CBOR_GETINFO };
230
163
        const uint8_t           cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
231
163
232
163
        fido_log_debug("%s: dev=%p", __func__, (void *)dev);
233
163
234
163
        if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) {
235
1
                fido_log_debug("%s: fido_tx", __func__);
236
1
                return (FIDO_ERR_TX);
237
1
        }
238
162
239
162
        return (FIDO_OK);
240
162
}
241
242
static int
243
fido_dev_get_cbor_info_rx(fido_dev_t *dev, fido_cbor_info_t *ci, int ms)
244
162
{
245
162
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
246
162
        unsigned char   reply[512];
247
162
        int             reply_len;
248
162
249
162
        fido_log_debug("%s: dev=%p, ci=%p, ms=%d", __func__, (void *)dev,
250
162
            (void *)ci, ms);
251
162
252
162
        memset(ci, 0, sizeof(*ci));
253
162
254
162
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
255
28
                fido_log_debug("%s: fido_rx", __func__);
256
28
                return (FIDO_ERR_RX);
257
28
        }
258
134
259
134
        return (cbor_parse_reply(reply, (size_t)reply_len, ci,
260
134
            parse_reply_element));
261
134
}
262
263
static int
264
fido_dev_get_cbor_info_wait(fido_dev_t *dev, fido_cbor_info_t *ci, int ms)
265
163
{
266
163
        int r;
267
163
268
163
        if ((r = fido_dev_get_cbor_info_tx(dev)) != FIDO_OK ||
269
163
            (r = fido_dev_get_cbor_info_rx(dev, ci, ms)) != FIDO_OK)
270
163
                return (r);
271
12
272
12
        return (FIDO_OK);
273
12
}
274
275
int
276
fido_dev_get_cbor_info(fido_dev_t *dev, fido_cbor_info_t *ci)
277
163
{
278
163
        return (fido_dev_get_cbor_info_wait(dev, ci, -1));
279
163
}
280
281
/*
282
 * get/set functions for fido_cbor_info_t; always at the end of the file
283
 */
284
285
fido_cbor_info_t *
286
fido_cbor_info_new(void)
287
164
{
288
164
        return (calloc(1, sizeof(fido_cbor_info_t)));
289
164
}
290
291
static void
292
free_str_array(fido_str_array_t *sa)
293
326
{
294
797
        for (size_t i = 0; i < sa->len; i++)
295
471
                free(sa->ptr[i]);
296
326
297
326
        free(sa->ptr);
298
326
        sa->ptr = NULL;
299
326
        sa->len = 0;
300
326
}
301
302
static void
303
free_opt_array(fido_opt_array_t *oa)
304
163
{
305
293
        for (size_t i = 0; i < oa->len; i++)
306
130
                free(oa->name[i]);
307
163
308
163
        free(oa->name);
309
163
        free(oa->value);
310
163
        oa->name = NULL;
311
163
        oa->value = NULL;
312
163
}
313
314
static void
315
free_byte_array(fido_byte_array_t *ba)
316
163
{
317
163
        free(ba->ptr);
318
163
319
163
        ba->ptr = NULL;
320
163
        ba->len = 0;
321
163
}
322
323
void
324
fido_cbor_info_free(fido_cbor_info_t **ci_p)
325
163
{
326
163
        fido_cbor_info_t *ci;
327
163
328
163
        if (ci_p == NULL || (ci = *ci_p) ==  NULL)
329
163
                return;
330
163
331
163
        free_str_array(&ci->versions);
332
163
        free_str_array(&ci->extensions);
333
163
        free_opt_array(&ci->options);
334
163
        free_byte_array(&ci->protocols);
335
163
        free(ci);
336
163
337
163
        *ci_p = NULL;
338
163
}
339
340
char **
341
fido_cbor_info_versions_ptr(const fido_cbor_info_t *ci)
342
276
{
343
276
        return (ci->versions.ptr);
344
276
}
345
346
size_t
347
fido_cbor_info_versions_len(const fido_cbor_info_t *ci)
348
439
{
349
439
        return (ci->versions.len);
350
439
}
351
352
char **
353
fido_cbor_info_extensions_ptr(const fido_cbor_info_t *ci)
354
195
{
355
195
        return (ci->extensions.ptr);
356
195
}
357
358
size_t
359
fido_cbor_info_extensions_len(const fido_cbor_info_t *ci)
360
358
{
361
358
        return (ci->extensions.len);
362
358
}
363
364
const unsigned char *
365
fido_cbor_info_aaguid_ptr(const fido_cbor_info_t *ci)
366
163
{
367
163
        return (ci->aaguid);
368
163
}
369
370
size_t
371
fido_cbor_info_aaguid_len(const fido_cbor_info_t *ci)
372
163
{
373
163
        return (sizeof(ci->aaguid));
374
163
}
375
376
char **
377
fido_cbor_info_options_name_ptr(const fido_cbor_info_t *ci)
378
130
{
379
130
        return (ci->options.name);
380
130
}
381
382
const bool *
383
fido_cbor_info_options_value_ptr(const fido_cbor_info_t *ci)
384
130
{
385
130
        return (ci->options.value);
386
130
}
387
388
size_t
389
fido_cbor_info_options_len(const fido_cbor_info_t *ci)
390
293
{
391
293
        return (ci->options.len);
392
293
}
393
394
uint64_t
395
fido_cbor_info_maxmsgsiz(const fido_cbor_info_t *ci)
396
163
{
397
163
        return (ci->maxmsgsiz);
398
163
}
399
400
const uint8_t *
401
fido_cbor_info_protocols_ptr(const fido_cbor_info_t *ci)
402
163
{
403
163
        return (ci->protocols.ptr);
404
163
}
405
406
size_t
407
fido_cbor_info_protocols_len(const fido_cbor_info_t *ci)
408
163
{
409
163
        return (ci->protocols.len);
410
163
}
/home/pedro/projects/libfido2/src/io.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 <stdint.h>
8
#include <stdio.h>
9
#include <string.h>
10
11
#include "fido.h"
12
#include "packed.h"
13
14
PACKED_TYPE(frame_t,
15
struct frame {
16
        uint32_t cid; /* channel id */
17
        union {
18
                uint8_t type;
19
                struct {
20
                        uint8_t cmd;
21
                        uint8_t bcnth;
22
                        uint8_t bcntl;
23
                        uint8_t data[CTAP_RPT_SIZE - 7];
24
                } init;
25
                struct {
26
                        uint8_t seq;
27
                        uint8_t data[CTAP_RPT_SIZE - 5];
28
                } cont;
29
        } body;
30
})
31
32
#ifndef MIN
33
27.2k
#define MIN(x, y) ((x) > (y) ? (y) : (x))
34
#endif
35
36
static size_t
37
tx_preamble(fido_dev_t *d,  uint8_t cmd, const void *buf, size_t count)
38
19.3k
{
39
19.3k
        struct frame    *fp;
40
19.3k
        unsigned char   pkt[sizeof(*fp) + 1];
41
19.3k
        int             n;
42
19.3k
43
19.3k
        if (d->io.write == NULL || (cmd & 0x80) == 0)
44
0
                return (0);
45
19.3k
46
19.3k
        memset(&pkt, 0, sizeof(pkt));
47
19.3k
        fp = (struct frame *)(pkt + 1);
48
19.3k
        fp->cid = d->cid;
49
19.3k
        fp->body.init.cmd = 0x80 | cmd;
50
19.3k
        fp->body.init.bcnth = (count >> 8) & 0xff;
51
19.3k
        fp->body.init.bcntl = count & 0xff;
52
19.3k
        count = MIN(count, sizeof(fp->body.init.data));
53
19.3k
        if (count)
54
18.4k
                memcpy(&fp->body.init.data, buf, count);
55
19.3k
56
19.3k
        n = d->io.write(d->io_handle, pkt, sizeof(pkt));
57
19.3k
        if (n < 0 || (size_t)n != sizeof(pkt))
58
89
                return (0);
59
19.2k
60
19.2k
        return (count);
61
19.2k
}
62
63
static size_t
64
tx_frame(fido_dev_t *d, int seq, const void *buf, size_t count)
65
7.90k
{
66
7.90k
        struct frame    *fp;
67
7.90k
        unsigned char    pkt[sizeof(*fp) + 1];
68
7.90k
        int              n;
69
7.90k
70
7.90k
        if (d->io.write == NULL || seq < 0 || seq > UINT8_MAX)
71
7.90k
                return (0);
72
7.90k
73
7.90k
        memset(&pkt, 0, sizeof(pkt));
74
7.90k
        fp = (struct frame *)(pkt + 1);
75
7.90k
        fp->cid = d->cid;
76
7.90k
        fp->body.cont.seq = (uint8_t)seq;
77
7.90k
        count = MIN(count, sizeof(fp->body.cont.data));
78
7.90k
        memcpy(&fp->body.cont.data, buf, count);
79
7.90k
80
7.90k
        n = d->io.write(d->io_handle, pkt, sizeof(pkt));
81
7.90k
        if (n < 0 || (size_t)n != sizeof(pkt))
82
30
                return (0);
83
7.87k
84
7.87k
        return (count);
85
7.87k
}
86
87
int
88
fido_tx(fido_dev_t *d, uint8_t cmd, const void *buf, size_t count)
89
19.3k
{
90
19.3k
        int     seq = 0;
91
19.3k
        size_t  sent;
92
19.3k
93
19.3k
        fido_log_debug("%s: d=%p, cmd=0x%02x, buf=%p, count=%zu", __func__,
94
19.3k
            (void *)d, cmd, buf, count);
95
19.3k
        fido_log_xxd(buf, count);
96
19.3k
97
19.3k
        if (d->io_handle == NULL || count > UINT16_MAX) {
98
2
                fido_log_debug("%s: invalid argument (%p, %zu)", __func__,
99
2
                    d->io_handle, count);
100
2
                return (-1);
101
2
        }
102
19.3k
103
19.3k
        if ((sent = tx_preamble(d, cmd, buf, count)) == 0) {
104
991
                fido_log_debug("%s: tx_preamble", __func__);
105
991
                return (-1);
106
991
        }
107
18.3k
108
26.2k
        while (sent < count) {
109
7.91k
                if (seq & 0x80) {
110
3
                        fido_log_debug("%s: seq & 0x80", __func__);
111
3
                        return (-1);
112
3
                }
113
7.90k
                const uint8_t *p = (const uint8_t *)buf + sent;
114
7.90k
                size_t n = tx_frame(d, seq++, p, count - sent);
115
7.90k
                if (n == 0) {
116
30
                        fido_log_debug("%s: tx_frame", __func__);
117
30
                        return (-1);
118
30
                }
119
7.87k
                sent += n;
120
7.87k
        }
121
18.3k
122
18.3k
        return (0);
123
18.3k
}
124
125
static int
126
rx_frame(fido_dev_t *d, struct frame *fp, int ms)
127
29.2k
{
128
29.2k
        int n;
129
29.2k
130
29.2k
        if (d->io.read == NULL)
131
29.2k
                return (-1);
132
29.2k
133
29.2k
        n = d->io.read(d->io_handle, (unsigned char *)fp, sizeof(*fp), ms);
134
29.2k
        if (n < 0 || (size_t)n != sizeof(*fp))
135
5.52k
                return (-1);
136
23.7k
137
23.7k
        return (0);
138
23.7k
}
139
140
static int
141
rx_preamble(fido_dev_t *d, struct frame *fp, int ms)
142
18.2k
{
143
19.6k
        do {
144
19.6k
                if (rx_frame(d, fp, ms) < 0)
145
5.39k
                        return (-1);
146
14.2k
#ifdef FIDO_FUZZ
147
14.2k
                fp->cid = d->cid;
148
14.2k
#endif
149
14.2k
        } while (fp->cid == d->cid &&
150
14.2k
            fp->body.init.cmd == (CTAP_FRAME_INIT | CTAP_KEEPALIVE));
151
18.2k
152
18.2k
        return (0);
153
18.2k
}
154
155
int
156
fido_rx(fido_dev_t *d, uint8_t cmd, void *buf, size_t count, int ms)
157
18.2k
{
158
18.2k
        struct frame    f;
159
18.2k
        uint16_t        r;
160
18.2k
        uint16_t        flen;
161
18.2k
        int             seq;
162
18.2k
163
18.2k
        if (d->io_handle == NULL || (cmd & 0x80) == 0) {
164
0
                fido_log_debug("%s: invalid argument (%p, 0x%02x)", __func__,
165
0
                    d->io_handle, cmd);
166
0
                return (-1);
167
0
        }
168
18.2k
169
18.2k
        if (rx_preamble(d, &f, ms) < 0) {
170
5.39k
                fido_log_debug("%s: rx_preamble", __func__);
171
5.39k
                return (-1);
172
5.39k
        }
173
12.9k
174
12.9k
        fido_log_debug("%s: initiation frame at %p, len %zu", __func__,
175
12.9k
            (void *)&f, sizeof(f));
176
12.9k
        fido_log_xxd(&f, sizeof(f));
177
12.9k
178
12.9k
#ifdef FIDO_FUZZ
179
12.9k
        f.cid = d->cid;
180
12.9k
        f.body.init.cmd = cmd;
181
12.9k
#endif
182
12.9k
183
12.9k
        if (f.cid != d->cid || f.body.init.cmd != cmd) {
184
0
                fido_log_debug("%s: cid (0x%x, 0x%x), cmd (0x%02x, 0x%02x)",
185
0
                    __func__, f.cid, d->cid, f.body.init.cmd, cmd);
186
0
                return (-1);
187
0
        }
188
12.9k
189
12.9k
        flen = (f.body.init.bcnth << 8) | f.body.init.bcntl;
190
12.9k
        if (count < (size_t)flen) {
191
387
                fido_log_debug("%s: count < flen (%zu, %zu)", __func__, count,
192
387
                    (size_t)flen);
193
387
                return (-1);
194
387
        }
195
12.5k
        if (flen < sizeof(f.body.init.data)) {
196
8.39k
                memcpy(buf, f.body.init.data, flen);
197
8.39k
                return (flen);
198
8.39k
        }
199
4.12k
200
4.12k
        memcpy(buf, f.body.init.data, sizeof(f.body.init.data));
201
4.12k
        r = sizeof(f.body.init.data);
202
4.12k
        seq = 0;
203
4.12k
204
13.6k
        while ((size_t)r < flen) {
205
9.64k
                if (rx_frame(d, &f, ms) < 0) {
206
131
                        fido_log_debug("%s: rx_frame", __func__);
207
131
                        return (-1);
208
131
                }
209
9.51k
210
9.51k
                fido_log_debug("%s: continuation frame at %p, len %zu",
211
9.51k
                    __func__, (void *)&f, sizeof(f));
212
9.51k
                fido_log_xxd(&f, sizeof(f));
213
9.51k
214
9.51k
#ifdef FIDO_FUZZ
215
9.51k
                f.cid = d->cid;
216
9.51k
                f.body.cont.seq = seq;
217
9.51k
#endif
218
9.51k
219
9.51k
                if (f.cid != d->cid || f.body.cont.seq != seq++) {
220
0
                        fido_log_debug("%s: cid (0x%x, 0x%x), seq (%d, %d)",
221
0
                            __func__, f.cid, d->cid, f.body.cont.seq, seq);
222
0
                        return (-1);
223
0
                }
224
9.51k
225
9.51k
                uint8_t *p = (uint8_t *)buf + r;
226
9.51k
227
9.51k
                if ((size_t)(flen - r) > sizeof(f.body.cont.data)) {
228
5.54k
                        memcpy(p, f.body.cont.data, sizeof(f.body.cont.data));
229
5.54k
                        r += sizeof(f.body.cont.data);
230
5.54k
                } else {
231
3.97k
                        memcpy(p, f.body.cont.data, flen - r);
232
3.97k
                        r += (flen - r); /* break */
233
3.97k
                }
234
9.51k
        }
235
4.12k
236
4.12k
        fido_log_debug("%s: payload at %p, len %zu", __func__, buf, (size_t)r);
237
3.98k
        fido_log_xxd(buf, r);
238
3.98k
239
3.98k
        return (r);
240
4.12k
}
241
242
int
243
fido_rx_cbor_status(fido_dev_t *d, int ms)
244
168
{
245
168
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
246
168
        unsigned char   reply[2048];
247
168
        int             reply_len;
248
168
249
168
        if ((reply_len = fido_rx(d, cmd, &reply, sizeof(reply), ms)) < 0 ||
250
168
            (size_t)reply_len < 1) {
251
143
                fido_log_debug("%s: fido_rx", __func__);
252
143
                return (FIDO_ERR_RX);
253
143
        }
254
25
255
25
        return (reply[0]);
256
25
}
/home/pedro/projects/libfido2/src/iso7816.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 <string.h>
8
#include "fido.h"
9
10
iso7816_apdu_t *
11
iso7816_new(uint8_t ins, uint8_t p1, uint16_t payload_len)
12
571
{
13
571
        iso7816_apdu_t  *apdu;
14
571
        size_t           alloc_len;
15
571
16
571
        alloc_len = sizeof(iso7816_apdu_t) + payload_len;
17
571
18
571
        if ((apdu = calloc(1, alloc_len)) == NULL)
19
571
                return (NULL);
20
566
21
566
        apdu->alloc_len = alloc_len;
22
566
        apdu->payload_len = payload_len;
23
566
        apdu->payload_ptr = apdu->payload;
24
566
        apdu->header.ins = ins;
25
566
        apdu->header.p1 = p1;
26
566
        apdu->header.lc2 = (payload_len >> 8) & 0xff;
27
566
        apdu->header.lc3 = payload_len & 0xff;
28
566
29
566
        return (apdu);
30
566
}
31
32
void
33
iso7816_free(iso7816_apdu_t **apdu_p)
34
586
{
35
586
        iso7816_apdu_t *apdu;
36
586
37
586
        if (apdu_p == NULL || (apdu = *apdu_p) == NULL)
38
586
                return;
39
566
40
566
        explicit_bzero(apdu, apdu->alloc_len);
41
566
        free(apdu);
42
566
43
566
        *apdu_p = NULL;
44
566
}
45
46
int
47
iso7816_add(iso7816_apdu_t *apdu, const void *buf, size_t cnt)
48
2.14k
{
49
2.14k
        if (cnt > apdu->payload_len || cnt > UINT16_MAX)
50
2.14k
                return (-1);
51
2.14k
52
2.14k
        memcpy(apdu->payload_ptr, buf, cnt);
53
2.14k
        apdu->payload_ptr += cnt;
54
2.14k
        apdu->payload_len -= (uint16_t)cnt;
55
2.14k
56
2.14k
        return (0);
57
2.14k
}
58
59
const unsigned char *
60
iso7816_ptr(const iso7816_apdu_t *apdu)
61
1.52k
{
62
1.52k
        return ((const unsigned char *)&apdu->header);
63
1.52k
}
64
65
size_t
66
iso7816_len(const iso7816_apdu_t *apdu)
67
1.52k
{
68
1.52k
        return (apdu->alloc_len - sizeof(apdu->alloc_len) -
69
1.52k
            sizeof(apdu->payload_len) - sizeof(apdu->payload_ptr));
70
1.52k
}
/home/pedro/projects/libfido2/src/log.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 <stdarg.h>
8
#include <stdio.h>
9
#include <stdlib.h>
10
#include "fido.h"
11
12
#ifndef FIDO_NO_DIAGNOSTIC
13
14
#ifndef TLS
15
#define TLS
16
#endif
17
18
static TLS int logging;
19
20
void
21
fido_log_init(void)
22
0
{
23
0
        logging = 1;
24
0
}
25
26
void
27
fido_log_xxd(const void *buf, size_t count)
28
45.7k
{
29
45.7k
        const uint8_t   *ptr = buf;
30
45.7k
        size_t           i;
31
45.7k
32
45.7k
        if (!logging)
33
45.7k
                return;
34
0
35
0
        fprintf(stderr, "  ");
36
0
37
0
        for (i = 0; i < count; i++) {
38
0
                fprintf(stderr, "%02x ", *ptr++);
39
0
                if ((i + 1) % 16 == 0 && i + 1 < count)
40
0
                        fprintf(stderr, "\n  ");
41
0
        }
42
0
43
0
        fprintf(stderr, "\n");
44
0
        fflush(stderr);
45
0
}
46
47
void
48
fido_log_debug(const char *fmt, ...)
49
105k
{
50
105k
        va_list  ap;
51
105k
52
105k
        if (!logging)
53
105k
                return;
54
0
55
0
        va_start(ap, fmt);
56
0
        vfprintf(stderr, fmt, ap);
57
0
        va_end(ap);
58
0
59
0
        fprintf(stderr, "\n");
60
0
        fflush(stderr);
61
0
}
62
63
#endif /* !FIDO_NO_DIAGNOSTIC */
/home/pedro/projects/libfido2/src/pin.c
Line
Count
Source
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 <string.h>
8
#include "fido.h"
9
#include "fido/es256.h"
10
11
static int
12
parse_pintoken(const cbor_item_t *key, const cbor_item_t *val, void *arg)
13
1.35k
{
14
1.35k
        fido_blob_t *token = arg;
15
1.35k
16
1.35k
        if (cbor_isa_uint(key) == false ||
17
1.35k
            cbor_int_get_width(key) != CBOR_INT_8 ||
18
1.35k
            cbor_get_uint8(key) != 2) {
19
478
                fido_log_debug("%s: cbor type", __func__);
20
478
                return (0); /* ignore */
21
478
        }
22
872
23
872
        return (fido_blob_decode(val, token));
24
872
}
25
26
static int
27
fido_dev_get_pin_token_tx(fido_dev_t *dev, const char *pin,
28
    const fido_blob_t *ecdh, const es256_pk_t *pk)
29
1.60k
{
30
1.60k
        fido_blob_t      f;
31
1.60k
        fido_blob_t     *p = NULL;
32
1.60k
        cbor_item_t     *argv[6];
33
1.60k
        int              r;
34
1.60k
35
1.60k
        memset(&f, 0, sizeof(f));
36
1.60k
        memset(argv, 0, sizeof(argv));
37
1.60k
38
1.60k
        if ((p = fido_blob_new()) == NULL || fido_blob_set(p,
39
1.59k
            (const unsigned char *)pin, strlen(pin)) < 0) {
40
49
                fido_log_debug("%s: fido_blob_set", __func__);
41
49
                r = FIDO_ERR_INVALID_ARGUMENT;
42
49
                goto fail;
43
49
        }
44
1.55k
45
1.55k
        if ((argv[0] = cbor_build_uint8(1)) == NULL ||
46
1.55k
            (argv[1] = cbor_build_uint8(5)) == NULL ||
47
1.55k
            (argv[2] = es256_pk_encode(pk, 0)) == NULL ||
48
1.55k
            (argv[5] = cbor_encode_pin_hash_enc(ecdh, p)) == NULL) {
49
306
                fido_log_debug("%s: cbor encode", __func__);
50
306
                r = FIDO_ERR_INTERNAL;
51
306
                goto fail;
52
306
        }
53
1.25k
54
1.25k
        if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 6, &f) < 0 ||
55
1.25k
            fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
56
55
                fido_log_debug("%s: fido_tx", __func__);
57
55
                r = FIDO_ERR_TX;
58
55
                goto fail;
59
55
        }
60
1.19k
61
1.19k
        r = FIDO_OK;
62
1.60k
fail:
63
1.60k
        cbor_vector_free(argv, nitems(argv));
64
1.60k
        fido_blob_free(&p);
65
1.60k
        free(f.ptr);
66
1.60k
67
1.60k
        return (r);
68
1.19k
}
69
70
static int
71
fido_dev_get_pin_token_rx(fido_dev_t *dev, const fido_blob_t *ecdh,
72
    fido_blob_t *token, int ms)
73
1.19k
{
74
1.19k
        const uint8_t    cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
75
1.19k
        fido_blob_t     *aes_token = NULL;
76
1.19k
        unsigned char    reply[2048];
77
1.19k
        int              reply_len;
78
1.19k
        int              r;
79
1.19k
80
1.19k
        if ((aes_token = fido_blob_new()) == NULL) {
81
9
                r = FIDO_ERR_INTERNAL;
82
9
                goto fail;
83
9
        }
84
1.18k
85
1.18k
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
86
61
                fido_log_debug("%s: fido_rx", __func__);
87
61
                r = FIDO_ERR_RX;
88
61
                goto fail;
89
61
        }
90
1.12k
91
1.12k
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, aes_token,
92
1.12k
            parse_pintoken)) != FIDO_OK) {
93
94
                fido_log_debug("%s: parse_pintoken", __func__);
94
94
                goto fail;
95
94
        }
96
1.03k
97
1.03k
        if  (aes256_cbc_dec(ecdh, aes_token, token) < 0) {
98
76
                fido_log_debug("%s: aes256_cbc_dec", __func__);
99
76
                r = FIDO_ERR_RX;
100
76
                goto fail;
101
76
        }
102
956
103
956
        r = FIDO_OK;
104
1.19k
fail:
105
1.19k
        fido_blob_free(&aes_token);
106
1.19k
107
1.19k
        return (r);
108
956
}
109
110
static int
111
fido_dev_get_pin_token_wait(fido_dev_t *dev, const char *pin,
112
    const fido_blob_t *ecdh, const es256_pk_t *pk, fido_blob_t *token, int ms)
113
1.60k
{
114
1.60k
        int r;
115
1.60k
116
1.60k
        if ((r = fido_dev_get_pin_token_tx(dev, pin, ecdh, pk)) != FIDO_OK ||
117
1.60k
            (r = fido_dev_get_pin_token_rx(dev, ecdh, token, ms)) != FIDO_OK)
118
1.60k
                return (r);
119
956
120
956
        return (FIDO_OK);
121
956
}
122
123
int
124
fido_dev_get_pin_token(fido_dev_t *dev, const char *pin,
125
    const fido_blob_t *ecdh, const es256_pk_t *pk, fido_blob_t *token)
126
1.60k
{
127
1.60k
        return (fido_dev_get_pin_token_wait(dev, pin, ecdh, pk, token, -1));
128
1.60k
}
129
130
static int
131
pad64(const char *pin, fido_blob_t **ppin)
132
453
{
133
453
        size_t  pin_len;
134
453
        size_t  ppin_len;
135
453
136
453
        pin_len = strlen(pin);
137
453
        if (pin_len < 4 || pin_len > 255) {
138
9
                fido_log_debug("%s: invalid pin length", __func__);
139
9
                return (FIDO_ERR_PIN_POLICY_VIOLATION);
140
9
        }
141
444
142
444
        if ((*ppin = fido_blob_new()) == NULL)
143
444
                return (FIDO_ERR_INTERNAL);
144
441
145
441
        ppin_len = (pin_len + 63) & ~63;
146
441
        if (ppin_len < pin_len || ((*ppin)->ptr = calloc(1, ppin_len)) == NULL) {
147
4
                fido_blob_free(ppin);
148
4
                return (FIDO_ERR_INTERNAL);
149
4
        }
150
437
151
437
        memcpy((*ppin)->ptr, pin, pin_len);
152
437
        (*ppin)->len = ppin_len;
153
437
154
437
        return (FIDO_OK);
155
437
}
156
157
static int
158
fido_dev_change_pin_tx(fido_dev_t *dev, const char *pin, const char *oldpin)
159
237
{
160
237
        fido_blob_t      f;
161
237
        fido_blob_t     *ppin = NULL;
162
237
        fido_blob_t     *ecdh = NULL;
163
237
        fido_blob_t     *opin = NULL;
164
237
        cbor_item_t     *argv[6];
165
237
        es256_pk_t      *pk = NULL;
166
237
        int r;
167
237
168
237
        memset(&f, 0, sizeof(f));
169
237
        memset(argv, 0, sizeof(argv));
170
237
171
237
        if ((opin = fido_blob_new()) == NULL || fido_blob_set(opin,
172
236
            (const unsigned char *)oldpin, strlen(oldpin)) < 0) {
173
6
                fido_log_debug("%s: fido_blob_set", __func__);
174
6
                r = FIDO_ERR_INVALID_ARGUMENT;
175
6
                goto fail;
176
6
        }
177
231
178
231
        if ((r = pad64(pin, &ppin)) != FIDO_OK) {
179
8
                fido_log_debug("%s: pad64", __func__);
180
8
                goto fail;
181
8
        }
182
223
183
223
        if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
184
156
                fido_log_debug("%s: fido_do_ecdh", __func__);
185
156
                goto fail;
186
156
        }
187
67
188
67
        if ((argv[0] = cbor_build_uint8(1)) == NULL ||
189
67
            (argv[1] = cbor_build_uint8(4)) == NULL ||
190
67
            (argv[2] = es256_pk_encode(pk, 0)) == NULL ||
191
67
            (argv[3] = cbor_encode_change_pin_auth(ecdh, ppin, opin)) == NULL ||
192
67
            (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL ||
193
67
            (argv[5] = cbor_encode_pin_hash_enc(ecdh, opin)) == NULL) {
194
48
                fido_log_debug("%s: cbor encode", __func__);
195
48
                r = FIDO_ERR_INTERNAL;
196
48
                goto fail;
197
48
        }
198
19
199
19
        if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 6, &f) < 0 ||
200
19
            fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
201
4
                fido_log_debug("%s: fido_tx", __func__);
202
4
                r = FIDO_ERR_TX;
203
4
                goto fail;
204
4
        }
205
15
206
15
        r = FIDO_OK;
207
237
fail:
208
237
        cbor_vector_free(argv, nitems(argv));
209
237
        es256_pk_free(&pk);
210
237
        fido_blob_free(&ppin);
211
237
        fido_blob_free(&ecdh);
212
237
        fido_blob_free(&opin);
213
237
        free(f.ptr);
214
237
215
237
        return (r);
216
15
217
15
}
218
219
static int
220
fido_dev_set_pin_tx(fido_dev_t *dev, const char *pin)
221
222
{
222
222
        fido_blob_t      f;
223
222
        fido_blob_t     *ppin = NULL;
224
222
        fido_blob_t     *ecdh = NULL;
225
222
        cbor_item_t     *argv[5];
226
222
        es256_pk_t      *pk = NULL;
227
222
        int              r;
228
222
229
222
        memset(&f, 0, sizeof(f));
230
222
        memset(argv, 0, sizeof(argv));
231
222
232
222
        if ((r = pad64(pin, &ppin)) != FIDO_OK) {
233
8
                fido_log_debug("%s: pad64", __func__);
234
8
                goto fail;
235
8
        }
236
214
237
214
        if ((r = fido_do_ecdh(dev, &pk, &ecdh)) != FIDO_OK) {
238
157
                fido_log_debug("%s: fido_do_ecdh", __func__);
239
157
                goto fail;
240
157
        }
241
57
242
57
        if ((argv[0] = cbor_build_uint8(1)) == NULL ||
243
57
            (argv[1] = cbor_build_uint8(3)) == NULL ||
244
57
            (argv[2] = es256_pk_encode(pk, 0)) == NULL ||
245
57
            (argv[3] = cbor_encode_set_pin_auth(ecdh, ppin)) == NULL ||
246
57
            (argv[4] = cbor_encode_pin_enc(ecdh, ppin)) == NULL) {
247
33
                fido_log_debug("%s: cbor encode", __func__);
248
33
                r = FIDO_ERR_INTERNAL;
249
33
                goto fail;
250
33
        }
251
24
252
24
        if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 5, &f) < 0 ||
253
24
            fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
254
6
                fido_log_debug("%s: fido_tx", __func__);
255
6
                r = FIDO_ERR_TX;
256
6
                goto fail;
257
6
        }
258
18
259
18
        r = FIDO_OK;
260
222
fail:
261
222
        cbor_vector_free(argv, nitems(argv));
262
222
        es256_pk_free(&pk);
263
222
        fido_blob_free(&ppin);
264
222
        fido_blob_free(&ecdh);
265
222
        free(f.ptr);
266
222
267
222
        return (r);
268
18
}
269
270
static int
271
fido_dev_set_pin_wait(fido_dev_t *dev, const char *pin, const char *oldpin,
272
    int ms)
273
459
{
274
459
        int r;
275
459
276
459
        if (oldpin != NULL) {
277
237
                if ((r = fido_dev_change_pin_tx(dev, pin, oldpin)) != FIDO_OK) {
278
222
                        fido_log_debug("%s: fido_dev_change_pin_tx", __func__);
279
222
                        return (r);
280
222
                }
281
222
        } else {
282
222
                if ((r = fido_dev_set_pin_tx(dev, pin)) != FIDO_OK) {
283
204
                        fido_log_debug("%s: fido_dev_set_pin_tx", __func__);
284
204
                        return (r);
285
204
                }
286
33
        }
287
33
288
33
        if ((r = fido_rx_cbor_status(dev, ms)) != FIDO_OK) {
289
28
                fido_log_debug("%s: fido_rx_cbor_status", __func__);
290
28
                return (r);
291
28
        }
292
5
293
5
        return (FIDO_OK);
294
5
}
295
296
int
297
fido_dev_set_pin(fido_dev_t *dev, const char *pin, const char *oldpin)
298
459
{
299
459
        return (fido_dev_set_pin_wait(dev, pin, oldpin, -1));
300
459
}
301
302
static int
303
parse_retry_count(const cbor_item_t *key, const cbor_item_t *val, void *arg)
304
162
{
305
162
        int             *retries = arg;
306
162
        uint64_t         n;
307
162
308
162
        if (cbor_isa_uint(key) == false ||
309
162
            cbor_int_get_width(key) != CBOR_INT_8 ||
310
162
            cbor_get_uint8(key) != 3) {
311
151
                fido_log_debug("%s: cbor type", __func__);
312
151
                return (0); /* ignore */
313
151
        }
314
11
315
11
        if (cbor_decode_uint64(val, &n) < 0 || n > INT_MAX) {
316
3
                fido_log_debug("%s: cbor_decode_uint64", __func__);
317
3
                return (-1);
318
3
        }
319
8
320
8
        *retries = (int)n;
321
8
322
8
        return (0);
323
8
}
324
325
static int
326
fido_dev_get_retry_count_tx(fido_dev_t *dev)
327
117
{
328
117
        fido_blob_t      f;
329
117
        cbor_item_t     *argv[2];
330
117
        int              r;
331
117
332
117
        memset(&f, 0, sizeof(f));
333
117
        memset(argv, 0, sizeof(argv));
334
117
335
117
        if ((argv[0] = cbor_build_uint8(1)) == NULL ||
336
117
            (argv[1] = cbor_build_uint8(1)) == NULL) {
337
4
                r = FIDO_ERR_INTERNAL;
338
4
                goto fail;
339
4
        }
340
113
341
113
        if (cbor_build_frame(CTAP_CBOR_CLIENT_PIN, argv, 2, &f) < 0 ||
342
113
            fido_tx(dev, CTAP_FRAME_INIT | CTAP_CMD_CBOR, f.ptr, f.len) < 0) {
343
16
                fido_log_debug("%s: fido_tx", __func__);
344
16
                r = FIDO_ERR_TX;
345
16
                goto fail;
346
16
        }
347
97
348
97
        r = FIDO_OK;
349
117
fail:
350
117
        cbor_vector_free(argv, nitems(argv));
351
117
        free(f.ptr);
352
117
353
117
        return (r);
354
97
}
355
356
static int
357
fido_dev_get_retry_count_rx(fido_dev_t *dev, int *retries, int ms)
358
97
{
359
97
        const uint8_t   cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
360
97
        unsigned char   reply[512];
361
97
        int             reply_len;
362
97
        int             r;
363
97
364
97
        *retries = 0;
365
97
366
97
        if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply), ms)) < 0) {
367
22
                fido_log_debug("%s: fido_rx", __func__);
368
22
                return (FIDO_ERR_RX);
369
22
        }
370
75
371
75
        if ((r = cbor_parse_reply(reply, (size_t)reply_len, retries,
372
75
            parse_retry_count)) != FIDO_OK) {
373
62
                fido_log_debug("%s: parse_retry_count", __func__);
374
62
                return (r);
375
62
        }
376
13
377
13
        return (FIDO_OK);
378
13
}
379
380
static int
381
fido_dev_get_retry_count_wait(fido_dev_t *dev, int *retries, int ms)
382
117
{
383
117
        int r;
384
117
385
117
        if ((r = fido_dev_get_retry_count_tx(dev)) != FIDO_OK ||
386
117
            (r = fido_dev_get_retry_count_rx(dev, retries, ms)) != FIDO_OK)
387
117
                return (r);
388
13
389
13
        return (FIDO_OK);
390
13
}
391
392
int
393
fido_dev_get_retry_count(fido_dev_t *dev, int *retries)
394
117
{
395
117
        return (fido_dev_get_retry_count_wait(dev, retries, -1));
396
117
}
397
398
int
399
cbor_add_pin_params(fido_dev_t *dev, const fido_blob_t *hmac_data,
400
    const es256_pk_t *pk, const fido_blob_t *ecdh, const char *pin,
401
    cbor_item_t **auth, cbor_item_t **opt)
402
1.41k
{
403
1.41k
        fido_blob_t     *token = NULL;
404
1.41k
        int              r;
405
1.41k
406
1.41k
        if ((token = fido_blob_new()) == NULL) {
407
11
                r = FIDO_ERR_INTERNAL;
408
11
                goto fail;
409
11
        }
410
1.40k
411
1.40k
        if ((r = fido_dev_get_pin_token(dev, pin, ecdh, pk, token)) != FIDO_OK) {
412
573
                fido_log_debug("%s: fido_dev_get_pin_token", __func__);
413
573
                goto fail;
414
573
        }
415
831
416
831
        if ((*auth = cbor_encode_pin_auth(token, hmac_data)) == NULL ||
417
831
            (*opt = cbor_encode_pin_opt()) == NULL) {
418
29
                fido_log_debug("%s: cbor encode", __func__);
419
29
                r = FIDO_ERR_INTERNAL;
420
29
                goto fail;
421
29
        }
422
802
423
802
        r = FIDO_OK;
424
1.41k
fail:
425
1.41k
        fido_blob_free(&token);
426
1.41k
427
1.41k
        return (r);
428
802
}
/home/pedro/projects/libfido2/src/reset.c
Line
Count
Source
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 <stdlib.h>
8
#include "fido.h"
9
10
static int
11
fido_dev_reset_tx(fido_dev_t *dev)
12
38
{
13
38
        const unsigned char     cbor[] = { CTAP_CBOR_RESET };
14
38
        const uint8_t           cmd = CTAP_FRAME_INIT | CTAP_CMD_CBOR;
15
38
16
38
        if (fido_tx(dev, cmd, cbor, sizeof(cbor)) < 0) {
17
1
                fido_log_debug("%s: fido_tx", __func__);
18
1
                return (FIDO_ERR_TX);
19
1
        }
20
37
21
37
        return (FIDO_OK);
22
37
}
23
24
static int
25
fido_dev_reset_wait(fido_dev_t *dev, int ms)
26
38
{
27
38
        int r;
28
38
29
38
        if ((r = fido_dev_reset_tx(dev)) != FIDO_OK ||
30
38
            (r = fido_rx_cbor_status(dev, ms)) != FIDO_OK)
31
38
                return (r);
32
2
33
2
        return (FIDO_OK);
34
2
}
35
36
int
37
fido_dev_reset(fido_dev_t *dev)
38
38
{
39
38
        return (fido_dev_reset_wait(dev, -1));
40
38
}
/home/pedro/projects/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/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
13
{
45
13
        if (cbor_isa_bytestring(item) == false ||
46
13
            cbor_bytestring_is_definite(item) == false ||
47
13
            cbor_bytestring_length(item) != len) {
48
3
                fido_log_debug("%s: cbor type", __func__);
49
3
                return (-1);
50
3
        }
51
10
52
10
        memcpy(ptr, cbor_bytestring_handle(item), len);
53
10
54
10
        return (0);
55
10
}
56
57
static int
58
decode_rsa_pubkey(const cbor_item_t *key, const cbor_item_t *val, void *arg)
59
91
{
60
91
        rs256_pk_t *k = arg;
61
91
62
91
        if (cbor_isa_negint(key) == false ||
63
91
            cbor_int_get_width(key) != CBOR_INT_8)
64
63
                return (0); /* ignore */
65
28
66
28
        switch (cbor_get_uint8(key)) {
67
28
        case 0: /* modulus */
68
1
                return (decode_bignum(val, &k->n, sizeof(k->n)));
69
28
        case 1: /* public exponent */
70
12
                return (decode_bignum(val, &k->e, sizeof(k->e)));
71
15
        }
72
15
73
15
        return (0); /* ignore */
74
15
}
75
76
int
77
rs256_pk_decode(const cbor_item_t *item, rs256_pk_t *k)
78
24
{
79
24
        if (cbor_isa_map(item) == false ||
80
24
            cbor_map_is_definite(item) == false ||
81
24
            cbor_map_iter(item, k, decode_rsa_pubkey) < 0) {
82
3
                fido_log_debug("%s: cbor type", __func__);
83
3
                return (-1);
84
3
        }
85
21
86
21
        return (0);
87
21
}
88
89
rs256_pk_t *
90
rs256_pk_new(void)
91
249
{
92
249
        return (calloc(1, sizeof(rs256_pk_t)));
93
249
}
94
95
void
96
rs256_pk_free(rs256_pk_t **pkp)
97
572
{
98
572
        rs256_pk_t *pk;
99
572
100
572
        if (pkp == NULL || (pk = *pkp) == NULL)
101
572
                return;
102
247
103
247
        explicit_bzero(pk, sizeof(*pk));
104
247
        free(pk);
105
247
106
247
        *pkp = NULL;
107
247
}
108
109
int
110
rs256_pk_from_ptr(rs256_pk_t *pk, const void *ptr, size_t len)
111
134
{
112
134
        if (len < sizeof(*pk))
113
130
                return (FIDO_ERR_INVALID_ARGUMENT);
114
4
115
4
        memcpy(pk, ptr, sizeof(*pk));
116
4
117
4
        return (FIDO_OK);
118
4
}
119
120
EVP_PKEY *
121
rs256_pk_to_EVP_PKEY(const rs256_pk_t *k)
122
177
{
123
177
        RSA             *rsa = NULL;
124
177
        EVP_PKEY        *pkey = NULL;
125
177
        BIGNUM          *n = NULL;
126
177
        BIGNUM          *e = NULL;
127
177
        int              ok = -1;
128
177
129
177
        if ((n = BN_new()) == NULL || (e = BN_new()) == NULL)
130
177
                goto fail;
131
169
132
169
        if (BN_bin2bn(k->n, sizeof(k->n), n) == NULL ||
133
169
            BN_bin2bn(k->e, sizeof(k->e), e) == NULL) {
134
8
                fido_log_debug("%s: BN_bin2bn", __func__);
135
8
                goto fail;
136
8
        }
137
161
138
161
        if ((rsa = RSA_new()) == NULL || RSA_set0_key(rsa, n, e, NULL) == 0) {
139
3
                fido_log_debug("%s: RSA_set0_key", __func__);
140
3
                goto fail;
141
3
        }
142
158
143
158
        /* at this point, n and e belong to rsa */
144
158
        n = NULL;
145
158
        e = NULL;
146
158
147
158
        if ((pkey = EVP_PKEY_new()) == NULL ||
148
158
            EVP_PKEY_assign_RSA(pkey, rsa) == 0) {
149
9
                fido_log_debug("%s: EVP_PKEY_assign_RSA", __func__);
150
9
                goto fail;
151
9
        }
152
149
153
149
        rsa = NULL; /* at this point, rsa belongs to evp */
154
149
155
149
        ok = 0;
156
177
fail:
157
177
        if (n != NULL)
158
177
                BN_free(n);
159
177
        if (e != NULL)
160
177
                BN_free(e);
161
177
        if (rsa != NULL)
162
177
                RSA_free(rsa);
163
177
        if (ok < 0 && pkey != NULL) {
164
5
                EVP_PKEY_free(pkey);
165
5
                pkey = NULL;
166
5
        }
167
177
168
177
        return (pkey);
169
149
}
170
171
int
172
rs256_pk_from_RSA(rs256_pk_t *pk, const RSA *rsa)
173
113
{
174
113
        const BIGNUM    *n = NULL;
175
113
        const BIGNUM    *e = NULL;
176
113
        const BIGNUM    *d = NULL;
177
113
        int              k;
178
113
179
113
        if (RSA_bits(rsa) != 2048) {
180
111
                fido_log_debug("%s: invalid key length", __func__);
181
111
                return (FIDO_ERR_INVALID_ARGUMENT);
182
111
        }
183
2
184
2
        RSA_get0_key(rsa, &n, &e, &d);
185
2
186
2
        if (n == NULL || e == NULL) {
187
0
                fido_log_debug("%s: RSA_get0_key", __func__);
188
0
                return (FIDO_ERR_INTERNAL);
189
0
        }
190
2
191
2
        if ((k = BN_num_bytes(n)) < 0 || (size_t)k > sizeof(pk->n) ||
192
2
            (k = BN_num_bytes(e)) < 0 || (size_t)k > sizeof(pk->e)) {
193
0
                fido_log_debug("%s: invalid key", __func__);
194
0
                return (FIDO_ERR_INTERNAL);
195
0
        }
196
2
197
2
        if ((k = BN_bn2bin(n, pk->n)) < 0 || (size_t)k > sizeof(pk->n) ||
198
2
            (k = BN_bn2bin(e, pk->e)) < 0 || (size_t)k > sizeof(pk->e)) {
199
0
                fido_log_debug("%s: BN_bn2bin", __func__);
200
0
                return (FIDO_ERR_INTERNAL);
201
0
        }
202
2
203
2
        return (FIDO_OK);
204
2
}
/home/pedro/projects/libfido2/src/u2f.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/sha.h>
8
#include <openssl/x509.h>
9
10
#include <string.h>
11
#ifdef HAVE_UNISTD_H
12
#include <unistd.h>
13
#endif
14
15
#include "fido.h"
16
#include "fido/es256.h"
17
18
#if defined(_MSC_VER)
19
static int
20
usleep(unsigned int usec)
21
{
22
        Sleep(usec / 1000);
23
24
        return (0);
25
}
26
#endif
27
28
static int
29
sig_get(fido_blob_t *sig, const unsigned char **buf, size_t *len)
30
156
{
31
156
        sig->len = *len; /* consume the whole buffer */
32
156
        if ((sig->ptr = calloc(1, sig->len)) == NULL ||
33
156
            fido_buf_read(buf, len, sig->ptr, sig->len) < 0) {
34
2
                fido_log_debug("%s: fido_buf_read", __func__);
35
2
                if (sig->ptr != NULL) {
36
0
                        explicit_bzero(sig->ptr, sig->len);
37
0
                        free(sig->ptr);
38
0
                        sig->ptr = NULL;
39
0
                        sig->len = 0;
40
0
                        return (-1);
41
0
                }
42
156
        }
43
156
44
156
        return (0);
45
156
}
46
47
static int
48
x5c_get(fido_blob_t *x5c, const unsigned char **buf, size_t *len)
49
29
{
50
29
        X509    *cert = NULL;
51
29
        int      ok = -1;
52
29
53
29
        if (*len > LONG_MAX) {
54
0
                fido_log_debug("%s: invalid len %zu", __func__, *len);
55
0
                goto fail;
56
0
        }
57
29
58
29
        /* find out the certificate's length */
59
29
        const unsigned char *end = *buf;
60
29
        if ((cert = d2i_X509(NULL, &end, (long)*len)) == NULL || end <= *buf ||
61
29
            (x5c->len = (size_t)(end - *buf)) >= *len) {
62
1
                fido_log_debug("%s: d2i_X509", __func__);
63
1
                goto fail;
64
1
        }
65
28
66
28
        /* read accordingly */
67
28
        if ((x5c->ptr = calloc(1, x5c->len)) == NULL ||
68
28
            fido_buf_read(buf, len, x5c->ptr, x5c->len) < 0) {
69
1
                fido_log_debug("%s: fido_buf_read", __func__);
70
1
                goto fail;
71
1
        }
72
27
73
27
        ok = 0;
74
29
fail:
75
29
        if (cert != NULL)
76
29
                X509_free(cert);
77
29
78
29
        if (ok < 0) {
79
2
                free(x5c->ptr);
80
2
                x5c->ptr = NULL;
81
2
                x5c->len = 0;
82
2
        }
83
29
84
29
        return (ok);
85
27
}
86
87
static int
88
authdata_fake(const char *rp_id, uint8_t flags, uint32_t sigcount,
89
    fido_blob_t *fake_cbor_ad)
90
129
{
91
129
        fido_authdata_t  ad;
92
129
        cbor_item_t     *item = NULL;
93
129
        size_t           alloc_len;
94
129
95
129
        memset(&ad, 0, sizeof(ad));
96
129
97
129
        if (SHA256((const void *)rp_id, strlen(rp_id),
98
129
            ad.rp_id_hash) != ad.rp_id_hash) {
99
1
                fido_log_debug("%s: sha256", __func__);
100
1
                return (-1);
101
1
        }
102
128
103
128
        ad.flags = flags; /* XXX translate? */
104
128
        ad.sigcount = sigcount;
105
128
106
128
        if ((item = cbor_build_bytestring((const unsigned char *)&ad,
107
128
            sizeof(ad))) == NULL) {
108
1
                fido_log_debug("%s: cbor_build_bytestring", __func__);
109
1
                return (-1);
110
1
        }
111
127
112
127
        if (fake_cbor_ad->ptr != NULL ||
113
127
            (fake_cbor_ad->len = cbor_serialize_alloc(item, &fake_cbor_ad->ptr,
114
127
            &alloc_len)) == 0) {
115
1
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
116
1
                cbor_decref(&item);
117
1
                return (-1);
118
1
        }
119
126
120
126
        cbor_decref(&item);
121
126
122
126
        return (0);
123
126
}
124
125
static int
126
send_dummy_register(fido_dev_t *dev, int ms)
127
18
{
128
18
        const uint8_t    cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG;
129
18
        iso7816_apdu_t  *apdu = NULL;
130
18
        unsigned char    challenge[SHA256_DIGEST_LENGTH];
131
18
        unsigned char    application[SHA256_DIGEST_LENGTH];
132
18
        unsigned char    reply[2048];
133
18
        int              r;
134
18
135
18
#ifdef FIDO_FUZZ
136
18
        ms = 0; /* XXX */
137
18
#endif
138
18
139
18
        /* dummy challenge & application */
140
18
        memset(&challenge, 0xff, sizeof(challenge));
141
18
        memset(&application, 0xff, sizeof(application));
142
18
143
18
        if ((apdu = iso7816_new(U2F_CMD_REGISTER, 0, 2 *
144
18
            SHA256_DIGEST_LENGTH)) == NULL ||
145
18
            iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
146
18
            iso7816_add(apdu, &application, sizeof(application)) < 0) {
147
1
                fido_log_debug("%s: iso7816", __func__);
148
1
                r = FIDO_ERR_INTERNAL;
149
1
                goto fail;
150
1
        }
151
17
152
123
        do {
153
123
                if (fido_tx(dev, cmd, iso7816_ptr(apdu),
154
123
                    iso7816_len(apdu)) < 0) {
155
1
                        fido_log_debug("%s: fido_tx", __func__);
156
1
                        r = FIDO_ERR_TX;
157
1
                        goto fail;
158
1
                }
159
122
                if (fido_rx(dev, cmd, &reply, sizeof(reply), ms) < 2) {
160
14
                        fido_log_debug("%s: fido_rx", __func__);
161
14
                        r = FIDO_ERR_RX;
162
14
                        goto fail;
163
14
                }
164
108
                if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) {
165
1
                        fido_log_debug("%s: usleep", __func__);
166
1
                        r = FIDO_ERR_RX;
167
1
                        goto fail;
168
1
                }
169
107
        } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
170
17
171
17
        r = FIDO_OK;
172
18
fail:
173
18
        iso7816_free(&apdu);
174
18
175
18
        return (r);
176
1
}
177
178
static int
179
key_lookup(fido_dev_t *dev, const char *rp_id, const fido_blob_t *key_id,
180
    int *found, int ms)
181
363
{
182
363
        const uint8_t    cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG;
183
363
        iso7816_apdu_t  *apdu = NULL;
184
363
        unsigned char    challenge[SHA256_DIGEST_LENGTH];
185
363
        unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
186
363
        unsigned char    reply[8];
187
363
        uint8_t          key_id_len;
188
363
        int              r;
189
363
190
363
        if (key_id->len > UINT8_MAX || rp_id == NULL) {
191
4
                fido_log_debug("%s: key_id->len=%zu, rp_id=%p", __func__,
192
4
                    key_id->len, (const void *)rp_id);
193
4
                r = FIDO_ERR_INVALID_ARGUMENT;
194
4
                goto fail;
195
4
        }
196
359
197
359
        memset(&challenge, 0xff, sizeof(challenge));
198
359
        memset(&rp_id_hash, 0, sizeof(rp_id_hash));
199
359
200
359
        if (SHA256((const void *)rp_id, strlen(rp_id),
201
359
            rp_id_hash) != rp_id_hash) {
202
3
                fido_log_debug("%s: sha256", __func__);
203
3
                r = FIDO_ERR_INTERNAL;
204
3
                goto fail;
205
3
        }
206
356
207
356
        key_id_len = (uint8_t)key_id->len;
208
356
209
356
        if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_CHECK, 2 *
210
356
            SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL ||
211
356
            iso7816_add(apdu, &challenge, sizeof(challenge)) < 0 ||
212
356
            iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
213
356
            iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
214
356
            iso7816_add(apdu, key_id->ptr, key_id_len) < 0) {
215
2
                fido_log_debug("%s: iso7816", __func__);
216
2
                r = FIDO_ERR_INTERNAL;
217
2
                goto fail;
218
2
        }
219
354
220
354
        if (fido_tx(dev, cmd, iso7816_ptr(apdu), iso7816_len(apdu)) < 0) {
221
3
                fido_log_debug("%s: fido_tx", __func__);
222
3
                r = FIDO_ERR_TX;
223
3
                goto fail;
224
3
        }
225
351
        if (fido_rx(dev, cmd, &reply, sizeof(reply), ms) != 2) {
226
90
                fido_log_debug("%s: fido_rx", __func__);
227
90
                r = FIDO_ERR_RX;
228
90
                goto fail;
229
90
        }
230
261
231
261
        switch ((reply[0] << 8) | reply[1]) {
232
261
        case SW_CONDITIONS_NOT_SATISFIED:
233
177
                *found = 1; /* key exists */
234
177
                break;
235
261
        case SW_WRONG_DATA:
236
80
                *found = 0; /* key does not exist */
237
80
                break;
238
261
        default:
239
4
                /* unexpected sw */
240
4
                r = FIDO_ERR_INTERNAL;
241
4
                goto fail;
242
257
        }
243
257
244
257
        r = FIDO_OK;
245
363
fail:
246
363
        iso7816_free(&apdu);
247
363
248
363
        return (r);
249
257
}
250
251
static int
252
parse_auth_reply(fido_blob_t *sig, fido_blob_t *ad, const char *rp_id,
253
    const unsigned char *reply, size_t len)
254
134
{
255
134
        uint8_t         flags;
256
134
        uint32_t        sigcount;
257
134
258
134
        if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) {
259
4
                fido_log_debug("%s: unexpected sw", __func__);
260
4
                return (FIDO_ERR_RX);
261
4
        }
262
130
263
130
        len -= 2;
264
130
265
130
        if (fido_buf_read(&reply, &len, &flags, sizeof(flags)) < 0 ||
266
130
            fido_buf_read(&reply, &len, &sigcount, sizeof(sigcount)) < 0) {
267
1
                fido_log_debug("%s: fido_buf_read", __func__);
268
1
                return (FIDO_ERR_RX);
269
1
        }
270
129
271
129
        if (sig_get(sig, &reply, &len) < 0) {
272
0
                fido_log_debug("%s: sig_get", __func__);
273
0
                return (FIDO_ERR_RX);
274
0
        }
275
129
276
129
        if (authdata_fake(rp_id, flags, sigcount, ad) < 0) {
277
3
                fido_log_debug("%s; authdata_fake", __func__);
278
3
                return (FIDO_ERR_RX);
279
3
        }
280
126
281
126
        return (FIDO_OK);
282
126
}
283
284
static int
285
do_auth(fido_dev_t *dev, const fido_blob_t *cdh, const char *rp_id,
286
    const fido_blob_t *key_id, fido_blob_t *sig, fido_blob_t *ad, int ms)
287
159
{
288
159
        const uint8_t    cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG;
289
159
        iso7816_apdu_t  *apdu = NULL;
290
159
        unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
291
159
        unsigned char    reply[128];
292
159
        int              reply_len;
293
159
        uint8_t          key_id_len;
294
159
        int              r;
295
159
296
159
#ifdef FIDO_FUZZ
297
159
        ms = 0; /* XXX */
298
159
#endif
299
159
300
159
        if (cdh->len != SHA256_DIGEST_LENGTH || key_id->len > UINT8_MAX ||
301
159
            rp_id == NULL) {
302
7
                r = FIDO_ERR_INVALID_ARGUMENT;
303
7
                goto fail;
304
7
        }
305
152
306
152
        memset(&rp_id_hash, 0, sizeof(rp_id_hash));
307
152
308
152
        if (SHA256((const void *)rp_id, strlen(rp_id),
309
152
            rp_id_hash) != rp_id_hash) {
310
1
                fido_log_debug("%s: sha256", __func__);
311
1
                r = FIDO_ERR_INTERNAL;
312
1
                goto fail;
313
1
        }
314
151
315
151
        key_id_len = (uint8_t)key_id->len;
316
151
317
151
        if ((apdu = iso7816_new(U2F_CMD_AUTH, U2F_AUTH_SIGN, 2 *
318
151
            SHA256_DIGEST_LENGTH + sizeof(key_id_len) + key_id_len)) == NULL ||
319
151
            iso7816_add(apdu, cdh->ptr, cdh->len) < 0 ||
320
151
            iso7816_add(apdu, &rp_id_hash, sizeof(rp_id_hash)) < 0 ||
321
151
            iso7816_add(apdu, &key_id_len, sizeof(key_id_len)) < 0 ||
322
151
            iso7816_add(apdu, key_id->ptr, key_id_len) < 0) {
323
1
                fido_log_debug("%s: iso7816", __func__);
324
1
                r = FIDO_ERR_INTERNAL;
325
1
                goto fail;
326
1
        }
327
150
328
432
        do {
329
432
                if (fido_tx(dev, cmd, iso7816_ptr(apdu),
330
432
                    iso7816_len(apdu)) < 0) {
331
2
                        fido_log_debug("%s: fido_tx", __func__);
332
2
                        r = FIDO_ERR_TX;
333
2
                        goto fail;
334
2
                }
335
430
                if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply),
336
430
                    ms)) < 2) {
337
12
                        fido_log_debug("%s: fido_rx", __func__);
338
12
                        r = FIDO_ERR_RX;
339
12
                        goto fail;
340
12
                }
341
418
                if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) {
342
2
                        fido_log_debug("%s: usleep", __func__);
343
2
                        r = FIDO_ERR_RX;
344
2
                        goto fail;
345
2
                }
346
416
        } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
347
150
348
150
        if ((r = parse_auth_reply(sig, ad, rp_id, reply,
349
134
            (size_t)reply_len)) != FIDO_OK) {
350
8
                fido_log_debug("%s: parse_auth_reply", __func__);
351
8
                goto fail;
352
8
        }
353
159
354
159
fail:
355
159
        iso7816_free(&apdu);
356
159
357
159
        return (r);
358
134
}
359
360
static int
361
cbor_blob_from_ec_point(const uint8_t *ec_point, size_t ec_point_len,
362
    fido_blob_t *cbor_blob)
363
27
{
364
27
        es256_pk_t      *pk = NULL;
365
27
        cbor_item_t     *pk_cbor = NULL;
366
27
        size_t           alloc_len;
367
27
        int              ok = -1;
368
27
369
27
        /* only handle uncompressed points */
370
27
        if (ec_point_len != 65 || ec_point[0] != 0x04) {
371
1
                fido_log_debug("%s: unexpected format", __func__);
372
1
                goto fail;
373
1
        }
374
26
375
26
        if ((pk = es256_pk_new()) == NULL ||
376
26
            es256_pk_set_x(pk, &ec_point[1]) < 0 ||
377
26
            es256_pk_set_y(pk, &ec_point[33]) < 0) {
378
1
                fido_log_debug("%s: es256_pk_set", __func__);
379
1
                goto fail;
380
1
        }
381
25
382
25
        if ((pk_cbor = es256_pk_encode(pk, 0)) == NULL) {
383
1
                fido_log_debug("%s: es256_pk_encode", __func__);
384
1
                goto fail;
385
1
        }
386
24
387
24
        if ((cbor_blob->len = cbor_serialize_alloc(pk_cbor, &cbor_blob->ptr,
388
24
            &alloc_len)) != 77) {
389
1
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
390
1
                goto fail;
391
1
        }
392
23
393
23
        ok = 0;
394
27
fail:
395
27
        es256_pk_free(&pk);
396
27
397
27
        if (pk_cbor)
398
24
                cbor_decref(&pk_cbor);
399
27
400
27
        return (ok);
401
23
}
402
403
static int
404
encode_cred_authdata(const char *rp_id, const uint8_t *kh, uint8_t kh_len,
405
    const uint8_t *pubkey, size_t pubkey_len, fido_blob_t *out)
406
27
{
407
27
        fido_authdata_t          authdata;
408
27
        fido_attcred_raw_t       attcred_raw;
409
27
        fido_blob_t              pk_blob;
410
27
        fido_blob_t              authdata_blob;
411
27
        cbor_item_t             *authdata_cbor = NULL;
412
27
        unsigned char           *ptr;
413
27
        size_t                   len;
414
27
        size_t                   alloc_len;
415
27
        int                      ok = -1;
416
27
417
27
        memset(&pk_blob, 0, sizeof(pk_blob));
418
27
        memset(&authdata, 0, sizeof(authdata));
419
27
        memset(&authdata_blob, 0, sizeof(authdata_blob));
420
27
        memset(out, 0, sizeof(*out));
421
27
422
27
        if (rp_id == NULL) {
423
0
                fido_log_debug("%s: NULL rp_id", __func__);
424
0
                goto fail;
425
0
        }
426
27
427
27
        if (cbor_blob_from_ec_point(pubkey, pubkey_len, &pk_blob) < 0) {
428
4
                fido_log_debug("%s: cbor_blob_from_ec_point", __func__);
429
4
                goto fail;
430
4
        }
431
23
432
23
        if (SHA256((const void *)rp_id, strlen(rp_id),
433
23
            authdata.rp_id_hash) != authdata.rp_id_hash) {
434
1
                fido_log_debug("%s: sha256", __func__);
435
1
                goto fail;
436
1
        }
437
22
438
22
        authdata.flags = (CTAP_AUTHDATA_ATT_CRED | CTAP_AUTHDATA_USER_PRESENT);
439
22
        authdata.sigcount = 0;
440
22
441
22
        memset(&attcred_raw.aaguid, 0, sizeof(attcred_raw.aaguid));
442
22
        attcred_raw.id_len = (uint16_t)(kh_len << 8); /* XXX */
443
22
444
22
        len = authdata_blob.len = sizeof(authdata) + sizeof(attcred_raw) +
445
22
            kh_len + pk_blob.len;
446
22
        ptr = authdata_blob.ptr = calloc(1, authdata_blob.len);
447
22
448
22
        fido_log_debug("%s: ptr=%p, len=%zu", __func__, (void *)ptr, len);
449
22
450
22
        if (authdata_blob.ptr == NULL)
451
22
                goto fail;
452
21
453
21
        if (fido_buf_write(&ptr, &len, &authdata, sizeof(authdata)) < 0 ||
454
21
            fido_buf_write(&ptr, &len, &attcred_raw, sizeof(attcred_raw)) < 0 ||
455
21
            fido_buf_write(&ptr, &len, kh, kh_len) < 0 ||
456
21
            fido_buf_write(&ptr, &len, pk_blob.ptr, pk_blob.len) < 0) {
457
0
                fido_log_debug("%s: fido_buf_write", __func__);
458
0
                goto fail;
459
0
        }
460
21
461
21
        if ((authdata_cbor = fido_blob_encode(&authdata_blob)) == NULL) {
462
1
                fido_log_debug("%s: fido_blob_encode", __func__);
463
1
                goto fail;
464
1
        }
465
20
466
20
        if ((out->len = cbor_serialize_alloc(authdata_cbor, &out->ptr,
467
20
            &alloc_len)) == 0) {
468
1
                fido_log_debug("%s: cbor_serialize_alloc", __func__);
469
1
                goto fail;
470
1
        }
471
19
472
19
        ok = 0;
473
27
fail:
474
27
        if (authdata_cbor)
475
20
                cbor_decref(&authdata_cbor);
476
27
477
27
        if (pk_blob.ptr) {
478
23
                explicit_bzero(pk_blob.ptr, pk_blob.len);
479
23
                free(pk_blob.ptr);
480
23
        }
481
27
        if (authdata_blob.ptr) {
482
21
                explicit_bzero(authdata_blob.ptr, authdata_blob.len);
483
21
                free(authdata_blob.ptr);
484
21
        }
485
27
486
27
        return (ok);
487
19
}
488
489
static int
490
parse_register_reply(fido_cred_t *cred, const unsigned char *reply, size_t len)
491
34
{
492
34
        fido_blob_t      x5c;
493
34
        fido_blob_t      sig;
494
34
        fido_blob_t      ad;
495
34
        uint8_t          dummy;
496
34
        uint8_t          pubkey[65];
497
34
        uint8_t          kh_len = 0;
498
34
        uint8_t         *kh = NULL;
499
34
        int              r;
500
34
501
34
        memset(&x5c, 0, sizeof(x5c));
502
34
        memset(&sig, 0, sizeof(sig));
503
34
        memset(&ad, 0, sizeof(ad));
504
34
        r = FIDO_ERR_RX;
505
34
506
34
        /* status word */
507
34
        if (len < 2 || ((reply[len - 2] << 8) | reply[len - 1]) != SW_NO_ERROR) {
508
1
                fido_log_debug("%s: unexpected sw", __func__);
509
1
                goto fail;
510
1
        }
511
33
512
33
        len -= 2;
513
33
514
33
        /* reserved byte */
515
33
        if (fido_buf_read(&reply, &len, &dummy, sizeof(dummy)) < 0 ||
516
33
            dummy != 0x05) {
517
2
                fido_log_debug("%s: reserved byte", __func__);
518
2
                goto fail;
519
2
        }
520
31
521
31
        /* pubkey + key handle */
522
31
        if (fido_buf_read(&reply, &len, &pubkey, sizeof(pubkey)) < 0 ||
523
31
            fido_buf_read(&reply, &len, &kh_len, sizeof(kh_len)) < 0 ||
524
31
            (kh = calloc(1, kh_len)) == NULL ||
525
31
            fido_buf_read(&reply, &len, kh, kh_len) < 0) {
526
2
                fido_log_debug("%s: fido_buf_read", __func__);
527
2
                goto fail;
528
2
        }
529
29
530
29
        /* x5c + sig */
531
29
        if (x5c_get(&x5c, &reply, &len) < 0 ||
532
29
            sig_get(&sig, &reply, &len) < 0) {
533
2
                fido_log_debug("%s: x5c || sig", __func__);
534
2
                goto fail;
535
2
        }
536
27
537
27
        /* authdata */
538
27
        if (encode_cred_authdata(cred->rp.id, kh, kh_len, pubkey,
539
27
            sizeof(pubkey), &ad) < 0) {
540
8
                fido_log_debug("%s: encode_cred_authdata", __func__);
541
8
                goto fail;
542
8
        }
543
19
544
19
        if (fido_cred_set_fmt(cred, "fido-u2f") != FIDO_OK ||
545
19
            fido_cred_set_authdata(cred, ad.ptr, ad.len) != FIDO_OK ||
546
19
            fido_cred_set_x509(cred, x5c.ptr, x5c.len) != FIDO_OK ||
547
19
            fido_cred_set_sig(cred, sig.ptr, sig.len) != FIDO_OK) {
548
6
                fido_log_debug("%s: fido_cred_set", __func__);
549
6
                r = FIDO_ERR_INTERNAL;
550
6
                goto fail;
551
6
        }
552
13
553
13
        r = FIDO_OK;
554
34
fail:
555
34
        if (kh) {
556
30
                explicit_bzero(kh, kh_len);
557
30
                free(kh);
558
30
        }
559
34
        if (x5c.ptr) {
560
27
                explicit_bzero(x5c.ptr, x5c.len);
561
27
                free(x5c.ptr);
562
27
        }
563
34
        if (sig.ptr) {
564
26
                explicit_bzero(sig.ptr, sig.len);
565
26
                free(sig.ptr);
566
26
        }
567
34
        if (ad.ptr) {
568
19
                explicit_bzero(ad.ptr, ad.len);
569
19
                free(ad.ptr);
570
19
        }
571
34
572
34
        return (r);
573
13
}
574
575
int
576
u2f_register(fido_dev_t *dev, fido_cred_t *cred, int ms)
577
90
{
578
90
        const uint8_t    cmd = CTAP_FRAME_INIT | CTAP_CMD_MSG;
579
90
        iso7816_apdu_t  *apdu = NULL;
580
90
        unsigned char    rp_id_hash[SHA256_DIGEST_LENGTH];
581
90
        unsigned char    reply[2048];
582
90
        int              reply_len;
583
90
        int              found;
584
90
        int              r;
585
90
586
90
#ifdef FIDO_FUZZ
587
90
        ms = 0; /* XXX */
588
90
#endif
589
90
590
90
        if (cred->rk == FIDO_OPT_TRUE || cred->uv == FIDO_OPT_TRUE) {
591
1
                fido_log_debug("%s: rk=%d, uv=%d", __func__, cred->rk,
592
1
                    cred->uv);
593
1
                return (FIDO_ERR_UNSUPPORTED_OPTION);
594
1
        }
595
89
596
89
        if (cred->type != COSE_ES256 || cred->cdh.ptr == NULL ||
597
89
            cred->rp.id == NULL || cred->cdh.len != SHA256_DIGEST_LENGTH) {
598
9
                fido_log_debug("%s: type=%d, cdh=(%p,%zu)" , __func__,
599
9
                    cred->type, (void *)cred->cdh.ptr, cred->cdh.len);
600
9
                return (FIDO_ERR_INVALID_ARGUMENT);
601
9
        }
602
80
603
98
        for (size_t i = 0; i < cred->excl.len; i++) {
604
51
                if ((r = key_lookup(dev, cred->rp.id, &cred->excl.ptr[i],
605
51
                    &found, ms)) != FIDO_OK) {
606
15
                        fido_log_debug("%s: key_lookup", __func__);
607
15
                        return (r);
608
15
                }
609
36
                if (found) {
610
18
                        if ((r = send_dummy_register(dev, ms)) != FIDO_OK) {
611
17
                                fido_log_debug("%s: send_dummy_register",
612
17
                                    __func__);
613
17
                                return (r);
614
17
                        }
615
1
                        return (FIDO_ERR_CREDENTIAL_EXCLUDED);
616
1
                }
617
36
        }
618
80
619
80
        memset(&rp_id_hash, 0, sizeof(rp_id_hash));
620
47
621
47
        if (SHA256((const void *)cred->rp.id, strlen(cred->rp.id),
622
47
            rp_id_hash) != rp_id_hash) {
623
1
                fido_log_debug("%s: sha256", __func__);
624
1
                return (FIDO_ERR_INTERNAL);
625
1
        }
626
46
627
46
        if ((apdu = iso7816_new(U2F_CMD_REGISTER, 0, 2 *
628
46
            SHA256_DIGEST_LENGTH)) == NULL ||
629
46
            iso7816_add(apdu, cred->cdh.ptr, cred->cdh.len) < 0 ||
630
46
            iso7816_add(apdu, rp_id_hash, sizeof(rp_id_hash)) < 0) {
631
1
                fido_log_debug("%s: iso7816", __func__);
632
1
                r = FIDO_ERR_INTERNAL;
633
1
                goto fail;
634
1
        }
635
45
636
616
        do {
637
616
                if (fido_tx(dev, cmd, iso7816_ptr(apdu),
638
616
                    iso7816_len(apdu)) < 0) {
639
1
                        fido_log_debug("%s: fido_tx", __func__);
640
1
                        r = FIDO_ERR_TX;
641
1
                        goto fail;
642
1
                }
643
615
                if ((reply_len = fido_rx(dev, cmd, &reply, sizeof(reply),
644
615
                    ms)) < 2) {
645
9
                        fido_log_debug("%s: fido_rx", __func__);
646
9
                        r = FIDO_ERR_RX;
647
9
                        goto fail;
648
9
                }
649
606
                if (usleep((ms == -1 ? 100 : ms) * 1000) < 0) {
650
1
                        fido_log_debug("%s: usleep", __func__);
651
1
                        r = FIDO_ERR_RX;
652
1
                        goto fail;
653
1
                }
654
605
        } while (((reply[0] << 8) | reply[1]) == SW_CONDITIONS_NOT_SATISFIED);
655
45
656
45
        if ((r = parse_register_reply(cred, reply,
657
34
            (size_t)reply_len)) != FIDO_OK) {
658
21
                fido_log_debug("%s: parse_register_reply", __func__);
659
21
                goto fail;
660
21
        }
661
46
fail:
662
46
        iso7816_free(&apdu);
663
46
664
46
        return (r);
665
34
}
666
667
static int
668
u2f_authenticate_single(fido_dev_t *dev, const fido_blob_t *key_id,
669
    fido_assert_t *fa, size_t idx, int ms)
670
312
{
671
312
        fido_blob_t     sig;
672
312
        fido_blob_t     ad;
673
312
        int             found;
674
312
        int             r;
675
312
676
312
        memset(&sig, 0, sizeof(sig));
677
312
        memset(&ad, 0, sizeof(ad));
678
312
679
312
        if ((r = key_lookup(dev, fa->rp_id, key_id, &found, ms)) != FIDO_OK) {
680
91
                fido_log_debug("%s: key_lookup", __func__);
681
91
                goto fail;
682
91
        }
683
221
684
221
        if (!found) {
685
62
                fido_log_debug("%s: not found", __func__);
686
62
                r = FIDO_ERR_CREDENTIAL_EXCLUDED;
687
62
                goto fail;
688
62
        }
689
159
690
159
        if (fa->up == FIDO_OPT_FALSE) {
691
0
                fido_log_debug("%s: checking for key existence only", __func__);
692
0
                r = FIDO_ERR_USER_PRESENCE_REQUIRED;
693
0
                goto fail;
694
0
        }
695
159
696
159
        if ((r = do_auth(dev, &fa->cdh, fa->rp_id, key_id, &sig, &ad,
697
159
            ms)) != FIDO_OK) {
698
33
                fido_log_debug("%s: do_auth", __func__);
699
33
                goto fail;
700
33
        }
701
126
702
126
        if (fido_blob_set(&fa->stmt[idx].id, key_id->ptr, key_id->len) < 0 ||
703
126
            fido_assert_set_authdata(fa, idx, ad.ptr, ad.len) != FIDO_OK ||
704
126
            fido_assert_set_sig(fa, idx, sig.ptr, sig.len) != FIDO_OK) {
705
4
                fido_log_debug("%s: fido_assert_set", __func__);
706
4
                r = FIDO_ERR_INTERNAL;
707
4
                goto fail;
708
4
        }
709
122
710
122
        r = FIDO_OK;
711
312
fail:
712
312
        if (sig.ptr) {
713
128
                explicit_bzero(sig.ptr, sig.len);
714
128
                free(sig.ptr);
715
128
        }
716
312
        if (ad.ptr) {
717
126
                explicit_bzero(ad.ptr, ad.len);
718
126
                free(ad.ptr);
719
126
        }
720
312
721
312
        return (r);
722
122
}
723
724
int
725
u2f_authenticate(fido_dev_t *dev, fido_assert_t *fa, int ms)
726
136
{
727
136
        int     nauth_ok = 0;
728
136
        int     r;
729
136
730
136
        if (fa->uv == FIDO_OPT_TRUE || fa->allow_list.ptr == NULL) {
731
4
                fido_log_debug("%s: uv=%d, allow_list=%p", __func__, fa->uv,
732
4
                    (void *)fa->allow_list.ptr);
733
4
                return (FIDO_ERR_UNSUPPORTED_OPTION);
734
4
        }
735
132
736
132
        if ((r = fido_assert_set_count(fa, fa->allow_list.len)) != FIDO_OK) {
737
1
                fido_log_debug("%s: fido_assert_set_count", __func__);
738
1
                return (r);
739
1
        }
740
131
741
315
        for (size_t i = 0; i < fa->allow_list.len; i++) {
742
312
                if ((r = u2f_authenticate_single(dev, &fa->allow_list.ptr[i],
743
312
                    fa, nauth_ok, ms)) == FIDO_OK) {
744
122
                        nauth_ok++;
745
190
                } else if (r != FIDO_ERR_CREDENTIAL_EXCLUDED) {
746
128
                        fido_log_debug("%s: u2f_authenticate_single", __func__);
747
128
                        return (r);
748
128
                }
749
312
                /* ignore credentials that don't exist */
750
312
        }
751
131
752
131
        fa->stmt_len = nauth_ok;
753
3
754
3
        if (nauth_ok == 0)
755
1
                return (FIDO_ERR_NO_CREDENTIALS);
756
2
757
2
        return (FIDO_OK);
758
2
}