version 1.85, 2010/10/28 11:22:09 |
version 1.86, 2010/11/21 10:57:07 |
|
|
"SSH PRIVATE KEY FILE FORMAT 1.1\n"; |
"SSH PRIVATE KEY FILE FORMAT 1.1\n"; |
|
|
/* |
/* |
* Saves the authentication (private) key in a file, encrypting it with |
* Serialises the authentication (private) key to a blob, encrypting it with |
* passphrase. The identification of the file (lowest 64 bits of n) will |
* passphrase. The identification of the blob (lowest 64 bits of n) will |
* precede the key to provide identification of the key without needing a |
* precede the key to provide identification of the key without needing a |
* passphrase. |
* passphrase. |
*/ |
*/ |
|
|
static int |
static int |
key_save_private_rsa1(Key *key, const char *filename, const char *passphrase, |
key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, |
const char *comment) |
const char *comment) |
{ |
{ |
Buffer buffer, encrypted; |
Buffer buffer, encrypted; |
u_char buf[100], *cp; |
u_char buf[100], *cp; |
int fd, i, cipher_num; |
int i, cipher_num; |
CipherContext ciphercontext; |
CipherContext ciphercontext; |
Cipher *cipher; |
Cipher *cipher; |
u_int32_t rnd; |
u_int32_t rnd; |
|
|
memset(buf, 0, sizeof(buf)); |
memset(buf, 0, sizeof(buf)); |
buffer_free(&buffer); |
buffer_free(&buffer); |
|
|
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); |
buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted)); |
if (fd < 0) { |
|
error("open %s failed: %s.", filename, strerror(errno)); |
|
buffer_free(&encrypted); |
|
return 0; |
|
} |
|
if (atomicio(vwrite, fd, buffer_ptr(&encrypted), |
|
buffer_len(&encrypted)) != buffer_len(&encrypted)) { |
|
error("write to key file %s failed: %s", filename, |
|
strerror(errno)); |
|
buffer_free(&encrypted); |
|
close(fd); |
|
unlink(filename); |
|
return 0; |
|
} |
|
close(fd); |
|
buffer_free(&encrypted); |
buffer_free(&encrypted); |
|
|
return 1; |
return 1; |
} |
} |
|
|
/* save SSH v2 key in OpenSSL PEM format */ |
/* convert SSH v2 key in OpenSSL PEM format */ |
static int |
static int |
key_save_private_pem(Key *key, const char *filename, const char *_passphrase, |
key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase, |
const char *comment) |
const char *comment) |
{ |
{ |
FILE *fp; |
|
int fd; |
|
int success = 0; |
int success = 0; |
int len = strlen(_passphrase); |
int blen, len = strlen(_passphrase); |
u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; |
u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; |
const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; |
const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; |
|
const u_char *bptr; |
|
BIO *bio; |
|
|
if (len > 0 && len <= 4) { |
if (len > 0 && len <= 4) { |
error("passphrase too short: have %d bytes, need > 4", len); |
error("passphrase too short: have %d bytes, need > 4", len); |
return 0; |
return 0; |
} |
} |
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); |
if ((bio = BIO_new(BIO_s_mem())) == NULL) { |
if (fd < 0) { |
error("%s: BIO_new failed", __func__); |
error("open %s failed: %s.", filename, strerror(errno)); |
|
return 0; |
return 0; |
} |
} |
fp = fdopen(fd, "w"); |
|
if (fp == NULL) { |
|
error("fdopen %s failed: %s.", filename, strerror(errno)); |
|
close(fd); |
|
return 0; |
|
} |
|
switch (key->type) { |
switch (key->type) { |
case KEY_DSA: |
case KEY_DSA: |
success = PEM_write_DSAPrivateKey(fp, key->dsa, |
success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, |
cipher, passphrase, len, NULL, NULL); |
cipher, passphrase, len, NULL, NULL); |
break; |
break; |
case KEY_ECDSA: |
case KEY_ECDSA: |
success = PEM_write_ECPrivateKey(fp, key->ecdsa, |
success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, |
cipher, passphrase, len, NULL, NULL); |
cipher, passphrase, len, NULL, NULL); |
break; |
break; |
case KEY_RSA: |
case KEY_RSA: |
success = PEM_write_RSAPrivateKey(fp, key->rsa, |
success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, |
cipher, passphrase, len, NULL, NULL); |
cipher, passphrase, len, NULL, NULL); |
break; |
break; |
} |
} |
fclose(fp); |
if (success) { |
|
if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) |
|
success = 0; |
|
else |
|
buffer_append(blob, bptr, blen); |
|
} |
|
BIO_free(bio); |
return success; |
return success; |
} |
} |
|
|
int |
/* Save a key blob to a file */ |
key_save_private(Key *key, const char *filename, const char *passphrase, |
static int |
|
key_save_private_blob(Buffer *keybuf, const char *filename) |
|
{ |
|
int fd; |
|
|
|
if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { |
|
error("open %s failed: %s.", filename, strerror(errno)); |
|
return 0; |
|
} |
|
if (atomicio(vwrite, fd, buffer_ptr(keybuf), |
|
buffer_len(keybuf)) != buffer_len(keybuf)) { |
|
error("write to key file %s failed: %s", filename, |
|
strerror(errno)); |
|
close(fd); |
|
unlink(filename); |
|
return 0; |
|
} |
|
close(fd); |
|
return 1; |
|
} |
|
|
|
/* Serialise "key" to buffer "blob" */ |
|
static int |
|
key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, |
const char *comment) |
const char *comment) |
{ |
{ |
switch (key->type) { |
switch (key->type) { |
case KEY_RSA1: |
case KEY_RSA1: |
return key_save_private_rsa1(key, filename, passphrase, |
return key_private_rsa1_to_blob(key, blob, passphrase, comment); |
comment); |
|
case KEY_DSA: |
case KEY_DSA: |
case KEY_ECDSA: |
case KEY_ECDSA: |
case KEY_RSA: |
case KEY_RSA: |
return key_save_private_pem(key, filename, passphrase, |
return key_private_pem_to_blob(key, blob, passphrase, comment); |
comment); |
|
default: |
default: |
break; |
error("%s: cannot save key type %d", __func__, key->type); |
|
return 0; |
} |
} |
error("key_save_private: cannot save key type %d", key->type); |
|
return 0; |
|
} |
} |
|
|
|
int |
|
key_save_private(Key *key, const char *filename, const char *passphrase, |
|
const char *comment) |
|
{ |
|
Buffer keyblob; |
|
int success = 0; |
|
|
|
buffer_init(&keyblob); |
|
if (!key_private_to_blob(key, &keyblob, passphrase, comment)) |
|
goto out; |
|
if (!key_save_private_blob(&keyblob, filename)) |
|
goto out; |
|
success = 1; |
|
out: |
|
buffer_free(&keyblob); |
|
return success; |
|
} |
|
|
/* |
/* |
* Loads the public part of the ssh v1 key file. Returns NULL if an error was |
* Parse the public, unencrypted portion of a RSA1 key. |
* encountered (the file does not exist or is not readable), and the key |
|
* otherwise. |
|
*/ |
*/ |
|
|
static Key * |
static Key * |
key_load_public_rsa1(int fd, const char *filename, char **commentp) |
key_parse_public_rsa1(Buffer *blob, char **commentp) |
{ |
{ |
Buffer buffer; |
|
Key *pub; |
Key *pub; |
struct stat st; |
|
char *cp; |
/* Check that it is at least big enough to contain the ID string. */ |
u_int i; |
if (buffer_len(blob) < sizeof(authfile_id_string)) { |
|
debug3("Truncated RSA1 identifier"); |
|
return NULL; |
|
} |
|
|
|
/* |
|
* Make sure it begins with the id string. Consume the id string |
|
* from the buffer. |
|
*/ |
|
if (memcmp(buffer_ptr(blob), authfile_id_string, |
|
sizeof(authfile_id_string)) != 0) { |
|
debug3("Incorrect RSA1 identifier"); |
|
return NULL; |
|
} |
|
buffer_consume(blob, sizeof(authfile_id_string)); |
|
|
|
/* Skip cipher type and reserved data. */ |
|
(void) buffer_get_char(blob); /* cipher type */ |
|
(void) buffer_get_int(blob); /* reserved */ |
|
|
|
/* Read the public key from the buffer. */ |
|
(void) buffer_get_int(blob); |
|
pub = key_new(KEY_RSA1); |
|
buffer_get_bignum(blob, pub->rsa->n); |
|
buffer_get_bignum(blob, pub->rsa->e); |
|
if (commentp) |
|
*commentp = buffer_get_string(blob, NULL); |
|
/* The encrypted private part is not parsed by this function. */ |
|
buffer_clear(blob); |
|
|
|
return pub; |
|
} |
|
|
|
/* Load the contents of a key file into a buffer */ |
|
static int |
|
key_load_file(int fd, const char *filename, Buffer *blob) |
|
{ |
size_t len; |
size_t len; |
|
u_char *cp; |
|
struct stat st; |
|
|
if (fstat(fd, &st) < 0) { |
if (fstat(fd, &st) < 0) { |
error("fstat for key file %.200s failed: %.100s", |
error("%s: fstat of key file %.200s%sfailed: %.100s", __func__, |
filename, strerror(errno)); |
filename == NULL ? "" : filename, |
return NULL; |
filename == NULL ? "" : " ", |
|
strerror(errno)); |
|
close(fd); |
|
return 0; |
} |
} |
if (st.st_size > 1*1024*1024) { |
if (st.st_size > 1*1024*1024) { |
error("key file %.200s too large", filename); |
error("%s: key file %.200s%stoo large", __func__, |
return NULL; |
filename == NULL ? "" : filename, |
|
filename == NULL ? "" : " "); |
|
close(fd); |
|
return 0; |
} |
} |
len = (size_t)st.st_size; /* truncated */ |
len = (size_t)st.st_size; /* truncated */ |
|
|
buffer_init(&buffer); |
buffer_init(blob); |
cp = buffer_append_space(&buffer, len); |
cp = buffer_append_space(blob, len); |
|
|
if (atomicio(read, fd, cp, len) != len) { |
if (atomicio(read, fd, cp, len) != len) { |
debug("Read from key file %.200s failed: %.100s", filename, |
debug("%s: read from key file %.200s%sfailed: %.100s", __func__, |
|
filename == NULL ? "" : filename, |
|
filename == NULL ? "" : " ", |
strerror(errno)); |
strerror(errno)); |
buffer_free(&buffer); |
buffer_clear(blob); |
return NULL; |
close(fd); |
|
return 0; |
} |
} |
|
return 1; |
|
} |
|
|
/* Check that it is at least big enough to contain the ID string. */ |
/* |
if (len < sizeof(authfile_id_string)) { |
* Loads the public part of the ssh v1 key file. Returns NULL if an error was |
debug3("Not a RSA1 key file %.200s.", filename); |
* encountered (the file does not exist or is not readable), and the key |
|
* otherwise. |
|
*/ |
|
static Key * |
|
key_load_public_rsa1(int fd, const char *filename, char **commentp) |
|
{ |
|
Buffer buffer; |
|
Key *pub; |
|
|
|
buffer_init(&buffer); |
|
if (!key_load_file(fd, filename, &buffer)) { |
buffer_free(&buffer); |
buffer_free(&buffer); |
return NULL; |
return NULL; |
} |
} |
/* |
|
* Make sure it begins with the id string. Consume the id string |
|
* from the buffer. |
|
*/ |
|
for (i = 0; i < sizeof(authfile_id_string); i++) |
|
if (buffer_get_char(&buffer) != authfile_id_string[i]) { |
|
debug3("Not a RSA1 key file %.200s.", filename); |
|
buffer_free(&buffer); |
|
return NULL; |
|
} |
|
/* Skip cipher type and reserved data. */ |
|
(void) buffer_get_char(&buffer); /* cipher type */ |
|
(void) buffer_get_int(&buffer); /* reserved */ |
|
|
|
/* Read the public key from the buffer. */ |
pub = key_parse_public_rsa1(&buffer, commentp); |
(void) buffer_get_int(&buffer); |
if (pub == NULL) |
pub = key_new(KEY_RSA1); |
debug3("Could not load \"%s\" as a RSA1 public key", filename); |
buffer_get_bignum(&buffer, pub->rsa->n); |
|
buffer_get_bignum(&buffer, pub->rsa->e); |
|
if (commentp) |
|
*commentp = buffer_get_string(&buffer, NULL); |
|
/* The encrypted private part is not parsed by this function. */ |
|
|
|
buffer_free(&buffer); |
buffer_free(&buffer); |
return pub; |
return pub; |
} |
} |
|
|
return NULL; |
return NULL; |
} |
} |
|
|
/* |
|
* Loads the private key from the file. Returns 0 if an error is encountered |
|
* (file does not exist or is not readable, or passphrase is bad). This |
|
* initializes the private key. |
|
* Assumes we are called under uid of the owner of the file. |
|
*/ |
|
|
|
static Key * |
static Key * |
key_load_private_rsa1(int fd, const char *filename, const char *passphrase, |
key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) |
char **commentp) |
|
{ |
{ |
u_int i; |
|
int check1, check2, cipher_type; |
int check1, check2, cipher_type; |
size_t len; |
Buffer decrypted; |
Buffer buffer, decrypted; |
|
u_char *cp; |
u_char *cp; |
CipherContext ciphercontext; |
CipherContext ciphercontext; |
Cipher *cipher; |
Cipher *cipher; |
Key *prv = NULL; |
Key *prv = NULL; |
struct stat st; |
|
|
|
if (fstat(fd, &st) < 0) { |
|
error("fstat for key file %.200s failed: %.100s", |
|
filename, strerror(errno)); |
|
close(fd); |
|
return NULL; |
|
} |
|
if (st.st_size > 1*1024*1024) { |
|
error("key file %.200s too large", filename); |
|
close(fd); |
|
return (NULL); |
|
} |
|
len = (size_t)st.st_size; /* truncated */ |
|
|
|
buffer_init(&buffer); |
|
cp = buffer_append_space(&buffer, len); |
|
|
|
if (atomicio(read, fd, cp, len) != len) { |
|
debug("Read from key file %.200s failed: %.100s", filename, |
|
strerror(errno)); |
|
buffer_free(&buffer); |
|
close(fd); |
|
return NULL; |
|
} |
|
|
|
/* Check that it is at least big enough to contain the ID string. */ |
/* Check that it is at least big enough to contain the ID string. */ |
if (len < sizeof(authfile_id_string)) { |
if (buffer_len(blob) < sizeof(authfile_id_string)) { |
debug3("Not a RSA1 key file %.200s.", filename); |
debug3("Truncated RSA1 identifier"); |
buffer_free(&buffer); |
|
close(fd); |
|
return NULL; |
return NULL; |
} |
} |
|
|
/* |
/* |
* Make sure it begins with the id string. Consume the id string |
* Make sure it begins with the id string. Consume the id string |
* from the buffer. |
* from the buffer. |
*/ |
*/ |
for (i = 0; i < sizeof(authfile_id_string); i++) |
if (memcmp(buffer_ptr(blob), authfile_id_string, |
if (buffer_get_char(&buffer) != authfile_id_string[i]) { |
sizeof(authfile_id_string)) != 0) { |
debug3("Not a RSA1 key file %.200s.", filename); |
debug3("Incorrect RSA1 identifier"); |
buffer_free(&buffer); |
return NULL; |
close(fd); |
} |
return NULL; |
buffer_consume(blob, sizeof(authfile_id_string)); |
} |
|
|
|
/* Read cipher type. */ |
/* Read cipher type. */ |
cipher_type = buffer_get_char(&buffer); |
cipher_type = buffer_get_char(blob); |
(void) buffer_get_int(&buffer); /* Reserved data. */ |
(void) buffer_get_int(blob); /* Reserved data. */ |
|
|
/* Read the public key from the buffer. */ |
/* Read the public key from the buffer. */ |
(void) buffer_get_int(&buffer); |
(void) buffer_get_int(blob); |
prv = key_new_private(KEY_RSA1); |
prv = key_new_private(KEY_RSA1); |
|
|
buffer_get_bignum(&buffer, prv->rsa->n); |
buffer_get_bignum(blob, prv->rsa->n); |
buffer_get_bignum(&buffer, prv->rsa->e); |
buffer_get_bignum(blob, prv->rsa->e); |
if (commentp) |
if (commentp) |
*commentp = buffer_get_string(&buffer, NULL); |
*commentp = buffer_get_string(blob, NULL); |
else |
else |
xfree(buffer_get_string(&buffer, NULL)); |
(void)buffer_get_string_ptr(blob, NULL); |
|
|
/* Check that it is a supported cipher. */ |
/* Check that it is a supported cipher. */ |
cipher = cipher_by_number(cipher_type); |
cipher = cipher_by_number(cipher_type); |
if (cipher == NULL) { |
if (cipher == NULL) { |
debug("Unsupported cipher %d used in key file %.200s.", |
debug("Unsupported RSA1 cipher %d", cipher_type); |
cipher_type, filename); |
|
buffer_free(&buffer); |
|
goto fail; |
goto fail; |
} |
} |
/* Initialize space for decrypted data. */ |
/* Initialize space for decrypted data. */ |
buffer_init(&decrypted); |
buffer_init(&decrypted); |
cp = buffer_append_space(&decrypted, buffer_len(&buffer)); |
cp = buffer_append_space(&decrypted, buffer_len(blob)); |
|
|
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ |
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ |
cipher_set_key_string(&ciphercontext, cipher, passphrase, |
cipher_set_key_string(&ciphercontext, cipher, passphrase, |
CIPHER_DECRYPT); |
CIPHER_DECRYPT); |
cipher_crypt(&ciphercontext, cp, |
cipher_crypt(&ciphercontext, cp, |
buffer_ptr(&buffer), buffer_len(&buffer)); |
buffer_ptr(blob), buffer_len(blob)); |
cipher_cleanup(&ciphercontext); |
cipher_cleanup(&ciphercontext); |
memset(&ciphercontext, 0, sizeof(ciphercontext)); |
memset(&ciphercontext, 0, sizeof(ciphercontext)); |
buffer_free(&buffer); |
buffer_clear(blob); |
|
|
check1 = buffer_get_char(&decrypted); |
check1 = buffer_get_char(&decrypted); |
check2 = buffer_get_char(&decrypted); |
check2 = buffer_get_char(&decrypted); |
if (check1 != buffer_get_char(&decrypted) || |
if (check1 != buffer_get_char(&decrypted) || |
check2 != buffer_get_char(&decrypted)) { |
check2 != buffer_get_char(&decrypted)) { |
if (strcmp(passphrase, "") != 0) |
if (strcmp(passphrase, "") != 0) |
debug("Bad passphrase supplied for key file %.200s.", |
debug("Bad passphrase supplied for RSA1 key"); |
filename); |
|
/* Bad passphrase. */ |
/* Bad passphrase. */ |
buffer_free(&decrypted); |
buffer_free(&decrypted); |
goto fail; |
goto fail; |
|
|
|
|
/* enable blinding */ |
/* enable blinding */ |
if (RSA_blinding_on(prv->rsa, NULL) != 1) { |
if (RSA_blinding_on(prv->rsa, NULL) != 1) { |
error("key_load_private_rsa1: RSA_blinding_on failed"); |
error("%s: RSA_blinding_on failed", __func__); |
goto fail; |
goto fail; |
} |
} |
close(fd); |
|
return prv; |
return prv; |
|
|
fail: |
fail: |
if (commentp) |
if (commentp) |
xfree(*commentp); |
xfree(*commentp); |
close(fd); |
|
key_free(prv); |
key_free(prv); |
return NULL; |
return NULL; |
} |
} |
|
|
Key * |
static Key * |
key_load_private_pem(int fd, int type, const char *passphrase, |
key_parse_private_pem(Buffer *blob, int type, const char *passphrase, |
char **commentp) |
char **commentp) |
{ |
{ |
FILE *fp; |
|
EVP_PKEY *pk = NULL; |
EVP_PKEY *pk = NULL; |
Key *prv = NULL; |
Key *prv = NULL; |
char *name = "<no key>"; |
char *name = "<no key>"; |
|
BIO *bio; |
|
|
fp = fdopen(fd, "r"); |
if ((bio = BIO_new_mem_buf(buffer_ptr(blob), |
if (fp == NULL) { |
buffer_len(blob))) == NULL) { |
error("fdopen failed: %s", strerror(errno)); |
error("%s: BIO_new_mem_buf failed", __func__); |
close(fd); |
|
return NULL; |
return NULL; |
} |
} |
pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase); |
|
|
pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase); |
|
BIO_free(bio); |
if (pk == NULL) { |
if (pk == NULL) { |
debug("PEM_read_PrivateKey failed"); |
debug("%s: PEM_read_PrivateKey failed", __func__); |
(void)ERR_get_error(); |
(void)ERR_get_error(); |
} else if (pk->type == EVP_PKEY_RSA && |
} else if (pk->type == EVP_PKEY_RSA && |
(type == KEY_UNSPEC||type==KEY_RSA)) { |
(type == KEY_UNSPEC||type==KEY_RSA)) { |
|
|
RSA_print_fp(stderr, prv->rsa, 8); |
RSA_print_fp(stderr, prv->rsa, 8); |
#endif |
#endif |
if (RSA_blinding_on(prv->rsa, NULL) != 1) { |
if (RSA_blinding_on(prv->rsa, NULL) != 1) { |
error("key_load_private_pem: RSA_blinding_on failed"); |
error("%s: RSA_blinding_on failed", __func__); |
key_free(prv); |
key_free(prv); |
prv = NULL; |
prv = NULL; |
} |
} |
|
|
key_dump_ec_key(prv->ecdsa); |
key_dump_ec_key(prv->ecdsa); |
#endif |
#endif |
} else { |
} else { |
error("PEM_read_PrivateKey: mismatch or " |
error("%s: PEM_read_PrivateKey: mismatch or " |
"unknown EVP_PKEY save_type %d", pk->save_type); |
"unknown EVP_PKEY save_type %d", __func__, pk->save_type); |
} |
} |
fclose(fp); |
|
if (pk != NULL) |
if (pk != NULL) |
EVP_PKEY_free(pk); |
EVP_PKEY_free(pk); |
if (prv != NULL && commentp) |
if (prv != NULL && commentp) |
|
|
return prv; |
return prv; |
} |
} |
|
|
|
Key * |
|
key_load_private_pem(int fd, int type, const char *passphrase, |
|
char **commentp) |
|
{ |
|
Buffer buffer; |
|
Key *prv; |
|
|
|
buffer_init(&buffer); |
|
if (!key_load_file(fd, NULL, &buffer)) { |
|
buffer_free(&buffer); |
|
return NULL; |
|
} |
|
prv = key_parse_private_pem(&buffer, type, passphrase, commentp); |
|
buffer_free(&buffer); |
|
return prv; |
|
} |
|
|
int |
int |
key_perm_ok(int fd, const char *filename) |
key_perm_ok(int fd, const char *filename) |
{ |
{ |
|
|
return 1; |
return 1; |
} |
} |
|
|
|
static Key * |
|
key_parse_private_type(Buffer *blob, int type, const char *passphrase, |
|
char **commentp) |
|
{ |
|
switch (type) { |
|
case KEY_RSA1: |
|
return key_parse_private_rsa1(blob, passphrase, commentp); |
|
case KEY_DSA: |
|
case KEY_ECDSA: |
|
case KEY_RSA: |
|
case KEY_UNSPEC: |
|
return key_parse_private_pem(blob, type, passphrase, commentp); |
|
default: |
|
break; |
|
} |
|
return NULL; |
|
} |
|
|
Key * |
Key * |
key_load_private_type(int type, const char *filename, const char *passphrase, |
key_load_private_type(int type, const char *filename, const char *passphrase, |
char **commentp, int *perm_ok) |
char **commentp, int *perm_ok) |
{ |
{ |
int fd; |
int fd; |
|
Key *ret; |
|
Buffer buffer; |
|
|
fd = open(filename, O_RDONLY); |
fd = open(filename, O_RDONLY); |
if (fd < 0) { |
if (fd < 0) { |
|
|
} |
} |
if (perm_ok != NULL) |
if (perm_ok != NULL) |
*perm_ok = 1; |
*perm_ok = 1; |
switch (type) { |
|
case KEY_RSA1: |
buffer_init(&buffer); |
return key_load_private_rsa1(fd, filename, passphrase, |
if (!key_load_file(fd, filename, &buffer)) { |
commentp); |
buffer_free(&buffer); |
/* closes fd */ |
|
case KEY_DSA: |
|
case KEY_ECDSA: |
|
case KEY_RSA: |
|
case KEY_UNSPEC: |
|
return key_load_private_pem(fd, type, passphrase, commentp); |
|
/* closes fd */ |
|
default: |
|
close(fd); |
close(fd); |
break; |
return NULL; |
} |
} |
return NULL; |
close(fd); |
|
ret = key_parse_private_type(&buffer, type, passphrase, commentp); |
|
buffer_free(&buffer); |
|
return ret; |
} |
} |
|
|
Key * |
Key * |
|
|
char **commentp) |
char **commentp) |
{ |
{ |
Key *pub, *prv; |
Key *pub, *prv; |
|
Buffer buffer, pubcopy; |
int fd; |
int fd; |
|
|
fd = open(filename, O_RDONLY); |
fd = open(filename, O_RDONLY); |
|
|
close(fd); |
close(fd); |
return NULL; |
return NULL; |
} |
} |
pub = key_load_public_rsa1(fd, filename, commentp); |
|
lseek(fd, (off_t) 0, SEEK_SET); /* rewind */ |
buffer_init(&buffer); |
|
if (!key_load_file(fd, filename, &buffer)) { |
|
buffer_free(&buffer); |
|
close(fd); |
|
return NULL; |
|
} |
|
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) { |
if (pub == NULL) { |
/* closes fd */ |
prv = key_parse_private_type(&buffer, KEY_UNSPEC, |
prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL); |
passphrase, NULL); |
/* use the filename as a comment for PEM */ |
/* use the filename as a comment for PEM */ |
if (commentp && prv) |
if (commentp && prv) |
*commentp = xstrdup(filename); |
*commentp = xstrdup(filename); |
} else { |
} else { |
/* it's a SSH v1 key if the public key part is readable */ |
|
key_free(pub); |
key_free(pub); |
/* closes fd */ |
prv = key_parse_private_type(&buffer, KEY_RSA1, passphrase, |
prv = key_load_private_rsa1(fd, filename, passphrase, NULL); |
commentp); |
} |
} |
|
buffer_free(&buffer); |
return prv; |
return prv; |
} |
} |
|
|