10afa8e06SEd Maste /*
2*2ccfa855SEd Maste * Copyright (c) 2018-2022 Yubico AB. All rights reserved.
30afa8e06SEd Maste * Use of this source code is governed by a BSD-style
40afa8e06SEd Maste * license that can be found in the LICENSE file.
5*2ccfa855SEd Maste * SPDX-License-Identifier: BSD-2-Clause
60afa8e06SEd Maste */
70afa8e06SEd Maste
80afa8e06SEd Maste #include <sys/types.h>
90afa8e06SEd Maste #include <sys/stat.h>
100afa8e06SEd Maste
110afa8e06SEd Maste #include <openssl/ec.h>
120afa8e06SEd Maste #include <openssl/evp.h>
130afa8e06SEd Maste #include <openssl/pem.h>
140afa8e06SEd Maste
150afa8e06SEd Maste #include <fido.h>
160afa8e06SEd Maste #include <fido/es256.h>
17*2ccfa855SEd Maste #include <fido/es384.h>
180afa8e06SEd Maste #include <fido/rs256.h>
190afa8e06SEd Maste #include <fido/eddsa.h>
200afa8e06SEd Maste
210afa8e06SEd Maste #include <errno.h>
220afa8e06SEd Maste #include <fcntl.h>
230afa8e06SEd Maste #include <limits.h>
240afa8e06SEd Maste #include <stdlib.h>
250afa8e06SEd Maste #include <string.h>
260afa8e06SEd Maste #ifdef HAVE_UNISTD_H
270afa8e06SEd Maste #include <unistd.h>
280afa8e06SEd Maste #endif
290afa8e06SEd Maste #ifdef _MSC_VER
300afa8e06SEd Maste #include "../openbsd-compat/posix_win.h"
310afa8e06SEd Maste #endif
320afa8e06SEd Maste #include "../openbsd-compat/openbsd-compat.h"
330afa8e06SEd Maste #include "extern.h"
340afa8e06SEd Maste
350afa8e06SEd Maste int
base10(const char * str,long long * ll)360afa8e06SEd Maste base10(const char *str, long long *ll)
370afa8e06SEd Maste {
380afa8e06SEd Maste char *ep;
390afa8e06SEd Maste
400afa8e06SEd Maste *ll = strtoll(str, &ep, 10);
410afa8e06SEd Maste if (str == ep || *ep != '\0')
420afa8e06SEd Maste return (-1);
430afa8e06SEd Maste else if (*ll == LLONG_MIN && errno == ERANGE)
440afa8e06SEd Maste return (-1);
450afa8e06SEd Maste else if (*ll == LLONG_MAX && errno == ERANGE)
460afa8e06SEd Maste return (-1);
470afa8e06SEd Maste
480afa8e06SEd Maste return (0);
490afa8e06SEd Maste }
500afa8e06SEd Maste
510afa8e06SEd Maste int
write_blob(const char * path,const unsigned char * ptr,size_t len)520afa8e06SEd Maste write_blob(const char *path, const unsigned char *ptr, size_t len)
530afa8e06SEd Maste {
540afa8e06SEd Maste int fd, ok = -1;
550afa8e06SEd Maste ssize_t n;
560afa8e06SEd Maste
570afa8e06SEd Maste if ((fd = open(path, O_WRONLY | O_CREAT, 0600)) < 0) {
580afa8e06SEd Maste warn("open %s", path);
590afa8e06SEd Maste goto fail;
600afa8e06SEd Maste }
610afa8e06SEd Maste
620afa8e06SEd Maste if ((n = write(fd, ptr, len)) < 0) {
630afa8e06SEd Maste warn("write");
640afa8e06SEd Maste goto fail;
650afa8e06SEd Maste }
660afa8e06SEd Maste if ((size_t)n != len) {
670afa8e06SEd Maste warnx("write");
680afa8e06SEd Maste goto fail;
690afa8e06SEd Maste }
700afa8e06SEd Maste
710afa8e06SEd Maste ok = 0;
720afa8e06SEd Maste fail:
730afa8e06SEd Maste if (fd != -1) {
740afa8e06SEd Maste close(fd);
750afa8e06SEd Maste }
760afa8e06SEd Maste
770afa8e06SEd Maste return (ok);
780afa8e06SEd Maste }
790afa8e06SEd Maste
800afa8e06SEd Maste int
read_blob(const char * path,unsigned char ** ptr,size_t * len)810afa8e06SEd Maste read_blob(const char *path, unsigned char **ptr, size_t *len)
820afa8e06SEd Maste {
830afa8e06SEd Maste int fd, ok = -1;
840afa8e06SEd Maste struct stat st;
850afa8e06SEd Maste ssize_t n;
860afa8e06SEd Maste
870afa8e06SEd Maste *ptr = NULL;
880afa8e06SEd Maste *len = 0;
890afa8e06SEd Maste
900afa8e06SEd Maste if ((fd = open(path, O_RDONLY)) < 0) {
910afa8e06SEd Maste warn("open %s", path);
920afa8e06SEd Maste goto fail;
930afa8e06SEd Maste }
940afa8e06SEd Maste if (fstat(fd, &st) < 0) {
950afa8e06SEd Maste warn("stat %s", path);
960afa8e06SEd Maste goto fail;
970afa8e06SEd Maste }
980afa8e06SEd Maste if (st.st_size < 0) {
990afa8e06SEd Maste warnx("stat %s: invalid size", path);
1000afa8e06SEd Maste goto fail;
1010afa8e06SEd Maste }
1020afa8e06SEd Maste *len = (size_t)st.st_size;
1030afa8e06SEd Maste if ((*ptr = malloc(*len)) == NULL) {
1040afa8e06SEd Maste warn("malloc");
1050afa8e06SEd Maste goto fail;
1060afa8e06SEd Maste }
1070afa8e06SEd Maste if ((n = read(fd, *ptr, *len)) < 0) {
1080afa8e06SEd Maste warn("read");
1090afa8e06SEd Maste goto fail;
1100afa8e06SEd Maste }
1110afa8e06SEd Maste if ((size_t)n != *len) {
1120afa8e06SEd Maste warnx("read");
1130afa8e06SEd Maste goto fail;
1140afa8e06SEd Maste }
1150afa8e06SEd Maste
1160afa8e06SEd Maste ok = 0;
1170afa8e06SEd Maste fail:
1180afa8e06SEd Maste if (fd != -1) {
1190afa8e06SEd Maste close(fd);
1200afa8e06SEd Maste }
1210afa8e06SEd Maste if (ok < 0) {
1220afa8e06SEd Maste free(*ptr);
1230afa8e06SEd Maste *ptr = NULL;
1240afa8e06SEd Maste *len = 0;
1250afa8e06SEd Maste }
1260afa8e06SEd Maste
1270afa8e06SEd Maste return (ok);
1280afa8e06SEd Maste }
1290afa8e06SEd Maste
1300afa8e06SEd Maste EC_KEY *
read_ec_pubkey(const char * path)1310afa8e06SEd Maste read_ec_pubkey(const char *path)
1320afa8e06SEd Maste {
1330afa8e06SEd Maste FILE *fp = NULL;
1340afa8e06SEd Maste EVP_PKEY *pkey = NULL;
1350afa8e06SEd Maste EC_KEY *ec = NULL;
1360afa8e06SEd Maste
1370afa8e06SEd Maste if ((fp = fopen(path, "r")) == NULL) {
1380afa8e06SEd Maste warn("fopen");
1390afa8e06SEd Maste goto fail;
1400afa8e06SEd Maste }
1410afa8e06SEd Maste
1420afa8e06SEd Maste if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
1430afa8e06SEd Maste warnx("PEM_read_PUBKEY");
1440afa8e06SEd Maste goto fail;
1450afa8e06SEd Maste }
1460afa8e06SEd Maste if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) {
1470afa8e06SEd Maste warnx("EVP_PKEY_get1_EC_KEY");
1480afa8e06SEd Maste goto fail;
1490afa8e06SEd Maste }
1500afa8e06SEd Maste
1510afa8e06SEd Maste fail:
1520afa8e06SEd Maste if (fp != NULL) {
1530afa8e06SEd Maste fclose(fp);
1540afa8e06SEd Maste }
1550afa8e06SEd Maste if (pkey != NULL) {
1560afa8e06SEd Maste EVP_PKEY_free(pkey);
1570afa8e06SEd Maste }
1580afa8e06SEd Maste
1590afa8e06SEd Maste return (ec);
1600afa8e06SEd Maste }
1610afa8e06SEd Maste
1620afa8e06SEd Maste int
write_es256_pubkey(const char * path,const void * ptr,size_t len)163*2ccfa855SEd Maste write_es256_pubkey(const char *path, const void *ptr, size_t len)
1640afa8e06SEd Maste {
1650afa8e06SEd Maste FILE *fp = NULL;
1660afa8e06SEd Maste EVP_PKEY *pkey = NULL;
1670afa8e06SEd Maste es256_pk_t *pk = NULL;
1680afa8e06SEd Maste int fd = -1;
1690afa8e06SEd Maste int ok = -1;
1700afa8e06SEd Maste
1710afa8e06SEd Maste if ((pk = es256_pk_new()) == NULL) {
1720afa8e06SEd Maste warnx("es256_pk_new");
1730afa8e06SEd Maste goto fail;
1740afa8e06SEd Maste }
1750afa8e06SEd Maste
1760afa8e06SEd Maste if (es256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
1770afa8e06SEd Maste warnx("es256_pk_from_ptr");
1780afa8e06SEd Maste goto fail;
1790afa8e06SEd Maste }
1800afa8e06SEd Maste
1810afa8e06SEd Maste if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
1820afa8e06SEd Maste warn("open %s", path);
1830afa8e06SEd Maste goto fail;
1840afa8e06SEd Maste }
1850afa8e06SEd Maste
1860afa8e06SEd Maste if ((fp = fdopen(fd, "w")) == NULL) {
1870afa8e06SEd Maste warn("fdopen");
1880afa8e06SEd Maste goto fail;
1890afa8e06SEd Maste }
1900afa8e06SEd Maste fd = -1; /* owned by fp now */
1910afa8e06SEd Maste
1920afa8e06SEd Maste if ((pkey = es256_pk_to_EVP_PKEY(pk)) == NULL) {
1930afa8e06SEd Maste warnx("es256_pk_to_EVP_PKEY");
1940afa8e06SEd Maste goto fail;
1950afa8e06SEd Maste }
1960afa8e06SEd Maste
1970afa8e06SEd Maste if (PEM_write_PUBKEY(fp, pkey) == 0) {
1980afa8e06SEd Maste warnx("PEM_write_PUBKEY");
1990afa8e06SEd Maste goto fail;
2000afa8e06SEd Maste }
2010afa8e06SEd Maste
2020afa8e06SEd Maste ok = 0;
2030afa8e06SEd Maste fail:
2040afa8e06SEd Maste es256_pk_free(&pk);
2050afa8e06SEd Maste
2060afa8e06SEd Maste if (fp != NULL) {
2070afa8e06SEd Maste fclose(fp);
2080afa8e06SEd Maste }
2090afa8e06SEd Maste if (fd != -1) {
2100afa8e06SEd Maste close(fd);
2110afa8e06SEd Maste }
2120afa8e06SEd Maste if (pkey != NULL) {
2130afa8e06SEd Maste EVP_PKEY_free(pkey);
2140afa8e06SEd Maste }
2150afa8e06SEd Maste
2160afa8e06SEd Maste return (ok);
2170afa8e06SEd Maste }
2180afa8e06SEd Maste
219*2ccfa855SEd Maste int
write_es384_pubkey(const char * path,const void * ptr,size_t len)220*2ccfa855SEd Maste write_es384_pubkey(const char *path, const void *ptr, size_t len)
221*2ccfa855SEd Maste {
222*2ccfa855SEd Maste FILE *fp = NULL;
223*2ccfa855SEd Maste EVP_PKEY *pkey = NULL;
224*2ccfa855SEd Maste es384_pk_t *pk = NULL;
225*2ccfa855SEd Maste int fd = -1;
226*2ccfa855SEd Maste int ok = -1;
227*2ccfa855SEd Maste
228*2ccfa855SEd Maste if ((pk = es384_pk_new()) == NULL) {
229*2ccfa855SEd Maste warnx("es384_pk_new");
230*2ccfa855SEd Maste goto fail;
231*2ccfa855SEd Maste }
232*2ccfa855SEd Maste
233*2ccfa855SEd Maste if (es384_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
234*2ccfa855SEd Maste warnx("es384_pk_from_ptr");
235*2ccfa855SEd Maste goto fail;
236*2ccfa855SEd Maste }
237*2ccfa855SEd Maste
238*2ccfa855SEd Maste if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
239*2ccfa855SEd Maste warn("open %s", path);
240*2ccfa855SEd Maste goto fail;
241*2ccfa855SEd Maste }
242*2ccfa855SEd Maste
243*2ccfa855SEd Maste if ((fp = fdopen(fd, "w")) == NULL) {
244*2ccfa855SEd Maste warn("fdopen");
245*2ccfa855SEd Maste goto fail;
246*2ccfa855SEd Maste }
247*2ccfa855SEd Maste fd = -1; /* owned by fp now */
248*2ccfa855SEd Maste
249*2ccfa855SEd Maste if ((pkey = es384_pk_to_EVP_PKEY(pk)) == NULL) {
250*2ccfa855SEd Maste warnx("es384_pk_to_EVP_PKEY");
251*2ccfa855SEd Maste goto fail;
252*2ccfa855SEd Maste }
253*2ccfa855SEd Maste
254*2ccfa855SEd Maste if (PEM_write_PUBKEY(fp, pkey) == 0) {
255*2ccfa855SEd Maste warnx("PEM_write_PUBKEY");
256*2ccfa855SEd Maste goto fail;
257*2ccfa855SEd Maste }
258*2ccfa855SEd Maste
259*2ccfa855SEd Maste ok = 0;
260*2ccfa855SEd Maste fail:
261*2ccfa855SEd Maste es384_pk_free(&pk);
262*2ccfa855SEd Maste
263*2ccfa855SEd Maste if (fp != NULL) {
264*2ccfa855SEd Maste fclose(fp);
265*2ccfa855SEd Maste }
266*2ccfa855SEd Maste if (fd != -1) {
267*2ccfa855SEd Maste close(fd);
268*2ccfa855SEd Maste }
269*2ccfa855SEd Maste if (pkey != NULL) {
270*2ccfa855SEd Maste EVP_PKEY_free(pkey);
271*2ccfa855SEd Maste }
272*2ccfa855SEd Maste
273*2ccfa855SEd Maste return (ok);
274*2ccfa855SEd Maste }
275*2ccfa855SEd Maste
2760afa8e06SEd Maste RSA *
read_rsa_pubkey(const char * path)2770afa8e06SEd Maste read_rsa_pubkey(const char *path)
2780afa8e06SEd Maste {
2790afa8e06SEd Maste FILE *fp = NULL;
2800afa8e06SEd Maste EVP_PKEY *pkey = NULL;
2810afa8e06SEd Maste RSA *rsa = NULL;
2820afa8e06SEd Maste
2830afa8e06SEd Maste if ((fp = fopen(path, "r")) == NULL) {
2840afa8e06SEd Maste warn("fopen");
2850afa8e06SEd Maste goto fail;
2860afa8e06SEd Maste }
2870afa8e06SEd Maste
2880afa8e06SEd Maste if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
2890afa8e06SEd Maste warnx("PEM_read_PUBKEY");
2900afa8e06SEd Maste goto fail;
2910afa8e06SEd Maste }
2920afa8e06SEd Maste if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) {
2930afa8e06SEd Maste warnx("EVP_PKEY_get1_RSA");
2940afa8e06SEd Maste goto fail;
2950afa8e06SEd Maste }
2960afa8e06SEd Maste
2970afa8e06SEd Maste fail:
2980afa8e06SEd Maste if (fp != NULL) {
2990afa8e06SEd Maste fclose(fp);
3000afa8e06SEd Maste }
3010afa8e06SEd Maste if (pkey != NULL) {
3020afa8e06SEd Maste EVP_PKEY_free(pkey);
3030afa8e06SEd Maste }
3040afa8e06SEd Maste
3050afa8e06SEd Maste return (rsa);
3060afa8e06SEd Maste }
3070afa8e06SEd Maste
3080afa8e06SEd Maste int
write_rs256_pubkey(const char * path,const void * ptr,size_t len)309*2ccfa855SEd Maste write_rs256_pubkey(const char *path, const void *ptr, size_t len)
3100afa8e06SEd Maste {
3110afa8e06SEd Maste FILE *fp = NULL;
3120afa8e06SEd Maste EVP_PKEY *pkey = NULL;
3130afa8e06SEd Maste rs256_pk_t *pk = NULL;
3140afa8e06SEd Maste int fd = -1;
3150afa8e06SEd Maste int ok = -1;
3160afa8e06SEd Maste
3170afa8e06SEd Maste if ((pk = rs256_pk_new()) == NULL) {
3180afa8e06SEd Maste warnx("rs256_pk_new");
3190afa8e06SEd Maste goto fail;
3200afa8e06SEd Maste }
3210afa8e06SEd Maste
3220afa8e06SEd Maste if (rs256_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
3230afa8e06SEd Maste warnx("rs256_pk_from_ptr");
3240afa8e06SEd Maste goto fail;
3250afa8e06SEd Maste }
3260afa8e06SEd Maste
3270afa8e06SEd Maste if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
3280afa8e06SEd Maste warn("open %s", path);
3290afa8e06SEd Maste goto fail;
3300afa8e06SEd Maste }
3310afa8e06SEd Maste
3320afa8e06SEd Maste if ((fp = fdopen(fd, "w")) == NULL) {
3330afa8e06SEd Maste warn("fdopen");
3340afa8e06SEd Maste goto fail;
3350afa8e06SEd Maste }
3360afa8e06SEd Maste fd = -1; /* owned by fp now */
3370afa8e06SEd Maste
3380afa8e06SEd Maste if ((pkey = rs256_pk_to_EVP_PKEY(pk)) == NULL) {
3390afa8e06SEd Maste warnx("rs256_pk_to_EVP_PKEY");
3400afa8e06SEd Maste goto fail;
3410afa8e06SEd Maste }
3420afa8e06SEd Maste
3430afa8e06SEd Maste if (PEM_write_PUBKEY(fp, pkey) == 0) {
3440afa8e06SEd Maste warnx("PEM_write_PUBKEY");
3450afa8e06SEd Maste goto fail;
3460afa8e06SEd Maste }
3470afa8e06SEd Maste
3480afa8e06SEd Maste ok = 0;
3490afa8e06SEd Maste fail:
3500afa8e06SEd Maste rs256_pk_free(&pk);
3510afa8e06SEd Maste
3520afa8e06SEd Maste if (fp != NULL) {
3530afa8e06SEd Maste fclose(fp);
3540afa8e06SEd Maste }
3550afa8e06SEd Maste if (fd != -1) {
3560afa8e06SEd Maste close(fd);
3570afa8e06SEd Maste }
3580afa8e06SEd Maste if (pkey != NULL) {
3590afa8e06SEd Maste EVP_PKEY_free(pkey);
3600afa8e06SEd Maste }
3610afa8e06SEd Maste
3620afa8e06SEd Maste return (ok);
3630afa8e06SEd Maste }
3640afa8e06SEd Maste
3650afa8e06SEd Maste EVP_PKEY *
read_eddsa_pubkey(const char * path)3660afa8e06SEd Maste read_eddsa_pubkey(const char *path)
3670afa8e06SEd Maste {
3680afa8e06SEd Maste FILE *fp = NULL;
3690afa8e06SEd Maste EVP_PKEY *pkey = NULL;
3700afa8e06SEd Maste
3710afa8e06SEd Maste if ((fp = fopen(path, "r")) == NULL) {
3720afa8e06SEd Maste warn("fopen");
3730afa8e06SEd Maste goto fail;
3740afa8e06SEd Maste }
3750afa8e06SEd Maste
3760afa8e06SEd Maste if ((pkey = PEM_read_PUBKEY(fp, NULL, NULL, NULL)) == NULL) {
3770afa8e06SEd Maste warnx("PEM_read_PUBKEY");
3780afa8e06SEd Maste goto fail;
3790afa8e06SEd Maste }
3800afa8e06SEd Maste
3810afa8e06SEd Maste fail:
3820afa8e06SEd Maste if (fp) {
3830afa8e06SEd Maste fclose(fp);
3840afa8e06SEd Maste }
3850afa8e06SEd Maste
3860afa8e06SEd Maste return (pkey);
3870afa8e06SEd Maste }
3880afa8e06SEd Maste
3890afa8e06SEd Maste int
write_eddsa_pubkey(const char * path,const void * ptr,size_t len)3900afa8e06SEd Maste write_eddsa_pubkey(const char *path, const void *ptr, size_t len)
3910afa8e06SEd Maste {
3920afa8e06SEd Maste FILE *fp = NULL;
3930afa8e06SEd Maste EVP_PKEY *pkey = NULL;
3940afa8e06SEd Maste eddsa_pk_t *pk = NULL;
3950afa8e06SEd Maste int fd = -1;
3960afa8e06SEd Maste int ok = -1;
3970afa8e06SEd Maste
3980afa8e06SEd Maste if ((pk = eddsa_pk_new()) == NULL) {
3990afa8e06SEd Maste warnx("eddsa_pk_new");
4000afa8e06SEd Maste goto fail;
4010afa8e06SEd Maste }
4020afa8e06SEd Maste
4030afa8e06SEd Maste if (eddsa_pk_from_ptr(pk, ptr, len) != FIDO_OK) {
4040afa8e06SEd Maste warnx("eddsa_pk_from_ptr");
4050afa8e06SEd Maste goto fail;
4060afa8e06SEd Maste }
4070afa8e06SEd Maste
4080afa8e06SEd Maste if ((fd = open(path, O_WRONLY | O_CREAT, 0644)) < 0) {
4090afa8e06SEd Maste warn("open %s", path);
4100afa8e06SEd Maste goto fail;
4110afa8e06SEd Maste }
4120afa8e06SEd Maste
4130afa8e06SEd Maste if ((fp = fdopen(fd, "w")) == NULL) {
4140afa8e06SEd Maste warn("fdopen");
4150afa8e06SEd Maste goto fail;
4160afa8e06SEd Maste }
4170afa8e06SEd Maste fd = -1; /* owned by fp now */
4180afa8e06SEd Maste
4190afa8e06SEd Maste if ((pkey = eddsa_pk_to_EVP_PKEY(pk)) == NULL) {
4200afa8e06SEd Maste warnx("eddsa_pk_to_EVP_PKEY");
4210afa8e06SEd Maste goto fail;
4220afa8e06SEd Maste }
4230afa8e06SEd Maste
4240afa8e06SEd Maste if (PEM_write_PUBKEY(fp, pkey) == 0) {
4250afa8e06SEd Maste warnx("PEM_write_PUBKEY");
4260afa8e06SEd Maste goto fail;
4270afa8e06SEd Maste }
4280afa8e06SEd Maste
4290afa8e06SEd Maste ok = 0;
4300afa8e06SEd Maste fail:
4310afa8e06SEd Maste eddsa_pk_free(&pk);
4320afa8e06SEd Maste
4330afa8e06SEd Maste if (fp != NULL) {
4340afa8e06SEd Maste fclose(fp);
4350afa8e06SEd Maste }
4360afa8e06SEd Maste if (fd != -1) {
4370afa8e06SEd Maste close(fd);
4380afa8e06SEd Maste }
4390afa8e06SEd Maste if (pkey != NULL) {
4400afa8e06SEd Maste EVP_PKEY_free(pkey);
4410afa8e06SEd Maste }
4420afa8e06SEd Maste
4430afa8e06SEd Maste return (ok);
4440afa8e06SEd Maste }
445