1 /* $OpenBSD: authfile.c,v 1.107 2014/06/24 01:13:21 djm Exp $ */ 2 /* 3 * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/param.h> 30 #include <sys/uio.h> 31 32 #include <errno.h> 33 #include <fcntl.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include "cipher.h" 40 #include "key.h" 41 #include "ssh.h" 42 #include "log.h" 43 #include "authfile.h" 44 #include "rsa.h" 45 #include "misc.h" 46 #include "atomicio.h" 47 #include "sshbuf.h" 48 #include "ssherr.h" 49 50 #define MAX_KEY_FILE_SIZE (1024 * 1024) 51 52 /* Save a key blob to a file */ 53 static int 54 sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename) 55 { 56 int fd, oerrno; 57 58 if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) 59 return SSH_ERR_SYSTEM_ERROR; 60 if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf), 61 sshbuf_len(keybuf)) != sshbuf_len(keybuf)) { 62 oerrno = errno; 63 close(fd); 64 unlink(filename); 65 errno = oerrno; 66 return SSH_ERR_SYSTEM_ERROR; 67 } 68 close(fd); 69 return 0; 70 } 71 72 int 73 sshkey_save_private(struct sshkey *key, const char *filename, 74 const char *passphrase, const char *comment, 75 int force_new_format, const char *new_format_cipher, int new_format_rounds) 76 { 77 struct sshbuf *keyblob = NULL; 78 int r; 79 80 if ((keyblob = sshbuf_new()) == NULL) 81 return SSH_ERR_ALLOC_FAIL; 82 if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment, 83 force_new_format, new_format_cipher, new_format_rounds)) != 0) 84 goto out; 85 if ((r = sshkey_save_private_blob(keyblob, filename)) != 0) 86 goto out; 87 r = 0; 88 out: 89 sshbuf_free(keyblob); 90 return r; 91 } 92 93 /* Load a key from a fd into a buffer */ 94 int 95 sshkey_load_file(int fd, const char *filename, struct sshbuf *blob) 96 { 97 u_char buf[1024]; 98 size_t len; 99 struct stat st; 100 int r; 101 102 if (fstat(fd, &st) < 0) 103 return SSH_ERR_SYSTEM_ERROR; 104 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 105 st.st_size > MAX_KEY_FILE_SIZE) 106 return SSH_ERR_INVALID_FORMAT; 107 for (;;) { 108 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { 109 if (errno == EPIPE) 110 break; 111 r = SSH_ERR_SYSTEM_ERROR; 112 goto out; 113 } 114 if ((r = sshbuf_put(blob, buf, len)) != 0) 115 goto out; 116 if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) { 117 r = SSH_ERR_INVALID_FORMAT; 118 goto out; 119 } 120 } 121 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 122 st.st_size != (off_t)sshbuf_len(blob)) { 123 r = SSH_ERR_FILE_CHANGED; 124 goto out; 125 } 126 r = 0; 127 128 out: 129 explicit_bzero(buf, sizeof(buf)); 130 if (r != 0) 131 sshbuf_reset(blob); 132 return r; 133 } 134 135 #ifdef WITH_SSH1 136 /* 137 * Loads the public part of the ssh v1 key file. Returns NULL if an error was 138 * encountered (the file does not exist or is not readable), and the key 139 * otherwise. 140 */ 141 static int 142 sshkey_load_public_rsa1(int fd, const char *filename, 143 struct sshkey **keyp, char **commentp) 144 { 145 struct sshbuf *b = NULL; 146 int r; 147 148 *keyp = NULL; 149 if (commentp != NULL) 150 *commentp = NULL; 151 152 if ((b = sshbuf_new()) == NULL) 153 return SSH_ERR_ALLOC_FAIL; 154 if ((r = sshkey_load_file(fd, filename, b)) != 0) 155 goto out; 156 if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0) 157 goto out; 158 r = 0; 159 out: 160 sshbuf_free(b); 161 return r; 162 } 163 #endif /* WITH_SSH1 */ 164 165 #ifdef WITH_OPENSSL 166 /* XXX Deprecate? */ 167 int 168 sshkey_load_private_pem(int fd, int type, const char *passphrase, 169 struct sshkey **keyp, char **commentp) 170 { 171 struct sshbuf *buffer = NULL; 172 int r; 173 174 *keyp = NULL; 175 if (commentp != NULL) 176 *commentp = NULL; 177 178 if ((buffer = sshbuf_new()) == NULL) 179 return SSH_ERR_ALLOC_FAIL; 180 if ((r = sshkey_load_file(fd, NULL, buffer)) != 0) 181 goto out; 182 if ((r = sshkey_parse_private_pem_fileblob(buffer, type, passphrase, 183 keyp, commentp)) != 0) 184 goto out; 185 r = 0; 186 out: 187 sshbuf_free(buffer); 188 return r; 189 } 190 #endif /* WITH_OPENSSL */ 191 192 /* XXX remove error() calls from here? */ 193 int 194 sshkey_perm_ok(int fd, const char *filename) 195 { 196 struct stat st; 197 198 if (fstat(fd, &st) < 0) 199 return SSH_ERR_SYSTEM_ERROR; 200 /* 201 * if a key owned by the user is accessed, then we check the 202 * permissions of the file. if the key owned by a different user, 203 * then we don't care. 204 */ 205 if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) { 206 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 207 error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); 208 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 209 error("Permissions 0%3.3o for '%s' are too open.", 210 (u_int)st.st_mode & 0777, filename); 211 error("It is recommended that your private key files are NOT accessible by others."); 212 error("This private key will be ignored."); 213 return SSH_ERR_KEY_BAD_PERMISSIONS; 214 } 215 return 0; 216 } 217 218 /* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */ 219 int 220 sshkey_load_private_type(int type, const char *filename, const char *passphrase, 221 struct sshkey **keyp, char **commentp, int *perm_ok) 222 { 223 int fd, r; 224 struct sshbuf *buffer = NULL; 225 226 *keyp = NULL; 227 if (commentp != NULL) 228 *commentp = NULL; 229 230 if ((fd = open(filename, O_RDONLY)) < 0) { 231 if (perm_ok != NULL) 232 *perm_ok = 0; 233 return SSH_ERR_SYSTEM_ERROR; 234 } 235 if (sshkey_perm_ok(fd, filename) != 0) { 236 if (perm_ok != NULL) 237 *perm_ok = 0; 238 r = SSH_ERR_KEY_BAD_PERMISSIONS; 239 goto out; 240 } 241 if (perm_ok != NULL) 242 *perm_ok = 1; 243 244 if ((buffer = sshbuf_new()) == NULL) { 245 r = SSH_ERR_ALLOC_FAIL; 246 goto out; 247 } 248 if ((r = sshkey_load_file(fd, filename, buffer)) != 0) 249 goto out; 250 if ((r = sshkey_parse_private_fileblob_type(buffer, type, passphrase, 251 keyp, commentp)) != 0) 252 goto out; 253 r = 0; 254 out: 255 close(fd); 256 if (buffer != NULL) 257 sshbuf_free(buffer); 258 return r; 259 } 260 261 /* XXX this is almost identical to sshkey_load_private_type() */ 262 int 263 sshkey_load_private(const char *filename, const char *passphrase, 264 struct sshkey **keyp, char **commentp) 265 { 266 struct sshbuf *buffer = NULL; 267 int r, fd; 268 269 *keyp = NULL; 270 if (commentp != NULL) 271 *commentp = NULL; 272 273 if ((fd = open(filename, O_RDONLY)) < 0) 274 return SSH_ERR_SYSTEM_ERROR; 275 if (sshkey_perm_ok(fd, filename) != 0) { 276 r = SSH_ERR_KEY_BAD_PERMISSIONS; 277 goto out; 278 } 279 280 if ((buffer = sshbuf_new()) == NULL) { 281 r = SSH_ERR_ALLOC_FAIL; 282 goto out; 283 } 284 if ((r = sshkey_load_file(fd, filename, buffer)) != 0 || 285 (r = sshkey_parse_private_fileblob(buffer, passphrase, filename, 286 keyp, commentp)) != 0) 287 goto out; 288 r = 0; 289 out: 290 close(fd); 291 if (buffer != NULL) 292 sshbuf_free(buffer); 293 return r; 294 } 295 296 static int 297 sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp) 298 { 299 FILE *f; 300 char line[SSH_MAX_PUBKEY_BYTES]; 301 char *cp; 302 u_long linenum = 0; 303 int r; 304 305 if (commentp != NULL) 306 *commentp = NULL; 307 if ((f = fopen(filename, "r")) == NULL) 308 return SSH_ERR_SYSTEM_ERROR; 309 while (read_keyfile_line(f, filename, line, sizeof(line), 310 &linenum) != -1) { 311 cp = line; 312 switch (*cp) { 313 case '#': 314 case '\n': 315 case '\0': 316 continue; 317 } 318 /* Abort loading if this looks like a private key */ 319 if (strncmp(cp, "-----BEGIN", 10) == 0 || 320 strcmp(cp, "SSH PRIVATE KEY FILE") == 0) 321 break; 322 /* Skip leading whitespace. */ 323 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 324 ; 325 if (*cp) { 326 if ((r = sshkey_read(k, &cp)) == 0) { 327 cp[strcspn(cp, "\r\n")] = '\0'; 328 if (commentp) { 329 *commentp = strdup(*cp ? 330 cp : filename); 331 if (*commentp == NULL) 332 r = SSH_ERR_ALLOC_FAIL; 333 } 334 fclose(f); 335 return r; 336 } 337 } 338 } 339 fclose(f); 340 return SSH_ERR_INVALID_FORMAT; 341 } 342 343 /* load public key from ssh v1 private or any pubkey file */ 344 int 345 sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp) 346 { 347 struct sshkey *pub = NULL; 348 char file[MAXPATHLEN]; 349 int r, fd; 350 351 if (keyp != NULL) 352 *keyp = NULL; 353 if (commentp != NULL) 354 *commentp = NULL; 355 356 if ((fd = open(filename, O_RDONLY)) < 0) 357 goto skip; 358 #ifdef WITH_SSH1 359 /* try rsa1 private key */ 360 r = sshkey_load_public_rsa1(fd, filename, keyp, commentp); 361 close(fd); 362 switch (r) { 363 case SSH_ERR_INTERNAL_ERROR: 364 case SSH_ERR_ALLOC_FAIL: 365 case SSH_ERR_INVALID_ARGUMENT: 366 case SSH_ERR_SYSTEM_ERROR: 367 case 0: 368 return r; 369 } 370 #endif /* WITH_SSH1 */ 371 372 /* try ssh2 public key */ 373 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) 374 return SSH_ERR_ALLOC_FAIL; 375 if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) { 376 if (keyp != NULL) 377 *keyp = pub; 378 return 0; 379 } 380 sshkey_free(pub); 381 382 #ifdef WITH_SSH1 383 /* try rsa1 public key */ 384 if ((pub = sshkey_new(KEY_RSA1)) == NULL) 385 return SSH_ERR_ALLOC_FAIL; 386 if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) { 387 if (keyp != NULL) 388 *keyp = pub; 389 return 0; 390 } 391 sshkey_free(pub); 392 #endif /* WITH_SSH1 */ 393 394 skip: 395 /* try .pub suffix */ 396 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) 397 return SSH_ERR_ALLOC_FAIL; 398 r = SSH_ERR_ALLOC_FAIL; /* in case strlcpy or strlcat fail */ 399 if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && 400 (strlcat(file, ".pub", sizeof file) < sizeof(file)) && 401 (r = sshkey_try_load_public(pub, file, commentp)) == 0) { 402 if (keyp != NULL) 403 *keyp = pub; 404 return 0; 405 } 406 sshkey_free(pub); 407 return r; 408 } 409 410 /* Load the certificate associated with the named private key */ 411 int 412 sshkey_load_cert(const char *filename, struct sshkey **keyp) 413 { 414 struct sshkey *pub = NULL; 415 char *file = NULL; 416 int r = SSH_ERR_INTERNAL_ERROR; 417 418 *keyp = NULL; 419 420 if (asprintf(&file, "%s-cert.pub", filename) == -1) 421 return SSH_ERR_ALLOC_FAIL; 422 423 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) { 424 goto out; 425 } 426 if ((r = sshkey_try_load_public(pub, file, NULL)) != 0) 427 goto out; 428 429 *keyp = pub; 430 pub = NULL; 431 r = 0; 432 433 out: 434 if (file != NULL) 435 free(file); 436 if (pub != NULL) 437 sshkey_free(pub); 438 return r; 439 } 440 441 /* Load private key and certificate */ 442 int 443 sshkey_load_private_cert(int type, const char *filename, const char *passphrase, 444 struct sshkey **keyp, int *perm_ok) 445 { 446 struct sshkey *key = NULL, *cert = NULL; 447 int r; 448 449 *keyp = NULL; 450 451 switch (type) { 452 #ifdef WITH_OPENSSL 453 case KEY_RSA: 454 case KEY_DSA: 455 case KEY_ECDSA: 456 case KEY_ED25519: 457 #endif /* WITH_OPENSSL */ 458 case KEY_UNSPEC: 459 break; 460 default: 461 return SSH_ERR_KEY_TYPE_UNKNOWN; 462 } 463 464 if ((r = sshkey_load_private_type(type, filename, 465 passphrase, &key, NULL, perm_ok)) != 0 || 466 (r = sshkey_load_cert(filename, &cert)) != 0) 467 goto out; 468 469 /* Make sure the private key matches the certificate */ 470 if (sshkey_equal_public(key, cert) == 0) { 471 r = SSH_ERR_KEY_CERT_MISMATCH; 472 goto out; 473 } 474 475 if ((r = sshkey_to_certified(key, sshkey_cert_is_legacy(cert))) != 0 || 476 (r = sshkey_cert_copy(cert, key)) != 0) 477 goto out; 478 r = 0; 479 *keyp = key; 480 key = NULL; 481 out: 482 if (key != NULL) 483 sshkey_free(key); 484 if (cert != NULL) 485 sshkey_free(cert); 486 return r; 487 } 488 489 /* 490 * Returns success if the specified "key" is listed in the file "filename", 491 * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error. 492 * If strict_type is set then the key type must match exactly, 493 * otherwise a comparison that ignores certficiate data is performed. 494 */ 495 int 496 sshkey_in_file(struct sshkey *key, const char *filename, int strict_type) 497 { 498 FILE *f; 499 char line[SSH_MAX_PUBKEY_BYTES]; 500 char *cp; 501 u_long linenum = 0; 502 int r = 0; 503 struct sshkey *pub = NULL; 504 int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) = 505 strict_type ? sshkey_equal : sshkey_equal_public; 506 507 if ((f = fopen(filename, "r")) == NULL) { 508 if (errno == ENOENT) 509 return SSH_ERR_KEY_NOT_FOUND; 510 else 511 return SSH_ERR_SYSTEM_ERROR; 512 } 513 514 while (read_keyfile_line(f, filename, line, sizeof(line), 515 &linenum) != -1) { 516 cp = line; 517 518 /* Skip leading whitespace. */ 519 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 520 ; 521 522 /* Skip comments and empty lines */ 523 switch (*cp) { 524 case '#': 525 case '\n': 526 case '\0': 527 continue; 528 } 529 530 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) { 531 r = SSH_ERR_ALLOC_FAIL; 532 goto out; 533 } 534 if ((r = sshkey_read(pub, &cp)) != 0) 535 goto out; 536 if (sshkey_compare(key, pub)) { 537 r = 0; 538 goto out; 539 } 540 sshkey_free(pub); 541 pub = NULL; 542 } 543 r = SSH_ERR_KEY_NOT_FOUND; 544 out: 545 if (pub != NULL) 546 sshkey_free(pub); 547 fclose(f); 548 return r; 549 } 550 551