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