1 /* $OpenBSD: authfile.c,v 1.135 2019/09/03 08:30:47 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/uio.h> 30 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <stdio.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <unistd.h> 37 #include <limits.h> 38 39 #include "cipher.h" 40 #include "ssh.h" 41 #include "log.h" 42 #include "authfile.h" 43 #include "misc.h" 44 #include "atomicio.h" 45 #include "sshkey.h" 46 #include "sshbuf.h" 47 #include "ssherr.h" 48 #include "krl.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)) == -1) 59 return SSH_ERR_SYSTEM_ERROR; 60 if (atomicio(vwrite, fd, sshbuf_mutable_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 format, const char *openssh_format_cipher, int openssh_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 format, openssh_format_cipher, openssh_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, 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) == -1) 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 136 /* XXX remove error() calls from here? */ 137 int 138 sshkey_perm_ok(int fd, const char *filename) 139 { 140 struct stat st; 141 142 if (fstat(fd, &st) == -1) 143 return SSH_ERR_SYSTEM_ERROR; 144 /* 145 * if a key owned by the user is accessed, then we check the 146 * permissions of the file. if the key owned by a different user, 147 * then we don't care. 148 */ 149 if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) { 150 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 151 error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); 152 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 153 error("Permissions 0%3.3o for '%s' are too open.", 154 (u_int)st.st_mode & 0777, filename); 155 error("It is required that your private key files are NOT accessible by others."); 156 error("This private key will be ignored."); 157 return SSH_ERR_KEY_BAD_PERMISSIONS; 158 } 159 return 0; 160 } 161 162 int 163 sshkey_load_private_type(int type, const char *filename, const char *passphrase, 164 struct sshkey **keyp, char **commentp) 165 { 166 int fd, r; 167 168 if (keyp != NULL) 169 *keyp = NULL; 170 if (commentp != NULL) 171 *commentp = NULL; 172 173 if ((fd = open(filename, O_RDONLY)) == -1) 174 return SSH_ERR_SYSTEM_ERROR; 175 176 r = sshkey_perm_ok(fd, filename); 177 if (r != 0) 178 goto out; 179 180 r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp); 181 if (r == 0 && keyp && *keyp) 182 r = sshkey_set_filename(*keyp, filename); 183 out: 184 close(fd); 185 return r; 186 } 187 188 int 189 sshkey_load_private_type_fd(int fd, int type, const char *passphrase, 190 struct sshkey **keyp, char **commentp) 191 { 192 struct sshbuf *buffer = NULL; 193 int r; 194 195 if (keyp != NULL) 196 *keyp = NULL; 197 if ((buffer = sshbuf_new()) == NULL) { 198 r = SSH_ERR_ALLOC_FAIL; 199 goto out; 200 } 201 if ((r = sshkey_load_file(fd, buffer)) != 0 || 202 (r = sshkey_parse_private_fileblob_type(buffer, type, 203 passphrase, keyp, commentp)) != 0) 204 goto out; 205 206 /* success */ 207 r = 0; 208 out: 209 sshbuf_free(buffer); 210 return r; 211 } 212 213 /* XXX this is almost identical to sshkey_load_private_type() */ 214 int 215 sshkey_load_private(const char *filename, const char *passphrase, 216 struct sshkey **keyp, char **commentp) 217 { 218 struct sshbuf *buffer = NULL; 219 int r, fd; 220 221 if (keyp != NULL) 222 *keyp = NULL; 223 if (commentp != NULL) 224 *commentp = NULL; 225 226 if ((fd = open(filename, O_RDONLY)) == -1) 227 return SSH_ERR_SYSTEM_ERROR; 228 if (sshkey_perm_ok(fd, filename) != 0) { 229 r = SSH_ERR_KEY_BAD_PERMISSIONS; 230 goto out; 231 } 232 233 if ((buffer = sshbuf_new()) == NULL) { 234 r = SSH_ERR_ALLOC_FAIL; 235 goto out; 236 } 237 if ((r = sshkey_load_file(fd, buffer)) != 0 || 238 (r = sshkey_parse_private_fileblob(buffer, passphrase, keyp, 239 commentp)) != 0) 240 goto out; 241 if (keyp && *keyp && 242 (r = sshkey_set_filename(*keyp, filename)) != 0) 243 goto out; 244 r = 0; 245 out: 246 close(fd); 247 sshbuf_free(buffer); 248 return r; 249 } 250 251 static int 252 sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp) 253 { 254 FILE *f; 255 char *line = NULL, *cp; 256 size_t linesize = 0; 257 int r; 258 259 if (commentp != NULL) 260 *commentp = NULL; 261 if ((f = fopen(filename, "r")) == NULL) 262 return SSH_ERR_SYSTEM_ERROR; 263 while (getline(&line, &linesize, f) != -1) { 264 cp = line; 265 switch (*cp) { 266 case '#': 267 case '\n': 268 case '\0': 269 continue; 270 } 271 /* Abort loading if this looks like a private key */ 272 if (strncmp(cp, "-----BEGIN", 10) == 0 || 273 strcmp(cp, "SSH PRIVATE KEY FILE") == 0) 274 break; 275 /* Skip leading whitespace. */ 276 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 277 ; 278 if (*cp) { 279 if ((r = sshkey_read(k, &cp)) == 0) { 280 cp[strcspn(cp, "\r\n")] = '\0'; 281 if (commentp) { 282 *commentp = strdup(*cp ? 283 cp : filename); 284 if (*commentp == NULL) 285 r = SSH_ERR_ALLOC_FAIL; 286 } 287 free(line); 288 fclose(f); 289 return r; 290 } 291 } 292 } 293 free(line); 294 fclose(f); 295 return SSH_ERR_INVALID_FORMAT; 296 } 297 298 /* load public key from any pubkey file */ 299 int 300 sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp) 301 { 302 struct sshkey *pub = NULL; 303 char *file = NULL; 304 int r; 305 306 if (keyp != NULL) 307 *keyp = NULL; 308 if (commentp != NULL) 309 *commentp = NULL; 310 311 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) 312 return SSH_ERR_ALLOC_FAIL; 313 if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) { 314 if (keyp != NULL) { 315 *keyp = pub; 316 pub = NULL; 317 } 318 r = 0; 319 goto out; 320 } 321 sshkey_free(pub); 322 323 /* try .pub suffix */ 324 if (asprintf(&file, "%s.pub", filename) == -1) 325 return SSH_ERR_ALLOC_FAIL; 326 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) { 327 r = SSH_ERR_ALLOC_FAIL; 328 goto out; 329 } 330 if ((r = sshkey_try_load_public(pub, file, commentp)) == 0) { 331 if (keyp != NULL) { 332 *keyp = pub; 333 pub = NULL; 334 } 335 r = 0; 336 } 337 out: 338 free(file); 339 sshkey_free(pub); 340 return r; 341 } 342 343 /* Load the certificate associated with the named private key */ 344 int 345 sshkey_load_cert(const char *filename, struct sshkey **keyp) 346 { 347 struct sshkey *pub = NULL; 348 char *file = NULL; 349 int r = SSH_ERR_INTERNAL_ERROR; 350 351 if (keyp != NULL) 352 *keyp = NULL; 353 354 if (asprintf(&file, "%s-cert.pub", filename) == -1) 355 return SSH_ERR_ALLOC_FAIL; 356 357 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) { 358 goto out; 359 } 360 if ((r = sshkey_try_load_public(pub, file, NULL)) != 0) 361 goto out; 362 /* success */ 363 if (keyp != NULL) { 364 *keyp = pub; 365 pub = NULL; 366 } 367 r = 0; 368 out: 369 free(file); 370 sshkey_free(pub); 371 return r; 372 } 373 374 /* Load private key and certificate */ 375 int 376 sshkey_load_private_cert(int type, const char *filename, const char *passphrase, 377 struct sshkey **keyp) 378 { 379 struct sshkey *key = NULL, *cert = NULL; 380 int r; 381 382 if (keyp != NULL) 383 *keyp = NULL; 384 385 switch (type) { 386 #ifdef WITH_OPENSSL 387 case KEY_RSA: 388 case KEY_DSA: 389 case KEY_ECDSA: 390 #endif /* WITH_OPENSSL */ 391 case KEY_ED25519: 392 case KEY_XMSS: 393 case KEY_UNSPEC: 394 break; 395 default: 396 return SSH_ERR_KEY_TYPE_UNKNOWN; 397 } 398 399 if ((r = sshkey_load_private_type(type, filename, 400 passphrase, &key, NULL)) != 0 || 401 (r = sshkey_load_cert(filename, &cert)) != 0) 402 goto out; 403 404 /* Make sure the private key matches the certificate */ 405 if (sshkey_equal_public(key, cert) == 0) { 406 r = SSH_ERR_KEY_CERT_MISMATCH; 407 goto out; 408 } 409 410 if ((r = sshkey_to_certified(key)) != 0 || 411 (r = sshkey_cert_copy(cert, key)) != 0) 412 goto out; 413 r = 0; 414 if (keyp != NULL) { 415 *keyp = key; 416 key = NULL; 417 } 418 out: 419 sshkey_free(key); 420 sshkey_free(cert); 421 return r; 422 } 423 424 /* 425 * Returns success if the specified "key" is listed in the file "filename", 426 * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error. 427 * If "strict_type" is set then the key type must match exactly, 428 * otherwise a comparison that ignores certficiate data is performed. 429 * If "check_ca" is set and "key" is a certificate, then its CA key is 430 * also checked and sshkey_in_file() will return success if either is found. 431 */ 432 int 433 sshkey_in_file(struct sshkey *key, const char *filename, int strict_type, 434 int check_ca) 435 { 436 FILE *f; 437 char *line = NULL, *cp; 438 size_t linesize = 0; 439 int r = 0; 440 struct sshkey *pub = NULL; 441 442 int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) = 443 strict_type ? sshkey_equal : sshkey_equal_public; 444 445 if ((f = fopen(filename, "r")) == NULL) 446 return SSH_ERR_SYSTEM_ERROR; 447 448 while (getline(&line, &linesize, f) != -1) { 449 sshkey_free(pub); 450 pub = NULL; 451 cp = line; 452 453 /* Skip leading whitespace. */ 454 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 455 ; 456 457 /* Skip comments and empty lines */ 458 switch (*cp) { 459 case '#': 460 case '\n': 461 case '\0': 462 continue; 463 } 464 465 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) { 466 r = SSH_ERR_ALLOC_FAIL; 467 goto out; 468 } 469 switch (r = sshkey_read(pub, &cp)) { 470 case 0: 471 break; 472 case SSH_ERR_KEY_LENGTH: 473 continue; 474 default: 475 goto out; 476 } 477 if (sshkey_compare(key, pub) || 478 (check_ca && sshkey_is_cert(key) && 479 sshkey_compare(key->cert->signature_key, pub))) { 480 r = 0; 481 goto out; 482 } 483 } 484 r = SSH_ERR_KEY_NOT_FOUND; 485 out: 486 free(line); 487 sshkey_free(pub); 488 fclose(f); 489 return r; 490 } 491 492 /* 493 * Checks whether the specified key is revoked, returning 0 if not, 494 * SSH_ERR_KEY_REVOKED if it is or another error code if something 495 * unexpected happened. 496 * This will check both the key and, if it is a certificate, its CA key too. 497 * "revoked_keys_file" may be a KRL or a one-per-line list of public keys. 498 */ 499 int 500 sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file) 501 { 502 int r; 503 504 r = ssh_krl_file_contains_key(revoked_keys_file, key); 505 /* If this was not a KRL to begin with then continue below */ 506 if (r != SSH_ERR_KRL_BAD_MAGIC) 507 return r; 508 509 /* 510 * If the file is not a KRL or we can't handle KRLs then attempt to 511 * parse the file as a flat list of keys. 512 */ 513 switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) { 514 case 0: 515 /* Key found => revoked */ 516 return SSH_ERR_KEY_REVOKED; 517 case SSH_ERR_KEY_NOT_FOUND: 518 /* Key not found => not revoked */ 519 return 0; 520 default: 521 /* Some other error occurred */ 522 return r; 523 } 524 } 525 526 /* 527 * Advanced *cpp past the end of key options, defined as the first unquoted 528 * whitespace character. Returns 0 on success or -1 on failure (e.g. 529 * unterminated quotes). 530 */ 531 int 532 sshkey_advance_past_options(char **cpp) 533 { 534 char *cp = *cpp; 535 int quoted = 0; 536 537 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 538 if (*cp == '\\' && cp[1] == '"') 539 cp++; /* Skip both */ 540 else if (*cp == '"') 541 quoted = !quoted; 542 } 543 *cpp = cp; 544 /* return failure for unterminated quotes */ 545 return (*cp == '\0' && quoted) ? -1 : 0; 546 } 547 548