version 1.87, 2010/11/29 18:57:04 |
version 1.88, 2011/05/04 21:15:29 |
|
|
#include "misc.h" |
#include "misc.h" |
#include "atomicio.h" |
#include "atomicio.h" |
|
|
|
#define MAX_KEY_FILE_SIZE (1024 * 1024) |
|
|
/* Version identification string for SSH v1 identity files. */ |
/* Version identification string for SSH v1 identity files. */ |
static const char authfile_id_string[] = |
static const char authfile_id_string[] = |
"SSH PRIVATE KEY FILE FORMAT 1.1\n"; |
"SSH PRIVATE KEY FILE FORMAT 1.1\n"; |
|
|
return pub; |
return pub; |
} |
} |
|
|
/* Load the contents of a key file into a buffer */ |
/* Load a key from a fd into a buffer */ |
static int |
int |
key_load_file(int fd, const char *filename, Buffer *blob) |
key_load_file(int fd, const char *filename, Buffer *blob) |
{ |
{ |
|
u_char buf[1024]; |
size_t len; |
size_t len; |
u_char *cp; |
|
struct stat st; |
struct stat st; |
|
|
if (fstat(fd, &st) < 0) { |
if (fstat(fd, &st) < 0) { |
|
|
filename == NULL ? "" : filename, |
filename == NULL ? "" : filename, |
filename == NULL ? "" : " ", |
filename == NULL ? "" : " ", |
strerror(errno)); |
strerror(errno)); |
close(fd); |
|
return 0; |
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__, |
error("%s: key file %.200s%stoo large", __func__, |
filename == NULL ? "" : filename, |
filename == NULL ? "" : filename, |
filename == NULL ? "" : " "); |
filename == NULL ? "" : " "); |
close(fd); |
|
return 0; |
return 0; |
} |
} |
len = (size_t)st.st_size; /* truncated */ |
|
|
|
buffer_init(blob); |
buffer_init(blob); |
cp = buffer_append_space(blob, len); |
for (;;) { |
|
if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { |
if (atomicio(read, fd, cp, len) != len) { |
if (errno == EPIPE) |
debug("%s: read from key file %.200s%sfailed: %.100s", __func__, |
break; |
filename == NULL ? "" : filename, |
debug("%s: read from key file %.200s%sfailed: %.100s", |
filename == NULL ? "" : " ", |
__func__, filename == NULL ? "" : filename, |
strerror(errno)); |
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); |
buffer_clear(blob); |
close(fd); |
|
return 0; |
return 0; |
} |
} |
|
|
return 1; |
return 1; |
} |
} |
|
|
|
|
} |
} |
|
|
Key * |
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, |
key_load_private(const char *filename, const char *passphrase, |
char **commentp) |
char **commentp) |
{ |
{ |
Key *pub, *prv; |
Key *prv; |
Buffer buffer, pubcopy; |
Buffer buffer; |
int fd; |
int fd; |
|
|
fd = open(filename, O_RDONLY); |
fd = open(filename, O_RDONLY); |
|
|
} |
} |
close(fd); |
close(fd); |
|
|
buffer_init(&pubcopy); |
prv = key_parse_private(&buffer, filename, passphrase, commentp); |
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); |
|
} |
|
buffer_free(&buffer); |
buffer_free(&buffer); |
return prv; |
return prv; |
} |
} |