diff options
Diffstat (limited to 'sshpubk.c')
-rw-r--r-- | sshpubk.c | 207 |
1 files changed, 100 insertions, 107 deletions
@@ -199,8 +199,7 @@ static int rsa1_load_s_internal(BinarySource *src, RSAKey *key, bool pub_only, if (enclen & 7) goto end; - buf = strbuf_new_nm(); - put_datapl(buf, get_data(src, enclen)); + buf = strbuf_dup_nm(get_data(src, enclen)); unsigned char keybuf[16]; hash_simple(&ssh_md5, ptrlen_from_asciz(passphrase), keybuf); @@ -563,12 +562,20 @@ const ssh_keyalg *const all_keyalgs[] = { &ssh_rsa, &ssh_rsa_sha256, &ssh_rsa_sha512, - &ssh_dss, + &ssh_dsa, &ssh_ecdsa_nistp256, &ssh_ecdsa_nistp384, &ssh_ecdsa_nistp521, &ssh_ecdsa_ed25519, &ssh_ecdsa_ed448, + &opensshcert_ssh_dsa, + &opensshcert_ssh_rsa, + &opensshcert_ssh_rsa_sha256, + &opensshcert_ssh_rsa_sha512, + &opensshcert_ssh_ecdsa_ed25519, + &opensshcert_ssh_ecdsa_nistp256, + &opensshcert_ssh_ecdsa_nistp384, + &opensshcert_ssh_ecdsa_nistp521, }; const size_t n_keyalgs = lenof(all_keyalgs); @@ -586,6 +593,18 @@ const ssh_keyalg *find_pubkey_alg(const char *name) return find_pubkey_alg_len(ptrlen_from_asciz(name)); } +ptrlen pubkey_blob_to_alg_name(ptrlen blob) +{ + BinarySource src[1]; + BinarySource_BARE_INIT_PL(src, blob); + return get_string(src); +} + +const ssh_keyalg *pubkey_blob_to_alg(ptrlen blob) +{ + return find_pubkey_alg_len(pubkey_blob_to_alg_name(blob)); +} + struct ppk_cipher { const char *name; size_t blocklen, keylen, ivlen; @@ -1226,7 +1245,7 @@ bool ppk_loadpub_s(BinarySource *src, char **algorithm, BinarySink *bs, bool ret = openssh_loadpub(src, algorithm, bs, commentptr, errorstr); return ret; } else if (type != SSH_KEYTYPE_SSH2) { - error = "not a PuTTY SSH-2 private key"; + error = "not a public key or a PuTTY SSH-2 private key"; goto error; } @@ -1238,7 +1257,7 @@ bool ppk_loadpub_s(BinarySource *src, char **algorithm, BinarySink *bs, if (0 == strncmp(header, "PuTTY-User-Key-File-", 20)) error = "PuTTY key format too new"; else - error = "not a PuTTY SSH-2 private key"; + error = "not a public key or a PuTTY SSH-2 private key"; goto error; } error = "file format error"; @@ -1380,37 +1399,6 @@ int base64_lines(int datalen) return (datalen + 47) / 48; } -static void base64_encode_s(BinarySink *bs, const unsigned char *data, - int datalen, int cpl) -{ - int linelen = 0; - char out[4]; - int n, i; - - while (datalen > 0) { - n = (datalen < 3 ? datalen : 3); - base64_encode_atom(data, n, out); - data += n; - datalen -= n; - for (i = 0; i < 4; i++) { - if (linelen >= cpl) { - linelen = 0; - put_byte(bs, '\n'); - } - put_byte(bs, out[i]); - linelen++; - } - } - put_byte(bs, '\n'); -} - -void base64_encode(FILE *fp, const unsigned char *data, int datalen, int cpl) -{ - stdio_sink ss; - stdio_sink_init(&ss, fp); - base64_encode_s(BinarySink_UPCAST(&ss), data, datalen, cpl); -} - const ppk_save_parameters ppk_save_default_parameters = { .fmt_version = 3, @@ -1550,33 +1538,33 @@ strbuf *ppk_save_sb(ssh2_userkey *key, const char *passphrase, } strbuf *out = strbuf_new_nm(); - strbuf_catf(out, "PuTTY-User-Key-File-%u: %s\n", - params.fmt_version, ssh_key_ssh_id(key->key)); - strbuf_catf(out, "Encryption: %s\n", cipherstr); - strbuf_catf(out, "Comment: %s\n", key->comment); - strbuf_catf(out, "Public-Lines: %d\n", base64_lines(pub_blob->len)); - base64_encode_s(BinarySink_UPCAST(out), pub_blob->u, pub_blob->len, 64); + put_fmt(out, "PuTTY-User-Key-File-%u: %s\n", + params.fmt_version, ssh_key_ssh_id(key->key)); + put_fmt(out, "Encryption: %s\n", cipherstr); + put_fmt(out, "Comment: %s\n", key->comment); + put_fmt(out, "Public-Lines: %d\n", base64_lines(pub_blob->len)); + base64_encode_bs(BinarySink_UPCAST(out), ptrlen_from_strbuf(pub_blob), 64); if (params.fmt_version == 3 && ciphertype->keylen != 0) { - strbuf_catf(out, "Key-Derivation: %s\n", - params.argon2_flavour == Argon2d ? "Argon2d" : - params.argon2_flavour == Argon2i ? "Argon2i" : "Argon2id"); - strbuf_catf(out, "Argon2-Memory: %"PRIu32"\n", params.argon2_mem); + put_fmt(out, "Key-Derivation: %s\n", + params.argon2_flavour == Argon2d ? "Argon2d" : + params.argon2_flavour == Argon2i ? "Argon2i" : "Argon2id"); + put_fmt(out, "Argon2-Memory: %"PRIu32"\n", params.argon2_mem); assert(!params.argon2_passes_auto); - strbuf_catf(out, "Argon2-Passes: %"PRIu32"\n", params.argon2_passes); - strbuf_catf(out, "Argon2-Parallelism: %"PRIu32"\n", - params.argon2_parallelism); - strbuf_catf(out, "Argon2-Salt: "); + put_fmt(out, "Argon2-Passes: %"PRIu32"\n", params.argon2_passes); + put_fmt(out, "Argon2-Parallelism: %"PRIu32"\n", + params.argon2_parallelism); + put_fmt(out, "Argon2-Salt: "); for (size_t i = 0; i < passphrase_salt->len; i++) - strbuf_catf(out, "%02x", passphrase_salt->u[i]); - strbuf_catf(out, "\n"); + put_fmt(out, "%02x", passphrase_salt->u[i]); + put_fmt(out, "\n"); } - strbuf_catf(out, "Private-Lines: %d\n", base64_lines(priv_encrypted_len)); - base64_encode_s(BinarySink_UPCAST(out), - priv_blob_encrypted, priv_encrypted_len, 64); - strbuf_catf(out, "Private-MAC: "); + put_fmt(out, "Private-Lines: %d\n", base64_lines(priv_encrypted_len)); + base64_encode_bs(BinarySink_UPCAST(out), + make_ptrlen(priv_blob_encrypted, priv_encrypted_len), 64); + put_fmt(out, "Private-MAC: "); for (i = 0; i < macalg->len; i++) - strbuf_catf(out, "%02x", priv_mac[i]); - strbuf_catf(out, "\n"); + put_fmt(out, "%02x", priv_mac[i]); + put_fmt(out, "\n"); strbuf_free(cipher_mac_keys_blob); strbuf_free(passphrase_salt); @@ -1740,7 +1728,7 @@ static void ssh2_fingerprint_blob_md5(ptrlen blob, strbuf *sb) hash_simple(&ssh_md5, blob, digest); for (unsigned i = 0; i < 16; i++) - strbuf_catf(sb, "%02x%s", digest[i], i==15 ? "" : ":"); + put_fmt(sb, "%02x%s", digest[i], i==15 ? "" : ":"); } static void ssh2_fingerprint_blob_sha256(ptrlen blob, strbuf *sb) @@ -1764,6 +1752,7 @@ static void ssh2_fingerprint_blob_sha256(ptrlen blob, strbuf *sb) char *ssh2_fingerprint_blob(ptrlen blob, FingerprintType fptype) { strbuf *sb = strbuf_new(); + strbuf *tmp = NULL; /* * Identify the key algorithm, if possible. @@ -1778,24 +1767,63 @@ char *ssh2_fingerprint_blob(ptrlen blob, FingerprintType fptype) const ssh_keyalg *alg = find_pubkey_alg_len(algname); if (alg) { int bits = ssh_key_public_bits(alg, blob); - strbuf_catf(sb, "%.*s %d ", PTRLEN_PRINTF(algname), bits); + put_fmt(sb, "%.*s %d ", PTRLEN_PRINTF(algname), bits); + + if (!ssh_fptype_is_cert(fptype) && alg->is_certificate) { + ssh_key *key = ssh_key_new_pub(alg, blob); + if (key) { + tmp = strbuf_new(); + ssh_key_public_blob(ssh_key_base_key(key), + BinarySink_UPCAST(tmp)); + blob = ptrlen_from_strbuf(tmp); + ssh_key_free(key); + } + } } else { - strbuf_catf(sb, "%.*s ", PTRLEN_PRINTF(algname)); + put_fmt(sb, "%.*s ", PTRLEN_PRINTF(algname)); } } - switch (fptype) { + switch (ssh_fptype_from_cert(fptype)) { case SSH_FPTYPE_MD5: ssh2_fingerprint_blob_md5(blob, sb); break; case SSH_FPTYPE_SHA256: ssh2_fingerprint_blob_sha256(blob, sb); break; + default: + unreachable("ssh_fptype_from_cert ruled out the other values"); } + if (tmp) + strbuf_free(tmp); + return strbuf_to_str(sb); } +char *ssh2_double_fingerprint_blob(ptrlen blob, FingerprintType fptype) +{ + if (ssh_fptype_is_cert(fptype)) + fptype = ssh_fptype_from_cert(fptype); + + char *fp = ssh2_fingerprint_blob(blob, fptype); + char *p = strrchr(fp, ' '); + char *hash = p ? p + 1 : fp; + + char *fpc = ssh2_fingerprint_blob(blob, ssh_fptype_to_cert(fptype)); + char *pc = strrchr(fpc, ' '); + char *hashc = pc ? pc + 1 : fpc; + + if (strcmp(hash, hashc)) { + char *tmp = dupprintf("%s (with certificate: %s)", fp, hashc); + sfree(fp); + fp = tmp; + } + + sfree(fpc); + return fp; +} + char **ssh2_all_fingerprints_for_blob(ptrlen blob) { char **fps = snewn(SSH_N_FPTYPES, char *); @@ -1813,6 +1841,15 @@ char *ssh2_fingerprint(ssh_key *data, FingerprintType fptype) return ret; } +char *ssh2_double_fingerprint(ssh_key *data, FingerprintType fptype) +{ + strbuf *blob = strbuf_new(); + ssh_key_public_blob(data, BinarySink_UPCAST(blob)); + char *ret = ssh2_double_fingerprint_blob(ptrlen_from_strbuf(blob), fptype); + strbuf_free(blob); + return ret; +} + char **ssh2_all_fingerprints(ssh_key *data) { strbuf *blob = strbuf_new(); @@ -1869,7 +1906,7 @@ static int key_type_s_internal(BinarySource *src) if (find_pubkey_alg_len(get_nonchars(src, " \n")) > 0 && get_chars(src, " ").len == 1 && get_chars(src, "0123456789ABCDEFGHIJKLMNOPQRSTUV" - "WXYZabcdefghijklmnopqrstuvwxyz+/=").len > 0 && + "WXYZabcdefghijklmnopqrstuvwxyz+/=").len > 0 && get_nonchars(src, " \n").len == 0) return SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH; @@ -1936,47 +1973,3 @@ const char *key_type_to_str(int type) unreachable("bad key type in key_type_to_str"); } } - -key_components *key_components_new(void) -{ - key_components *kc = snew(key_components); - kc->ncomponents = 0; - kc->componentsize = 0; - kc->components = NULL; - return kc; -} - -void key_components_add_text(key_components *kc, - const char *name, const char *value) -{ - sgrowarray(kc->components, kc->componentsize, kc->ncomponents); - size_t n = kc->ncomponents++; - kc->components[n].name = dupstr(name); - kc->components[n].is_mp_int = false; - kc->components[n].text = dupstr(value); -} - -void key_components_add_mp(key_components *kc, - const char *name, mp_int *value) -{ - sgrowarray(kc->components, kc->componentsize, kc->ncomponents); - size_t n = kc->ncomponents++; - kc->components[n].name = dupstr(name); - kc->components[n].is_mp_int = true; - kc->components[n].mp = mp_copy(value); -} - -void key_components_free(key_components *kc) -{ - for (size_t i = 0; i < kc->ncomponents; i++) { - sfree(kc->components[i].name); - if (kc->components[i].is_mp_int) { - mp_free(kc->components[i].mp); - } else { - smemclr(kc->components[i].text, strlen(kc->components[i].text)); - sfree(kc->components[i].text); - } - } - sfree(kc->components); - sfree(kc); -} |