X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=import.c;h=340785bdbd6000aead4857bd31dea4cad4aa5c02;hb=18f98bae214437264c6610ad56f57baef89be334;hp=6d3eaf41bc30daa3883e795bfd5ae6dfe3aec658;hpb=67202f798a9895ad773d1114b337e512c58afc7e;p=PuTTY.git diff --git a/import.c b/import.c index 6d3eaf41..340785bd 100644 --- a/import.c +++ b/import.c @@ -20,6 +20,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, struct ssh2_userkey *openssh_new_read(const Filename *filename, char *passphrase, const char **errmsg_p); +int openssh_auto_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase); int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, char *passphrase); int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, @@ -117,8 +119,8 @@ int export_ssh1(const Filename *filename, int type, struct RSAKey *key, int export_ssh2(const Filename *filename, int type, struct ssh2_userkey *key, char *passphrase) { - if (type == SSH_KEYTYPE_OPENSSH_PEM) - return openssh_pem_write(filename, key, passphrase); + if (type == SSH_KEYTYPE_OPENSSH_AUTO) + return openssh_auto_write(filename, key, passphrase); if (type == SSH_KEYTYPE_OPENSSH_NEW) return openssh_new_write(filename, key, passphrase); if (type == SSH_KEYTYPE_SSHCOM) @@ -193,14 +195,16 @@ static int ber_read_id_len(void *source, int sourcelen, return -1; if (*p & 0x80) { + unsigned len; int n = *p & 0x7F; p++, sourcelen--; if (sourcelen < n) return -1; - *length = 0; + len = 0; while (n--) - *length = (*length << 8) | (*p++); + len = (len << 8) | (*p++); sourcelen -= n; + *length = toint(len); } else { *length = *p; p++, sourcelen--; @@ -270,7 +274,15 @@ static int ber_write_id_len(void *dest, int id, int length, int flags) return len; } -static int put_string(void *target, void *data, int len) +static int put_uint32(void *target, unsigned val) +{ + unsigned char *d = (unsigned char *)target; + + PUT_32BIT(d, val); + return 4; +} + +static int put_string(void *target, const void *data, int len) { unsigned char *d = (unsigned char *)target; @@ -279,6 +291,11 @@ static int put_string(void *target, void *data, int len) return len+4; } +static int put_string_z(void *target, const char *string) +{ + return put_string(target, string, strlen(string)); +} + static int put_mp(void *target, void *data, int len) { unsigned char *d = (unsigned char *)target; @@ -347,7 +364,8 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, struct openssh_pem_key *ret; FILE *fp = NULL; char *line = NULL; - char *errmsg, *p; + const char *errmsg; + char *p; int headers_done; char base64_bit[4]; int base64_chars = 0; @@ -367,8 +385,8 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, goto error; } strip_crlf(line); - if (0 != strncmp(line, "-----BEGIN ", 11) || - 0 != strcmp(line+strlen(line)-16, "PRIVATE KEY-----")) { + if (!strstartswith(line, "-----BEGIN ") || + !strendswith(line, "PRIVATE KEY-----")) { errmsg = "file does not begin with OpenSSH key header"; goto error; } @@ -405,8 +423,8 @@ static struct openssh_pem_key *load_openssh_pem_key(const Filename *filename, goto error; } strip_crlf(line); - if (0 == strncmp(line, "-----END ", 9) && - 0 == strcmp(line+strlen(line)-16, "PRIVATE KEY-----")) { + if (strstartswith(line, "-----END ") && + strendswith(line, "PRIVATE KEY-----")) { sfree(line); line = NULL; break; /* done */ @@ -551,11 +569,11 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, { struct openssh_pem_key *key = load_openssh_pem_key(filename, errmsg_p); struct ssh2_userkey *retkey; - unsigned char *p; + unsigned char *p, *q; int ret, id, len, flags; int i, num_integers; struct ssh2_userkey *retval = NULL; - char *errmsg; + const char *errmsg; unsigned char *blob; int blobsize = 0, blobptr, privptr; char *modptr = NULL; @@ -641,7 +659,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, * decrypt, if the key was encrypted. */ ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags); p += ret; - if (ret < 0 || id != 16) { + if (ret < 0 || id != 16 || len < 0 || + key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; goto error; @@ -660,13 +679,15 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, /* And now for something completely different */ unsigned char *priv; int privlen; - struct ec_curve *curve; + const struct ssh_signkey *alg; + const struct ec_curve *curve; + int algnamelen, curvenamelen; /* Read INTEGER 1 */ ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, &id, &len, &flags); p += ret; - if (ret < 0 || id != 2 || key->keyblob+key->keyblob_len-p < len || - len != 1 || p[0] != 1) { + if (ret < 0 || id != 2 || len != 1 || + key->keyblob+key->keyblob_len-p < len || p[0] != 1) { errmsg = "ASN.1 decoding failure"; retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; goto error; @@ -676,7 +697,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, &id, &len, &flags); p += ret; - if (ret < 0 || id != 4 || key->keyblob+key->keyblob_len-p < len) { + if (ret < 0 || id != 4 || len < 0 || + key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; goto error; @@ -688,7 +710,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, &id, &len, &flags); p += ret; - if (ret < 0 || id != 0 || key->keyblob+key->keyblob_len-p < len) { + if (ret < 0 || id != 0 || len < 0 || + key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; goto error; @@ -696,20 +719,14 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, &id, &len, &flags); p += ret; - if (ret < 0 || id != 6 || key->keyblob+key->keyblob_len-p < len) { + if (ret < 0 || id != 6 || len < 0 || + key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; goto error; } - if (len == 8 && !memcmp(p, nistp256_oid, nistp256_oid_len)) { - curve = ec_p256(); - } else if (len == 5 && !memcmp(p, nistp384_oid, - nistp384_oid_len)) { - curve = ec_p384(); - } else if (len == 5 && !memcmp(p, nistp521_oid, - nistp521_oid_len)) { - curve = ec_p521(); - } else { + alg = ec_alg_by_oid(len, p, &curve); + if (!alg) { errmsg = "Unsupported ECDSA curve."; retval = NULL; goto error; @@ -719,7 +736,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, &id, &len, &flags); p += ret; - if (ret < 0 || id != 1 || key->keyblob+key->keyblob_len-p < len) { + if (ret < 0 || id != 1 || len < 0 || + key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; goto error; @@ -727,7 +745,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, &id, &len, &flags); p += ret; - if (ret < 0 || id != 3 || key->keyblob+key->keyblob_len-p < len || + if (ret < 0 || id != 3 || len < 0 || + key->keyblob+key->keyblob_len-p < len || len != ((((curve->fieldBits + 7) / 8) * 2) + 2)) { errmsg = "ASN.1 decoding failure"; retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; @@ -741,30 +760,42 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, errmsg = "out of memory"; goto error; } - if (curve->fieldBits == 256) { - retkey->alg = &ssh_ecdsa_nistp256; - } else if (curve->fieldBits == 384) { - retkey->alg = &ssh_ecdsa_nistp384; - } else { - retkey->alg = &ssh_ecdsa_nistp521; - } - blob = snewn((4+19 + 4+8 + 4+len) + (4+privlen), unsigned char); + retkey->alg = alg; + blob = snewn((4+19 + 4+8 + 4+len) + (4+1+privlen), unsigned char); if (!blob) { sfree(retkey); errmsg = "out of memory"; goto error; } - PUT_32BIT(blob, 19); - sprintf((char*)blob+4, "ecdsa-sha2-nistp%d", curve->fieldBits); - PUT_32BIT(blob+4+19, 8); - sprintf((char*)blob+4+19+4, "nistp%d", curve->fieldBits); - PUT_32BIT(blob+4+19+4+8, len); - memcpy(blob+4+19+4+8+4, p, len); - PUT_32BIT(blob+4+19+4+8+4+len, privlen); - memcpy(blob+4+19+4+8+4+len+4, priv, privlen); - retkey->data = retkey->alg->createkey(blob, 4+19+4+8+4+len, - blob+4+19+4+8+4+len, - 4+privlen); + + q = blob; + + algnamelen = strlen(alg->name); + PUT_32BIT(q, algnamelen); q += 4; + memcpy(q, alg->name, algnamelen); q += algnamelen; + + curvenamelen = strlen(curve->name); + PUT_32BIT(q, curvenamelen); q += 4; + memcpy(q, curve->name, curvenamelen); q += curvenamelen; + + PUT_32BIT(q, len); q += 4; + memcpy(q, p, len); q += len; + + /* + * To be acceptable to our createkey(), the private blob must + * contain a valid mpint, i.e. without the top bit set. But + * the input private string may have the top bit set, so we + * prefix a zero byte to ensure createkey() doesn't fail for + * that reason. + */ + PUT_32BIT(q, privlen+1); + q[4] = 0; + memcpy(q+5, priv, privlen); + + retkey->data = retkey->alg->createkey(retkey->alg, + blob, q-blob, + q, 5+privlen); + if (!retkey->data) { sfree(retkey); errmsg = "unable to create key data structure"; @@ -790,7 +821,7 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, &id, &len, &flags); p += ret; - if (ret < 0 || id != 2 || + if (ret < 0 || id != 2 || len < 0 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; retval = key->encrypted ? SSH2_WRONG_PASSPHRASE : NULL; @@ -852,7 +883,7 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, assert(privptr > 0); /* should have bombed by now if not */ retkey = snew(struct ssh2_userkey); retkey->alg = (key->keytype == OP_RSA ? &ssh_rsa : &ssh_dss); - retkey->data = retkey->alg->createkey(blob, privptr, + retkey->data = retkey->alg->createkey(retkey->alg, blob, privptr, blob+privptr, blobptr-privptr); if (!retkey->data) { @@ -863,6 +894,8 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename, } else { assert(0 && "Bad key type from load_openssh_pem_key"); + errmsg = "Bad key type from load_openssh_pem_key"; + goto error; } /* @@ -896,7 +929,7 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, int outlen; struct mpint_pos numbers[9]; int nnumbers, pos, len, seqlen, i; - char *header, *footer; + const char *header, *footer; char zero[1]; unsigned char iv[8]; int ret = 0; @@ -1043,7 +1076,7 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, } else if (key->alg == &ssh_ecdsa_nistp256 || key->alg == &ssh_ecdsa_nistp384 || key->alg == &ssh_ecdsa_nistp521) { - unsigned char *oid; + const unsigned char *oid; int oidlen; int pointlen; @@ -1057,28 +1090,9 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, * [1] * BIT STRING (0x00 public key point) */ - switch (((struct ec_key *)key->data)->publicKey.curve->fieldBits) { - case 256: - /* OID: 1.2.840.10045.3.1.7 (ansiX9p256r1) */ - oid = nistp256_oid; - oidlen = nistp256_oid_len; - pointlen = 32 * 2; - break; - case 384: - /* OID: 1.3.132.0.34 (secp384r1) */ - oid = nistp384_oid; - oidlen = nistp384_oid_len; - pointlen = 48 * 2; - break; - case 521: - /* OID: 1.3.132.0.35 (secp521r1) */ - oid = nistp521_oid; - oidlen = nistp521_oid_len; - pointlen = 66 * 2; - break; - default: - assert(0); - } + oid = ec_alg_oid(key->alg, &oidlen); + pointlen = (((struct ec_key *)key->data)->publicKey.curve->fieldBits + + 7) / 8 * 2; len = ber_write_id_len(NULL, 2, 1, 0); len += 1; @@ -1288,7 +1302,8 @@ static struct openssh_new_key *load_openssh_new_key(const Filename *filename, struct openssh_new_key *ret; FILE *fp = NULL; char *line = NULL; - char *errmsg, *p; + const char *errmsg; + char *p; char base64_bit[4]; int base64_chars = 0; const void *filedata; @@ -1531,7 +1546,7 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, struct ssh2_userkey *retkey; int i; struct ssh2_userkey *retval = NULL; - char *errmsg; + const char *errmsg; unsigned char *blob; int blobsize = 0; unsigned checkint0, checkint1; @@ -1615,8 +1630,8 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, retkey = NULL; for (key_index = 0; key_index < key->nkeys; key_index++) { - unsigned char *thiskey; - int thiskeylen, npieces; + const unsigned char *thiskey; + int thiskeylen; /* * Read the key type, which will tell us how to scan over @@ -1634,35 +1649,25 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, * of strings, so we just need to know how many of them to * skip over. (The numbers below exclude the key comment.) */ - if (match_ssh_id(stringlen, string, "ssh-rsa")) { - alg = &ssh_rsa; - npieces = 6; /* n,e,d,iqmp,q,p */ - } else if (match_ssh_id(stringlen, string, "ssh-dss")) { - alg = &ssh_dss; - npieces = 5; /* p,q,g,y,x */ - } else if (match_ssh_id(stringlen, string, - "ecdsa-sha2-nistp256")) { - alg = &ssh_ecdsa_nistp256; - npieces = 3; /* curve name, point, private exponent */ - } else if (match_ssh_id(stringlen, string, - "ecdsa-sha2-nistp384")) { - alg = &ssh_ecdsa_nistp384; - npieces = 3; /* curve name, point, private exponent */ - } else if (match_ssh_id(stringlen, string, - "ecdsa-sha2-nistp521")) { - alg = &ssh_ecdsa_nistp521; - npieces = 3; /* curve name, point, private exponent */ - } else { - errmsg = "private key did not start with type string\n"; + { + /* find_pubkey_alg needs a zero-terminated copy of the + * algorithm name */ + char *name_zt = dupprintf("%.*s", stringlen, (char *)string); + alg = find_pubkey_alg(name_zt); + sfree(name_zt); + } + + if (!alg) { + errmsg = "private key type not recognised\n"; goto error; } - thiskey = (unsigned char *)priv; + thiskey = priv; /* * Skip over the pieces of key. */ - for (i = 0; i < npieces; i++) { + for (i = 0; i < alg->openssh_private_npieces; i++) { if (!(string = get_ssh_string(&privlen, &priv, &stringlen))) { errmsg = "ran out of data in mid-private-key"; goto error; @@ -1674,7 +1679,7 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, if (key_index == key->key_wanted) { retkey = snew(struct ssh2_userkey); retkey->alg = alg; - retkey->data = alg->openssh_createkey(&thiskey, &thiskeylen); + retkey->data = alg->openssh_createkey(alg, &thiskey, &thiskeylen); if (!retkey->data) { sfree(retkey); errmsg = "unable to create key data structure"; @@ -1730,7 +1735,181 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename, int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, char *passphrase) { - return FALSE; + unsigned char *pubblob, *privblob, *outblob, *p; + unsigned char *private_section_start, *private_section_length_field; + int publen, privlen, commentlen, maxsize, padvalue, i; + unsigned checkint; + int ret = 0; + unsigned char bcrypt_salt[16]; + const int bcrypt_rounds = 16; + FILE *fp; + + /* + * Fetch the key blobs and find out the lengths of things. + */ + pubblob = key->alg->public_blob(key->data, &publen); + i = key->alg->openssh_fmtkey(key->data, NULL, 0); + privblob = snewn(i, unsigned char); + privlen = key->alg->openssh_fmtkey(key->data, privblob, i); + assert(privlen == i); + commentlen = strlen(key->comment); + + /* + * Allocate enough space for the full binary key format. No need + * to be absolutely precise here. + */ + maxsize = (16 + /* magic number */ + 32 + /* cipher name string */ + 32 + /* kdf name string */ + 64 + /* kdf options string */ + 4 + /* key count */ + 4+publen + /* public key string */ + 4 + /* string header for private section */ + 8 + /* checkint x 2 */ + 4+strlen(key->alg->name) + /* key type string */ + privlen + /* private blob */ + 4+commentlen + /* comment string */ + 16); /* padding at end of private section */ + outblob = snewn(maxsize, unsigned char); + + /* + * Construct the cleartext version of the blob. + */ + p = outblob; + + /* Magic number. */ + memcpy(p, "openssh-key-v1\0", 15); + p += 15; + + /* Cipher and kdf names, and kdf options. */ + if (!passphrase) { + memset(bcrypt_salt, 0, sizeof(bcrypt_salt)); /* prevent warnings */ + p += put_string_z(p, "none"); + p += put_string_z(p, "none"); + p += put_string_z(p, ""); + } else { + unsigned char *q; + for (i = 0; i < (int)sizeof(bcrypt_salt); i++) + bcrypt_salt[i] = random_byte(); + p += put_string_z(p, "aes256-cbc"); + p += put_string_z(p, "bcrypt"); + q = p; + p += 4; + p += put_string(p, bcrypt_salt, sizeof(bcrypt_salt)); + p += put_uint32(p, bcrypt_rounds); + PUT_32BIT_MSB_FIRST(q, (unsigned)(p - (q+4))); + } + + /* Number of keys. */ + p += put_uint32(p, 1); + + /* Public blob. */ + p += put_string(p, pubblob, publen); + + /* Begin private section. */ + private_section_length_field = p; + p += 4; + private_section_start = p; + + /* checkint. */ + checkint = 0; + for (i = 0; i < 4; i++) + checkint = (checkint << 8) + random_byte(); + p += put_uint32(p, checkint); + p += put_uint32(p, checkint); + + /* Private key. The main private blob goes inline, with no string + * wrapper. */ + p += put_string_z(p, key->alg->name); + memcpy(p, privblob, privlen); + p += privlen; + + /* Comment. */ + p += put_string_z(p, key->comment); + + /* Pad out the encrypted section. */ + padvalue = 1; + do { + *p++ = padvalue++; + } while ((p - private_section_start) & 15); + + assert(p - outblob < maxsize); + + /* Go back and fill in the length field for the private section. */ + PUT_32BIT_MSB_FIRST(private_section_length_field, + p - private_section_start); + + if (passphrase) { + /* + * Encrypt the private section. We need 48 bytes of key + * material: 32 bytes AES key + 16 bytes iv. + */ + unsigned char keybuf[48]; + void *ctx; + + openssh_bcrypt(passphrase, + bcrypt_salt, sizeof(bcrypt_salt), bcrypt_rounds, + keybuf, sizeof(keybuf)); + + ctx = aes_make_context(); + aes256_key(ctx, keybuf); + aes_iv(ctx, keybuf + 32); + aes_ssh2_encrypt_blk(ctx, private_section_start, + p - private_section_start); + aes_free_context(ctx); + + smemclr(keybuf, sizeof(keybuf)); + } + + /* + * And save it. We'll use Unix line endings just in case it's + * subsequently transferred in binary mode. + */ + fp = f_open(filename, "wb", TRUE); /* ensure Unix line endings */ + if (!fp) + goto error; + fputs("-----BEGIN OPENSSH PRIVATE KEY-----\n", fp); + base64_encode(fp, outblob, p - outblob, 64); + fputs("-----END OPENSSH PRIVATE KEY-----\n", fp); + fclose(fp); + ret = 1; + + error: + if (outblob) { + smemclr(outblob, maxsize); + sfree(outblob); + } + if (privblob) { + smemclr(privblob, privlen); + sfree(privblob); + } + if (pubblob) { + smemclr(pubblob, publen); + sfree(pubblob); + } + return ret; +} + +/* ---------------------------------------------------------------------- + * The switch function openssh_auto_write(), which chooses one of the + * concrete OpenSSH output formats based on the key type. + */ +int openssh_auto_write(const Filename *filename, struct ssh2_userkey *key, + char *passphrase) +{ + /* + * The old OpenSSH format supports a fixed list of key types. We + * assume that anything not in that fixed list is newer, and hence + * will use the new format. + */ + if (key->alg == &ssh_dss || + key->alg == &ssh_rsa || + key->alg == &ssh_ecdsa_nistp256 || + key->alg == &ssh_ecdsa_nistp384 || + key->alg == &ssh_ecdsa_nistp521) + return openssh_pem_write(filename, key, passphrase); + else + return openssh_new_write(filename, key, passphrase); } /* ---------------------------------------------------------------------- @@ -1822,7 +2001,8 @@ static struct sshcom_key *load_sshcom_key(const Filename *filename, FILE *fp; char *line = NULL; int hdrstart, len; - char *errmsg, *p; + const char *errmsg; + char *p; int headers_done; char base64_bit[4]; int base64_chars = 0; @@ -2067,7 +2247,7 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, const char **errmsg_p) { struct sshcom_key *key = load_sshcom_key(filename, errmsg_p); - char *errmsg; + const char *errmsg; int pos, len; const char prefix_rsa[] = "if-modn{sign{rsa"; const char prefix_dsa[] = "dl-modp{sign{dsa"; @@ -2278,7 +2458,7 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase, retkey = snew(struct ssh2_userkey); retkey->alg = alg; - retkey->data = alg->createkey(blob, publen, blob+publen, privlen); + retkey->data = alg->createkey(alg, blob, publen, blob+publen, privlen); if (!retkey->data) { sfree(retkey); errmsg = "unable to create key data structure"; @@ -2311,7 +2491,7 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, int outlen; struct mpint_pos numbers[6]; int nnumbers, initial_zero, pos, lenpos, i; - char *type; + const char *type; char *ciphertext; int cipherlen; int ret = 0; @@ -2407,7 +2587,7 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key, pos += 4; /* length field, fill in later */ pos += put_string(outblob+pos, type, strlen(type)); { - char *ciphertype = passphrase ? "3des-cbc" : "none"; + const char *ciphertype = passphrase ? "3des-cbc" : "none"; pos += put_string(outblob+pos, ciphertype, strlen(ciphertype)); } lenpos = pos; /* remember this position */