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_cred_t * 19 prepare_cred(FILE *in_f, int type, int flags) 20 { 21 fido_cred_t *cred = NULL; 22 struct blob cdh; 23 struct blob uid; 24 char *rpid = NULL; 25 char *uname = NULL; 26 int r; 27 28 memset(&cdh, 0, sizeof(cdh)); 29 memset(&uid, 0, sizeof(uid)); 30 31 r = base64_read(in_f, &cdh); 32 r |= string_read(in_f, &rpid); 33 r |= string_read(in_f, &uname); 34 r |= base64_read(in_f, &uid); 35 if (r < 0) 36 errx(1, "input error"); 37 38 if (flags & FLAG_DEBUG) { 39 fprintf(stderr, "client data hash:\n"); 40 xxd(cdh.ptr, cdh.len); 41 fprintf(stderr, "relying party id: %s\n", rpid); 42 fprintf(stderr, "user name: %s\n", uname); 43 fprintf(stderr, "user id:\n"); 44 xxd(uid.ptr, uid.len); 45 } 46 47 if ((cred = fido_cred_new()) == NULL) 48 errx(1, "fido_cred_new"); 49 50 if ((r = fido_cred_set_type(cred, type)) != FIDO_OK || 51 (r = fido_cred_set_clientdata_hash(cred, cdh.ptr, 52 cdh.len)) != FIDO_OK || 53 (r = fido_cred_set_rp(cred, rpid, NULL)) != FIDO_OK || 54 (r = fido_cred_set_user(cred, uid.ptr, uid.len, uname, NULL, 55 NULL)) != FIDO_OK) 56 errx(1, "fido_cred_set: %s", fido_strerr(r)); 57 58 if (flags & FLAG_RK) { 59 if ((r = fido_cred_set_rk(cred, FIDO_OPT_TRUE)) != FIDO_OK) 60 errx(1, "fido_cred_set_rk: %s", fido_strerr(r)); 61 } 62 if (flags & FLAG_UV) { 63 if ((r = fido_cred_set_uv(cred, FIDO_OPT_TRUE)) != FIDO_OK) 64 errx(1, "fido_cred_set_uv: %s", fido_strerr(r)); 65 } 66 if (flags & FLAG_HMAC) { 67 if ((r = fido_cred_set_extensions(cred, 68 FIDO_EXT_HMAC_SECRET)) != FIDO_OK) 69 errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); 70 } 71 if (flags & FLAG_LARGEBLOB) { 72 if ((r = fido_cred_set_extensions(cred, 73 FIDO_EXT_LARGEBLOB_KEY)) != FIDO_OK) 74 errx(1, "fido_cred_set_extensions: %s", fido_strerr(r)); 75 } 76 77 free(cdh.ptr); 78 free(uid.ptr); 79 free(rpid); 80 free(uname); 81 82 return (cred); 83 } 84 85 static void 86 print_attcred(FILE *out_f, const fido_cred_t *cred) 87 { 88 char *cdh = NULL; 89 char *authdata = NULL; 90 char *id = NULL; 91 char *sig = NULL; 92 char *x5c = NULL; 93 char *key = NULL; 94 int r; 95 96 r = base64_encode(fido_cred_clientdata_hash_ptr(cred), 97 fido_cred_clientdata_hash_len(cred), &cdh); 98 r |= base64_encode(fido_cred_authdata_ptr(cred), 99 fido_cred_authdata_len(cred), &authdata); 100 r |= base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), 101 &id); 102 r |= base64_encode(fido_cred_sig_ptr(cred), fido_cred_sig_len(cred), 103 &sig); 104 if (fido_cred_x5c_ptr(cred) != NULL) 105 r |= base64_encode(fido_cred_x5c_ptr(cred), 106 fido_cred_x5c_len(cred), &x5c); 107 if (fido_cred_largeblob_key_ptr(cred) != NULL) 108 r |= base64_encode(fido_cred_largeblob_key_ptr(cred), 109 fido_cred_largeblob_key_len(cred), &key); 110 if (r < 0) 111 errx(1, "output error"); 112 113 fprintf(out_f, "%s\n", cdh); 114 fprintf(out_f, "%s\n", fido_cred_rp_id(cred)); 115 fprintf(out_f, "%s\n", fido_cred_fmt(cred)); 116 fprintf(out_f, "%s\n", authdata); 117 fprintf(out_f, "%s\n", id); 118 fprintf(out_f, "%s\n", sig); 119 if (x5c != NULL) 120 fprintf(out_f, "%s\n", x5c); 121 if (key != NULL) { 122 fprintf(out_f, "%s\n", key); 123 explicit_bzero(key, strlen(key)); 124 } 125 126 free(cdh); 127 free(authdata); 128 free(id); 129 free(sig); 130 free(x5c); 131 free(key); 132 } 133 134 int 135 cred_make(int argc, char **argv) 136 { 137 fido_dev_t *dev = NULL; 138 fido_cred_t *cred = NULL; 139 char prompt[1024]; 140 char pin[1024]; 141 char *in_path = NULL; 142 char *out_path = NULL; 143 FILE *in_f = NULL; 144 FILE *out_f = NULL; 145 int type = COSE_ES256; 146 int flags = 0; 147 int cred_protect = -1; 148 int ch; 149 int r; 150 151 while ((ch = getopt(argc, argv, "bc:dhi:o:qruv")) != -1) { 152 switch (ch) { 153 case 'b': 154 flags |= FLAG_LARGEBLOB; 155 break; 156 case 'c': 157 if ((cred_protect = base10(optarg)) < 0) 158 errx(1, "-c: invalid argument '%s'", optarg); 159 break; 160 case 'd': 161 flags |= FLAG_DEBUG; 162 break; 163 case 'h': 164 flags |= FLAG_HMAC; 165 break; 166 case 'i': 167 in_path = optarg; 168 break; 169 case 'o': 170 out_path = optarg; 171 break; 172 case 'q': 173 flags |= FLAG_QUIET; 174 break; 175 case 'r': 176 flags |= FLAG_RK; 177 break; 178 case 'u': 179 flags |= FLAG_U2F; 180 break; 181 case 'v': 182 flags |= FLAG_UV; 183 break; 184 default: 185 usage(); 186 } 187 } 188 189 argc -= optind; 190 argv += optind; 191 192 if (argc < 1 || argc > 2) 193 usage(); 194 195 in_f = open_read(in_path); 196 out_f = open_write(out_path); 197 198 if (argc > 1 && cose_type(argv[1], &type) < 0) 199 errx(1, "unknown type %s", argv[1]); 200 201 fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); 202 203 cred = prepare_cred(in_f, type, flags); 204 205 dev = open_dev(argv[0]); 206 if (flags & FLAG_U2F) 207 fido_dev_force_u2f(dev); 208 209 if (cred_protect > 0) { 210 r = fido_cred_set_prot(cred, cred_protect); 211 if (r != FIDO_OK) { 212 errx(1, "fido_cred_set_prot: %s", fido_strerr(r)); 213 } 214 } 215 216 r = fido_dev_make_cred(dev, cred, NULL); 217 if (r == FIDO_ERR_PIN_REQUIRED && !(flags & FLAG_QUIET)) { 218 r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", 219 argv[0]); 220 if (r < 0 || (size_t)r >= sizeof(prompt)) 221 errx(1, "snprintf"); 222 if (!readpassphrase(prompt, pin, sizeof(pin), RPP_ECHO_OFF)) 223 errx(1, "readpassphrase"); 224 r = fido_dev_make_cred(dev, cred, pin); 225 } 226 227 explicit_bzero(pin, sizeof(pin)); 228 if (r != FIDO_OK) 229 errx(1, "fido_dev_make_cred: %s", fido_strerr(r)); 230 print_attcred(out_f, cred); 231 232 fido_dev_close(dev); 233 fido_dev_free(&dev); 234 fido_cred_free(&cred); 235 236 fclose(in_f); 237 fclose(out_f); 238 in_f = NULL; 239 out_f = NULL; 240 241 exit(0); 242 } 243