=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/authfile.c,v retrieving revision 1.87 retrieving revision 1.88 diff -u -r1.87 -r1.88 --- src/usr.bin/ssh/authfile.c 2010/11/29 18:57:04 1.87 +++ src/usr.bin/ssh/authfile.c 2011/05/04 21:15:29 1.88 @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.87 2010/11/29 18:57:04 markus Exp $ */ +/* $OpenBSD: authfile.c,v 1.88 2011/05/04 21:15:29 djm Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -64,6 +64,8 @@ #include "misc.h" #include "atomicio.h" +#define MAX_KEY_FILE_SIZE (1024 * 1024) + /* Version identification string for SSH v1 identity files. */ static const char authfile_id_string[] = "SSH PRIVATE KEY FILE FORMAT 1.1\n"; @@ -301,12 +303,12 @@ return pub; } -/* Load the contents of a key file into a buffer */ -static int +/* Load a key from a fd into a buffer */ +int key_load_file(int fd, const char *filename, Buffer *blob) { + u_char buf[1024]; size_t len; - u_char *cp; struct stat st; if (fstat(fd, &st) < 0) { @@ -314,30 +316,45 @@ filename == NULL ? "" : filename, filename == NULL ? "" : " ", strerror(errno)); - close(fd); return 0; } - if (st.st_size > 1*1024*1024) { + if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && + st.st_size > MAX_KEY_FILE_SIZE) { + toobig: error("%s: key file %.200s%stoo large", __func__, filename == NULL ? "" : filename, filename == NULL ? "" : " "); - close(fd); return 0; } - len = (size_t)st.st_size; /* truncated */ - buffer_init(blob); - cp = buffer_append_space(blob, len); - - if (atomicio(read, fd, cp, len) != len) { - debug("%s: read from key file %.200s%sfailed: %.100s", __func__, - filename == NULL ? "" : filename, - filename == NULL ? "" : " ", - strerror(errno)); + for (;;) { + if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { + if (errno == EPIPE) + break; + debug("%s: read from key file %.200s%sfailed: %.100s", + __func__, filename == NULL ? "" : filename, + filename == NULL ? "" : " ", strerror(errno)); + buffer_clear(blob); + bzero(buf, sizeof(buf)); + return 0; + } + buffer_append(blob, buf, len); + if (buffer_len(blob) > MAX_KEY_FILE_SIZE) { + buffer_clear(blob); + bzero(buf, sizeof(buf)); + goto toobig; + } + } + bzero(buf, sizeof(buf)); + if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && + st.st_size != buffer_len(blob)) { + debug("%s: key file %.200s%schanged size while reading", + __func__, filename == NULL ? "" : filename, + filename == NULL ? "" : " "); buffer_clear(blob); - close(fd); return 0; } + return 1; } @@ -654,11 +671,38 @@ } Key * +key_parse_private(Buffer *buffer, const char *filename, + const char *passphrase, char **commentp) +{ + Key *pub, *prv; + Buffer pubcopy; + + buffer_init(&pubcopy); + buffer_append(&pubcopy, buffer_ptr(buffer), buffer_len(buffer)); + /* it's a SSH v1 key if the public key part is readable */ + pub = key_parse_public_rsa1(&pubcopy, commentp); + buffer_free(&pubcopy); + if (pub == NULL) { + prv = key_parse_private_type(buffer, KEY_UNSPEC, + passphrase, NULL); + /* use the filename as a comment for PEM */ + if (commentp && prv) + *commentp = xstrdup(filename); + } else { + key_free(pub); + /* key_parse_public_rsa1() has already loaded the comment */ + prv = key_parse_private_type(buffer, KEY_RSA1, passphrase, + NULL); + } + return prv; +} + +Key * key_load_private(const char *filename, const char *passphrase, char **commentp) { - Key *pub, *prv; - Buffer buffer, pubcopy; + Key *prv; + Buffer buffer; int fd; fd = open(filename, O_RDONLY); @@ -681,23 +725,7 @@ } close(fd); - buffer_init(&pubcopy); - buffer_append(&pubcopy, buffer_ptr(&buffer), buffer_len(&buffer)); - /* it's a SSH v1 key if the public key part is readable */ - pub = key_parse_public_rsa1(&pubcopy, commentp); - buffer_free(&pubcopy); - if (pub == NULL) { - prv = key_parse_private_type(&buffer, KEY_UNSPEC, - passphrase, NULL); - /* use the filename as a comment for PEM */ - if (commentp && prv) - *commentp = xstrdup(filename); - } else { - key_free(pub); - /* key_parse_public_rsa1() has already loaded the comment */ - prv = key_parse_private_type(&buffer, KEY_RSA1, passphrase, - NULL); - } + prv = key_parse_private(&buffer, filename, passphrase, commentp); buffer_free(&buffer); return prv; }