forked from solokeys/solo1
/
extensions.c
178 lines (153 loc) · 4.57 KB
/
extensions.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// Copyright 2019 SoloKeys Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
#include <stdint.h>
#include "extensions.h"
#include "u2f.h"
#include "ctap.h"
#include "wallet.h"
#include "solo.h"
#include "device.h"
#include "log.h"
#define htonl(x) (((x & 0xff) << 24) | ((x & 0xff00) << 8) \
| ((x & 0xff0000) >> 8) | ((x & 0xff000000) >> 24) )
ReqSrcEnum g_request_source = REQ_SRC_UNKNOWN;
inline ReqSrcEnum get_request_source(void){
printf1(TAG_WALLET, "Extension request source: FIDO %d \r\n", g_request_source);
return g_request_source;
}
int is_extension_request(uint8_t * kh, int len)
{
wallet_request * req = (wallet_request *) kh;
if (len < WALLET_MIN_LENGTH)
return 0;
return memcmp(req->tag, WALLET_TAG, sizeof(WALLET_TAG)-1) == 0;
}
int extension_needs_atomic_count(uint8_t klen, uint8_t * keyh)
{
return ((wallet_request *) keyh)->operation == WalletRegister
|| ((wallet_request *) keyh)->operation == WalletSign;
}
static uint8_t * output_buffer_ptr;
uint8_t output_buffer_offset;
uint8_t output_buffer_size;
void extension_writeback_init(uint8_t * buffer, uint8_t size)
{
output_buffer_ptr = buffer;
output_buffer_offset = 0;
output_buffer_size = size;
}
void extension_writeback(uint8_t * buf, uint8_t size)
{
if ((output_buffer_offset + size) > output_buffer_size)
{
return;
}
memmove(output_buffer_ptr + output_buffer_offset, buf, size);
output_buffer_offset += size;
}
int16_t bridge_u2f_to_extensions(uint8_t * _chal, uint8_t * _appid, uint8_t klen, uint8_t * keyh)
{
int8_t ret = 0;
uint32_t count;
uint8_t up = 1;
uint8_t sig[72];
if (extension_needs_atomic_count(klen, keyh))
{
count = htonl(ctap_atomic_count(0));
}
else
{
count = htonl(10);
}
u2f_response_writeback(&up,1);
u2f_response_writeback((uint8_t *)&count,4);
u2f_response_writeback((uint8_t *)&ret,1);
#ifdef IS_BOOTLOADER
ret = bootloader_bridge(klen, keyh);
#else
g_request_source = REQ_SRC_U2F;
ret = bridge_u2f_to_solo(sig, keyh, klen);
u2f_response_writeback(sig,72);
#endif
if (ret != 0)
{
u2f_reset_response();
u2f_response_writeback(&up,1);
u2f_response_writeback((uint8_t *)&count,4);
memset(sig,0,sizeof(sig));
sig[0] = ret;
u2f_response_writeback(sig,72);
}
return U2F_SW_NO_ERROR;
}
// Returns 1 if this is a extension request.
// Else 0 if nothing is done.
int16_t extend_fido2(CredentialId * credid, uint8_t * output)
{
if (is_extension_request((uint8_t*)credid, sizeof(CredentialId)))
{
g_request_source = REQ_SRC_FIDO2;
printf1(TAG_EXT,"IS EXT REQ\r\n");
output[0] = bridge_u2f_to_solo(output+1, (uint8_t*)credid, sizeof(CredentialId));
return 1;
}
else
{
return 0;
}
}
int16_t extend_u2f(APDU_HEADER * req, uint8_t * payload, uint32_t len)
{
struct u2f_authenticate_request * auth = (struct u2f_authenticate_request *) payload;
uint16_t rcode;
if (req->ins == U2F_AUTHENTICATE)
{
if (req->p1 == U2F_AUTHENTICATE_CHECK)
{
if (is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests
{
rcode = U2F_SW_CONDITIONS_NOT_SATISFIED;
}
else
{
rcode = U2F_SW_WRONG_DATA;
}
printf1(TAG_EXT,"Ignoring U2F check request\n");
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
goto end;
}
else
{
if ( ! is_extension_request((uint8_t *) &auth->kh, auth->khl)) // Pin requests
{
rcode = U2F_SW_WRONG_DATA;
printf1(TAG_EXT, "Ignoring U2F auth request\n");
dump_hex1(TAG_EXT, (uint8_t *) &auth->kh, auth->khl);
goto end;
}
rcode = bridge_u2f_to_extensions(auth->chal, auth->app, auth->khl, (uint8_t*)&auth->kh);
}
}
else if (req->ins == U2F_VERSION)
{
printf1(TAG_EXT, "U2F_VERSION\n");
if (len)
{
rcode = U2F_SW_WRONG_LENGTH;
}
else
{
rcode = u2f_version();
}
}
else
{
rcode = U2F_SW_INS_NOT_SUPPORTED;
}
end:
return rcode;
}