1 /* 2 * Copyright (c) 2018-2022 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 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8 #include <fido.h> 9 #include <fido/es256.h> 10 #include <fido/es384.h> 11 #include <fido/rs256.h> 12 #include <fido/eddsa.h> 13 14 #include <stdio.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #ifdef HAVE_UNISTD_H 18 #include <unistd.h> 19 #endif 20 21 #include "../openbsd-compat/openbsd-compat.h" 22 #include "extern.h" 23 24 static fido_assert_t * 25 prepare_assert(FILE *in_f, int flags) 26 { 27 fido_assert_t *assert = NULL; 28 struct blob cdh; 29 struct blob authdata; 30 struct blob sig; 31 char *rpid = NULL; 32 int r; 33 34 memset(&cdh, 0, sizeof(cdh)); 35 memset(&authdata, 0, sizeof(authdata)); 36 memset(&sig, 0, sizeof(sig)); 37 38 r = base64_read(in_f, &cdh); 39 r |= string_read(in_f, &rpid); 40 r |= base64_read(in_f, &authdata); 41 r |= base64_read(in_f, &sig); 42 if (r < 0) 43 errx(1, "input error"); 44 45 if (flags & FLAG_DEBUG) { 46 fprintf(stderr, "client data hash:\n"); 47 xxd(cdh.ptr, cdh.len); 48 fprintf(stderr, "relying party id: %s\n", rpid); 49 fprintf(stderr, "authenticator data:\n"); 50 xxd(authdata.ptr, authdata.len); 51 fprintf(stderr, "signature:\n"); 52 xxd(sig.ptr, sig.len); 53 } 54 55 if ((assert = fido_assert_new()) == NULL) 56 errx(1, "fido_assert_new"); 57 if ((r = fido_assert_set_count(assert, 1)) != FIDO_OK) 58 errx(1, "fido_assert_count: %s", fido_strerr(r)); 59 60 if ((r = fido_assert_set_clientdata_hash(assert, cdh.ptr, 61 cdh.len)) != FIDO_OK || 62 (r = fido_assert_set_rp(assert, rpid)) != FIDO_OK || 63 (r = fido_assert_set_authdata(assert, 0, authdata.ptr, 64 authdata.len)) != FIDO_OK || 65 (r = fido_assert_set_sig(assert, 0, sig.ptr, sig.len)) != FIDO_OK) 66 errx(1, "fido_assert_set: %s", fido_strerr(r)); 67 68 if (flags & FLAG_UP) { 69 if ((r = fido_assert_set_up(assert, FIDO_OPT_TRUE)) != FIDO_OK) 70 errx(1, "fido_assert_set_up: %s", fido_strerr(r)); 71 } 72 if (flags & FLAG_UV) { 73 if ((r = fido_assert_set_uv(assert, FIDO_OPT_TRUE)) != FIDO_OK) 74 errx(1, "fido_assert_set_uv: %s", fido_strerr(r)); 75 } 76 if (flags & FLAG_HMAC) { 77 if ((r = fido_assert_set_extensions(assert, 78 FIDO_EXT_HMAC_SECRET)) != FIDO_OK) 79 errx(1, "fido_assert_set_extensions: %s", 80 fido_strerr(r)); 81 } 82 83 free(cdh.ptr); 84 free(authdata.ptr); 85 free(sig.ptr); 86 free(rpid); 87 88 return (assert); 89 } 90 91 static void * 92 load_pubkey(int type, const char *file) 93 { 94 EC_KEY *ec = NULL; 95 RSA *rsa = NULL; 96 EVP_PKEY *eddsa = NULL; 97 es256_pk_t *es256_pk = NULL; 98 es384_pk_t *es384_pk = NULL; 99 rs256_pk_t *rs256_pk = NULL; 100 eddsa_pk_t *eddsa_pk = NULL; 101 void *pk = NULL; 102 103 switch (type) { 104 case COSE_ES256: 105 if ((ec = read_ec_pubkey(file)) == NULL) 106 errx(1, "read_ec_pubkey"); 107 if ((es256_pk = es256_pk_new()) == NULL) 108 errx(1, "es256_pk_new"); 109 if (es256_pk_from_EC_KEY(es256_pk, ec) != FIDO_OK) 110 errx(1, "es256_pk_from_EC_KEY"); 111 pk = es256_pk; 112 EC_KEY_free(ec); 113 break; 114 case COSE_ES384: 115 if ((ec = read_ec_pubkey(file)) == NULL) 116 errx(1, "read_ec_pubkey"); 117 if ((es384_pk = es384_pk_new()) == NULL) 118 errx(1, "es384_pk_new"); 119 if (es384_pk_from_EC_KEY(es384_pk, ec) != FIDO_OK) 120 errx(1, "es384_pk_from_EC_KEY"); 121 pk = es384_pk; 122 EC_KEY_free(ec); 123 break; 124 case COSE_RS256: 125 if ((rsa = read_rsa_pubkey(file)) == NULL) 126 errx(1, "read_rsa_pubkey"); 127 if ((rs256_pk = rs256_pk_new()) == NULL) 128 errx(1, "rs256_pk_new"); 129 if (rs256_pk_from_RSA(rs256_pk, rsa) != FIDO_OK) 130 errx(1, "rs256_pk_from_RSA"); 131 pk = rs256_pk; 132 RSA_free(rsa); 133 break; 134 case COSE_EDDSA: 135 if ((eddsa = read_eddsa_pubkey(file)) == NULL) 136 errx(1, "read_eddsa_pubkey"); 137 if ((eddsa_pk = eddsa_pk_new()) == NULL) 138 errx(1, "eddsa_pk_new"); 139 if (eddsa_pk_from_EVP_PKEY(eddsa_pk, eddsa) != FIDO_OK) 140 errx(1, "eddsa_pk_from_EVP_PKEY"); 141 pk = eddsa_pk; 142 EVP_PKEY_free(eddsa); 143 break; 144 default: 145 errx(1, "invalid type %d", type); 146 } 147 148 return (pk); 149 } 150 151 int 152 assert_verify(int argc, char **argv) 153 { 154 fido_assert_t *assert = NULL; 155 void *pk = NULL; 156 char *in_path = NULL; 157 FILE *in_f = NULL; 158 int type = COSE_ES256; 159 int flags = 0; 160 int ch; 161 int r; 162 163 while ((ch = getopt(argc, argv, "dhi:pv")) != -1) { 164 switch (ch) { 165 case 'd': 166 flags |= FLAG_DEBUG; 167 break; 168 case 'h': 169 flags |= FLAG_HMAC; 170 break; 171 case 'i': 172 in_path = optarg; 173 break; 174 case 'p': 175 flags |= FLAG_UP; 176 break; 177 case 'v': 178 flags |= FLAG_UV; 179 break; 180 default: 181 usage(); 182 } 183 } 184 185 argc -= optind; 186 argv += optind; 187 188 if (argc < 1 || argc > 2) 189 usage(); 190 191 in_f = open_read(in_path); 192 193 if (argc > 1 && cose_type(argv[1], &type) < 0) 194 errx(1, "unknown type %s", argv[1]); 195 196 fido_init((flags & FLAG_DEBUG) ? FIDO_DEBUG : 0); 197 198 pk = load_pubkey(type, argv[0]); 199 assert = prepare_assert(in_f, flags); 200 if ((r = fido_assert_verify(assert, 0, type, pk)) != FIDO_OK) 201 errx(1, "fido_assert_verify: %s", fido_strerr(r)); 202 fido_assert_free(&assert); 203 204 fclose(in_f); 205 in_f = NULL; 206 207 exit(0); 208 } 209