summaryrefslogtreecommitdiff
path: root/authfile.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2011-09-06 14:56:29 +0100
committerColin Watson <cjwatson@debian.org>2011-09-06 14:56:29 +0100
commit978e62d6f14c60747bddef2cc72d66a9c8b83b54 (patch)
tree89400a44e42d84937deba7864e4964d6c7734da5 /authfile.c
parent87c685b8c6a49814fd782288097b3093f975aa72 (diff)
parent3a7e89697ca363de0f64e0d5704c57219294e41c (diff)
* New upstream release (http://www.openssh.org/txt/release-5.9).
- Introduce sandboxing of the pre-auth privsep child using an optional sshd_config(5) "UsePrivilegeSeparation=sandbox" mode that enables mandatory restrictions on the syscalls the privsep child can perform. - Add new SHA256-based HMAC transport integrity modes from http://www.ietf.org/id/draft-dbider-sha2-mac-for-ssh-02.txt. - The pre-authentication sshd(8) privilege separation slave process now logs via a socket shared with the master process, avoiding the need to maintain /dev/log inside the chroot (closes: #75043, #429243, #599240). - ssh(1) now warns when a server refuses X11 forwarding (closes: #504757). - sshd_config(5)'s AuthorizedKeysFile now accepts multiple paths, separated by whitespace (closes: #76312). The authorized_keys2 fallback is deprecated but documented (closes: #560156). - ssh(1) and sshd(8): set IPv6 traffic class from IPQoS, as well as IPv4 ToS/DSCP (closes: #498297). - ssh-add(1) now accepts keys piped from standard input. E.g. "ssh-add - < /path/to/key" (closes: #229124). - Clean up lost-passphrase text in ssh-keygen(1) (closes: #444691). - Say "required" rather than "recommended" in unprotected-private-key warning (LP: #663455).
Diffstat (limited to 'authfile.c')
-rw-r--r--authfile.c159
1 files changed, 97 insertions, 62 deletions
diff --git a/authfile.c b/authfile.c
index 2ed250232..e5fe0b801 100644
--- a/authfile.c
+++ b/authfile.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: authfile.c,v 1.87 2010/11/29 18:57:04 markus Exp $ */ 1/* $OpenBSD: authfile.c,v 1.92 2011/06/14 22:49:18 markus Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -70,6 +70,8 @@
70#include "atomicio.h" 70#include "atomicio.h"
71#include "pathnames.h" 71#include "pathnames.h"
72 72
73#define MAX_KEY_FILE_SIZE (1024 * 1024)
74
73/* Version identification string for SSH v1 identity files. */ 75/* Version identification string for SSH v1 identity files. */
74static const char authfile_id_string[] = 76static const char authfile_id_string[] =
75 "SSH PRIVATE KEY FILE FORMAT 1.1\n"; 77 "SSH PRIVATE KEY FILE FORMAT 1.1\n";
@@ -278,6 +280,7 @@ static Key *
278key_parse_public_rsa1(Buffer *blob, char **commentp) 280key_parse_public_rsa1(Buffer *blob, char **commentp)
279{ 281{
280 Key *pub; 282 Key *pub;
283 Buffer copy;
281 284
282 /* Check that it is at least big enough to contain the ID string. */ 285 /* Check that it is at least big enough to contain the ID string. */
283 if (buffer_len(blob) < sizeof(authfile_id_string)) { 286 if (buffer_len(blob) < sizeof(authfile_id_string)) {
@@ -294,31 +297,33 @@ key_parse_public_rsa1(Buffer *blob, char **commentp)
294 debug3("Incorrect RSA1 identifier"); 297 debug3("Incorrect RSA1 identifier");
295 return NULL; 298 return NULL;
296 } 299 }
297 buffer_consume(blob, sizeof(authfile_id_string)); 300 buffer_init(&copy);
301 buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
302 buffer_consume(&copy, sizeof(authfile_id_string));
298 303
299 /* Skip cipher type and reserved data. */ 304 /* Skip cipher type and reserved data. */
300 (void) buffer_get_char(blob); /* cipher type */ 305 (void) buffer_get_char(&copy); /* cipher type */
301 (void) buffer_get_int(blob); /* reserved */ 306 (void) buffer_get_int(&copy); /* reserved */
302 307
303 /* Read the public key from the buffer. */ 308 /* Read the public key from the buffer. */
304 (void) buffer_get_int(blob); 309 (void) buffer_get_int(&copy);
305 pub = key_new(KEY_RSA1); 310 pub = key_new(KEY_RSA1);
306 buffer_get_bignum(blob, pub->rsa->n); 311 buffer_get_bignum(&copy, pub->rsa->n);
307 buffer_get_bignum(blob, pub->rsa->e); 312 buffer_get_bignum(&copy, pub->rsa->e);
308 if (commentp) 313 if (commentp)
309 *commentp = buffer_get_string(blob, NULL); 314 *commentp = buffer_get_string(&copy, NULL);
310 /* The encrypted private part is not parsed by this function. */ 315 /* The encrypted private part is not parsed by this function. */
311 buffer_clear(blob); 316 buffer_free(&copy);
312 317
313 return pub; 318 return pub;
314} 319}
315 320
316/* Load the contents of a key file into a buffer */ 321/* Load a key from a fd into a buffer */
317static int 322int
318key_load_file(int fd, const char *filename, Buffer *blob) 323key_load_file(int fd, const char *filename, Buffer *blob)
319{ 324{
320 size_t len, readcount; 325 u_char buf[1024];
321 u_char *cp; 326 size_t len;
322 struct stat st; 327 struct stat st;
323 328
324 if (fstat(fd, &st) < 0) { 329 if (fstat(fd, &st) < 0) {
@@ -326,33 +331,45 @@ key_load_file(int fd, const char *filename, Buffer *blob)
326 filename == NULL ? "" : filename, 331 filename == NULL ? "" : filename,
327 filename == NULL ? "" : " ", 332 filename == NULL ? "" : " ",
328 strerror(errno)); 333 strerror(errno));
329 close(fd);
330 return 0; 334 return 0;
331 } 335 }
332 if (st.st_size > 1*1024*1024) { 336 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
337 st.st_size > MAX_KEY_FILE_SIZE) {
338 toobig:
333 error("%s: key file %.200s%stoo large", __func__, 339 error("%s: key file %.200s%stoo large", __func__,
334 filename == NULL ? "" : filename, 340 filename == NULL ? "" : filename,
335 filename == NULL ? "" : " "); 341 filename == NULL ? "" : " ");
336 close(fd);
337 return 0; 342 return 0;
338 } 343 }
339 len = (size_t)st.st_size; /* truncated */
340 if (0 == len && S_ISFIFO(st.st_mode))
341 len = 8192; /* we will try reading up to 8KiB from a FIFO */
342
343 buffer_init(blob); 344 buffer_init(blob);
344 cp = buffer_append_space(blob, len); 345 for (;;) {
345 346 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
346 readcount = atomicio(read, fd, cp, len); 347 if (errno == EPIPE)
347 if (readcount != len && !(readcount > 0 && S_ISFIFO(st.st_mode))) { 348 break;
348 debug("%s: read from key file %.200s%sfailed: %.100s", __func__, 349 debug("%s: read from key file %.200s%sfailed: %.100s",
349 filename == NULL ? "" : filename, 350 __func__, filename == NULL ? "" : filename,
350 filename == NULL ? "" : " ", 351 filename == NULL ? "" : " ", strerror(errno));
351 strerror(errno)); 352 buffer_clear(blob);
353 bzero(buf, sizeof(buf));
354 return 0;
355 }
356 buffer_append(blob, buf, len);
357 if (buffer_len(blob) > MAX_KEY_FILE_SIZE) {
358 buffer_clear(blob);
359 bzero(buf, sizeof(buf));
360 goto toobig;
361 }
362 }
363 bzero(buf, sizeof(buf));
364 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
365 st.st_size != buffer_len(blob)) {
366 debug("%s: key file %.200s%schanged size while reading",
367 __func__, filename == NULL ? "" : filename,
368 filename == NULL ? "" : " ");
352 buffer_clear(blob); 369 buffer_clear(blob);
353 close(fd);
354 return 0; 370 return 0;
355 } 371 }
372
356 return 1; 373 return 1;
357} 374}
358 375
@@ -407,6 +424,7 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
407 CipherContext ciphercontext; 424 CipherContext ciphercontext;
408 Cipher *cipher; 425 Cipher *cipher;
409 Key *prv = NULL; 426 Key *prv = NULL;
427 Buffer copy;
410 428
411 /* Check that it is at least big enough to contain the ID string. */ 429 /* Check that it is at least big enough to contain the ID string. */
412 if (buffer_len(blob) < sizeof(authfile_id_string)) { 430 if (buffer_len(blob) < sizeof(authfile_id_string)) {
@@ -423,41 +441,44 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
423 debug3("Incorrect RSA1 identifier"); 441 debug3("Incorrect RSA1 identifier");
424 return NULL; 442 return NULL;
425 } 443 }
426 buffer_consume(blob, sizeof(authfile_id_string)); 444 buffer_init(&copy);
445 buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
446 buffer_consume(&copy, sizeof(authfile_id_string));
427 447
428 /* Read cipher type. */ 448 /* Read cipher type. */
429 cipher_type = buffer_get_char(blob); 449 cipher_type = buffer_get_char(&copy);
430 (void) buffer_get_int(blob); /* Reserved data. */ 450 (void) buffer_get_int(&copy); /* Reserved data. */
431 451
432 /* Read the public key from the buffer. */ 452 /* Read the public key from the buffer. */
433 (void) buffer_get_int(blob); 453 (void) buffer_get_int(&copy);
434 prv = key_new_private(KEY_RSA1); 454 prv = key_new_private(KEY_RSA1);
435 455
436 buffer_get_bignum(blob, prv->rsa->n); 456 buffer_get_bignum(&copy, prv->rsa->n);
437 buffer_get_bignum(blob, prv->rsa->e); 457 buffer_get_bignum(&copy, prv->rsa->e);
438 if (commentp) 458 if (commentp)
439 *commentp = buffer_get_string(blob, NULL); 459 *commentp = buffer_get_string(&copy, NULL);
440 else 460 else
441 (void)buffer_get_string_ptr(blob, NULL); 461 (void)buffer_get_string_ptr(&copy, NULL);
442 462
443 /* Check that it is a supported cipher. */ 463 /* Check that it is a supported cipher. */
444 cipher = cipher_by_number(cipher_type); 464 cipher = cipher_by_number(cipher_type);
445 if (cipher == NULL) { 465 if (cipher == NULL) {
446 debug("Unsupported RSA1 cipher %d", cipher_type); 466 debug("Unsupported RSA1 cipher %d", cipher_type);
467 buffer_free(&copy);
447 goto fail; 468 goto fail;
448 } 469 }
449 /* Initialize space for decrypted data. */ 470 /* Initialize space for decrypted data. */
450 buffer_init(&decrypted); 471 buffer_init(&decrypted);
451 cp = buffer_append_space(&decrypted, buffer_len(blob)); 472 cp = buffer_append_space(&decrypted, buffer_len(&copy));
452 473
453 /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ 474 /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
454 cipher_set_key_string(&ciphercontext, cipher, passphrase, 475 cipher_set_key_string(&ciphercontext, cipher, passphrase,
455 CIPHER_DECRYPT); 476 CIPHER_DECRYPT);
456 cipher_crypt(&ciphercontext, cp, 477 cipher_crypt(&ciphercontext, cp,
457 buffer_ptr(blob), buffer_len(blob)); 478 buffer_ptr(&copy), buffer_len(&copy));
458 cipher_cleanup(&ciphercontext); 479 cipher_cleanup(&ciphercontext);
459 memset(&ciphercontext, 0, sizeof(ciphercontext)); 480 memset(&ciphercontext, 0, sizeof(ciphercontext));
460 buffer_clear(blob); 481 buffer_free(&copy);
461 482
462 check1 = buffer_get_char(&decrypted); 483 check1 = buffer_get_char(&decrypted);
463 check2 = buffer_get_char(&decrypted); 484 check2 = buffer_get_char(&decrypted);
@@ -610,7 +631,7 @@ key_perm_ok(int fd, const char *filename)
610 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 631 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
611 error("Permissions 0%3.3o for '%s' are too open.", 632 error("Permissions 0%3.3o for '%s' are too open.",
612 (u_int)st.st_mode & 0777, filename); 633 (u_int)st.st_mode & 0777, filename);
613 error("It is recommended that your private key files are NOT accessible by others."); 634 error("It is required that your private key files are NOT accessible by others.");
614 error("This private key will be ignored."); 635 error("This private key will be ignored.");
615 return 0; 636 return 0;
616 } 637 }
@@ -630,6 +651,7 @@ key_parse_private_type(Buffer *blob, int type, const char *passphrase,
630 case KEY_UNSPEC: 651 case KEY_UNSPEC:
631 return key_parse_private_pem(blob, type, passphrase, commentp); 652 return key_parse_private_pem(blob, type, passphrase, commentp);
632 default: 653 default:
654 error("%s: cannot parse key type %d", __func__, type);
633 break; 655 break;
634 } 656 }
635 return NULL; 657 return NULL;
@@ -674,11 +696,34 @@ key_load_private_type(int type, const char *filename, const char *passphrase,
674} 696}
675 697
676Key * 698Key *
699key_parse_private(Buffer *buffer, const char *filename,
700 const char *passphrase, char **commentp)
701{
702 Key *pub, *prv;
703
704 /* it's a SSH v1 key if the public key part is readable */
705 pub = key_parse_public_rsa1(buffer, commentp);
706 if (pub == NULL) {
707 prv = key_parse_private_type(buffer, KEY_UNSPEC,
708 passphrase, NULL);
709 /* use the filename as a comment for PEM */
710 if (commentp && prv)
711 *commentp = xstrdup(filename);
712 } else {
713 key_free(pub);
714 /* key_parse_public_rsa1() has already loaded the comment */
715 prv = key_parse_private_type(buffer, KEY_RSA1, passphrase,
716 NULL);
717 }
718 return prv;
719}
720
721Key *
677key_load_private(const char *filename, const char *passphrase, 722key_load_private(const char *filename, const char *passphrase,
678 char **commentp) 723 char **commentp)
679{ 724{
680 Key *pub, *prv; 725 Key *prv;
681 Buffer buffer, pubcopy; 726 Buffer buffer;
682 int fd; 727 int fd;
683 728
684 fd = open(filename, O_RDONLY); 729 fd = open(filename, O_RDONLY);
@@ -701,23 +746,7 @@ key_load_private(const char *filename, const char *passphrase,
701 } 746 }
702 close(fd); 747 close(fd);
703 748
704 buffer_init(&pubcopy); 749 prv = key_parse_private(&buffer, filename, passphrase, commentp);
705 buffer_append(&pubcopy, buffer_ptr(&buffer), buffer_len(&buffer));
706 /* it's a SSH v1 key if the public key part is readable */
707 pub = key_parse_public_rsa1(&pubcopy, commentp);
708 buffer_free(&pubcopy);
709 if (pub == NULL) {
710 prv = key_parse_private_type(&buffer, KEY_UNSPEC,
711 passphrase, NULL);
712 /* use the filename as a comment for PEM */
713 if (commentp && prv)
714 *commentp = xstrdup(filename);
715 } else {
716 key_free(pub);
717 /* key_parse_public_rsa1() has already loaded the comment */
718 prv = key_parse_private_type(&buffer, KEY_RSA1, passphrase,
719 NULL);
720 }
721 buffer_free(&buffer); 750 buffer_free(&buffer);
722 return prv; 751 return prv;
723} 752}
@@ -741,13 +770,19 @@ key_try_load_public(Key *k, const char *filename, char **commentp)
741 case '\0': 770 case '\0':
742 continue; 771 continue;
743 } 772 }
773 /* Abort loading if this looks like a private key */
774 if (strncmp(cp, "-----BEGIN", 10) == 0)
775 break;
744 /* Skip leading whitespace. */ 776 /* Skip leading whitespace. */
745 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 777 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
746 ; 778 ;
747 if (*cp) { 779 if (*cp) {
748 if (key_read(k, &cp) == 1) { 780 if (key_read(k, &cp) == 1) {
749 if (commentp) 781 cp[strcspn(cp, "\r\n")] = '\0';
750 *commentp=xstrdup(filename); 782 if (commentp) {
783 *commentp = xstrdup(*cp ?
784 cp : filename);
785 }
751 fclose(f); 786 fclose(f);
752 return 1; 787 return 1;
753 } 788 }