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