Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
main.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#include <ctype.h>
18#include <errno.h>
19#include <stdbool.h>
20#include <stddef.h>
21#include <stdint.h>
22#include <stdlib.h>
23#include <string.h>
24
25#ifdef __WIN32
26#include <winsock.h>
27#else
28#include <arpa/inet.h>
29#endif
30
31#include <openssl/evp.h>
32#include <openssl/rand.h>
33
34#include "cmdline.h"
35
36#include "parsing.h"
37#include "util.h"
38
39#include <yubihsm.h>
40
41#define INPUT_BUFSIZE 4096
42#define WRAPKEY_BUFSIZE 32
43
44#define OBJECT_HEADER_SIZE 59
45
46static bool wrap_data(uint8_t *key, size_t key_len, uint8_t *in, size_t in_len,
47 uint8_t *out, size_t *out_len) {
48
49 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
50 const EVP_CIPHER *cipher_type;
51
52 uint8_t nonce[13];
53 int nonce_len = 13;
54 int tag_len = 16;
55
56 int len;
57
58 switch (key_len) {
59 case 16:
60 cipher_type = EVP_aes_128_ccm();
61 break;
62
63 case 24:
64 cipher_type = EVP_aes_192_ccm();
65 break;
66
67 case 32:
68 cipher_type = EVP_aes_256_ccm();
69 break;
70
71 default:
72 return false;
73 }
74
75 if (RAND_bytes(nonce, nonce_len) != 1) {
76 return false;
77 }
78
79 memcpy(out, nonce, nonce_len);
80
81 // Select cipher
82 if (EVP_EncryptInit_ex(ctx, cipher_type, NULL, NULL, NULL) != 1) {
83 return false;
84 }
85
86 // Set nonce length
87 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_IVLEN, nonce_len, NULL) != 1) {
88 return false;
89 }
90
91 // Set tag length
92 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_SET_TAG, tag_len, NULL) != 1) {
93 return false;
94 }
95
96 // Initialize key and IV
97 if (EVP_EncryptInit_ex(ctx, NULL, NULL, key, nonce) != 1) {
98 return false;
99 }
100
101 // Provide the total plaintext length
102 if (EVP_EncryptUpdate(ctx, NULL, &len, NULL, in_len) != 1) {
103 return false;
104 }
105
106 // Provide the message to be encrypted, and obtain the encrypted output
107 if (EVP_EncryptUpdate(ctx, out + nonce_len, &len, in, in_len) != 1) {
108 return false;
109 }
110 *out_len = len;
111
112 // Finalize the encryption
113 if (EVP_EncryptFinal_ex(ctx, out + nonce_len + *out_len, &len) != 1) {
114 return false;
115 }
116 *out_len += len;
117
118 // Get the tag
119 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_CCM_GET_TAG, tag_len,
120 out + nonce_len + *out_len) != 1) {
121 return false;
122 }
123 *out_len += tag_len;
124 *out_len += nonce_len;
125
126 // Clean up
127 EVP_CIPHER_CTX_free(ctx);
128
129 return true;
130}
131
132static void format_header(yh_algorithm wrapkey_algorithm,
134 uint16_t data_len, uint16_t domains,
136 uint8_t *label, uint8_t *header) {
137
138 *header = (uint8_t) wrapkey_algorithm;
139 header++;
140
142 header += YH_CAPABILITIES_LEN;
143
144 *((uint16_t *) header) = htons(id);
145 header += sizeof(uint16_t);
146
147 *((uint16_t *) header) = htons(data_len);
148 header += sizeof(uint16_t);
149
150 *((uint16_t *) header) = htons(domains);
151 header += sizeof(uint16_t);
152
153 *header = (uint8_t) type;
154 header++;
155
156 *header = (uint8_t) algorithm;
157 header++;
158
159 *header = 0x00; // Sequence
160 header++;
161
162 *header = 0x02; // Origin
163 header++;
164
165 memcpy(header, label, YH_OBJ_LABEL_LEN);
166 header += YH_OBJ_LABEL_LEN;
167}
168
169static FILE *open_file(const char *name, bool input) {
170 if (input) {
171 if (strcmp(name, "-") == 0) {
172 return stdin;
173 } else {
174 return fopen(name, "rb");
175 }
176 } else {
177 if (strcmp(name, "-") == 0) {
178 return stdout;
179 } else {
180 return fopen(name, "wb");
181 }
182 }
183}
184
185static void dump_hex(const unsigned char *buf, unsigned int len) {
186 unsigned int i;
187 for (i = 0; i < len; i++) {
188 if (i && !(i % 32))
189 fprintf(stderr, "\n");
190 else if (i && !(i % 8))
191 fprintf(stderr, " ");
192 fprintf(stderr, "%02x", buf[i]);
193 }
194 fprintf(stderr, "\n");
195}
196
197int main(int argc, char *argv[]) {
198 struct gengetopt_args_info args_info;
199
200 int rc = EXIT_FAILURE;
201 yh_rc yhrc;
202
203 FILE *input_file = NULL;
204 FILE *output_file = NULL;
205 FILE *wrapkey_file = NULL;
206
207#pragma pack(push, 1)
208 union {
209 struct {
212 };
213 uint8_t buf[1];
214 } wrap_object = {{{0}, {0}}};
215#pragma pack(pop)
216 size_t wrap_object_len = sizeof(wrap_object.body);
217
218 if (cmdline_parser(argc, argv, &args_info) != 0) {
219 goto main_exit;
220 }
221
223 yhrc = yh_string_to_algo(args_info.algorithm_arg, &algorithm);
224 if (yhrc != YHR_SUCCESS) {
225 fprintf(stderr, "Unable to parse algorithm: %s\n", yh_strerror(yhrc));
226 goto main_exit;
227 }
228
230 yhrc = yh_string_to_capabilities(args_info.capabilities_arg, &capabilities);
231 if (yhrc != YHR_SUCCESS) {
232 fprintf(stderr, "Unable to parse capabilities: %s\n", yh_strerror(yhrc));
233 goto main_exit;
234 }
235
237 yhrc = yh_string_to_domains(args_info.domains_arg, &domains);
238 if (yhrc != YHR_SUCCESS) {
239 fprintf(stderr, "Unable to parse domains: %s\n", yh_strerror(yhrc));
240 goto main_exit;
241 }
242
243 uint16_t id = args_info.id_arg;
244
246 size_t label_len = strlen(args_info.label_arg);
248 fprintf(stderr,
249 "Unable to parse label: label too long, maximum length is %d\n",
251 goto main_exit;
252 }
253 memcpy(label, args_info.label_arg, label_len);
254
256 if (algo2type(algorithm, &type) == false) {
257 fprintf(stderr, "Invalid algorithm\n");
258 goto main_exit;
259 }
260
261 yh_capabilities delegated = {{0}};
262 bool has_delegated =
263 ((type == YH_AUTHENTICATION_KEY || type == YH_WRAP_KEY) ? true : false);
264 if (has_delegated == true) {
265 if (!args_info.delegated_given) {
266 fprintf(stderr, "Missing delegated capabilities argument\n");
267 goto main_exit;
268 }
269
270 yhrc = yh_string_to_capabilities(args_info.delegated_arg, &delegated);
271 if (yhrc != YHR_SUCCESS) {
272 fprintf(stderr, "Unable to parse delegated capabilities: %s\n",
273 yh_strerror(yhrc));
274 goto main_exit;
275 }
276 }
277
278 input_file = open_file(args_info.in_arg, true);
279 if (input_file == NULL) {
280 perror("Unable to open input file");
281 goto main_exit;
282 }
283
284 switch (type) {
286 char password[256] = {0};
287 size_t password_len = sizeof(password);
288
289 if (input_file == stdin) {
290 const char *prompt = "Derivation Password: ";
291 if (EVP_read_pw_string(password, password_len, prompt, 1)) {
292 fprintf(stderr, "Unable to read password prompt\n");
293 goto main_exit;
294 }
295 password_len = strlen(password);
296 } else {
297 if (read_file(input_file, (uint8_t *) password, &password_len) ==
298 false) {
299 fprintf(stderr, "Unable to read input file\n");
300 goto main_exit;
301 }
302 if (password[password_len - 1] == '\n') {
303 password_len--;
304 }
305 if (password[password_len - 1] == '\r') {
306 password_len--;
307 }
308 password[password_len] = '\0';
309 }
310
311 uint8_t key[YH_KEY_LEN * 2];
312 int ret =
313 PKCS5_PBKDF2_HMAC((const char *) password, password_len,
315 YH_DEFAULT_ITERS, EVP_sha256(), sizeof(key), key);
316 if (ret != 1) {
317 fprintf(stderr, "Unable to derive keys\n");
318 goto main_exit;
319 }
320
321 memcpy(wrap_object.body, delegated.capabilities, YH_CAPABILITIES_LEN);
322 wrap_object_len -= YH_CAPABILITIES_LEN;
323
324 memcpy(wrap_object.body + YH_CAPABILITIES_LEN, key, YH_KEY_LEN);
325 memcpy(wrap_object.body + YH_CAPABILITIES_LEN + YH_KEY_LEN,
326 key + YH_KEY_LEN, YH_KEY_LEN);
327 wrap_object_len = YH_CAPABILITIES_LEN + YH_KEY_LEN * 2;
328 } break;
329
330 case YH_WRAP_KEY: {
331 memcpy(wrap_object.body, delegated.capabilities, YH_CAPABILITIES_LEN);
332 wrap_object_len -= YH_CAPABILITIES_LEN;
333
334 if (read_file(input_file, wrap_object.body + YH_CAPABILITIES_LEN,
335 &wrap_object_len) == false) {
336 fprintf(stderr, "Unable to read input file\n");
337 goto main_exit;
338 }
339 wrap_object_len += YH_CAPABILITIES_LEN;
340 } break;
341
342 case YH_ASYMMETRIC_KEY: {
343 yh_algorithm parsed_algorithm;
344 if (read_file(input_file, wrap_object.body, &wrap_object_len) == false) {
345 fprintf(stderr, "Unable to read input file\n");
346 goto main_exit;
347 }
348
349 if (read_private_key(wrap_object.body, wrap_object_len, &parsed_algorithm,
350 wrap_object.body, &wrap_object_len, true) != true) {
351 fprintf(stderr, "Unable to read asymmetric private key\n");
352 goto main_exit;
353 }
354
355 if (parsed_algorithm != algorithm) {
356 fprintf(stderr, "Mismatched algorithm\n");
357 goto main_exit;
358 }
359 } break;
360
361 case YH_HMAC_KEY: {
362 if (read_file(input_file, wrap_object.body, &wrap_object_len) == false) {
363 fprintf(stderr, "Unable to read input file\n");
364 goto main_exit;
365 }
366
367 if (split_hmac_key(algorithm, wrap_object.body, wrap_object_len,
368 wrap_object.body, &wrap_object_len) != true) {
369 fprintf(stderr, "Unable to format hmac key\n");
370 goto main_exit;
371 }
372 } break;
373
374 default:
375 if (read_file(input_file, wrap_object.body, &wrap_object_len) == false) {
376 fprintf(stderr, "Unable to read input file\n");
377 goto main_exit;
378 }
379 }
380
381 wrapkey_file = open_file(args_info.wrapkey_arg, true);
382 if (wrapkey_file == NULL) {
383 perror("Unable to open wrapkey file");
384 goto main_exit;
385 }
386
387 uint8_t wrapkey_buf[WRAPKEY_BUFSIZE];
388 size_t wrapkey_buf_len = sizeof(wrapkey_buf);
389 if (read_file(wrapkey_file, wrapkey_buf, &wrapkey_buf_len) == false) {
390 fprintf(stderr, "Unable to read wrapkey file\n");
391 }
392
393 yh_algorithm wrapkey_algorithm;
394 switch (wrapkey_buf_len) {
395 case 16:
396 wrapkey_algorithm = YH_ALGO_AES128_CCM_WRAP;
397 break;
398 case 24:
399 wrapkey_algorithm = YH_ALGO_AES192_CCM_WRAP;
400 break;
401 case 32:
402 wrapkey_algorithm = YH_ALGO_AES256_CCM_WRAP;
403 break;
404 default:
405 fprintf(stderr, "Unable to parse wrapkey: invalid length\n");
406 goto main_exit;
407 }
408
409 output_file = open_file(args_info.out_arg, false);
410 if (output_file == NULL) {
411 perror("Unable to open output file");
412 goto main_exit;
413 }
414
415 format_header(wrapkey_algorithm, capabilities, id, wrap_object_len, domains,
416 type, algorithm, label, wrap_object.header);
417
418 uint8_t wrapped[2048] = {0};
419 size_t wrapped_len = sizeof(wrapped);
420
421 if (wrap_data(wrapkey_buf, wrapkey_buf_len, wrap_object.buf,
422 OBJECT_HEADER_SIZE + wrap_object_len, wrapped,
423 &wrapped_len) == false) {
424 fprintf(stderr, "Unable to wrap data\n");
425 goto main_exit;
426 }
427
428 if (getenv("DEBUG") != NULL) {
429 dump_hex(wrap_object.buf, OBJECT_HEADER_SIZE + wrap_object_len);
430 }
431 if (write_file(wrapped, wrapped_len, output_file, _base64) == false ||
432 write_file((uint8_t *) "\n", 1, output_file, _binary) == false) {
433 fprintf(stderr, "Unable to write output file\n");
434 goto main_exit;
435 }
436
437 rc = EXIT_SUCCESS;
438
439main_exit:
440
441 cmdline_parser_free(&args_info);
442
443 if (input_file != NULL) {
444 fclose(input_file);
445 input_file = NULL;
446 }
447
448 if (output_file != NULL) {
449 fclose(output_file);
450 output_file = NULL;
451 }
452
453 if (wrapkey_file != NULL) {
454 fclose(wrapkey_file);
455 wrapkey_file = NULL;
456 }
457
458 return rc;
459}
const uint8_t password[]
Definition attest.c:39
std::string name
char ** argv
const char * yh_strerror(yh_rc err)
Definition error.c:65
void YH_INTERNAL dump_hex(FILE *file, const uint8_t *ptr, uint16_t len)
Definition lib_util.c:33
unsigned short uint16_t
Definition stdint.h:125
unsigned char uint8_t
Definition stdint.h:124
Capabilities representation.
Definition yubihsm.h:162
uint8_t capabilities[YH_CAPABILITIES_LEN]
Capabilities is represented as an 8 byte uint8_t array.
Definition yubihsm.h:164
bool split_hmac_key(yh_algorithm algorithm, uint8_t *in, size_t in_len, uint8_t *out, size_t *out_len)
Definition util.c:653
bool algo2type(yh_algorithm algorithm, yh_object_type *type)
Definition util.c:374
bool read_file(FILE *fp, uint8_t *buf, size_t *buf_len)
Definition util.c:476
bool write_file(const uint8_t *buf, size_t buf_len, FILE *fp, format_t format)
Definition util.c:559
bool read_private_key(uint8_t *buf, size_t len, yh_algorithm *algo, uint8_t *bytes, size_t *bytes_len, bool internal_repr)
Definition util.c:116
#define OBJECT_HEADER_SIZE
Definition main.c:44
#define INPUT_BUFSIZE
Definition main.c:41
#define WRAPKEY_BUFSIZE
Definition main.c:42
@ _base64
Definition util.h:28
@ _binary
Definition util.h:29
yh_rc yh_string_to_domains(const char *domains, uint16_t *result)
Definition yubihsm.c:4535
yh_rc yh_string_to_capabilities(const char *capability, yh_capabilities *result)
Definition yubihsm.c:4115
yh_rc yh_string_to_algo(const char *string, yh_algorithm *algo)
Definition yubihsm.c:4403
#define YH_DEFAULT_ITERS
Number of iterations for PBKDF2 key derivation.
Definition yubihsm.h:117
yh_object_type type
Definition yubihsm.h:672
yh_object_type
Definition yubihsm.h:359
@ YH_WRAP_KEY
Definition yubihsm.h:369
@ YH_HMAC_KEY
HMAC Key is a secret key used when computing and verifying HMAC signatures.
Definition yubihsm.h:371
@ YH_ASYMMETRIC_KEY
Asymmetric Key is the private key of an asymmetric key-pair.
Definition yubihsm.h:366
@ YH_AUTHENTICATION_KEY
Authentication Key is used to establish Sessions with a device.
Definition yubihsm.h:364
#define YH_OBJ_LABEL_LEN
Max length of object labels.
Definition yubihsm.h:123
yh_algorithm
Definition yubihsm.h:390
@ YH_ALGO_AES256_CCM_WRAP
aes256-ccm-wrap
Definition yubihsm.h:474
@ YH_ALGO_AES192_CCM_WRAP
aes192-ccm-wrap
Definition yubihsm.h:472
@ YH_ALGO_AES128_CCM_WRAP
aes128-ccm-wrap
Definition yubihsm.h:448
yh_algorithm algorithm
Definition yubihsm.h:619
#define YH_DEFAULT_SALT
Salt to be used for PBKDF2 key derivation.
Definition yubihsm.h:115
#define YH_KEY_LEN
Length of authentication keys.
Definition yubihsm.h:95
#define YH_CAPABILITIES_LEN
Length of capabilities array.
Definition yubihsm.h:119
yh_rc
Definition yubihsm.h:170
@ YHR_SUCCESS
Returned value when function was successful.
Definition yubihsm.h:172
yh_capabilities capabilities
char * label
CK_RV ret
uint16_t domains
size_t out_len
size_t len
uint8_t buf[2048]
session operation op sign key_len
yh_rc rc
size_t label_len
memcpy((char *) pInfo->slotDescription, s, l)
size_t in_len