Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkmscode <kmscode@users.noreply.github.com>2021-07-03 16:51:10 +0300
committerkmscode <kmscode@users.noreply.github.com>2021-07-03 16:51:10 +0300
commit1b6701c760c21673e37013cfe3f065944489283e (patch)
treed69bdba7824a4ea1de1c5fb5798c183eb70f5323 /IMPORT.C
parent445a934bb702450f6bb63824eb2b387511271749 (diff)
PuTTY 0.75 from upstream
Diffstat (limited to 'IMPORT.C')
-rw-r--r--IMPORT.C732
1 files changed, 370 insertions, 362 deletions
diff --git a/IMPORT.C b/IMPORT.C
index c4410782..553fa750 100644
--- a/IMPORT.C
+++ b/IMPORT.C
@@ -13,12 +13,12 @@
#include "mpint.h"
#include "misc.h"
-static bool openssh_pem_encrypted(const Filename *file);
-static bool openssh_new_encrypted(const Filename *file);
+static bool openssh_pem_encrypted(BinarySource *src);
+static bool openssh_new_encrypted(BinarySource *src);
static ssh2_userkey *openssh_pem_read(
- const Filename *file, const char *passphrase, const char **errmsg_p);
+ BinarySource *src, const char *passphrase, const char **errmsg_p);
static ssh2_userkey *openssh_new_read(
- const Filename *file, const char *passphrase, const char **errmsg_p);
+ BinarySource *src, const char *passphrase, const char **errmsg_p);
static bool openssh_auto_write(
const Filename *file, ssh2_userkey *key, const char *passphrase);
static bool openssh_pem_write(
@@ -26,9 +26,9 @@ static bool openssh_pem_write(
static bool openssh_new_write(
const Filename *file, ssh2_userkey *key, const char *passphrase);
-static bool sshcom_encrypted(const Filename *file, char **comment);
+static bool sshcom_encrypted(BinarySource *src, char **comment);
static ssh2_userkey *sshcom_read(
- const Filename *file, const char *passphrase, const char **errmsg_p);
+ BinarySource *src, const char *passphrase, const char **errmsg_p);
static bool sshcom_write(
const Filename *file, ssh2_userkey *key, const char *passphrase);
@@ -38,11 +38,11 @@ static bool sshcom_write(
bool import_possible(int type)
{
if (type == SSH_KEYTYPE_OPENSSH_PEM)
- return true;
+ return true;
if (type == SSH_KEYTYPE_OPENSSH_NEW)
- return true;
+ return true;
if (type == SSH_KEYTYPE_SSHCOM)
- return true;
+ return true;
return false;
}
@@ -59,50 +59,97 @@ int import_target_type(int type)
return SSH_KEYTYPE_SSH2;
}
+static inline char *bsgetline(BinarySource *src)
+{
+ ptrlen line = get_chomped_line(src);
+ if (get_err(src))
+ return NULL;
+ return mkstr(line);
+}
+
/*
* Determine whether a foreign key is encrypted.
*/
-bool import_encrypted(const Filename *filename, int type, char **comment)
+bool import_encrypted_s(const Filename *filename, BinarySource *src,
+ int type, char **comment)
{
if (type == SSH_KEYTYPE_OPENSSH_PEM) {
- /* OpenSSH PEM format doesn't contain a key comment at all */
- *comment = dupstr(filename_to_str(filename));
- return openssh_pem_encrypted(filename);
+ /* OpenSSH PEM format doesn't contain a key comment at all */
+ *comment = dupstr(filename_to_str(filename));
+ return openssh_pem_encrypted(src);
} else if (type == SSH_KEYTYPE_OPENSSH_NEW) {
- /* OpenSSH new format does, but it's inside the encrypted
+ /* OpenSSH new format does, but it's inside the encrypted
* section for some reason */
- *comment = dupstr(filename_to_str(filename));
- return openssh_new_encrypted(filename);
+ *comment = dupstr(filename_to_str(filename));
+ return openssh_new_encrypted(src);
} else if (type == SSH_KEYTYPE_SSHCOM) {
- return sshcom_encrypted(filename, comment);
+ return sshcom_encrypted(src, comment);
}
return false;
}
+bool import_encrypted(const Filename *filename, int type, char **comment)
+{
+ LoadedFile *lf = lf_load_keyfile(filename, NULL);
+ if (!lf)
+ return false; /* couldn't even open the file */
+
+ bool toret = import_encrypted_s(filename, BinarySource_UPCAST(lf),
+ type, comment);
+ lf_free(lf);
+ return toret;
+}
+
/*
* Import an SSH-1 key.
*/
-int import_ssh1(const Filename *filename, int type,
- RSAKey *key, char *passphrase, const char **errmsg_p)
+int import_ssh1_s(BinarySource *src, int type,
+ RSAKey *key, char *passphrase, const char **errmsg_p)
{
return 0;
}
+int import_ssh1(const Filename *filename, int type,
+ RSAKey *key, char *passphrase, const char **errmsg_p)
+{
+ LoadedFile *lf = lf_load_keyfile(filename, errmsg_p);
+ if (!lf)
+ return false;
+
+ int toret = import_ssh1_s(BinarySource_UPCAST(lf),
+ type, key, passphrase, errmsg_p);
+ lf_free(lf);
+ return toret;
+}
+
/*
* Import an SSH-2 key.
*/
-ssh2_userkey *import_ssh2(const Filename *filename, int type,
- char *passphrase, const char **errmsg_p)
+ssh2_userkey *import_ssh2_s(BinarySource *src, int type,
+ char *passphrase, const char **errmsg_p)
{
if (type == SSH_KEYTYPE_OPENSSH_PEM)
- return openssh_pem_read(filename, passphrase, errmsg_p);
+ return openssh_pem_read(src, passphrase, errmsg_p);
else if (type == SSH_KEYTYPE_OPENSSH_NEW)
- return openssh_new_read(filename, passphrase, errmsg_p);
+ return openssh_new_read(src, passphrase, errmsg_p);
if (type == SSH_KEYTYPE_SSHCOM)
- return sshcom_read(filename, passphrase, errmsg_p);
+ return sshcom_read(src, passphrase, errmsg_p);
return NULL;
}
+ssh2_userkey *import_ssh2(const Filename *filename, int type,
+ char *passphrase, const char **errmsg_p)
+{
+ LoadedFile *lf = lf_load_keyfile(filename, errmsg_p);
+ if (!lf)
+ return false;
+
+ ssh2_userkey *toret = import_ssh2_s(BinarySource_UPCAST(lf),
+ type, passphrase, errmsg_p);
+ lf_free(lf);
+ return toret;
+}
+
/*
* Export an SSH-1 key.
*/
@@ -119,11 +166,11 @@ bool export_ssh2(const Filename *filename, int type,
ssh2_userkey *key, char *passphrase)
{
if (type == SSH_KEYTYPE_OPENSSH_AUTO)
- return openssh_auto_write(filename, key, passphrase);
+ return openssh_auto_write(filename, key, passphrase);
if (type == SSH_KEYTYPE_OPENSSH_NEW)
- return openssh_new_write(filename, key, passphrase);
+ return openssh_new_write(filename, key, passphrase);
if (type == SSH_KEYTYPE_SSHCOM)
- return sshcom_write(filename, key, passphrase);
+ return sshcom_write(filename, key, passphrase);
return false;
}
@@ -135,7 +182,7 @@ void strip_crlf(char *str)
char *p = str + strlen(str);
while (p > str && (p[-1] == '\r' || p[-1] == '\n'))
- *--p = '\0';
+ *--p = '\0';
}
/* ----------------------------------------------------------------------
@@ -150,9 +197,9 @@ void strip_crlf(char *str)
/*
* Read an ASN.1/BER identifier and length pair.
- *
+ *
* Flags are a combination of the #defines listed below.
- *
+ *
* Returns -1 if unsuccessful; otherwise returns the number of
* bytes used out of the source data.
*/
@@ -177,42 +224,42 @@ static void BinarySink_put_ber_id_len(BinarySink *bs,
int id, int length, int flags)
{
if (id <= 30) {
- /*
- * Identifier is one byte.
- */
- put_byte(bs, id | flags);
+ /*
+ * Identifier is one byte.
+ */
+ put_byte(bs, id | flags);
} else {
- int n;
- /*
- * Identifier is multiple bytes: the first byte is 11111
- * plus the flags, and subsequent bytes encode the value of
- * the identifier, 7 bits at a time, with the top bit of
- * each byte 1 except the last one which is 0.
- */
- put_byte(bs, 0x1F | flags);
- for (n = 1; (id >> (7*n)) > 0; n++)
- continue; /* count the bytes */
- while (n--)
- put_byte(bs, (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F));
+ int n;
+ /*
+ * Identifier is multiple bytes: the first byte is 11111
+ * plus the flags, and subsequent bytes encode the value of
+ * the identifier, 7 bits at a time, with the top bit of
+ * each byte 1 except the last one which is 0.
+ */
+ put_byte(bs, 0x1F | flags);
+ for (n = 1; (id >> (7*n)) > 0; n++)
+ continue; /* count the bytes */
+ while (n--)
+ put_byte(bs, (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F));
}
if (length < 128) {
- /*
- * Length is one byte.
- */
+ /*
+ * Length is one byte.
+ */
put_byte(bs, length);
} else {
- int n;
- /*
- * Length is multiple bytes. The first is 0x80 plus the
- * number of subsequent bytes, and the subsequent bytes
- * encode the actual length.
- */
- for (n = 1; (length >> (8*n)) > 0; n++)
- continue; /* count the bytes */
- put_byte(bs, 0x80 | n);
- while (n--)
- put_byte(bs, (length >> (8*n)) & 0xFF);
+ int n;
+ /*
+ * Length is multiple bytes. The first is 0x80 plus the
+ * number of subsequent bytes, and the subsequent bytes
+ * encode the actual length.
+ */
+ for (n = 1; (length >> (8*n)) > 0; n++)
+ continue; /* count the bytes */
+ put_byte(bs, 0x80 | n);
+ while (n--)
+ put_byte(bs, (length >> (8*n)) & 0xFF);
}
}
@@ -236,23 +283,23 @@ static ber_item BinarySource_get_ber(BinarySource *src)
if ((leadbyte & 0x1F) == 0x1F) {
unsigned char idbyte;
- toret.id = 0;
+ toret.id = 0;
do {
idbyte = get_byte(src);
- toret.id = (toret.id << 7) | (idbyte & 0x7F);
+ toret.id = (toret.id << 7) | (idbyte & 0x7F);
} while (idbyte & 0x80);
} else {
- toret.id = leadbyte & 0x1F;
+ toret.id = leadbyte & 0x1F;
}
lenbyte = get_byte(src);
if (lenbyte & 0x80) {
int nbytes = lenbyte & 0x7F;
length = 0;
- while (nbytes-- > 0)
- length = (length << 8) | get_byte(src);
+ while (nbytes-- > 0)
+ length = (length << 8) | get_byte(src);
} else {
- length = lenbyte;
+ length = lenbyte;
}
toret.data = get_data(src, length);
@@ -300,11 +347,10 @@ void BinarySink_put_mp_ssh2_from_string(BinarySink *bs, ptrlen str)
#define put_mp_ssh2_from_string(bs, str) \
BinarySink_put_mp_ssh2_from_string(BinarySink_UPCAST(bs), str)
-static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename,
+static struct openssh_pem_key *load_openssh_pem_key(BinarySource *src,
const char **errmsg_p)
{
struct openssh_pem_key *ret;
- FILE *fp = NULL;
char *line = NULL;
const char *errmsg;
char *p;
@@ -315,21 +361,14 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename,
ret = snew(struct openssh_pem_key);
ret->keyblob = strbuf_new_nm();
- fp = f_open(filename, "r", false);
- if (!fp) {
- errmsg = "unable to open key file";
- goto error;
- }
-
- if (!(line = fgetline(fp))) {
- errmsg = "unexpected end of file";
- goto error;
+ if (!(line = bsgetline(src))) {
+ errmsg = "unexpected end of file";
+ goto error;
}
- strip_crlf(line);
if (!strstartswith(line, "-----BEGIN ") ||
!strendswith(line, "PRIVATE KEY-----")) {
- errmsg = "file does not begin with OpenSSH key header";
- goto error;
+ errmsg = "file does not begin with OpenSSH key header";
+ goto error;
}
/*
* Parse the BEGIN line. For old-format keys, this tells us the
@@ -338,17 +377,17 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename,
* base64.
*/
if (!strcmp(line, "-----BEGIN RSA PRIVATE KEY-----")) {
- ret->keytype = OP_RSA;
+ ret->keytype = OP_RSA;
} else if (!strcmp(line, "-----BEGIN DSA PRIVATE KEY-----")) {
- ret->keytype = OP_DSA;
+ ret->keytype = OP_DSA;
} else if (!strcmp(line, "-----BEGIN EC PRIVATE KEY-----")) {
ret->keytype = OP_ECDSA;
} else if (!strcmp(line, "-----BEGIN OPENSSH PRIVATE KEY-----")) {
- errmsg = "this is a new-style OpenSSH key";
- goto error;
+ errmsg = "this is a new-style OpenSSH key";
+ goto error;
} else {
- errmsg = "unrecognised key type";
- goto error;
+ errmsg = "unrecognised key type";
+ goto error;
}
smemclr(line, strlen(line));
sfree(line);
@@ -359,65 +398,64 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename,
headers_done = false;
while (1) {
- if (!(line = fgetline(fp))) {
- errmsg = "unexpected end of file";
- goto error;
- }
- strip_crlf(line);
- if (strstartswith(line, "-----END ") &&
- strendswith(line, "PRIVATE KEY-----")) {
+ if (!(line = bsgetline(src))) {
+ errmsg = "unexpected end of file";
+ goto error;
+ }
+ if (strstartswith(line, "-----END ") &&
+ strendswith(line, "PRIVATE KEY-----")) {
sfree(line);
line = NULL;
- break; /* done */
+ break; /* done */
}
- if ((p = strchr(line, ':')) != NULL) {
- if (headers_done) {
- errmsg = "header found in body of key data";
- goto error;
- }
- *p++ = '\0';
- while (*p && isspace((unsigned char)*p)) p++;
- if (!strcmp(line, "Proc-Type")) {
- if (p[0] != '4' || p[1] != ',') {
- errmsg = "Proc-Type is not 4 (only 4 is supported)";
- goto error;
- }
- p += 2;
- if (!strcmp(p, "ENCRYPTED"))
- ret->encrypted = true;
- } else if (!strcmp(line, "DEK-Info")) {
- int i, ivlen;
-
- if (!strncmp(p, "DES-EDE3-CBC,", 13)) {
- ret->encryption = OP_E_3DES;
- ivlen = 8;
- } else if (!strncmp(p, "AES-128-CBC,", 12)) {
- ret->encryption = OP_E_AES;
- ivlen = 16;
- } else {
- errmsg = "unsupported cipher";
- goto error;
- }
- p = strchr(p, ',') + 1;/* always non-NULL, by above checks */
- for (i = 0; i < ivlen; i++) {
+ if ((p = strchr(line, ':')) != NULL) {
+ if (headers_done) {
+ errmsg = "header found in body of key data";
+ goto error;
+ }
+ *p++ = '\0';
+ while (*p && isspace((unsigned char)*p)) p++;
+ if (!strcmp(line, "Proc-Type")) {
+ if (p[0] != '4' || p[1] != ',') {
+ errmsg = "Proc-Type is not 4 (only 4 is supported)";
+ goto error;
+ }
+ p += 2;
+ if (!strcmp(p, "ENCRYPTED"))
+ ret->encrypted = true;
+ } else if (!strcmp(line, "DEK-Info")) {
+ int i, ivlen;
+
+ if (!strncmp(p, "DES-EDE3-CBC,", 13)) {
+ ret->encryption = OP_E_3DES;
+ ivlen = 8;
+ } else if (!strncmp(p, "AES-128-CBC,", 12)) {
+ ret->encryption = OP_E_AES;
+ ivlen = 16;
+ } else {
+ errmsg = "unsupported cipher";
+ goto error;
+ }
+ p = strchr(p, ',') + 1;/* always non-NULL, by above checks */
+ for (i = 0; i < ivlen; i++) {
unsigned j;
- if (1 != sscanf(p, "%2x", &j)) {
- errmsg = "expected more iv data in DEK-Info";
- goto error;
- }
- ret->iv[i] = j;
- p += 2;
- }
- if (*p) {
- errmsg = "more iv data than expected in DEK-Info";
- goto error;
- }
- }
- } else {
- headers_done = true;
-
- p = line;
- while (isbase64(*p)) {
+ if (1 != sscanf(p, "%2x", &j)) {
+ errmsg = "expected more iv data in DEK-Info";
+ goto error;
+ }
+ ret->iv[i] = j;
+ p += 2;
+ }
+ if (*p) {
+ errmsg = "more iv data than expected in DEK-Info";
+ goto error;
+ }
+ }
+ } else {
+ headers_done = true;
+
+ p = line;
+ while (isbase64(*p)) {
base64_bit[base64_chars++] = *p;
if (base64_chars == 4) {
unsigned char out[3];
@@ -437,20 +475,17 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename,
smemclr(out, sizeof(out));
}
- p++;
- }
- }
- smemclr(line, strlen(line));
- sfree(line);
- line = NULL;
+ p++;
+ }
+ }
+ smemclr(line, strlen(line));
+ sfree(line);
+ line = NULL;
}
- fclose(fp);
- fp = NULL;
-
if (!ret->keyblob || ret->keyblob->len == 0) {
- errmsg = "key body not present";
- goto error;
+ errmsg = "key body not present";
+ goto error;
}
if (ret->encrypted && ret->keyblob->len % 8 != 0) {
@@ -465,29 +500,28 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename,
error:
if (line) {
- smemclr(line, strlen(line));
- sfree(line);
- line = NULL;
+ smemclr(line, strlen(line));
+ sfree(line);
+ line = NULL;
}
smemclr(base64_bit, sizeof(base64_bit));
if (ret) {
- if (ret->keyblob)
+ if (ret->keyblob)
strbuf_free(ret->keyblob);
smemclr(ret, sizeof(*ret));
- sfree(ret);
+ sfree(ret);
}
if (errmsg_p) *errmsg_p = errmsg;
- if (fp) fclose(fp);
return NULL;
}
-static bool openssh_pem_encrypted(const Filename *filename)
+static bool openssh_pem_encrypted(BinarySource *src)
{
- struct openssh_pem_key *key = load_openssh_pem_key(filename, NULL);
+ struct openssh_pem_key *key = load_openssh_pem_key(src, NULL);
bool ret;
if (!key)
- return false;
+ return false;
ret = key->encrypted;
strbuf_free(key->keyblob);
smemclr(key, sizeof(*key));
@@ -516,9 +550,9 @@ static void openssh_pem_derivekey(
h = ssh_hash_new(&ssh_md5);
put_datapl(h, passphrase);
put_data(h, iv, 8);
- ssh_hash_final(h, keybuf);
+ ssh_hash_digest(h, keybuf);
- h = ssh_hash_new(&ssh_md5);
+ ssh_hash_reset(h);
put_data(h, keybuf, 16);
put_datapl(h, passphrase);
put_data(h, iv, 8);
@@ -526,9 +560,9 @@ static void openssh_pem_derivekey(
}
static ssh2_userkey *openssh_pem_read(
- const Filename *filename, const char *passphrase, const char **errmsg_p)
+ BinarySource *filesrc, const char *passphrase, const char **errmsg_p)
{
- struct openssh_pem_key *key = load_openssh_pem_key(filename, errmsg_p);
+ struct openssh_pem_key *key = load_openssh_pem_key(filesrc, errmsg_p);
ssh2_userkey *retkey;
const ssh_keyalg *alg;
BinarySource src[1];
@@ -538,8 +572,10 @@ static ssh2_userkey *openssh_pem_read(
strbuf *blob = strbuf_new_nm();
int privptr = 0, publen;
- if (!key)
- return NULL;
+ if (!key) {
+ strbuf_free(blob);
+ return NULL;
+ }
if (key->encrypted) {
unsigned char keybuf[32];
@@ -583,7 +619,7 @@ static ssh2_userkey *openssh_pem_read(
* SEQUENCE, but beneath is an INTEGER 1, OCTET STRING priv
* EXPLICIT [0] OID curve, EXPLICIT [1] BIT STRING pubPoint
*/
-
+
BinarySource_BARE_INIT(src, key->keyblob->u, key->keyblob->len);
{
@@ -607,7 +643,7 @@ static ssh2_userkey *openssh_pem_read(
else if (key->keytype == OP_DSA)
num_integers = 6;
else
- num_integers = 0; /* placate compiler warnings */
+ num_integers = 0; /* placate compiler warnings */
if (key->keytype == OP_ECDSA) {
@@ -752,8 +788,8 @@ static ssh2_userkey *openssh_pem_read(
} else {
unreachable("Bad key type from load_openssh_pem_key");
- errmsg = "Bad key type from load_openssh_pem_key";
- goto error;
+ errmsg = "Bad key type from load_openssh_pem_key";
+ goto error;
}
/*
@@ -984,7 +1020,7 @@ static bool openssh_pem_write(
* old-style 3DES.
*/
if (passphrase) {
- unsigned char keybuf[32];
+ unsigned char keybuf[32];
int origlen, outlen, pad;
/*
@@ -1009,17 +1045,17 @@ static bool openssh_pem_write(
pad = outlen - origlen;
put_padding(outblob, pad, pad);
- /*
- * Invent an iv, and derive the encryption key.
- */
+ /*
+ * Invent an iv, and derive the encryption key.
+ */
random_read(iv, 8);
openssh_pem_derivekey(ptrlen_from_asciz(passphrase), iv, keybuf);
- /*
- * Now encrypt the key blob.
- */
- des3_encrypt_pubkey_ossh(keybuf, iv,
+ /*
+ * Now encrypt the key blob.
+ */
+ des3_encrypt_pubkey_ossh(keybuf, iv,
outblob->u, outlen);
smemclr(keybuf, sizeof(keybuf));
@@ -1031,13 +1067,13 @@ static bool openssh_pem_write(
*/
fp = f_open(filename, "wb", true); /* ensure Unix line endings */
if (!fp)
- goto error;
+ goto error;
fputs(header, fp);
if (passphrase) {
- fprintf(fp, "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,");
- for (i = 0; i < 8; i++)
- fprintf(fp, "%02X", iv[i]);
- fprintf(fp, "\n\n");
+ fprintf(fp, "Proc-Type: 4,ENCRYPTED\nDEK-Info: DES-EDE3-CBC,");
+ for (i = 0; i < 8; i++)
+ fprintf(fp, "%02X", iv[i]);
+ fprintf(fp, "\n\n");
}
base64_encode(fp, outblob->u, outblob->len, 64);
fputs(footer, fp);
@@ -1087,11 +1123,10 @@ struct openssh_new_key {
strbuf *keyblob;
};
-static struct openssh_new_key *load_openssh_new_key(const Filename *filename,
+static struct openssh_new_key *load_openssh_new_key(BinarySource *filesrc,
const char **errmsg_p)
{
struct openssh_new_key *ret;
- FILE *fp = NULL;
char *line = NULL;
const char *errmsg;
char *p;
@@ -1104,35 +1139,27 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename,
ret = snew(struct openssh_new_key);
ret->keyblob = strbuf_new_nm();
- fp = f_open(filename, "r", false);
- if (!fp) {
- errmsg = "unable to open key file";
- goto error;
- }
-
- if (!(line = fgetline(fp))) {
- errmsg = "unexpected end of file";
- goto error;
+ if (!(line = bsgetline(filesrc))) {
+ errmsg = "unexpected end of file";
+ goto error;
}
- strip_crlf(line);
if (0 != strcmp(line, "-----BEGIN OPENSSH PRIVATE KEY-----")) {
- errmsg = "file does not begin with OpenSSH new-style key header";
- goto error;
+ errmsg = "file does not begin with OpenSSH new-style key header";
+ goto error;
}
smemclr(line, strlen(line));
sfree(line);
line = NULL;
while (1) {
- if (!(line = fgetline(fp))) {
- errmsg = "unexpected end of file";
- goto error;
- }
- strip_crlf(line);
- if (0 == strcmp(line, "-----END OPENSSH PRIVATE KEY-----")) {
+ if (!(line = bsgetline(filesrc))) {
+ errmsg = "unexpected end of file";
+ goto error;
+ }
+ if (0 == strcmp(line, "-----END OPENSSH PRIVATE KEY-----")) {
sfree(line);
line = NULL;
- break; /* done */
+ break; /* done */
}
p = line;
@@ -1158,17 +1185,14 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename,
p++;
}
- smemclr(line, strlen(line));
- sfree(line);
- line = NULL;
+ smemclr(line, strlen(line));
+ sfree(line);
+ line = NULL;
}
- fclose(fp);
- fp = NULL;
-
- if (ret->keyblob->len == 0 || !ret->keyblob) {
- errmsg = "key body not present";
- goto error;
+ if (ret->keyblob->len == 0) {
+ errmsg = "key body not present";
+ goto error;
}
BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(ret->keyblob));
@@ -1213,20 +1237,19 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename,
goto error;
}
break;
- case ON_K_BCRYPT:
- {
- BinarySource opts[1];
+ case ON_K_BCRYPT: {
+ BinarySource opts[1];
- BinarySource_BARE_INIT_PL(opts, str);
- ret->kdfopts.bcrypt.salt = get_string(opts);
- ret->kdfopts.bcrypt.rounds = get_uint32(opts);
+ BinarySource_BARE_INIT_PL(opts, str);
+ ret->kdfopts.bcrypt.salt = get_string(opts);
+ ret->kdfopts.bcrypt.rounds = get_uint32(opts);
- if (get_err(opts)) {
- errmsg = "failed to parse bcrypt options string";
- goto error;
- }
+ if (get_err(opts)) {
+ errmsg = "failed to parse bcrypt options string";
+ goto error;
}
break;
+ }
}
/*
@@ -1273,28 +1296,27 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename,
error:
if (line) {
- smemclr(line, strlen(line));
- sfree(line);
- line = NULL;
+ smemclr(line, strlen(line));
+ sfree(line);
+ line = NULL;
}
smemclr(base64_bit, sizeof(base64_bit));
if (ret) {
strbuf_free(ret->keyblob);
smemclr(ret, sizeof(*ret));
- sfree(ret);
+ sfree(ret);
}
if (errmsg_p) *errmsg_p = errmsg;
- if (fp) fclose(fp);
return NULL;
}
-static bool openssh_new_encrypted(const Filename *filename)
+static bool openssh_new_encrypted(BinarySource *src)
{
- struct openssh_new_key *key = load_openssh_new_key(filename, NULL);
+ struct openssh_new_key *key = load_openssh_new_key(src, NULL);
bool ret;
if (!key)
- return false;
+ return false;
ret = (key->cipher != ON_E_NONE);
strbuf_free(key->keyblob);
smemclr(key, sizeof(*key));
@@ -1303,9 +1325,9 @@ static bool openssh_new_encrypted(const Filename *filename)
}
static ssh2_userkey *openssh_new_read(
- const Filename *filename, const char *passphrase, const char **errmsg_p)
+ BinarySource *filesrc, const char *passphrase, const char **errmsg_p)
{
- struct openssh_new_key *key = load_openssh_new_key(filename, errmsg_p);
+ struct openssh_new_key *key = load_openssh_new_key(filesrc, errmsg_p);
ssh2_userkey *retkey = NULL;
ssh2_userkey *retval = NULL;
const char *errmsg;
@@ -1315,7 +1337,7 @@ static ssh2_userkey *openssh_new_read(
const ssh_keyalg *alg = NULL;
if (!key)
- return NULL;
+ return NULL;
if (key->cipher != ON_E_NONE) {
unsigned char keybuf[48];
@@ -1442,7 +1464,7 @@ static ssh2_userkey *openssh_new_read(
}
}
- if (!retkey) {
+ if (!retkey->key) {
errmsg = "key index out of range";
goto error;
}
@@ -1583,7 +1605,7 @@ static bool openssh_new_write(
*/
fp = f_open(filename, "wb", true); /* ensure Unix line endings */
if (!fp)
- goto error;
+ goto error;
fputs("-----BEGIN OPENSSH PRIVATE KEY-----\n", fp);
base64_encode(fp, cblob->u, cblob->len, 64);
fputs("-----END OPENSSH PRIVATE KEY-----\n", fp);
@@ -1631,26 +1653,26 @@ static bool openssh_auto_write(
* except that mpints are a bit different: they're more like the
* old SSH-1 mpint. You have a 32-bit bit count N, followed by
* (N+7)/8 bytes of data.
- *
+ *
* So. The blob contains:
- *
+ *
* - uint32 0x3f6ff9eb (magic number)
* - uint32 size (total blob size)
* - string key-type (see below)
* - string cipher-type (tells you if key is encrypted)
* - string encrypted-blob
- *
+ *
* (The first size field includes the size field itself and the
* magic number before it. All other size fields are ordinary SSH-2
* strings, so the size field indicates how much data is to
* _follow_.)
- *
+ *
* The encrypted blob, once decrypted, contains a single string
* which in turn contains the payload. (This allows padding to be
* added after that string while still making it clear where the
* real payload ends. Also it probably makes for a reasonable
* decryption check.)
- *
+ *
* The payload blob, for an RSA key, contains:
* - mpint e
* - mpint d
@@ -1658,7 +1680,7 @@ static bool openssh_auto_write(
* - mpint u (presumably inverse of p mod q)
* - mpint p (p is the smaller prime)
* - mpint q (q is the larger)
- *
+ *
* For a DSA key, the payload blob contains:
* - uint32 0
* - mpint p
@@ -1666,30 +1688,30 @@ static bool openssh_auto_write(
* - mpint q
* - mpint y
* - mpint x
- *
+ *
* Alternatively, if the parameters are `predefined', that
* (0,p,g,q) sequence can be replaced by a uint32 1 and a string
* containing some predefined parameter specification. *shudder*,
* but I doubt we'll encounter this in real life.
- *
+ *
* The key type strings are ghastly. The RSA key I looked at had a
* type string of
- *
+ *
* `if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}'
- *
+ *
* and the DSA key wasn't much better:
- *
+ *
* `dl-modp{sign{dsa-nist-sha1},dh{plain}}'
- *
+ *
* It isn't clear that these will always be the same. I think it
* might be wise just to look at the `if-modn{sign{rsa' and
* `dl-modp{sign{dsa' prefixes.
- *
+ *
* Finally, the encryption. The cipher-type string appears to be
* either `none' or `3des-cbc'. Looks as if this is SSH-2-style
* 3des-cbc (i.e. outer cbc rather than inner). The key is created
* from the passphrase by means of yet another hashing faff:
- *
+ *
* - first 16 bytes are MD5(passphrase)
* - next 16 bytes are MD5(passphrase || first 16 bytes)
* - if there were more, they'd be MD5(passphrase || first 32),
@@ -1703,11 +1725,10 @@ struct sshcom_key {
strbuf *keyblob;
};
-static struct sshcom_key *load_sshcom_key(const Filename *filename,
- const char **errmsg_p)
+static struct sshcom_key *load_sshcom_key(BinarySource *src,
+ const char **errmsg_p)
{
struct sshcom_key *ret;
- FILE *fp;
char *line = NULL;
int hdrstart, len;
const char *errmsg;
@@ -1720,19 +1741,13 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename,
ret->comment[0] = '\0';
ret->keyblob = strbuf_new_nm();
- fp = f_open(filename, "r", false);
- if (!fp) {
- errmsg = "unable to open key file";
- goto error;
- }
- if (!(line = fgetline(fp))) {
- errmsg = "unexpected end of file";
- goto error;
+ if (!(line = bsgetline(src))) {
+ errmsg = "unexpected end of file";
+ goto error;
}
- strip_crlf(line);
if (0 != strcmp(line, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----")) {
- errmsg = "file does not begin with ssh.com key header";
- goto error;
+ errmsg = "file does not begin with ssh.com key header";
+ goto error;
}
smemclr(line, strlen(line));
sfree(line);
@@ -1740,54 +1755,51 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename,
headers_done = false;
while (1) {
- if (!(line = fgetline(fp))) {
- errmsg = "unexpected end of file";
- goto error;
- }
- strip_crlf(line);
+ if (!(line = bsgetline(src))) {
+ errmsg = "unexpected end of file";
+ goto error;
+ }
if (!strcmp(line, "---- END SSH2 ENCRYPTED PRIVATE KEY ----")) {
sfree(line);
line = NULL;
break; /* done */
}
- if ((p = strchr(line, ':')) != NULL) {
- if (headers_done) {
- errmsg = "header found in body of key data";
- goto error;
- }
- *p++ = '\0';
- while (*p && isspace((unsigned char)*p)) p++;
- hdrstart = p - line;
+ if ((p = strchr(line, ':')) != NULL) {
+ if (headers_done) {
+ errmsg = "header found in body of key data";
+ goto error;
+ }
+ *p++ = '\0';
+ while (*p && isspace((unsigned char)*p)) p++;
+ hdrstart = p - line;
/*
* Header lines can end in a trailing backslash for
* continuation.
*/
- len = hdrstart + strlen(line+hdrstart);
- assert(!line[len]);
+ len = hdrstart + strlen(line+hdrstart);
+ assert(!line[len]);
while (line[len-1] == '\\') {
- char *line2;
- int line2len;
+ char *line2;
+ int line2len;
- line2 = fgetline(fp);
- if (!line2) {
+ line2 = bsgetline(src);
+ if (!line2) {
errmsg = "unexpected end of file";
goto error;
}
- strip_crlf(line2);
- line2len = strlen(line2);
- line = sresize(line, len + line2len + 1, char);
- strcpy(line + len - 1, line2);
- len += line2len - 1;
- assert(!line[len]);
+ line2len = strlen(line2);
+ line = sresize(line, len + line2len + 1, char);
+ strcpy(line + len - 1, line2);
+ len += line2len - 1;
+ assert(!line[len]);
- smemclr(line2, strlen(line2));
- sfree(line2);
- line2 = NULL;
+ smemclr(line2, strlen(line2));
+ sfree(line2);
+ line2 = NULL;
}
- p = line + hdrstart;
- strip_crlf(p);
+ p = line + hdrstart;
if (!strcmp(line, "Comment")) {
/* Strip quotes in comment if present. */
if (p[0] == '"' && p[strlen(p)-1] == '"') {
@@ -1797,11 +1809,11 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename,
strncpy(ret->comment, p, sizeof(ret->comment));
ret->comment[sizeof(ret->comment)-1] = '\0';
}
- } else {
- headers_done = true;
+ } else {
+ headers_done = true;
- p = line;
- while (isbase64(*p)) {
+ p = line;
+ while (isbase64(*p)) {
base64_bit[base64_chars++] = *p;
if (base64_chars == 4) {
unsigned char out[3];
@@ -1818,44 +1830,40 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename,
put_data(ret->keyblob, out, len);
}
- p++;
- }
- }
- smemclr(line, strlen(line));
- sfree(line);
- line = NULL;
+ p++;
+ }
+ }
+ smemclr(line, strlen(line));
+ sfree(line);
+ line = NULL;
}
if (ret->keyblob->len == 0) {
- errmsg = "key body not present";
- goto error;
+ errmsg = "key body not present";
+ goto error;
}
- fclose(fp);
if (errmsg_p) *errmsg_p = NULL;
return ret;
error:
- if (fp)
- fclose(fp);
-
if (line) {
- smemclr(line, strlen(line));
- sfree(line);
- line = NULL;
+ smemclr(line, strlen(line));
+ sfree(line);
+ line = NULL;
}
if (ret) {
strbuf_free(ret->keyblob);
smemclr(ret, sizeof(*ret));
- sfree(ret);
+ sfree(ret);
}
if (errmsg_p) *errmsg_p = errmsg;
return NULL;
}
-static bool sshcom_encrypted(const Filename *filename, char **comment)
+static bool sshcom_encrypted(BinarySource *filesrc, char **comment)
{
- struct sshcom_key *key = load_sshcom_key(filename, NULL);
+ struct sshcom_key *key = load_sshcom_key(filesrc, NULL);
BinarySource src[1];
ptrlen str;
bool answer = false;
@@ -1895,10 +1903,10 @@ void BinarySink_put_mp_sshcom_from_string(BinarySink *bs, ptrlen str)
int bits = nbytes * 8 - 1;
while (bits > 0) {
- if (*bytes & (1 << (bits & 7)))
- break;
- if (!(bits-- & 7))
- bytes++, nbytes--;
+ if (*bytes & (1 << (bits & 7)))
+ break;
+ if (!(bits-- & 7))
+ bytes++, nbytes--;
}
put_uint32(bs, bits+1);
@@ -1922,7 +1930,7 @@ static void sshcom_derivekey(ptrlen passphrase, uint8_t *keybuf)
/*
* Derive the encryption key for an ssh.com key file from the
* passphrase and iv/salt:
- *
+ *
* - let block A equal MD5(passphrase)
* - let block B equal MD5(passphrase || A)
* - block C would be MD5(passphrase || A || B) and so on
@@ -1932,15 +1940,15 @@ static void sshcom_derivekey(ptrlen passphrase, uint8_t *keybuf)
h = ssh_hash_new(&ssh_md5);
put_datapl(h, passphrase);
- ssh_hash_final(ssh_hash_copy(h), keybuf);
+ ssh_hash_digest_nondestructive(h, keybuf);
put_data(h, keybuf, 16);
ssh_hash_final(h, keybuf + 16);
}
static ssh2_userkey *sshcom_read(
- const Filename *filename, const char *passphrase, const char **errmsg_p)
+ BinarySource *filesrc, const char *passphrase, const char **errmsg_p)
{
- struct sshcom_key *key = load_sshcom_key(filename, errmsg_p);
+ struct sshcom_key *key = load_sshcom_key(filesrc, errmsg_p);
const char *errmsg;
BinarySource src[1];
ptrlen str, ciphertext;
@@ -2005,15 +2013,15 @@ static ssh2_userkey *sshcom_read(
* Decrypt it if necessary.
*/
if (encrypted) {
- /*
- * Derive encryption key from passphrase and iv/salt:
- *
- * - let block A equal MD5(passphrase)
- * - let block B equal MD5(passphrase || A)
- * - block C would be MD5(passphrase || A || B) and so on
- * - encryption key is the first N bytes of A || B
- */
- unsigned char keybuf[32], iv[8];
+ /*
+ * Derive encryption key from passphrase and iv/salt:
+ *
+ * - let block A equal MD5(passphrase)
+ * - let block B equal MD5(passphrase || A)
+ * - block C would be MD5(passphrase || A || B) and so on
+ * - encryption key is the first N bytes of A || B
+ */
+ unsigned char keybuf[32], iv[8];
if (ciphertext.len % 8 != 0) {
errmsg = "encrypted part of key is not a multiple of cipher block"
@@ -2023,12 +2031,12 @@ static ssh2_userkey *sshcom_read(
sshcom_derivekey(ptrlen_from_asciz(passphrase), keybuf);
- /*
- * Now decrypt the key blob in place (casting away const from
- * ciphertext being a ptrlen).
- */
+ /*
+ * Now decrypt the key blob in place (casting away const from
+ * ciphertext being a ptrlen).
+ */
memset(iv, 0, sizeof(iv));
- des3_decrypt_pubkey_ossh(keybuf, iv,
+ des3_decrypt_pubkey_ossh(keybuf, iv,
(char *)ciphertext.ptr, ciphertext.len);
smemclr(keybuf, sizeof(keybuf));
@@ -2118,9 +2126,9 @@ static ssh2_userkey *sshcom_read(
alg, make_ptrlen(blob->u, publen),
make_ptrlen(blob->u + publen, blob->len - publen));
if (!retkey->key) {
- sfree(retkey);
- errmsg = "unable to create key data structure";
- goto error;
+ sfree(retkey);
+ errmsg = "unable to create key data structure";
+ goto error;
}
retkey->comment = dupstr(key->comment);
@@ -2192,8 +2200,8 @@ static bool sshcom_write(
numbers[5] = p;
nnumbers = 6;
- initial_zero = false;
- type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}";
+ initial_zero = false;
+ type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}";
} else if (ssh_key_alg(key->key) == &ssh_dss) {
ptrlen p, q, g, y, x;
@@ -2219,8 +2227,8 @@ static bool sshcom_write(
numbers[4] = x;
nnumbers = 5;
- initial_zero = true;
- type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}";
+ initial_zero = true;
+ type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}";
} else {
goto error; /* unsupported key type */
}
@@ -2240,13 +2248,13 @@ static bool sshcom_write(
if (initial_zero)
put_uint32(outblob, 0);
for (i = 0; i < nnumbers; i++)
- put_mp_sshcom_from_string(outblob, numbers[i]);
+ put_mp_sshcom_from_string(outblob, numbers[i]);
/* Now wrap up the encrypted payload. */
PUT_32BIT_MSB_FIRST(outblob->s + lenpos + 4,
outblob->len - (lenpos + 8));
/* Pad encrypted blob to a multiple of cipher block size. */
if (passphrase) {
- int padding = -(outblob->len - (lenpos+4)) & 7;
+ int padding = -(outblob->len - (lenpos+4)) & 7;
uint8_t padding_buf[8];
random_read(padding_buf, padding);
put_data(outblob, padding_buf, padding);
@@ -2263,15 +2271,15 @@ static bool sshcom_write(
* Encrypt the key.
*/
if (passphrase) {
- unsigned char keybuf[32], iv[8];
+ unsigned char keybuf[32], iv[8];
sshcom_derivekey(ptrlen_from_asciz(passphrase), keybuf);
- /*
- * Now decrypt the key blob.
- */
+ /*
+ * Now decrypt the key blob.
+ */
memset(iv, 0, sizeof(iv));
- des3_encrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen);
+ des3_encrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen);
smemclr(keybuf, sizeof(keybuf));
}
@@ -2282,7 +2290,7 @@ static bool sshcom_write(
*/
fp = f_open(filename, "wb", true); /* ensure Unix line endings */
if (!fp)
- goto error;
+ goto error;
fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);
fprintf(fp, "Comment: \"");
/*
@@ -2292,14 +2300,14 @@ static bool sshcom_write(
* Don't ask me, I didn't design it.
*/
{
- int slen = 60; /* starts at 60 due to "Comment: " */
- char *c = key->comment;
- while ((int)strlen(c) > slen) {
- fprintf(fp, "%.*s\\\n", slen, c);
- c += slen;
- slen = 70; /* allow 70 chars on subsequent lines */
- }
- fprintf(fp, "%s\"\n", c);
+ int slen = 60; /* starts at 60 due to "Comment: " */
+ char *c = key->comment;
+ while ((int)strlen(c) > slen) {
+ fprintf(fp, "%.*s\\\n", slen, c);
+ c += slen;
+ slen = 70; /* allow 70 chars on subsequent lines */
+ }
+ fprintf(fp, "%s\"\n", c);
}
base64_encode(fp, outblob->u, outblob->len, 70);
fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);