diff options
Diffstat (limited to 'crypto/openssh/authfile.c')
-rw-r--r-- | crypto/openssh/authfile.c | 154 |
1 files changed, 96 insertions, 58 deletions
diff --git a/crypto/openssh/authfile.c b/crypto/openssh/authfile.c index f2aec26..1d7e53c 100644 --- a/crypto/openssh/authfile.c +++ b/crypto/openssh/authfile.c @@ -1,4 +1,4 @@ -/* $OpenBSD: authfile.c,v 1.87 2010/11/29 18:57:04 markus Exp $ */ +/* $OpenBSD: authfile.c,v 1.92 2011/06/14 22:49:18 markus Exp $ */ /* * Author: Tatu Ylonen <ylo@cs.hut.fi> * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland @@ -69,6 +69,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"; @@ -277,6 +279,7 @@ static Key * key_parse_public_rsa1(Buffer *blob, char **commentp) { Key *pub; + Buffer copy; /* Check that it is at least big enough to contain the ID string. */ if (buffer_len(blob) < sizeof(authfile_id_string)) { @@ -293,31 +296,33 @@ key_parse_public_rsa1(Buffer *blob, char **commentp) debug3("Incorrect RSA1 identifier"); return NULL; } - buffer_consume(blob, sizeof(authfile_id_string)); + buffer_init(©); + buffer_append(©, buffer_ptr(blob), buffer_len(blob)); + buffer_consume(©, sizeof(authfile_id_string)); /* Skip cipher type and reserved data. */ - (void) buffer_get_char(blob); /* cipher type */ - (void) buffer_get_int(blob); /* reserved */ + (void) buffer_get_char(©); /* cipher type */ + (void) buffer_get_int(©); /* reserved */ /* Read the public key from the buffer. */ - (void) buffer_get_int(blob); + (void) buffer_get_int(©); pub = key_new(KEY_RSA1); - buffer_get_bignum(blob, pub->rsa->n); - buffer_get_bignum(blob, pub->rsa->e); + buffer_get_bignum(©, pub->rsa->n); + buffer_get_bignum(©, pub->rsa->e); if (commentp) - *commentp = buffer_get_string(blob, NULL); + *commentp = buffer_get_string(©, NULL); /* The encrypted private part is not parsed by this function. */ - buffer_clear(blob); + buffer_free(©); 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) { @@ -325,30 +330,45 @@ key_load_file(int fd, const char *filename, Buffer *blob) 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; } @@ -403,6 +423,7 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) CipherContext ciphercontext; Cipher *cipher; Key *prv = NULL; + Buffer copy; /* Check that it is at least big enough to contain the ID string. */ if (buffer_len(blob) < sizeof(authfile_id_string)) { @@ -419,41 +440,44 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) debug3("Incorrect RSA1 identifier"); return NULL; } - buffer_consume(blob, sizeof(authfile_id_string)); + buffer_init(©); + buffer_append(©, buffer_ptr(blob), buffer_len(blob)); + buffer_consume(©, sizeof(authfile_id_string)); /* Read cipher type. */ - cipher_type = buffer_get_char(blob); - (void) buffer_get_int(blob); /* Reserved data. */ + cipher_type = buffer_get_char(©); + (void) buffer_get_int(©); /* Reserved data. */ /* Read the public key from the buffer. */ - (void) buffer_get_int(blob); + (void) buffer_get_int(©); prv = key_new_private(KEY_RSA1); - buffer_get_bignum(blob, prv->rsa->n); - buffer_get_bignum(blob, prv->rsa->e); + buffer_get_bignum(©, prv->rsa->n); + buffer_get_bignum(©, prv->rsa->e); if (commentp) - *commentp = buffer_get_string(blob, NULL); + *commentp = buffer_get_string(©, NULL); else - (void)buffer_get_string_ptr(blob, NULL); + (void)buffer_get_string_ptr(©, NULL); /* Check that it is a supported cipher. */ cipher = cipher_by_number(cipher_type); if (cipher == NULL) { debug("Unsupported RSA1 cipher %d", cipher_type); + buffer_free(©); goto fail; } /* Initialize space for decrypted data. */ buffer_init(&decrypted); - cp = buffer_append_space(&decrypted, buffer_len(blob)); + cp = buffer_append_space(&decrypted, buffer_len(©)); /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ cipher_set_key_string(&ciphercontext, cipher, passphrase, CIPHER_DECRYPT); cipher_crypt(&ciphercontext, cp, - buffer_ptr(blob), buffer_len(blob)); + buffer_ptr(©), buffer_len(©)); cipher_cleanup(&ciphercontext); memset(&ciphercontext, 0, sizeof(ciphercontext)); - buffer_clear(blob); + buffer_free(©); check1 = buffer_get_char(&decrypted); check2 = buffer_get_char(&decrypted); @@ -606,7 +630,7 @@ key_perm_ok(int fd, const char *filename) error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); error("Permissions 0%3.3o for '%s' are too open.", (u_int)st.st_mode & 0777, filename); - error("It is recommended that your private key files are NOT accessible by others."); + error("It is required that your private key files are NOT accessible by others."); error("This private key will be ignored."); return 0; } @@ -626,6 +650,7 @@ key_parse_private_type(Buffer *blob, int type, const char *passphrase, case KEY_UNSPEC: return key_parse_private_pem(blob, type, passphrase, commentp); default: + error("%s: cannot parse key type %d", __func__, type); break; } return NULL; @@ -670,11 +695,34 @@ key_load_private_type(int type, const char *filename, const char *passphrase, } Key * +key_parse_private(Buffer *buffer, const char *filename, + const char *passphrase, char **commentp) +{ + Key *pub, *prv; + + /* it's a SSH v1 key if the public key part is readable */ + pub = key_parse_public_rsa1(buffer, commentp); + 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); @@ -697,23 +745,7 @@ key_load_private(const char *filename, const char *passphrase, } 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; } @@ -737,13 +769,19 @@ key_try_load_public(Key *k, const char *filename, char **commentp) case '\0': continue; } + /* Abort loading if this looks like a private key */ + if (strncmp(cp, "-----BEGIN", 10) == 0) + break; /* Skip leading whitespace. */ for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) ; if (*cp) { if (key_read(k, &cp) == 1) { - if (commentp) - *commentp=xstrdup(filename); + cp[strcspn(cp, "\r\n")] = '\0'; + if (commentp) { + *commentp = xstrdup(*cp ? + cp : filename); + } fclose(f); return 1; } |