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