X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/c232b3e336238048cb3a8c3548906182ee54c9cd..8154b6022bd42b4aba03fc9adcbabd4f588b6575:/import.c diff --git a/import.c b/import.c index 7ad09ac7..b6d32cb5 100644 --- a/import.c +++ b/import.c @@ -8,6 +8,7 @@ #include #include +#include "putty.h" #include "ssh.h" #include "misc.h" @@ -23,13 +24,17 @@ ((unsigned long)(unsigned char)(cp)[2] << 8) | \ ((unsigned long)(unsigned char)(cp)[3])) -int openssh_encrypted(char *filename); -struct ssh2_userkey *openssh_read(char *filename, char *passphrase); -int openssh_write(char *filename, struct ssh2_userkey *key, char *passphrase); +int openssh_encrypted(const Filename *filename); +struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase, + const char **errmsg_p); +int openssh_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase); -int sshcom_encrypted(char *filename, char **comment); -struct ssh2_userkey *sshcom_read(char *filename, char *passphrase); -int sshcom_write(char *filename, struct ssh2_userkey *key, char *passphrase); +int sshcom_encrypted(const Filename *filename, char **comment); +struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, + const char **errmsg_p); +int sshcom_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase); /* * Given a key type, determine whether we know how to import it. @@ -59,10 +64,11 @@ int import_target_type(int type) /* * Determine whether a foreign key is encrypted. */ -int import_encrypted(char *filename, int type, char **comment) +int import_encrypted(const Filename *filename, int type, char **comment) { if (type == SSH_KEYTYPE_OPENSSH) { - *comment = dupstr(filename); /* OpenSSH doesn't do key comments */ + /* OpenSSH doesn't do key comments */ + *comment = dupstr(filename_to_str(filename)); return openssh_encrypted(filename); } if (type == SSH_KEYTYPE_SSHCOM) { @@ -74,7 +80,8 @@ int import_encrypted(char *filename, int type, char **comment) /* * Import an SSH1 key. */ -int import_ssh1(char *filename, int type, struct RSAKey *key, char *passphrase) +int import_ssh1(const Filename *filename, int type, + struct RSAKey *key, char *passphrase, const char **errmsg_p) { return 0; } @@ -82,19 +89,21 @@ int import_ssh1(char *filename, int type, struct RSAKey *key, char *passphrase) /* * Import an SSH2 key. */ -struct ssh2_userkey *import_ssh2(char *filename, int type, char *passphrase) +struct ssh2_userkey *import_ssh2(const Filename *filename, int type, + char *passphrase, const char **errmsg_p) { if (type == SSH_KEYTYPE_OPENSSH) - return openssh_read(filename, passphrase); + return openssh_read(filename, passphrase, errmsg_p); if (type == SSH_KEYTYPE_SSHCOM) - return sshcom_read(filename, passphrase); + return sshcom_read(filename, passphrase, errmsg_p); return NULL; } /* * Export an SSH1 key. */ -int export_ssh1(char *filename, int type, struct RSAKey *key, char *passphrase) +int export_ssh1(const Filename *filename, int type, struct RSAKey *key, + char *passphrase) { return 0; } @@ -102,7 +111,7 @@ int export_ssh1(char *filename, int type, struct RSAKey *key, char *passphrase) /* * Export an SSH2 key. */ -int export_ssh2(char *filename, int type, +int export_ssh2(const Filename *filename, int type, struct ssh2_userkey *key, char *passphrase) { if (type == SSH_KEYTYPE_OPENSSH) @@ -122,11 +131,6 @@ int export_ssh2(char *filename, int type, (c) == '+' || (c) == '/' || (c) == '=' \ ) -extern int base64_decode_atom(char *atom, unsigned char *out); -extern int base64_lines(int datalen); -extern void base64_encode_atom(unsigned char *data, int n, char *out); -extern void base64_encode(FILE *fp, unsigned char *data, int datalen, int cpl); - /* * Read an ASN.1/BER identifier and length pair. * @@ -146,8 +150,8 @@ extern void base64_encode(FILE *fp, unsigned char *data, int datalen, int cpl); /* Primitive versus constructed bit. */ #define ASN1_CONSTRUCTED (1 << 5) -int ber_read_id_len(void *source, int sourcelen, - int *id, int *length, int *flags) +static int ber_read_id_len(void *source, int sourcelen, + int *id, int *length, int *flags) { unsigned char *p = (unsigned char *) source; @@ -158,12 +162,11 @@ int ber_read_id_len(void *source, int sourcelen, if ((*p & 0x1F) == 0x1F) { *id = 0; while (*p & 0x80) { - *id = (*id << 7) | (*p & 0x7F); p++, sourcelen--; if (sourcelen == 0) return -1; + *id = (*id << 7) | (*p & 0x7F); } - *id = (*id << 7) | (*p & 0x7F); p++, sourcelen--; } else { *id = *p & 0x1F; @@ -196,7 +199,7 @@ int ber_read_id_len(void *source, int sourcelen, * Will avoid writing anything if dest is NULL, but still return * amount of space required. */ -int ber_write_id_len(void *dest, int id, int length, int flags) +static int ber_write_id_len(void *dest, int id, int length, int flags) { unsigned char *d = (unsigned char *)dest; int len = 0; @@ -280,7 +283,7 @@ static int put_mp(void *target, void *data, int len) /* Simple structure to point to an mp-int within a blob. */ struct mpint_pos { void *start; int bytes; }; -int ssh2_read_mpint(void *data, int len, struct mpint_pos *ret) +static int ssh2_read_mpint(void *data, int len, struct mpint_pos *ret) { int bytes; unsigned char *d = (unsigned char *) data; @@ -314,7 +317,8 @@ struct openssh_key { int keyblob_len, keyblob_size; }; -struct openssh_key *load_openssh_key(char *filename) +static struct openssh_key *load_openssh_key(const Filename *filename, + const char **errmsg_p) { struct openssh_key *ret; FILE *fp; @@ -324,21 +328,21 @@ struct openssh_key *load_openssh_key(char *filename) char base64_bit[4]; int base64_chars = 0; - ret = smalloc(sizeof(*ret)); + ret = snew(struct openssh_key); ret->keyblob = NULL; ret->keyblob_len = ret->keyblob_size = 0; ret->encrypted = 0; memset(ret->iv, 0, sizeof(ret->iv)); - fp = fopen(filename, "r"); + fp = f_open(*filename, "r"); if (!fp) { - errmsg = "Unable to open key file"; + errmsg = "unable to open key file"; goto error; } if (!fgets(buffer, sizeof(buffer), fp) || 0 != strncmp(buffer, "-----BEGIN ", 11) || 0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) { - errmsg = "File does not begin with OpenSSH key header"; + errmsg = "file does not begin with OpenSSH key header"; goto error; } if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n")) @@ -346,14 +350,14 @@ struct openssh_key *load_openssh_key(char *filename) else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n")) ret->type = OSSH_DSA; else { - errmsg = "Unrecognised key type"; + errmsg = "unrecognised key type"; goto error; } headers_done = 0; while (1) { if (!fgets(buffer, sizeof(buffer), fp)) { - errmsg = "Unexpected end of file"; + errmsg = "unexpected end of file"; goto error; } if (0 == strncmp(buffer, "-----END ", 9) && @@ -361,7 +365,7 @@ struct openssh_key *load_openssh_key(char *filename) break; /* done */ if ((p = strchr(buffer, ':')) != NULL) { if (headers_done) { - errmsg = "Header found in body of key data"; + errmsg = "header found in body of key data"; goto error; } *p++ = '\0'; @@ -378,7 +382,7 @@ struct openssh_key *load_openssh_key(char *filename) int i, j; if (strncmp(p, "DES-EDE3-CBC,", 13)) { - errmsg = "Ciphers other than DES-EDE3-CBC not supported"; + errmsg = "ciphers other than DES-EDE3-CBC not supported"; goto error; } p += 13; @@ -389,7 +393,7 @@ struct openssh_key *load_openssh_key(char *filename) p += 2; } if (i < 8) { - errmsg = "Expected 16-digit iv in DEK-Info"; + errmsg = "expected 16-digit iv in DEK-Info"; goto error; } } @@ -408,13 +412,14 @@ struct openssh_key *load_openssh_key(char *filename) len = base64_decode_atom(base64_bit, out); if (len <= 0) { - errmsg = "Invalid base64 encoding"; + errmsg = "invalid base64 encoding"; goto error; } if (ret->keyblob_len + len > ret->keyblob_size) { ret->keyblob_size = ret->keyblob_len + len + 256; - ret->keyblob = srealloc(ret->keyblob, ret->keyblob_size); + ret->keyblob = sresize(ret->keyblob, ret->keyblob_size, + unsigned char); } memcpy(ret->keyblob + ret->keyblob_len, out, len); @@ -429,17 +434,18 @@ struct openssh_key *load_openssh_key(char *filename) } if (ret->keyblob_len == 0 || !ret->keyblob) { - errmsg = "Key body not present"; + errmsg = "key body not present"; goto error; } if (ret->encrypted && ret->keyblob_len % 8 != 0) { - errmsg = "Encrypted key blob is not a multiple of cipher block size"; + errmsg = "encrypted key blob is not a multiple of cipher block size"; goto error; } memset(buffer, 0, sizeof(buffer)); memset(base64_bit, 0, sizeof(base64_bit)); + if (errmsg_p) *errmsg_p = NULL; return ret; error: @@ -453,12 +459,13 @@ struct openssh_key *load_openssh_key(char *filename) memset(&ret, 0, sizeof(ret)); sfree(ret); } + if (errmsg_p) *errmsg_p = errmsg; return NULL; } -int openssh_encrypted(char *filename) +int openssh_encrypted(const Filename *filename) { - struct openssh_key *key = load_openssh_key(filename); + struct openssh_key *key = load_openssh_key(filename, NULL); int ret; if (!key) @@ -471,9 +478,10 @@ int openssh_encrypted(char *filename) return ret; } -struct ssh2_userkey *openssh_read(char *filename, char *passphrase) +struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase, + const char **errmsg_p) { - struct openssh_key *key = load_openssh_key(filename); + struct openssh_key *key = load_openssh_key(filename, errmsg_p); struct ssh2_userkey *retkey; unsigned char *p; int ret, id, len, flags; @@ -481,9 +489,11 @@ struct ssh2_userkey *openssh_read(char *filename, char *passphrase) struct ssh2_userkey *retval = NULL; char *errmsg; unsigned char *blob; - int blobsize, blobptr, privptr; - char *modptr; - int modlen; + int blobsize = 0, blobptr, privptr; + char *modptr = NULL; + int modlen = 0; + + blob = NULL; if (!key) return NULL; @@ -501,20 +511,20 @@ struct ssh2_userkey *openssh_read(char *filename, char *passphrase) unsigned char keybuf[32]; MD5Init(&md5c); - MD5Update(&md5c, passphrase, strlen(passphrase)); - MD5Update(&md5c, key->iv, 8); + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); + MD5Update(&md5c, (unsigned char *)key->iv, 8); MD5Final(keybuf, &md5c); MD5Init(&md5c); MD5Update(&md5c, keybuf, 16); - MD5Update(&md5c, passphrase, strlen(passphrase)); - MD5Update(&md5c, key->iv, 8); + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); + MD5Update(&md5c, (unsigned char *)key->iv, 8); MD5Final(keybuf+16, &md5c); /* * Now decrypt the key blob. */ - des3_decrypt_pubkey_ossh(keybuf, key->iv, + des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv, key->keyblob, key->keyblob_len); memset(&md5c, 0, sizeof(md5c)); @@ -555,12 +565,14 @@ struct ssh2_userkey *openssh_read(char *filename, char *passphrase) num_integers = 9; else if (key->type == OSSH_DSA) num_integers = 6; + else + num_integers = 0; /* placate compiler warnings */ /* * Space to create key blob in. */ blobsize = 256+key->keyblob_len; - blob = smalloc(blobsize); + blob = snewn(blobsize, unsigned char); PUT_32BIT(blob, 7); if (key->type == OSSH_DSA) memcpy(blob+4, "ssh-dss", 7); @@ -576,6 +588,7 @@ struct ssh2_userkey *openssh_read(char *filename, char *passphrase) if (ret < 0 || id != 2 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; + retval = SSH2_WRONG_PASSPHRASE; goto error; } @@ -585,7 +598,7 @@ struct ssh2_userkey *openssh_read(char *filename, char *passphrase) * this is some sort of version indication). */ if (len != 1 || p[0] != 0) { - errmsg = "Version number mismatch"; + errmsg = "version number mismatch"; goto error; } } else if (key->type == OSSH_RSA) { @@ -596,7 +609,7 @@ struct ssh2_userkey *openssh_read(char *filename, char *passphrase) */ if (i == 1) { /* Save the details for after we deal with number 2. */ - modptr = p; + modptr = (char *)p; modlen = len; } else if (i != 6 && i != 7) { PUT_32BIT(blob+blobptr, len); @@ -632,7 +645,7 @@ struct ssh2_userkey *openssh_read(char *filename, char *passphrase) * the sanity checks for free. */ assert(privptr > 0); /* should have bombed by now if not */ - retkey = smalloc(sizeof(struct ssh2_userkey)); + retkey = snew(struct ssh2_userkey); retkey->alg = (key->type == OSSH_RSA ? &ssh_rsa : &ssh_dss); retkey->data = retkey->alg->createkey(blob, privptr, blob+privptr, blobptr-privptr); @@ -655,13 +668,15 @@ struct ssh2_userkey *openssh_read(char *filename, char *passphrase) sfree(key->keyblob); memset(&key, 0, sizeof(key)); sfree(key); + if (errmsg_p) *errmsg_p = errmsg; return retval; } -int openssh_write(char *filename, struct ssh2_userkey *key, char *passphrase) +int openssh_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase) { unsigned char *pubblob, *privblob, *spareblob; - int publen, privlen, sparelen; + int publen, privlen, sparelen = 0; unsigned char *outblob; int outlen; struct mpint_pos numbers[9]; @@ -714,7 +729,7 @@ int openssh_write(char *filename, struct ssh2_userkey *key, char *passphrase) dmp1.bytes = (bignum_bitcount(bdmp1)+8)/8; dmq1.bytes = (bignum_bitcount(bdmq1)+8)/8; sparelen = dmp1.bytes + dmq1.bytes; - spareblob = smalloc(sparelen); + spareblob = snewn(sparelen, unsigned char); dmp1.start = spareblob; dmq1.start = spareblob + dmp1.bytes; for (i = 0; i < dmp1.bytes; i++) @@ -777,15 +792,16 @@ int openssh_write(char *filename, struct ssh2_userkey *key, char *passphrase) seqlen = len; /* Now add on the SEQUENCE header. */ len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED); - /* And round up to the cipher block size. */ + /* Round up to the cipher block size, ensuring we have at least one + * byte of padding (see below). */ + outlen = len; if (passphrase) - len = (len+7) &~ 7; + outlen = (outlen+8) &~ 7; /* * Now we know how big outblob needs to be. Allocate it. */ - outlen = len; - outblob = smalloc(outlen); + outblob = snewn(outlen, unsigned char); /* * And write the data into it. @@ -797,8 +813,27 @@ int openssh_write(char *filename, struct ssh2_userkey *key, char *passphrase) memcpy(outblob+pos, numbers[i].start, numbers[i].bytes); pos += numbers[i].bytes; } + + /* + * Padding on OpenSSH keys is deterministic. The number of + * padding bytes is always more than zero, and always at most + * the cipher block length. The value of each padding byte is + * equal to the number of padding bytes. So a plaintext that's + * an exact multiple of the block size will be padded with 08 + * 08 08 08 08 08 08 08 (assuming a 64-bit block cipher); a + * plaintext one byte less than a multiple of the block size + * will be padded with just 01. + * + * This enables the OpenSSL key decryption function to strip + * off the padding algorithmically and return the unpadded + * plaintext to the next layer: it looks at the final byte, and + * then expects to find that many bytes at the end of the data + * with the same value. Those are all removed and the rest is + * returned. + */ + assert(pos == len); while (pos < outlen) { - outblob[pos++] = random_byte(); + outblob[pos++] = outlen - len; } /* @@ -820,13 +855,13 @@ int openssh_write(char *filename, struct ssh2_userkey *key, char *passphrase) for (i = 0; i < 8; i++) iv[i] = random_byte(); MD5Init(&md5c); - MD5Update(&md5c, passphrase, strlen(passphrase)); + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); MD5Update(&md5c, iv, 8); MD5Final(keybuf, &md5c); MD5Init(&md5c); MD5Update(&md5c, keybuf, 16); - MD5Update(&md5c, passphrase, strlen(passphrase)); + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); MD5Update(&md5c, iv, 8); MD5Final(keybuf+16, &md5c); @@ -843,7 +878,7 @@ int openssh_write(char *filename, struct ssh2_userkey *key, char *passphrase) * And save it. We'll use Unix line endings just in case it's * subsequently transferred in binary mode. */ - fp = fopen(filename, "wb"); /* ensure Unix line endings */ + fp = f_open(*filename, "wb"); /* ensure Unix line endings */ if (!fp) goto error; fputs(header, fp); @@ -960,7 +995,8 @@ struct sshcom_key { int keyblob_len, keyblob_size; }; -struct sshcom_key *load_sshcom_key(char *filename) +static struct sshcom_key *load_sshcom_key(const Filename *filename, + const char **errmsg_p) { struct sshcom_key *ret; FILE *fp; @@ -971,33 +1007,33 @@ struct sshcom_key *load_sshcom_key(char *filename) char base64_bit[4]; int base64_chars = 0; - ret = smalloc(sizeof(*ret)); + ret = snew(struct sshcom_key); ret->comment[0] = '\0'; ret->keyblob = NULL; ret->keyblob_len = ret->keyblob_size = 0; - fp = fopen(filename, "r"); + fp = f_open(*filename, "r"); if (!fp) { - errmsg = "Unable to open key file"; + errmsg = "unable to open key file"; goto error; } if (!fgets(buffer, sizeof(buffer), fp) || 0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) { - errmsg = "File does not begin with ssh.com key header"; + errmsg = "file does not begin with ssh.com key header"; goto error; } headers_done = 0; while (1) { if (!fgets(buffer, sizeof(buffer), fp)) { - errmsg = "Unexpected end of file"; + errmsg = "unexpected end of file"; goto error; } if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n")) break; /* done */ if ((p = strchr(buffer, ':')) != NULL) { if (headers_done) { - errmsg = "Header found in body of key data"; + errmsg = "header found in body of key data"; goto error; } *p++ = '\0'; @@ -1006,14 +1042,14 @@ struct sshcom_key *load_sshcom_key(char *filename) * Header lines can end in a trailing backslash for * continuation. */ - while ((len = strlen(p)) > sizeof(buffer) - (p-buffer) -1 || + while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) || p[len-1] != '\n' || p[len-2] == '\\') { - if (len > (p-buffer) + sizeof(buffer)-2) { - errmsg = "Header line too long to deal with"; + if (len > (int)((p-buffer) + sizeof(buffer)-2)) { + errmsg = "header line too long to deal with"; goto error; } if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) { - errmsg = "Unexpected end of file"; + errmsg = "unexpected end of file"; goto error; } } @@ -1041,13 +1077,14 @@ struct sshcom_key *load_sshcom_key(char *filename) len = base64_decode_atom(base64_bit, out); if (len <= 0) { - errmsg = "Invalid base64 encoding"; + errmsg = "invalid base64 encoding"; goto error; } if (ret->keyblob_len + len > ret->keyblob_size) { ret->keyblob_size = ret->keyblob_len + len + 256; - ret->keyblob = srealloc(ret->keyblob, ret->keyblob_size); + ret->keyblob = sresize(ret->keyblob, ret->keyblob_size, + unsigned char); } memcpy(ret->keyblob + ret->keyblob_len, out, len); @@ -1060,10 +1097,11 @@ struct sshcom_key *load_sshcom_key(char *filename) } if (ret->keyblob_len == 0 || !ret->keyblob) { - errmsg = "Key body not present"; + errmsg = "key body not present"; goto error; } + if (errmsg_p) *errmsg_p = NULL; return ret; error: @@ -1075,12 +1113,13 @@ struct sshcom_key *load_sshcom_key(char *filename) memset(&ret, 0, sizeof(ret)); sfree(ret); } + if (errmsg_p) *errmsg_p = errmsg; return NULL; } -int sshcom_encrypted(char *filename, char **comment) +int sshcom_encrypted(const Filename *filename, char **comment) { - struct sshcom_key *key = load_sshcom_key(filename); + struct sshcom_key *key = load_sshcom_key(filename, NULL); int pos, len, answer; *comment = NULL; @@ -1118,7 +1157,7 @@ int sshcom_encrypted(char *filename, char **comment) return answer; } -int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret) +static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret) { int bits; int bytes; @@ -1160,9 +1199,10 @@ static int sshcom_put_mpint(void *target, void *data, int len) return len+4; } -struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) +struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, + const char **errmsg_p) { - struct sshcom_key *key = load_sshcom_key(filename); + struct sshcom_key *key = load_sshcom_key(filename, errmsg_p); char *errmsg; int pos, len; const char prefix_rsa[] = "if-modn{sign{rsa"; @@ -1174,7 +1214,7 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) struct ssh2_userkey *ret = NULL, *retkey; const struct ssh_signkey *alg; unsigned char *blob = NULL; - int blobsize, publen, privlen; + int blobsize = 0, publen, privlen; if (!key) return NULL; @@ -1183,7 +1223,7 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) * Check magic number. */ if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) { - errmsg = "Key does not begin with magic number"; + errmsg = "key does not begin with magic number"; goto error; } @@ -1193,7 +1233,7 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) pos = 8; if (key->keyblob_len < pos+4 || (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { - errmsg = "Key blob does not contain a key type string"; + errmsg = "key blob does not contain a key type string"; goto error; } if (len > sizeof(prefix_rsa) - 1 && @@ -1203,7 +1243,7 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) { type = DSA; } else { - errmsg = "Key is of unknown type"; + errmsg = "key is of unknown type"; goto error; } pos += 4+len; @@ -1213,7 +1253,7 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) */ if (key->keyblob_len < pos+4 || (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { - errmsg = "Key blob does not contain a cipher type string"; + errmsg = "key blob does not contain a cipher type string"; goto error; } if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4)) @@ -1221,7 +1261,7 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8)) encrypted = 1; else { - errmsg = "Key encryption is of unknown type"; + errmsg = "key encryption is of unknown type"; goto error; } pos += 4+len; @@ -1231,13 +1271,13 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) */ if (key->keyblob_len < pos+4 || (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { - errmsg = "Key blob does not contain actual key data"; + errmsg = "key blob does not contain actual key data"; goto error; } - ciphertext = key->keyblob + pos + 4; + ciphertext = (char *)key->keyblob + pos + 4; cipherlen = len; if (cipherlen == 0) { - errmsg = "Length of key data is zero"; + errmsg = "length of key data is zero"; goto error; } @@ -1257,17 +1297,17 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) unsigned char keybuf[32], iv[8]; if (cipherlen % 8 != 0) { - errmsg = "Encrypted part of key is not a multiple of cipher block" + errmsg = "encrypted part of key is not a multiple of cipher block" " size"; goto error; } MD5Init(&md5c); - MD5Update(&md5c, passphrase, strlen(passphrase)); + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); MD5Final(keybuf, &md5c); MD5Init(&md5c); - MD5Update(&md5c, passphrase, strlen(passphrase)); + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); MD5Update(&md5c, keybuf, 16); MD5Final(keybuf+16, &md5c); @@ -1275,7 +1315,8 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) * Now decrypt the key blob. */ memset(iv, 0, sizeof(iv)); - des3_decrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen); + des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, + cipherlen); memset(&md5c, 0, sizeof(md5c)); memset(keybuf, 0, sizeof(keybuf)); @@ -1294,7 +1335,7 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) * Strip away the containing string to get to the real meat. */ len = GET_32BIT(ciphertext); - if (len > cipherlen-4) { + if (len < 0 || len > cipherlen-4) { errmsg = "containing string was ill-formed"; goto error; } @@ -1307,7 +1348,7 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) * end up feeding them to alg->createkey(). */ blobsize = cipherlen + 256; - blob = smalloc(blobsize); + blob = snewn(blobsize, unsigned char); privlen = 0; if (type == RSA) { struct mpint_pos n, e, d, u, p, q; @@ -1361,11 +1402,12 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) publen = pos; pos += put_mp(blob+pos, x.start, x.bytes); privlen = pos - publen; - } + } else + return NULL; assert(privlen > 0); /* should have bombed by now if not */ - retkey = smalloc(sizeof(struct ssh2_userkey)); + retkey = snew(struct ssh2_userkey); retkey->alg = alg; retkey->data = alg->createkey(blob, publen, blob+publen, privlen); if (!retkey->data) { @@ -1387,10 +1429,12 @@ struct ssh2_userkey *sshcom_read(char *filename, char *passphrase) sfree(key->keyblob); memset(&key, 0, sizeof(key)); sfree(key); + if (errmsg_p) *errmsg_p = errmsg; return ret; } -int sshcom_write(char *filename, struct ssh2_userkey *key, char *passphrase) +int sshcom_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase) { unsigned char *pubblob, *privblob; int publen, privlen; @@ -1475,7 +1519,7 @@ int sshcom_write(char *filename, struct ssh2_userkey *key, char *passphrase) outlen = 512; for (i = 0; i < nnumbers; i++) outlen += 4 + numbers[i].bytes; - outblob = smalloc(outlen); + outblob = snewn(outlen, unsigned char); /* * Create the unencrypted key blob. @@ -1506,7 +1550,7 @@ int sshcom_write(char *filename, struct ssh2_userkey *key, char *passphrase) while (padding--) outblob[pos++] = random_byte(); } - ciphertext = outblob+lenpos+4; + ciphertext = (char *)outblob+lenpos+4; cipherlen = pos - (lenpos+4); assert(!passphrase || cipherlen % 8 == 0); /* Wrap up the encrypted blob string. */ @@ -1532,11 +1576,11 @@ int sshcom_write(char *filename, struct ssh2_userkey *key, char *passphrase) unsigned char keybuf[32], iv[8]; MD5Init(&md5c); - MD5Update(&md5c, passphrase, strlen(passphrase)); + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); MD5Final(keybuf, &md5c); MD5Init(&md5c); - MD5Update(&md5c, passphrase, strlen(passphrase)); + MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); MD5Update(&md5c, keybuf, 16); MD5Final(keybuf+16, &md5c); @@ -1544,7 +1588,8 @@ int sshcom_write(char *filename, struct ssh2_userkey *key, char *passphrase) * Now decrypt the key blob. */ memset(iv, 0, sizeof(iv)); - des3_encrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen); + des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, + cipherlen); memset(&md5c, 0, sizeof(md5c)); memset(keybuf, 0, sizeof(keybuf)); @@ -1554,7 +1599,7 @@ int sshcom_write(char *filename, struct ssh2_userkey *key, char *passphrase) * And save it. We'll use Unix line endings just in case it's * subsequently transferred in binary mode. */ - fp = fopen(filename, "wb"); /* ensure Unix line endings */ + fp = f_open(*filename, "wb"); /* ensure Unix line endings */ if (!fp) goto error; fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); @@ -1568,7 +1613,7 @@ int sshcom_write(char *filename, struct ssh2_userkey *key, char *passphrase) { int slen = 60; /* starts at 60 due to "Comment: " */ char *c = key->comment; - while (strlen(c) > slen) { + while ((int)strlen(c) > slen) { fprintf(fp, "%.*s\\\n", slen, c); c += slen; slen = 70; /* allow 70 chars on subsequent lines */