summaryrefslogtreecommitdiff
path: root/authfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'authfile.c')
-rw-r--r--authfile.c154
1 files changed, 96 insertions, 58 deletions
diff --git a/authfile.c b/authfile.c
index f2aec267a..1d7e53cd1 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
@@ -69,6 +69,8 @@
69#include "misc.h" 69#include "misc.h"
70#include "atomicio.h" 70#include "atomicio.h"
71 71
72#define MAX_KEY_FILE_SIZE (1024 * 1024)
73
72/* Version identification string for SSH v1 identity files. */ 74/* Version identification string for SSH v1 identity files. */
73static const char authfile_id_string[] = 75static const char authfile_id_string[] =
74 "SSH PRIVATE KEY FILE FORMAT 1.1\n"; 76 "SSH PRIVATE KEY FILE FORMAT 1.1\n";
@@ -277,6 +279,7 @@ static Key *
277key_parse_public_rsa1(Buffer *blob, char **commentp) 279key_parse_public_rsa1(Buffer *blob, char **commentp)
278{ 280{
279 Key *pub; 281 Key *pub;
282 Buffer copy;
280 283
281 /* Check that it is at least big enough to contain the ID string. */ 284 /* Check that it is at least big enough to contain the ID string. */
282 if (buffer_len(blob) < sizeof(authfile_id_string)) { 285 if (buffer_len(blob) < sizeof(authfile_id_string)) {
@@ -293,31 +296,33 @@ key_parse_public_rsa1(Buffer *blob, char **commentp)
293 debug3("Incorrect RSA1 identifier"); 296 debug3("Incorrect RSA1 identifier");
294 return NULL; 297 return NULL;
295 } 298 }
296 buffer_consume(blob, sizeof(authfile_id_string)); 299 buffer_init(&copy);
300 buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
301 buffer_consume(&copy, sizeof(authfile_id_string));
297 302
298 /* Skip cipher type and reserved data. */ 303 /* Skip cipher type and reserved data. */
299 (void) buffer_get_char(blob); /* cipher type */ 304 (void) buffer_get_char(&copy); /* cipher type */
300 (void) buffer_get_int(blob); /* reserved */ 305 (void) buffer_get_int(&copy); /* reserved */
301 306
302 /* Read the public key from the buffer. */ 307 /* Read the public key from the buffer. */
303 (void) buffer_get_int(blob); 308 (void) buffer_get_int(&copy);
304 pub = key_new(KEY_RSA1); 309 pub = key_new(KEY_RSA1);
305 buffer_get_bignum(blob, pub->rsa->n); 310 buffer_get_bignum(&copy, pub->rsa->n);
306 buffer_get_bignum(blob, pub->rsa->e); 311 buffer_get_bignum(&copy, pub->rsa->e);
307 if (commentp) 312 if (commentp)
308 *commentp = buffer_get_string(blob, NULL); 313 *commentp = buffer_get_string(&copy, NULL);
309 /* The encrypted private part is not parsed by this function. */ 314 /* The encrypted private part is not parsed by this function. */
310 buffer_clear(blob); 315 buffer_free(&copy);
311 316
312 return pub; 317 return pub;
313} 318}
314 319
315/* Load the contents of a key file into a buffer */ 320/* Load a key from a fd into a buffer */
316static int 321int
317key_load_file(int fd, const char *filename, Buffer *blob) 322key_load_file(int fd, const char *filename, Buffer *blob)
318{ 323{
324 u_char buf[1024];
319 size_t len; 325 size_t len;
320 u_char *cp;
321 struct stat st; 326 struct stat st;
322 327
323 if (fstat(fd, &st) < 0) { 328 if (fstat(fd, &st) < 0) {
@@ -325,30 +330,45 @@ key_load_file(int fd, const char *filename, Buffer *blob)
325 filename == NULL ? "" : filename, 330 filename == NULL ? "" : filename,
326 filename == NULL ? "" : " ", 331 filename == NULL ? "" : " ",
327 strerror(errno)); 332 strerror(errno));
328 close(fd);
329 return 0; 333 return 0;
330 } 334 }
331 if (st.st_size > 1*1024*1024) { 335 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
336 st.st_size > MAX_KEY_FILE_SIZE) {
337 toobig:
332 error("%s: key file %.200s%stoo large", __func__, 338 error("%s: key file %.200s%stoo large", __func__,
333 filename == NULL ? "" : filename, 339 filename == NULL ? "" : filename,
334 filename == NULL ? "" : " "); 340 filename == NULL ? "" : " ");
335 close(fd);
336 return 0; 341 return 0;
337 } 342 }
338 len = (size_t)st.st_size; /* truncated */
339
340 buffer_init(blob); 343 buffer_init(blob);
341 cp = buffer_append_space(blob, len); 344 for (;;) {
342 345 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
343 if (atomicio(read, fd, cp, len) != len) { 346 if (errno == EPIPE)
344 debug("%s: read from key file %.200s%sfailed: %.100s", __func__, 347 break;
345 filename == NULL ? "" : filename, 348 debug("%s: read from key file %.200s%sfailed: %.100s",
346 filename == NULL ? "" : " ", 349 __func__, filename == NULL ? "" : filename,
347 strerror(errno)); 350 filename == NULL ? "" : " ", strerror(errno));
351 buffer_clear(blob);
352 bzero(buf, sizeof(buf));
353 return 0;
354 }
355 buffer_append(blob, buf, len);
356 if (buffer_len(blob) > MAX_KEY_FILE_SIZE) {
357 buffer_clear(blob);
358 bzero(buf, sizeof(buf));
359 goto toobig;
360 }
361 }
362 bzero(buf, sizeof(buf));
363 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
364 st.st_size != buffer_len(blob)) {
365 debug("%s: key file %.200s%schanged size while reading",
366 __func__, filename == NULL ? "" : filename,
367 filename == NULL ? "" : " ");
348 buffer_clear(blob); 368 buffer_clear(blob);
349 close(fd);
350 return 0; 369 return 0;
351 } 370 }
371
352 return 1; 372 return 1;
353} 373}
354 374
@@ -403,6 +423,7 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
403 CipherContext ciphercontext; 423 CipherContext ciphercontext;
404 Cipher *cipher; 424 Cipher *cipher;
405 Key *prv = NULL; 425 Key *prv = NULL;
426 Buffer copy;
406 427
407 /* Check that it is at least big enough to contain the ID string. */ 428 /* Check that it is at least big enough to contain the ID string. */
408 if (buffer_len(blob) < sizeof(authfile_id_string)) { 429 if (buffer_len(blob) < sizeof(authfile_id_string)) {
@@ -419,41 +440,44 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
419 debug3("Incorrect RSA1 identifier"); 440 debug3("Incorrect RSA1 identifier");
420 return NULL; 441 return NULL;
421 } 442 }
422 buffer_consume(blob, sizeof(authfile_id_string)); 443 buffer_init(&copy);
444 buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
445 buffer_consume(&copy, sizeof(authfile_id_string));
423 446
424 /* Read cipher type. */ 447 /* Read cipher type. */
425 cipher_type = buffer_get_char(blob); 448 cipher_type = buffer_get_char(&copy);
426 (void) buffer_get_int(blob); /* Reserved data. */ 449 (void) buffer_get_int(&copy); /* Reserved data. */
427 450
428 /* Read the public key from the buffer. */ 451 /* Read the public key from the buffer. */
429 (void) buffer_get_int(blob); 452 (void) buffer_get_int(&copy);
430 prv = key_new_private(KEY_RSA1); 453 prv = key_new_private(KEY_RSA1);
431 454
432 buffer_get_bignum(blob, prv->rsa->n); 455 buffer_get_bignum(&copy, prv->rsa->n);
433 buffer_get_bignum(blob, prv->rsa->e); 456 buffer_get_bignum(&copy, prv->rsa->e);
434 if (commentp) 457 if (commentp)
435 *commentp = buffer_get_string(blob, NULL); 458 *commentp = buffer_get_string(&copy, NULL);
436 else 459 else
437 (void)buffer_get_string_ptr(blob, NULL); 460 (void)buffer_get_string_ptr(&copy, NULL);
438 461
439 /* Check that it is a supported cipher. */ 462 /* Check that it is a supported cipher. */
440 cipher = cipher_by_number(cipher_type); 463 cipher = cipher_by_number(cipher_type);
441 if (cipher == NULL) { 464 if (cipher == NULL) {
442 debug("Unsupported RSA1 cipher %d", cipher_type); 465 debug("Unsupported RSA1 cipher %d", cipher_type);
466 buffer_free(&copy);
443 goto fail; 467 goto fail;
444 } 468 }
445 /* Initialize space for decrypted data. */ 469 /* Initialize space for decrypted data. */
446 buffer_init(&decrypted); 470 buffer_init(&decrypted);
447 cp = buffer_append_space(&decrypted, buffer_len(blob)); 471 cp = buffer_append_space(&decrypted, buffer_len(&copy));
448 472
449 /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ 473 /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
450 cipher_set_key_string(&ciphercontext, cipher, passphrase, 474 cipher_set_key_string(&ciphercontext, cipher, passphrase,
451 CIPHER_DECRYPT); 475 CIPHER_DECRYPT);
452 cipher_crypt(&ciphercontext, cp, 476 cipher_crypt(&ciphercontext, cp,
453 buffer_ptr(blob), buffer_len(blob)); 477 buffer_ptr(&copy), buffer_len(&copy));
454 cipher_cleanup(&ciphercontext); 478 cipher_cleanup(&ciphercontext);
455 memset(&ciphercontext, 0, sizeof(ciphercontext)); 479 memset(&ciphercontext, 0, sizeof(ciphercontext));
456 buffer_clear(blob); 480 buffer_free(&copy);
457 481
458 check1 = buffer_get_char(&decrypted); 482 check1 = buffer_get_char(&decrypted);
459 check2 = buffer_get_char(&decrypted); 483 check2 = buffer_get_char(&decrypted);
@@ -606,7 +630,7 @@ key_perm_ok(int fd, const char *filename)
606 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 630 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
607 error("Permissions 0%3.3o for '%s' are too open.", 631 error("Permissions 0%3.3o for '%s' are too open.",
608 (u_int)st.st_mode & 0777, filename); 632 (u_int)st.st_mode & 0777, filename);
609 error("It is recommended that your private key files are NOT accessible by others."); 633 error("It is required that your private key files are NOT accessible by others.");
610 error("This private key will be ignored."); 634 error("This private key will be ignored.");
611 return 0; 635 return 0;
612 } 636 }
@@ -626,6 +650,7 @@ key_parse_private_type(Buffer *blob, int type, const char *passphrase,
626 case KEY_UNSPEC: 650 case KEY_UNSPEC:
627 return key_parse_private_pem(blob, type, passphrase, commentp); 651 return key_parse_private_pem(blob, type, passphrase, commentp);
628 default: 652 default:
653 error("%s: cannot parse key type %d", __func__, type);
629 break; 654 break;
630 } 655 }
631 return NULL; 656 return NULL;
@@ -670,11 +695,34 @@ key_load_private_type(int type, const char *filename, const char *passphrase,
670} 695}
671 696
672Key * 697Key *
698key_parse_private(Buffer *buffer, const char *filename,
699 const char *passphrase, char **commentp)
700{
701 Key *pub, *prv;
702
703 /* it's a SSH v1 key if the public key part is readable */
704 pub = key_parse_public_rsa1(buffer, commentp);
705 if (pub == NULL) {
706 prv = key_parse_private_type(buffer, KEY_UNSPEC,
707 passphrase, NULL);
708 /* use the filename as a comment for PEM */
709 if (commentp && prv)
710 *commentp = xstrdup(filename);
711 } else {
712 key_free(pub);
713 /* key_parse_public_rsa1() has already loaded the comment */
714 prv = key_parse_private_type(buffer, KEY_RSA1, passphrase,
715 NULL);
716 }
717 return prv;
718}
719
720Key *
673key_load_private(const char *filename, const char *passphrase, 721key_load_private(const char *filename, const char *passphrase,
674 char **commentp) 722 char **commentp)
675{ 723{
676 Key *pub, *prv; 724 Key *prv;
677 Buffer buffer, pubcopy; 725 Buffer buffer;
678 int fd; 726 int fd;
679 727
680 fd = open(filename, O_RDONLY); 728 fd = open(filename, O_RDONLY);
@@ -697,23 +745,7 @@ key_load_private(const char *filename, const char *passphrase,
697 } 745 }
698 close(fd); 746 close(fd);
699 747
700 buffer_init(&pubcopy); 748 prv = key_parse_private(&buffer, filename, passphrase, commentp);
701 buffer_append(&pubcopy, buffer_ptr(&buffer), buffer_len(&buffer));
702 /* it's a SSH v1 key if the public key part is readable */
703 pub = key_parse_public_rsa1(&pubcopy, commentp);
704 buffer_free(&pubcopy);
705 if (pub == NULL) {
706 prv = key_parse_private_type(&buffer, KEY_UNSPEC,
707 passphrase, NULL);
708 /* use the filename as a comment for PEM */
709 if (commentp && prv)
710 *commentp = xstrdup(filename);
711 } else {
712 key_free(pub);
713 /* key_parse_public_rsa1() has already loaded the comment */
714 prv = key_parse_private_type(&buffer, KEY_RSA1, passphrase,
715 NULL);
716 }
717 buffer_free(&buffer); 749 buffer_free(&buffer);
718 return prv; 750 return prv;
719} 751}
@@ -737,13 +769,19 @@ key_try_load_public(Key *k, const char *filename, char **commentp)
737 case '\0': 769 case '\0':
738 continue; 770 continue;
739 } 771 }
772 /* Abort loading if this looks like a private key */
773 if (strncmp(cp, "-----BEGIN", 10) == 0)
774 break;
740 /* Skip leading whitespace. */ 775 /* Skip leading whitespace. */
741 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 776 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
742 ; 777 ;
743 if (*cp) { 778 if (*cp) {
744 if (key_read(k, &cp) == 1) { 779 if (key_read(k, &cp) == 1) {
745 if (commentp) 780 cp[strcspn(cp, "\r\n")] = '\0';
746 *commentp=xstrdup(filename); 781 if (commentp) {
782 *commentp = xstrdup(*cp ?
783 cp : filename);
784 }
747 fclose(f); 785 fclose(f);
748 return 1; 786 return 1;
749 } 787 }