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