Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
yubico_otp.c
Go to the documentation of this file.
1/*
2 * Copyright 2015-2018 Yubico AB
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifdef NDEBUG
18#undef NDEBUG
19#endif
20#include <assert.h>
21#include <stdio.h>
22#include <stdint.h>
23#include <stdlib.h>
24#include <string.h>
25
26#include <openssl/aes.h>
27#include <openssl/evp.h>
28
29#include <yubihsm.h>
30
31#ifndef DEFAULT_CONNECTOR_URL
32#define DEFAULT_CONNECTOR_URL "http://127.0.0.1:12345"
33#endif
34
35const char *key_label = "label";
36const uint8_t password[] = "password";
37const uint8_t otp_key[] = {0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
38 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f};
39
40static const struct {
41 uint8_t key[16];
42 uint8_t id[6];
50} test_vectors[] =
51 {{"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
52 "\x01\x02\x03\x04\x05\x06", 0x0001, 0x0001, 0x01, 0x01, 0x0000, 0xfe36,
53 "\x2f\x5d\x71\xa4\x91\x5d\xec\x30\x4a\xa1\x3c\xcf\x97\xbb\x0d\xbb"},
54 {"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
55 "\x01\x02\x03\x04\x05\x06", 0x0001, 0x0001, 0x01, 0x02, 0x0000, 0x1152,
56 "\xcb\x71\x0b\x46\x2b\x7b\x1c\x23\x10\x0c\xb2\x46\x85\xb6\x4d\x33"},
57 {"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f",
58 "\x01\x02\x03\x04\x05\x06", 0x0fff, 0x0001, 0x01, 0x01, 0x0000, 0x9454,
59 "\x77\x99\x78\x12\x9b\xcc\x26\x42\xc8\xad\xf5\xc1\x99\x81\xa0\x16"},
60 {"\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88\x88",
61 "\x88\x88\x88\x88\x88\x88", 0x8888, 0x8888, 0x88, 0x88, 0x8888, 0xd3b6,
62 "\x20\x76\x5f\xc6\x83\xe0\xfc\x7b\x62\x42\x21\x86\x48\x4d\x82\x37"},
63 {"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
64 "\x00\x00\x00\x00\x00\x00", 0x0000, 0x0000, 0x00, 0x00, 0x0000, 0xa96a,
65 "\x99\x9b\x08\xbf\x0b\x3b\x98\xf8\x5b\x08\x76\xa8\x77\x15\x16\x16"},
66 {"\xc4\x42\x28\x90\x65\x30\x76\xcd\xe7\x3d\x44\x9b\x19\x1b\x41\x6a",
67 "\x33\xc6\x9e\x7f\x24\x9e", 0x0001, 0x13a7, 0x24, 0x00, 0xc63c, 0x1c86,
68 "\x7e\x0f\xc9\x87\x35\x16\x72\xc0\x70\xfa\x5c\x05\x95\xec\x68\xb8"}};
69
70uint16_t yubikey_crc16(const uint8_t *buf, size_t buf_size) {
71 uint16_t m_crc = 0xffff;
72
73 while (buf_size--) {
74 int i, j;
75 m_crc ^= (uint8_t) *buf++ & 0xFF;
76 for (i = 0; i < 8; i++) {
77 j = m_crc & 1;
78 m_crc >>= 1;
79 if (j) {
80 m_crc ^= 0x8408;
81 }
82 }
83 }
84
85 return m_crc;
86}
87
88int main(void) {
89 yh_connector *connector = NULL;
90 yh_session *session = NULL;
92
93 uint16_t authkey = 1;
94
95 const char *connector_url;
96
97 connector_url = getenv("DEFAULT_CONNECTOR_URL");
98 if (connector_url == NULL) {
99 connector_url = DEFAULT_CONNECTOR_URL;
100 }
101
102 yrc = yh_init();
103 assert(yrc == YHR_SUCCESS);
104
105 yrc = yh_init_connector(connector_url, &connector);
106 assert(yrc == YHR_SUCCESS);
107
108 yrc = yh_connect(connector, 0);
109 assert(yrc == YHR_SUCCESS);
110
111 yrc = yh_create_session_derived(connector, authkey, password,
112 sizeof(password), false, &session);
113 assert(yrc == YHR_SUCCESS);
114
116 assert(yrc == YHR_SUCCESS);
117
118 uint8_t session_id;
119 yrc = yh_get_session_id(session, &session_id);
120 assert(yrc == YHR_SUCCESS);
121
122 printf("Successfully established session %02d\n", session_id);
123
125 yrc =
126 yh_string_to_capabilities("create-otp-aead:decrypt-otp:randomize-otp-aead",
127 &capabilities);
128 assert(yrc == YHR_SUCCESS);
129
130 uint16_t domain_five = 16; // Domain five is 0b0000000000010000
131 uint16_t key_id = 0; // ID 0 lets the device generate an ID
132 uint32_t nonce_id = 0x12345678;
135 nonce_id);
136 assert(yrc == YHR_SUCCESS);
137
138 printf("Generated OTP key with ID %04x\n", key_id);
139
141 assert(yrc == YHR_SUCCESS);
142
144 &capabilities, nonce_id, otp_key,
145 sizeof(otp_key));
146 assert(yrc == YHR_SUCCESS);
147
148 for (size_t i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) {
149 uint8_t aead[512];
150 size_t aead_len = sizeof(aead);
151 yrc = yh_util_create_otp_aead(session, key_id, test_vectors[i].key,
152 test_vectors[i].id, aead, &aead_len);
153 assert(yrc == YHR_SUCCESS);
154
159
160 printf("Checking test vector %zu ... ", i);
161 yrc =
162 yh_util_decrypt_otp(session, key_id, aead, aead_len, test_vectors[i].otp,
165 assert(yrc == YHR_SUCCESS);
166
167 assert(test_vectors[i].use_counter == use_counter);
168 assert(test_vectors[i].session_counter == session_counter);
169 assert(test_vectors[i].timestamp_high == timestamp_high);
170 assert(test_vectors[i].timestamp_low == timestamp_low);
171
172 printf("OK\n");
173 }
174
175 printf("Put OTP key with ID %04x\n", key_id);
176
177 uint8_t otp_data[64];
178 size_t otp_data_len = sizeof(otp_data);
179 size_t tag_len = 8;
180 size_t nonce_len = 13;
181 uint8_t nonce[13] = {0};
182 uint8_t out_buf[32];
183 int out_len;
184 yrc = yh_util_randomize_otp_aead(session, key_id, otp_data, &otp_data_len);
185 assert(yrc == YHR_SUCCESS);
186
187 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
188
189 // Select cipher
190 assert(EVP_DecryptInit_ex(ctx, EVP_aes_128_ccm(), NULL, NULL, NULL) == 1);
191
192 // Set nonce length
193 assert(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, nonce_len, NULL) ==
194 1);
195
196 // Set expected tag value
197 assert(EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len,
198 otp_data + otp_data_len - tag_len) == 1);
199
200 // Specify key and IV
201 memcpy(nonce, &nonce_id, 4);
202 memcpy(nonce + 4, otp_data, 6);
203 assert(EVP_DecryptInit_ex(ctx, NULL, NULL, otp_key, nonce) == 1);
204
205 // Decrypt plaintext, verify tag: can only be called once
206 assert(EVP_DecryptUpdate(ctx, out_buf, &out_len, otp_data + 6,
207 otp_data_len - 6 - tag_len) == 1);
208
209 EVP_CIPHER_CTX_free(ctx);
210
211 struct {
212 union {
213 struct {
214 uint8_t id[6];
219 uint16_t rnd;
221 };
222 uint8_t raw[16];
223 };
224 } token = {.raw = {0}};
225
226 uint8_t otp[16] = {0};
227
228 memcpy(token.id, out_buf + 16, 6);
229 token.use_counter = 0xabcd;
230 token.timestamp_low = 0xdcba;
231 token.timestamp_high = 0xff;
232 token.session_counter = 0x00;
233 token.crc = ~yubikey_crc16(token.raw, 14);
234
235 AES_KEY k;
236 AES_set_encrypt_key(out_buf, 128, &k);
237 AES_ecb_encrypt(token.raw, otp, &k, AES_ENCRYPT);
238
243
244 yrc = yh_util_decrypt_otp(session, key_id, otp_data, otp_data_len, otp,
247 assert(yrc == YHR_SUCCESS);
248
249 assert(use_counter == token.use_counter);
250 assert(timestamp_low == token.timestamp_low);
251 assert(timestamp_high == token.timestamp_high);
252 assert(session_counter == token.session_counter);
253
255 assert(yrc == YHR_SUCCESS);
256
258 assert(yrc == YHR_SUCCESS);
259
260 yh_disconnect(connector);
261 assert(yrc == YHR_SUCCESS);
262
263 yrc = yh_exit();
264 assert(yrc == YHR_SUCCESS);
265
266 return 0;
267}
CK_SESSION_HANDLE session
unsigned short uint16_t
Definition stdint.h:125
unsigned int uint32_t
Definition stdint.h:126
unsigned char uint8_t
Definition stdint.h:124
Capabilities representation.
Definition yubihsm.h:162
uint16_t yubikey_crc16(const uint8_t *buf, size_t buf_size)
Definition yubico_otp.c:70
#define DEFAULT_CONNECTOR_URL
Definition yubico_otp.c:32
const uint8_t otp_key[]
Definition yubico_otp.c:37
uint16_t timestamp_low
Definition yubico_otp.c:44
uint16_t random
Definition yubico_otp.c:47
int main(void)
Definition yubico_otp.c:88
const char * key_label
Definition yubico_otp.c:35
uint8_t timestamp_high
Definition yubico_otp.c:45
uint16_t crc
Definition yubico_otp.c:48
uint8_t otp[32]
Definition yubico_otp.c:49
uint8_t session_counter
Definition yubico_otp.c:46
uint16_t use_counter
Definition yubico_otp.c:43
yh_rc yh_destroy_session(yh_session **session)
Definition yubihsm.c:890
yh_rc yh_util_decrypt_otp(yh_session *session, uint16_t key_id, const uint8_t *aead, size_t aead_len, const uint8_t *otp, uint16_t *useCtr, uint8_t *sessionCtr, uint8_t *tstph, uint16_t *tstpl)
Definition yubihsm.c:3261
yh_rc yh_exit(void)
Definition yubihsm.c:3910
yh_rc yh_create_session_derived(yh_connector *connector, uint16_t authkey_id, const uint8_t *password, size_t password_len, bool recreate, yh_session **session)
Definition yubihsm.c:593
yh_rc yh_util_randomize_otp_aead(yh_session *session, uint16_t key_id, uint8_t *out, size_t *out_len)
Definition yubihsm.c:3223
yh_rc yh_init(void)
Definition yubihsm.c:3857
yh_rc yh_util_close_session(yh_session *session)
Definition yubihsm.c:1257
yh_rc yh_authenticate_session(yh_session *session)
Definition yubihsm.c:2927
yh_rc yh_util_create_otp_aead(yh_session *session, uint16_t key_id, const uint8_t *key, const uint8_t *private_id, uint8_t *out, size_t *out_len)
Definition yubihsm.c:3179
yh_rc yh_init_connector(const char *url, yh_connector **connector)
Definition yubihsm.c:4024
yh_rc yh_util_generate_otp_aead_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, yh_algorithm algorithm, uint32_t nonce_id)
Definition yubihsm.c:3422
yh_rc yh_connect(yh_connector *connector, int timeout)
Definition yubihsm.c:4079
yh_rc yh_string_to_capabilities(const char *capability, yh_capabilities *result)
Definition yubihsm.c:4115
yh_rc yh_disconnect(yh_connector *connector)
Definition yubihsm.c:4097
yh_rc yh_util_import_otp_aead_key(yh_session *session, uint16_t *key_id, const char *label, uint16_t domains, const yh_capabilities *capabilities, uint32_t nonce_id, const uint8_t *in, size_t in_len)
Definition yubihsm.c:3337
yh_rc yh_util_delete_object(yh_session *session, uint16_t id, yh_object_type type)
Definition yubihsm.c:2222
yh_rc yh_get_session_id(yh_session *session, uint8_t *sid)
Definition yubihsm.c:2915
@ YH_OTP_AEAD_KEY
OTP AEAD Key is a secret key used to decrypt Yubico OTP values.
Definition yubihsm.h:376
@ YH_ALGO_AES128_YUBICO_OTP
aes128-yubico-otp
Definition yubihsm.h:464
yh_rc
Definition yubihsm.h:170
@ YHR_GENERIC_ERROR
Return value when encountering an unknown error.
Definition yubihsm.h:228
@ YHR_SUCCESS
Returned value when function was successful.
Definition yubihsm.h:172
yh_capabilities capabilities
uint16_t j
size_t out_len
uint8_t buf[2048]
yh_rc yrc
uint16_t key_id
memcpy((char *) pInfo->slotDescription, s, l)