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