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 35int 36base10(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 51int 52write_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; 72fail: 73 if (fd != -1) { 74 close(fd); 75 } 76 77 return (ok); 78} 79 80int 81read_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; 117fail: 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 130EC_KEY * 131read_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 151fail: 152 if (fp != NULL) { 153 fclose(fp); 154 } 155 if (pkey != NULL) { 156 EVP_PKEY_free(pkey); 157 } 158 159 return (ec); 160} 161 162int 163write_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; 203fail: 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 219int 220write_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; 260fail: 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 276RSA * 277read_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 297fail: 298 if (fp != NULL) { 299 fclose(fp); 300 } 301 if (pkey != NULL) { 302 EVP_PKEY_free(pkey); 303 } 304 305 return (rsa); 306} 307 308int 309write_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; 349fail: 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 365EVP_PKEY * 366read_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 381fail: 382 if (fp) { 383 fclose(fp); 384 } 385 386 return (pkey); 387} 388 389int 390write_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; 430fail: 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