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