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