Home | History | Annotate | Line # | Download | only in tools
util.c revision 1.1.1.2
      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 <sys/types.h>
      8 #include <sys/stat.h>
      9 
     10 #include <openssl/ec.h>
     11 #include <openssl/evp.h>
     12 #include <openssl/pem.h>
     13 
     14 #include <fido.h>
     15 #include <fido/es256.h>
     16 #include <fido/rs256.h>
     17 #include <fido/eddsa.h>
     18 
     19 #include <errno.h>
     20 #include <fcntl.h>
     21 #include <limits.h>
     22 #include <stdint.h>
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <string.h>
     26 
     27 #include "../openbsd-compat/openbsd-compat.h"
     28 #ifdef _MSC_VER
     29 #include "../openbsd-compat/posix_win.h"
     30 #endif
     31 
     32 #include "extern.h"
     33 
     34 void
     35 read_pin(const char *path, char *buf, size_t len)
     36 {
     37 	char prompt[1024];
     38 	int r;
     39 
     40 	r = snprintf(prompt, sizeof(prompt), "Enter PIN for %s: ", path);
     41 	if (r < 0 || (size_t)r >= sizeof(prompt))
     42 		errx(1, "snprintf");
     43 	if (!readpassphrase(prompt, buf, len, RPP_ECHO_OFF))
     44 		errx(1, "readpassphrase");
     45 }
     46 
     47 FILE *
     48 open_write(const char *file)
     49 {
     50 	int fd;
     51 	FILE *f;
     52 
     53 	if (file == NULL || strcmp(file, "-") == 0)
     54 		return (stdout);
     55 	if ((fd = open(file, O_WRONLY | O_CREAT, 0600)) < 0)
     56 		err(1, "open %s", file);
     57 	if ((f = fdopen(fd, "w")) == NULL)
     58 		err(1, "fdopen %s", file);
     59 
     60 	return (f);
     61 }
     62 
     63 FILE *
     64 open_read(const char *file)
     65 {
     66 	int fd;
     67 	FILE *f;
     68 
     69 	if (file == NULL || strcmp(file, "-") == 0) {
     70 #ifdef FIDO_FUZZ
     71 		setvbuf(stdin, NULL, _IONBF, 0);
     72 #endif
     73 		return (stdin);
     74 	}
     75 	if ((fd = open(file, O_RDONLY)) < 0)
     76 		err(1, "open %s", file);
     77 	if ((f = fdopen(fd, "r")) == NULL)
     78 		err(1, "fdopen %s", file);
     79 
     80 	return (f);
     81 }
     82 
     83 int
     84 base10(const char *str)
     85 {
     86 	char *ep;
     87 	long long ll;
     88 
     89 	ll = strtoll(str, &ep, 10);
     90 	if (str == ep || *ep != '\0')
     91 		return (-1);
     92 	else if (ll == LLONG_MIN && errno == ERANGE)
     93 		return (-1);
     94 	else if (ll == LLONG_MAX && errno == ERANGE)
     95 		return (-1);
     96 	else if (ll < 0 || ll > INT_MAX)
     97 		return (-1);
     98 
     99 	return ((int)ll);
    100 }
    101 
    102 void
    103 xxd(const void *buf, size_t count)
    104 {
    105 	const uint8_t	*ptr = buf;
    106 	size_t		 i;
    107 
    108 	fprintf(stderr, "  ");
    109 
    110 	for (i = 0; i < count; i++) {
    111 		fprintf(stderr, "%02x ", *ptr++);
    112 		if ((i + 1) % 16 == 0 && i + 1 < count)
    113 			fprintf(stderr, "\n  ");
    114 	}
    115 
    116 	fprintf(stderr, "\n");
    117 	fflush(stderr);
    118 }
    119 
    120 int
    121 string_read(FILE *f, char **out)
    122 {
    123 	char *line = NULL;
    124 	size_t linesize = 0;
    125 	ssize_t n;
    126 
    127 	*out = NULL;
    128 
    129 	if ((n = getline(&line, &linesize, f)) <= 0 ||
    130 	    (size_t)n != strlen(line)) {
    131 		free(line);
    132 		return (-1);
    133 	}
    134 
    135 	line[n - 1] = '\0'; /* trim \n */
    136 	*out = line;
    137 
    138 	return (0);
    139 }
    140 
    141 fido_dev_t *
    142 open_dev(const char *path)
    143 {
    144 	fido_dev_t *dev;
    145 	int r;
    146 
    147 	if ((dev = fido_dev_new()) == NULL)
    148 		errx(1, "fido_dev_new");
    149 
    150 	r = fido_dev_open(dev, path);
    151 	if (r != FIDO_OK)
    152 		errx(1, "fido_dev_open %s: %s", path, fido_strerr(r));
    153 
    154 	return (dev);
    155 }
    156 
    157 EC_KEY *
    158 read_ec_pubkey(const char *path)
    159 {
    160 	FILE *fp = NULL;
    161 	EVP_PKEY *pkey = NULL;
    162 	EC_KEY *ec = NULL;
    163 
    164 	if ((fp = fopen(path, "r")) == NULL) {
    165 		warn("fopen");
    166 		goto fail;
    167 	}
    168 
    169 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
    170 		warnx("PEM_read_PUBKEY");
    171 		goto fail;
    172 	}
    173 	if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
    174 		warnx("EVP_PKEY_get1_EC_KEY");
    175 		goto fail;
    176 	}
    177 
    178 fail:
    179 	if (fp) {
    180 		fclose(fp);
    181 	}
    182 	if (pkey) {
    183 		EVP_PKEY_free(pkey);
    184 	}
    185 
    186 	return (ec);
    187 }
    188 
    189 int
    190 write_ec_pubkey(FILE *f, const void *ptr, size_t len)
    191 {
    192 	EVP_PKEY *pkey = NULL;
    193 	es256_pk_t *pk = NULL;
    194 	int ok = -1;
    195 
    196 	if ((pk = es256_pk_new()) == NULL) {
    197 		warnx("es256_pk_new");
    198 		goto fail;
    199 	}
    200 
    201 	if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
    202 		warnx("es256_pk_from_ptr");
    203 		goto fail;
    204 	}
    205 
    206 	if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
    207 		warnx("es256_pk_to_EVP_PKEY");
    208 		goto fail;
    209 	}
    210 
    211 	if (PEM_write_PUBKEY(f, pkey) == 0) {
    212 		warnx("PEM_write_PUBKEY");
    213 		goto fail;
    214 	}
    215 
    216 	ok = 0;
    217 fail:
    218 	es256_pk_free(&pk);
    219 
    220 	if (pkey != NULL) {
    221 		EVP_PKEY_free(pkey);
    222 	}
    223 
    224 	return (ok);
    225 }
    226 
    227 RSA *
    228 read_rsa_pubkey(const char *path)
    229 {
    230 	FILE *fp = NULL;
    231 	EVP_PKEY *pkey = NULL;
    232 	RSA *rsa = NULL;
    233 
    234 	if ((fp = fopen(path, "r")) == NULL) {
    235 		warn("fopen");
    236 		goto fail;
    237 	}
    238 
    239 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
    240 		warnx("PEM_read_PUBKEY");
    241 		goto fail;
    242 	}
    243 	if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
    244 		warnx("EVP_PKEY_get1_RSA");
    245 		goto fail;
    246 	}
    247 
    248 fail:
    249 	if (fp) {
    250 		fclose(fp);
    251 	}
    252 	if (pkey) {
    253 		EVP_PKEY_free(pkey);
    254 	}
    255 
    256 	return (rsa);
    257 }
    258 
    259 int
    260 write_rsa_pubkey(FILE *f, const void *ptr, size_t len)
    261 {
    262 	EVP_PKEY *pkey = NULL;
    263 	rs256_pk_t *pk = NULL;
    264 	int ok = -1;
    265 
    266 	if ((pk = rs256_pk_new()) == NULL) {
    267 		warnx("rs256_pk_new");
    268 		goto fail;
    269 	}
    270 
    271 	if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
    272 		warnx("rs256_pk_from_ptr");
    273 		goto fail;
    274 	}
    275 
    276 	if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
    277 		warnx("rs256_pk_to_EVP_PKEY");
    278 		goto fail;
    279 	}
    280 
    281 	if (PEM_write_PUBKEY(f, pkey) == 0) {
    282 		warnx("PEM_write_PUBKEY");
    283 		goto fail;
    284 	}
    285 
    286 	ok = 0;
    287 fail:
    288 	rs256_pk_free(&pk);
    289 
    290 	if (pkey != NULL) {
    291 		EVP_PKEY_free(pkey);
    292 	}
    293 
    294 	return (ok);
    295 }
    296 
    297 EVP_PKEY *
    298 read_eddsa_pubkey(const char *path)
    299 {
    300 	FILE *fp = NULL;
    301 	EVP_PKEY *pkey = NULL;
    302 
    303 	if ((fp = fopen(path, "r")) == NULL) {
    304 		warn("fopen");
    305 		goto fail;
    306 	}
    307 
    308 	if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
    309 		warnx("PEM_read_PUBKEY");
    310 		goto fail;
    311 	}
    312 
    313 fail:
    314 	if (fp) {
    315 		fclose(fp);
    316 	}
    317 
    318 	return (pkey);
    319 }
    320 
    321 int
    322 write_eddsa_pubkey(FILE *f, const void *ptr, size_t len)
    323 {
    324 	EVP_PKEY *pkey = NULL;
    325 	eddsa_pk_t *pk = NULL;
    326 	int ok = -1;
    327 
    328 	if ((pk = eddsa_pk_new()) == NULL) {
    329 		warnx("eddsa_pk_new");
    330 		goto fail;
    331 	}
    332 
    333 	if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
    334 		warnx("eddsa_pk_from_ptr");
    335 		goto fail;
    336 	}
    337 
    338 	if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
    339 		warnx("eddsa_pk_to_EVP_PKEY");
    340 		goto fail;
    341 	}
    342 
    343 	if (PEM_write_PUBKEY(f, pkey) == 0) {
    344 		warnx("PEM_write_PUBKEY");
    345 		goto fail;
    346 	}
    347 
    348 	ok = 0;
    349 fail:
    350 	eddsa_pk_free(&pk);
    351 
    352 	if (pkey != NULL) {
    353 		EVP_PKEY_free(pkey);
    354 	}
    355 
    356 	return (ok);
    357 }
    358 
    359 void
    360 print_cred(FILE *out_f, int type, const fido_cred_t *cred)
    361 {
    362 	char *id;
    363 	int r;
    364 
    365 	r = base64_encode(fido_cred_id_ptr(cred), fido_cred_id_len(cred), &id);
    366 	if (r < 0)
    367 		errx(1, "output error");
    368 
    369 	fprintf(out_f, "%s\n", id);
    370 
    371 	if (type == COSE_ES256) {
    372 		write_ec_pubkey(out_f, fido_cred_pubkey_ptr(cred),
    373 		    fido_cred_pubkey_len(cred));
    374 	} else if (type == COSE_RS256) {
    375 		write_rsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
    376 		    fido_cred_pubkey_len(cred));
    377 	} else if (type == COSE_EDDSA) {
    378 		write_eddsa_pubkey(out_f, fido_cred_pubkey_ptr(cred),
    379 		    fido_cred_pubkey_len(cred));
    380 	} else {
    381 		errx(1, "print_cred: unknown type");
    382 	}
    383 
    384 	free(id);
    385 }
    386 
    387 int
    388 cose_type(const char *str, int *type)
    389 {
    390 	if (strcmp(str, "es256") == 0)
    391 		*type = COSE_ES256;
    392 	else if (strcmp(str, "rs256") == 0)
    393 		*type = COSE_RS256;
    394 	else if (strcmp(str, "eddsa") == 0)
    395 		*type = COSE_EDDSA;
    396 	else {
    397 		*type = 0;
    398 		return (-1);
    399 	}
    400 
    401 	return (0);
    402 }
    403 
    404 const char *
    405 cose_string(int type)
    406 {
    407 	switch (type) {
    408 	case COSE_EDDSA:
    409 		return ("eddsa");
    410 	case COSE_ES256:
    411 		return ("es256");
    412 	case COSE_RS256:
    413 		return ("rs256");
    414 	default:
    415 		return ("unknown");
    416 	}
    417 }
    418 
    419 const char *
    420 prot_string(int prot)
    421 {
    422 	switch (prot) {
    423 	case FIDO_CRED_PROT_UV_OPTIONAL:
    424 		return ("uvopt");
    425 	case FIDO_CRED_PROT_UV_OPTIONAL_WITH_ID:
    426 		return ("uvopt+id");
    427 	case FIDO_CRED_PROT_UV_REQUIRED:
    428 		return ("uvreq");
    429 	default:
    430 		return ("unknown");
    431 	}
    432 }
    433