1 /* $OpenBSD: authfile.c,v 1.128 2018/02/23 15:58:37 markus 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)) < 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, 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 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) < 0) 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 /* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */ 163 int 164 sshkey_load_private_type(int type, const char *filename, const char *passphrase, 165 struct sshkey **keyp, char **commentp, int *perm_ok) 166 { 167 int fd, r; 168 169 if (keyp != NULL) 170 *keyp = NULL; 171 if (commentp != NULL) 172 *commentp = NULL; 173 174 if ((fd = open(filename, O_RDONLY)) < 0) { 175 if (perm_ok != NULL) 176 *perm_ok = 0; 177 return SSH_ERR_SYSTEM_ERROR; 178 } 179 if (sshkey_perm_ok(fd, filename) != 0) { 180 if (perm_ok != NULL) 181 *perm_ok = 0; 182 r = SSH_ERR_KEY_BAD_PERMISSIONS; 183 goto out; 184 } 185 if (perm_ok != NULL) 186 *perm_ok = 1; 187 188 r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp); 189 if (r == 0 && keyp && *keyp) 190 r = sshkey_set_filename(*keyp, filename); 191 out: 192 close(fd); 193 return r; 194 } 195 196 int 197 sshkey_load_private_type_fd(int fd, int type, const char *passphrase, 198 struct sshkey **keyp, char **commentp) 199 { 200 struct sshbuf *buffer = NULL; 201 int r; 202 203 if (keyp != NULL) 204 *keyp = NULL; 205 if ((buffer = sshbuf_new()) == NULL) { 206 r = SSH_ERR_ALLOC_FAIL; 207 goto out; 208 } 209 if ((r = sshkey_load_file(fd, buffer)) != 0 || 210 (r = sshkey_parse_private_fileblob_type(buffer, type, 211 passphrase, keyp, commentp)) != 0) 212 goto out; 213 214 /* success */ 215 r = 0; 216 out: 217 sshbuf_free(buffer); 218 return r; 219 } 220 221 /* XXX this is almost identical to sshkey_load_private_type() */ 222 int 223 sshkey_load_private(const char *filename, const char *passphrase, 224 struct sshkey **keyp, char **commentp) 225 { 226 struct sshbuf *buffer = NULL; 227 int r, fd; 228 229 if (keyp != NULL) 230 *keyp = NULL; 231 if (commentp != NULL) 232 *commentp = NULL; 233 234 if ((fd = open(filename, O_RDONLY)) < 0) 235 return SSH_ERR_SYSTEM_ERROR; 236 if (sshkey_perm_ok(fd, filename) != 0) { 237 r = SSH_ERR_KEY_BAD_PERMISSIONS; 238 goto out; 239 } 240 241 if ((buffer = sshbuf_new()) == NULL) { 242 r = SSH_ERR_ALLOC_FAIL; 243 goto out; 244 } 245 if ((r = sshkey_load_file(fd, buffer)) != 0 || 246 (r = sshkey_parse_private_fileblob(buffer, passphrase, keyp, 247 commentp)) != 0) 248 goto out; 249 if (keyp && *keyp && 250 (r = sshkey_set_filename(*keyp, filename)) != 0) 251 goto out; 252 r = 0; 253 out: 254 close(fd); 255 sshbuf_free(buffer); 256 return r; 257 } 258 259 static int 260 sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp) 261 { 262 FILE *f; 263 char line[SSH_MAX_PUBKEY_BYTES]; 264 char *cp; 265 u_long linenum = 0; 266 int r; 267 268 if (commentp != NULL) 269 *commentp = NULL; 270 if ((f = fopen(filename, "r")) == NULL) 271 return SSH_ERR_SYSTEM_ERROR; 272 while (read_keyfile_line(f, filename, line, sizeof(line), 273 &linenum) != -1) { 274 cp = line; 275 switch (*cp) { 276 case '#': 277 case '\n': 278 case '\0': 279 continue; 280 } 281 /* Abort loading if this looks like a private key */ 282 if (strncmp(cp, "-----BEGIN", 10) == 0 || 283 strcmp(cp, "SSH PRIVATE KEY FILE") == 0) 284 break; 285 /* Skip leading whitespace. */ 286 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 287 ; 288 if (*cp) { 289 if ((r = sshkey_read(k, &cp)) == 0) { 290 cp[strcspn(cp, "\r\n")] = '\0'; 291 if (commentp) { 292 *commentp = strdup(*cp ? 293 cp : filename); 294 if (*commentp == NULL) 295 r = SSH_ERR_ALLOC_FAIL; 296 } 297 fclose(f); 298 return r; 299 } 300 } 301 } 302 fclose(f); 303 return SSH_ERR_INVALID_FORMAT; 304 } 305 306 /* load public key from any pubkey file */ 307 int 308 sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp) 309 { 310 struct sshkey *pub = NULL; 311 char *file = NULL; 312 int r; 313 314 if (keyp != NULL) 315 *keyp = NULL; 316 if (commentp != NULL) 317 *commentp = NULL; 318 319 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) 320 return SSH_ERR_ALLOC_FAIL; 321 if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) { 322 if (keyp != NULL) { 323 *keyp = pub; 324 pub = NULL; 325 } 326 r = 0; 327 goto out; 328 } 329 sshkey_free(pub); 330 331 /* try .pub suffix */ 332 if (asprintf(&file, "%s.pub", filename) == -1) 333 return SSH_ERR_ALLOC_FAIL; 334 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) { 335 r = SSH_ERR_ALLOC_FAIL; 336 goto out; 337 } 338 if ((r = sshkey_try_load_public(pub, file, commentp)) == 0) { 339 if (keyp != NULL) { 340 *keyp = pub; 341 pub = NULL; 342 } 343 r = 0; 344 } 345 out: 346 free(file); 347 sshkey_free(pub); 348 return r; 349 } 350 351 /* Load the certificate associated with the named private key */ 352 int 353 sshkey_load_cert(const char *filename, struct sshkey **keyp) 354 { 355 struct sshkey *pub = NULL; 356 char *file = NULL; 357 int r = SSH_ERR_INTERNAL_ERROR; 358 359 if (keyp != NULL) 360 *keyp = NULL; 361 362 if (asprintf(&file, "%s-cert.pub", filename) == -1) 363 return SSH_ERR_ALLOC_FAIL; 364 365 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) { 366 goto out; 367 } 368 if ((r = sshkey_try_load_public(pub, file, NULL)) != 0) 369 goto out; 370 /* success */ 371 if (keyp != NULL) { 372 *keyp = pub; 373 pub = NULL; 374 } 375 r = 0; 376 out: 377 free(file); 378 sshkey_free(pub); 379 return r; 380 } 381 382 /* Load private key and certificate */ 383 int 384 sshkey_load_private_cert(int type, const char *filename, const char *passphrase, 385 struct sshkey **keyp, int *perm_ok) 386 { 387 struct sshkey *key = NULL, *cert = NULL; 388 int r; 389 390 if (keyp != NULL) 391 *keyp = NULL; 392 393 switch (type) { 394 #ifdef WITH_OPENSSL 395 case KEY_RSA: 396 case KEY_DSA: 397 case KEY_ECDSA: 398 #endif /* WITH_OPENSSL */ 399 case KEY_ED25519: 400 case KEY_XMSS: 401 case KEY_UNSPEC: 402 break; 403 default: 404 return SSH_ERR_KEY_TYPE_UNKNOWN; 405 } 406 407 if ((r = sshkey_load_private_type(type, filename, 408 passphrase, &key, NULL, perm_ok)) != 0 || 409 (r = sshkey_load_cert(filename, &cert)) != 0) 410 goto out; 411 412 /* Make sure the private key matches the certificate */ 413 if (sshkey_equal_public(key, cert) == 0) { 414 r = SSH_ERR_KEY_CERT_MISMATCH; 415 goto out; 416 } 417 418 if ((r = sshkey_to_certified(key)) != 0 || 419 (r = sshkey_cert_copy(cert, key)) != 0) 420 goto out; 421 r = 0; 422 if (keyp != NULL) { 423 *keyp = key; 424 key = NULL; 425 } 426 out: 427 sshkey_free(key); 428 sshkey_free(cert); 429 return r; 430 } 431 432 /* 433 * Returns success if the specified "key" is listed in the file "filename", 434 * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error. 435 * If "strict_type" is set then the key type must match exactly, 436 * otherwise a comparison that ignores certficiate data is performed. 437 * If "check_ca" is set and "key" is a certificate, then its CA key is 438 * also checked and sshkey_in_file() will return success if either is found. 439 */ 440 int 441 sshkey_in_file(struct sshkey *key, const char *filename, int strict_type, 442 int check_ca) 443 { 444 FILE *f; 445 char line[SSH_MAX_PUBKEY_BYTES]; 446 char *cp; 447 u_long linenum = 0; 448 int r = 0; 449 struct sshkey *pub = NULL; 450 int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) = 451 strict_type ? sshkey_equal : sshkey_equal_public; 452 453 if ((f = fopen(filename, "r")) == NULL) 454 return SSH_ERR_SYSTEM_ERROR; 455 456 while (read_keyfile_line(f, filename, line, sizeof(line), 457 &linenum) != -1) { 458 cp = line; 459 460 /* Skip leading whitespace. */ 461 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 462 ; 463 464 /* Skip comments and empty lines */ 465 switch (*cp) { 466 case '#': 467 case '\n': 468 case '\0': 469 continue; 470 } 471 472 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) { 473 r = SSH_ERR_ALLOC_FAIL; 474 goto out; 475 } 476 if ((r = sshkey_read(pub, &cp)) != 0) 477 goto out; 478 if (sshkey_compare(key, pub) || 479 (check_ca && sshkey_is_cert(key) && 480 sshkey_compare(key->cert->signature_key, pub))) { 481 r = 0; 482 goto out; 483 } 484 sshkey_free(pub); 485 pub = NULL; 486 } 487 r = SSH_ERR_KEY_NOT_FOUND; 488 out: 489 sshkey_free(pub); 490 fclose(f); 491 return r; 492 } 493 494 /* 495 * Checks whether the specified key is revoked, returning 0 if not, 496 * SSH_ERR_KEY_REVOKED if it is or another error code if something 497 * unexpected happened. 498 * This will check both the key and, if it is a certificate, its CA key too. 499 * "revoked_keys_file" may be a KRL or a one-per-line list of public keys. 500 */ 501 int 502 sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file) 503 { 504 int r; 505 506 r = ssh_krl_file_contains_key(revoked_keys_file, key); 507 /* If this was not a KRL to begin with then continue below */ 508 if (r != SSH_ERR_KRL_BAD_MAGIC) 509 return r; 510 511 /* 512 * If the file is not a KRL or we can't handle KRLs then attempt to 513 * parse the file as a flat list of keys. 514 */ 515 switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) { 516 case 0: 517 /* Key found => revoked */ 518 return SSH_ERR_KEY_REVOKED; 519 case SSH_ERR_KEY_NOT_FOUND: 520 /* Key not found => not revoked */ 521 return 0; 522 default: 523 /* Some other error occurred */ 524 return r; 525 } 526 } 527 528