X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/1e87cce57fa5ba8819ba5b11fdbabefc6d8dab9e..f5c578b08c147e3a0c9a67c75ed57a7ddb7e20dd:/import.c diff --git a/import.c b/import.c index b6d32cb5..a3c24050 100644 --- a/import.c +++ b/import.c @@ -12,18 +12,6 @@ #include "ssh.h" #include "misc.h" -#define PUT_32BIT(cp, value) do { \ - (cp)[3] = (unsigned char)(value); \ - (cp)[2] = (unsigned char)((value) >> 8); \ - (cp)[1] = (unsigned char)((value) >> 16); \ - (cp)[0] = (unsigned char)((value) >> 24); } while (0) - -#define GET_32BIT(cp) \ - (((unsigned long)(unsigned char)(cp)[0] << 24) | \ - ((unsigned long)(unsigned char)(cp)[1] << 16) | \ - ((unsigned long)(unsigned char)(cp)[2] << 8) | \ - ((unsigned long)(unsigned char)(cp)[3])) - int openssh_encrypted(const Filename *filename); struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase, const char **errmsg_p); @@ -56,7 +44,7 @@ int import_possible(int type) int import_target_type(int type) { /* - * There are no known foreign SSH1 key formats. + * There are no known foreign SSH-1 key formats. */ return SSH_KEYTYPE_SSH2; } @@ -78,7 +66,7 @@ int import_encrypted(const Filename *filename, int type, char **comment) } /* - * Import an SSH1 key. + * Import an SSH-1 key. */ int import_ssh1(const Filename *filename, int type, struct RSAKey *key, char *passphrase, const char **errmsg_p) @@ -87,7 +75,7 @@ int import_ssh1(const Filename *filename, int type, } /* - * Import an SSH2 key. + * Import an SSH-2 key. */ struct ssh2_userkey *import_ssh2(const Filename *filename, int type, char *passphrase, const char **errmsg_p) @@ -100,7 +88,7 @@ struct ssh2_userkey *import_ssh2(const Filename *filename, int type, } /* - * Export an SSH1 key. + * Export an SSH-1 key. */ int export_ssh1(const Filename *filename, int type, struct RSAKey *key, char *passphrase) @@ -109,7 +97,7 @@ int export_ssh1(const Filename *filename, int type, struct RSAKey *key, } /* - * Export an SSH2 key. + * Export an SSH-2 key. */ int export_ssh2(const Filename *filename, int type, struct ssh2_userkey *key, char *passphrase) @@ -121,6 +109,17 @@ int export_ssh2(const Filename *filename, int type, return 0; } +/* + * Strip trailing CRs and LFs at the end of a line of text. + */ +void strip_crlf(char *str) +{ + char *p = str + strlen(str); + + while (p > str && (p[-1] == '\r' || p[-1] == '\n')) + *--p = '\0'; +} + /* ---------------------------------------------------------------------- * Helper routines. (The base64 ones are defined in sshpubk.c.) */ @@ -322,7 +321,7 @@ static struct openssh_key *load_openssh_key(const Filename *filename, { struct openssh_key *ret; FILE *fp; - char buffer[256]; + char *line = NULL; char *errmsg, *p; int headers_done; char base64_bit[4]; @@ -334,51 +333,60 @@ static struct openssh_key *load_openssh_key(const Filename *filename, ret->encrypted = 0; memset(ret->iv, 0, sizeof(ret->iv)); - fp = f_open(*filename, "r"); + fp = f_open(*filename, "r", FALSE); if (!fp) { 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")) { + + if (!(line = fgetline(fp))) { + errmsg = "unexpected end of file"; + goto error; + } + strip_crlf(line); + if (0 != strncmp(line, "-----BEGIN ", 11) || + 0 != strcmp(line+strlen(line)-16, "PRIVATE KEY-----")) { errmsg = "file does not begin with OpenSSH key header"; goto error; } - if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n")) + if (!strcmp(line, "-----BEGIN RSA PRIVATE KEY-----")) ret->type = OSSH_RSA; - else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n")) + else if (!strcmp(line, "-----BEGIN DSA PRIVATE KEY-----")) ret->type = OSSH_DSA; else { errmsg = "unrecognised key type"; goto error; } + memset(line, 0, strlen(line)); + sfree(line); + line = NULL; headers_done = 0; while (1) { - if (!fgets(buffer, sizeof(buffer), fp)) { + if (!(line = fgetline(fp))) { errmsg = "unexpected end of file"; goto error; } - if (0 == strncmp(buffer, "-----END ", 9) && - 0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) + strip_crlf(line); + if (0 == strncmp(line, "-----END ", 9) && + 0 == strcmp(line+strlen(line)-16, "PRIVATE KEY-----")) break; /* done */ - if ((p = strchr(buffer, ':')) != NULL) { + 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(buffer, "Proc-Type")) { + 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\n")) + if (!strcmp(p, "ENCRYPTED")) ret->encrypted = 1; - } else if (!strcmp(buffer, "DEK-Info")) { + } else if (!strcmp(line, "DEK-Info")) { int i, j; if (strncmp(p, "DES-EDE3-CBC,", 13)) { @@ -400,7 +408,7 @@ static struct openssh_key *load_openssh_key(const Filename *filename, } else { headers_done = 1; - p = buffer; + p = line; while (isbase64(*p)) { base64_bit[base64_chars++] = *p; if (base64_chars == 4) { @@ -431,6 +439,9 @@ static struct openssh_key *load_openssh_key(const Filename *filename, p++; } } + memset(line, 0, strlen(line)); + sfree(line); + line = NULL; } if (ret->keyblob_len == 0 || !ret->keyblob) { @@ -443,20 +454,23 @@ static struct openssh_key *load_openssh_key(const Filename *filename, goto error; } - memset(buffer, 0, sizeof(buffer)); memset(base64_bit, 0, sizeof(base64_bit)); if (errmsg_p) *errmsg_p = NULL; return ret; error: - memset(buffer, 0, sizeof(buffer)); + if (line) { + memset(line, 0, strlen(line)); + sfree(line); + line = NULL; + } memset(base64_bit, 0, sizeof(base64_bit)); if (ret) { if (ret->keyblob) { memset(ret->keyblob, 0, ret->keyblob_size); sfree(ret->keyblob); } - memset(&ret, 0, sizeof(ret)); + memset(ret, 0, sizeof(*ret)); sfree(ret); } if (errmsg_p) *errmsg_p = errmsg; @@ -473,7 +487,7 @@ int openssh_encrypted(const Filename *filename) ret = key->encrypted; memset(key->keyblob, 0, key->keyblob_size); sfree(key->keyblob); - memset(&key, 0, sizeof(key)); + memset(key, 0, sizeof(*key)); sfree(key); return ret; } @@ -666,7 +680,7 @@ struct ssh2_userkey *openssh_read(const Filename *filename, char *passphrase, } memset(key->keyblob, 0, key->keyblob_size); sfree(key->keyblob); - memset(&key, 0, sizeof(key)); + memset(key, 0, sizeof(*key)); sfree(key); if (errmsg_p) *errmsg_p = errmsg; return retval; @@ -778,6 +792,7 @@ int openssh_write(const Filename *filename, struct ssh2_userkey *key, footer = "-----END DSA PRIVATE KEY-----\n"; } else { assert(0); /* zoinks! */ + exit(1); /* XXX: GCC doesn't understand assert() on some systems. */ } /* @@ -878,7 +893,7 @@ int openssh_write(const Filename *filename, struct ssh2_userkey *key, * And save it. We'll use Unix line endings just in case it's * subsequently transferred in binary mode. */ - fp = f_open(*filename, "wb"); /* ensure Unix line endings */ + fp = f_open(*filename, "wb", TRUE); /* ensure Unix line endings */ if (!fp) goto error; fputs(header, fp); @@ -918,9 +933,9 @@ int openssh_write(const Filename *filename, struct ssh2_userkey *key, */ /* - * The format of the base64 blob is largely ssh2-packet-formatted, + * The format of the base64 blob is largely SSH-2-packet-formatted, * except that mpints are a bit different: they're more like the - * old ssh1 mpint. You have a 32-bit bit count N, followed by + * old SSH-1 mpint. You have a 32-bit bit count N, followed by * (N+7)/8 bytes of data. * * So. The blob contains: @@ -932,7 +947,7 @@ int openssh_write(const Filename *filename, struct ssh2_userkey *key, * - string encrypted-blob * * (The first size field includes the size field itself and the - * magic number before it. All other size fields are ordinary ssh2 + * magic number before it. All other size fields are ordinary SSH-2 * strings, so the size field indicates how much data is to * _follow_.) * @@ -977,7 +992,7 @@ int openssh_write(const Filename *filename, struct ssh2_userkey *key, * `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 SSH2-style + * 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: * @@ -1000,8 +1015,8 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, { struct sshcom_key *ret; FILE *fp; - char buffer[256]; - int len; + char *line = NULL; + int hdrstart, len; char *errmsg, *p; int headers_done; char base64_bit[4]; @@ -1012,49 +1027,72 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, ret->keyblob = NULL; ret->keyblob_len = ret->keyblob_size = 0; - fp = f_open(*filename, "r"); + fp = f_open(*filename, "r", FALSE); if (!fp) { errmsg = "unable to open key file"; goto error; } - if (!fgets(buffer, sizeof(buffer), fp) || - 0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) { + if (!(line = fgetline(fp))) { + 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; } + memset(line, 0, strlen(line)); + sfree(line); + line = NULL; headers_done = 0; while (1) { - if (!fgets(buffer, sizeof(buffer), fp)) { + if (!(line = fgetline(fp))) { errmsg = "unexpected end of file"; goto error; } - if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n")) + strip_crlf(line); + if (!strcmp(line, "---- END SSH2 ENCRYPTED PRIVATE KEY ----")) break; /* done */ - if ((p = strchr(buffer, ':')) != NULL) { + 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. */ - while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) || - p[len-1] != '\n' || p[len-2] == '\\') { - 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)) { + len = hdrstart + strlen(line+hdrstart); + assert(!line[len]); + while (line[len-1] == '\\') { + char *line2; + int line2len; + + line2 = fgetline(fp); + 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]); + + memset(line2, 0, strlen(line2)); + sfree(line2); + line2 = NULL; } - p[strcspn(p, "\n")] = '\0'; - if (!strcmp(buffer, "Comment")) { + p = line + hdrstart; + strip_crlf(p); + if (!strcmp(line, "Comment")) { /* Strip quotes in comment if present. */ if (p[0] == '"' && p[strlen(p)-1] == '"') { p++; @@ -1066,7 +1104,7 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, } else { headers_done = 1; - p = buffer; + p = line; while (isbase64(*p)) { base64_bit[base64_chars++] = *p; if (base64_chars == 4) { @@ -1094,6 +1132,9 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, p++; } } + memset(line, 0, strlen(line)); + sfree(line); + line = NULL; } if (ret->keyblob_len == 0 || !ret->keyblob) { @@ -1105,12 +1146,17 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, return ret; error: + if (line) { + memset(line, 0, strlen(line)); + sfree(line); + line = NULL; + } if (ret) { if (ret->keyblob) { memset(ret->keyblob, 0, ret->keyblob_size); sfree(ret->keyblob); } - memset(&ret, 0, sizeof(ret)); + memset(ret, 0, sizeof(*ret)); sfree(ret); } if (errmsg_p) *errmsg_p = errmsg; @@ -1152,7 +1198,7 @@ int sshcom_encrypted(const Filename *filename, char **comment) *comment = dupstr(key->comment); memset(key->keyblob, 0, key->keyblob_size); sfree(key->keyblob); - memset(&key, 0, sizeof(key)); + memset(key, 0, sizeof(*key)); sfree(key); return answer; } @@ -1427,7 +1473,7 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, } memset(key->keyblob, 0, key->keyblob_size); sfree(key->keyblob); - memset(&key, 0, sizeof(key)); + memset(key, 0, sizeof(*key)); sfree(key); if (errmsg_p) *errmsg_p = errmsg; return ret; @@ -1509,6 +1555,7 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}"; } else { assert(0); /* zoinks! */ + exit(1); /* XXX: GCC doesn't understand assert() on some systems. */ } /* @@ -1599,7 +1646,7 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, * And save it. We'll use Unix line endings just in case it's * subsequently transferred in binary mode. */ - fp = f_open(*filename, "wb"); /* ensure Unix line endings */ + fp = f_open(*filename, "wb", TRUE); /* ensure Unix line endings */ if (!fp) goto error; fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp);