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.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #ifdef HAVE_UNISTD_H 12 #include <unistd.h> 13 #endif 14 15 #include "../openbsd-compat/openbsd-compat.h" 16 #include "extern.h" 17 18 static fido_assert_t * 19 prepare_assert(FILE *in_f, int flags) 20 { 21 fido_assert_t *assert = NULL; 22 struct blob cdh; 23 struct blob id; 24 struct blob hmac_salt; 25 char *rpid = NULL; 26 int r; 27 28 memset(&cdh, 0, sizeof(cdh)); 29 memset(&id, 0, sizeof(id)); 30 memset(&hmac_salt, 0, sizeof(hmac_salt)); 31 32 r = base64_read(in_f, &cdh); 33 r |= string_read(in_f, &rpid); 34 if ((flags & FLAG_RK) == 0) 35 r |= base64_read(in_f, &id); 36 if (flags & FLAG_HMAC) 37 r |= base64_read(in_f, &hmac_salt); 38 if (r < 0) 39 errx(1, "input error"); 40 41 if (flags & FLAG_DEBUG) { 42 fprintf(stderr, "client data hash:\n"); 43 xxd(cdh.ptr, cdh.len); 44 fprintf(stderr, "relying party id: %s\n", rpid); 45 if ((flags & FLAG_RK) == 0) { 46 fprintf(stderr, "credential id:\n"); 47 xxd(id.ptr, id.len); 48 } 49 } 50 51 if ((assert = fido_assert_new()) == NULL) 52 errx(1, "fido_assert_new"); 53 54 if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr, 55 cdh.len)) != FIDO_OK || 56 (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK) 57 errx(1, "fido_assert_set: %s", fido_strerr(r)); 58 59 if (flags & FLAG_UP) { 60 if ((r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) 61 errx(1, "fido_assert_set_up: %s", fido_strerr(r)); 62 } 63 if (flags & FLAG_UV) { 64 if ((r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) 65 errx(1, "fido_assert_set_uv: %s", fido_strerr(r)); 66 } 67 if (flags & FLAG_HMAC) { 68 if ((r = fido_assert_set_extensions(assert, 69 FIDO_EXT_HMAC_SECRET)) != FIDO_OK) 70 errx(1, "fido_assert_set_extensions: %s", 71 fido_strerr(r)); 72 if ((r = fido_assert_set_hmac_salt(assert, hmac_salt.ptr, 73 hmac_salt.len)) != FIDO_OK) 74 errx(1, "fido_assert_set_hmac_salt: %s", 75 fido_strerr(r)); 76 } 77 if ((flags & FLAG_RK) == 0) { 78 if ((r = fido_assert_allow_cred(assert, id.ptr, 79 id.len)) != FIDO_OK) 80 errx(1, "fido_assert_allow_cred: %s", fido_strerr(r)); 81 } 82 83 free(hmac_salt.ptr); 84 free(cdh.ptr); 85 free(id.ptr); 86 free(rpid); 87 88 return (assert); 89 } 90 91 static void 92 print_assert(FILE *out_f, const fido_assert_t *assert, size_t idx, int flags) 93 { 94 char *cdh = NULL; 95 char *authdata = NULL; 96 char *sig = NULL; 97 char *user_id = NULL; 98 char *hmac_secret = NULL; 99 int r; 100 101 r = base64_encode(fido_assert_clientdata_hash_ptr(assert), 102 fido_assert_clientdata_hash_len(assert), &cdh); 103 r |= base64_encode(fido_assert_authdata_ptr(assert, idx), 104 fido_assert_authdata_len(assert, 0), &authdata); 105 r |= base64_encode(fido_assert_sig_ptr(assert, idx), 106 fido_assert_sig_len(assert, idx), &sig); 107 if (flags & FLAG_RK) 108 r |= base64_encode(fido_assert_user_id_ptr(assert, idx), 109 fido_assert_user_id_len(assert, idx), &user_id); 110 if (flags & FLAG_HMAC) 111 r |= base64_encode(fido_assert_hmac_secret_ptr(assert, idx), 112 fido_assert_hmac_secret_len(assert, idx), &hmac_secret); 113 if (r < 0) 114 errx(1, "output error"); 115 116 fprintf(out_f, "%s\n", cdh); 117 fprintf(out_f, "%s\n", fido_assert_rp_id(assert)); 118 fprintf(out_f, "%s\n", authdata); 119 fprintf(out_f, "%s\n", sig); 120 if (flags & FLAG_RK) 121 fprintf(out_f, "%s\n", user_id); 122 if (hmac_secret) { 123 fprintf(out_f, "%s\n", hmac_secret); 124 explicit_bzero(hmac_secret, strlen(hmac_secret)); 125 } 126 127 free(hmac_secret); 128 free(cdh); 129 free(authdata); 130 free(sig); 131 free(user_id); 132 } 133 134 int 135 assert_get(int argc, char **argv) 136 { 137 fido_dev_t *dev = NULL; 138 fido_assert_t *assert = NULL; 139 char pin[1024]; 140 char prompt[1024]; 141 char *in_path = NULL; 142 char *out_path = NULL; 143 FILE *in_f = NULL; 144 FILE *out_f = NULL; 145 int flags = 0; 146 int ch; 147 int r; 148 149 while ((ch = getopt(argc, argv, "dhi:o:pruv")) != -1) { 150 switch (ch) { 151 case 'd': 152 flags |= FLAG_DEBUG; 153 break; 154 case 'h': 155 flags |= FLAG_HMAC; 156 break; 157 case 'i': 158 in_path = optarg; 159 break; 160 case 'o': 161 out_path = optarg; 162 break; 163 case 'p': 164 flags |= FLAG_UP; 165 break; 166 case 'r': 167 flags |= FLAG_RK; 168 break; 169 case 'u': 170 flags |= FLAG_U2F; 171 break; 172 case 'v': 173 flags |= FLAG_UV; 174 break; 175 default: 176 usage(); 177 } 178 } 179 180 argc -= optind; 181 argv += optind; 182 183 if (argc < 1) 184 usage(); 185 186 in_f = open_read(in_path); 187 out_f = open_write(out_path); 188 189 fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); 190 191 assert = prepare_assert(in_f, flags); 192 193 dev = open_dev(argv[0]); 194 if (flags & FLAG_U2F) 195 fido_dev_force_u2f(dev); 196 197 if (flags & FLAG_UV) { 198 r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", 199 argv[0]); 200 if (r < 0 || (size_t)r >= sizeof(prompt)) 201 errx(1, "snprintf"); 202 if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) 203 errx(1, "readpassphrase"); 204 r = fido_dev_get_assert(dev, assert, pin); 205 } else 206 r = fido_dev_get_assert(dev, assert, NULL); 207 208 explicit_bzero(pin, sizeof(pin)); 209 210 if (r != FIDO_OK) 211 errx(1, "fido_dev_get_assert: %s", fido_strerr(r)); 212 213 if (flags & FLAG_RK) { 214 for (size_t idx = 0; idx < fido_assert_count(assert); idx++) 215 print_assert(out_f, assert, idx, flags); 216 } else { 217 if (fido_assert_count(assert) != 1) 218 errx(1, "fido_assert_count: %zu", 219 fido_assert_count(assert)); 220 print_assert(out_f, assert, 0, flags); 221 } 222 223 fido_dev_close(dev); 224 fido_dev_free(&dev); 225 fido_assert_free(&assert); 226 227 fclose(in_f); 228 fclose(out_f); 229 in_f = NULL; 230 out_f = NULL; 231 232 exit(0); 233 } 234