diff options
Diffstat (limited to 'sshkey.c')
-rw-r--r-- | sshkey.c | 299 |
1 files changed, 282 insertions, 17 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshkey.c,v 1.75 2019/05/20 00:20:35 djm Exp $ */ | 1 | /* $OpenBSD: sshkey.c,v 1.76 2019/06/21 04:21:05 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. | 4 | * Copyright (c) 2008 Alexander von Gernler. All rights reserved. |
@@ -78,7 +78,15 @@ | |||
78 | /* Version identification string for SSH v1 identity files. */ | 78 | /* Version identification string for SSH v1 identity files. */ |
79 | #define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n" | 79 | #define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n" |
80 | 80 | ||
81 | int sshkey_private_serialize_opt(const struct sshkey *key, | 81 | /* |
82 | * Constants relating to "shielding" support; protection of keys expected | ||
83 | * to remain in memory for long durations | ||
84 | */ | ||
85 | #define SSHKEY_SHIELD_PREKEY_LEN (16 * 1024) | ||
86 | #define SSHKEY_SHIELD_CIPHER "aes256-ctr" /* XXX want AES-EME* */ | ||
87 | #define SSHKEY_SHIELD_PREKEY_HASH SSH_DIGEST_SHA512 | ||
88 | |||
89 | int sshkey_private_serialize_opt(struct sshkey *key, | ||
82 | struct sshbuf *buf, enum sshkey_serialize_rep); | 90 | struct sshbuf *buf, enum sshkey_serialize_rep); |
83 | static int sshkey_from_blob_internal(struct sshbuf *buf, | 91 | static int sshkey_from_blob_internal(struct sshbuf *buf, |
84 | struct sshkey **keyp, int allow_cert); | 92 | struct sshkey **keyp, int allow_cert); |
@@ -604,6 +612,8 @@ sshkey_free(struct sshkey *k) | |||
604 | } | 612 | } |
605 | if (sshkey_is_cert(k)) | 613 | if (sshkey_is_cert(k)) |
606 | cert_free(k->cert); | 614 | cert_free(k->cert); |
615 | freezero(k->shielded_private, k->shielded_len); | ||
616 | freezero(k->shield_prekey, k->shield_prekey_len); | ||
607 | freezero(k, sizeof(*k)); | 617 | freezero(k, sizeof(*k)); |
608 | } | 618 | } |
609 | 619 | ||
@@ -1869,6 +1879,218 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp) | |||
1869 | return r; | 1879 | return r; |
1870 | } | 1880 | } |
1871 | 1881 | ||
1882 | int | ||
1883 | sshkey_is_shielded(struct sshkey *k) | ||
1884 | { | ||
1885 | return k != NULL && k->shielded_private != NULL; | ||
1886 | } | ||
1887 | |||
1888 | int | ||
1889 | sshkey_shield_private(struct sshkey *k) | ||
1890 | { | ||
1891 | struct sshbuf *prvbuf = NULL; | ||
1892 | u_char *prekey = NULL, *enc = NULL, keyiv[SSH_DIGEST_MAX_LENGTH]; | ||
1893 | struct sshcipher_ctx *cctx = NULL; | ||
1894 | const struct sshcipher *cipher; | ||
1895 | size_t i, enclen = 0; | ||
1896 | struct sshkey *kswap = NULL, tmp; | ||
1897 | int r = SSH_ERR_INTERNAL_ERROR; | ||
1898 | |||
1899 | #ifdef DEBUG_PK | ||
1900 | fprintf(stderr, "%s: entering for %s\n", __func__, sshkey_ssh_name(k)); | ||
1901 | #endif | ||
1902 | if ((cipher = cipher_by_name(SSHKEY_SHIELD_CIPHER)) == NULL) { | ||
1903 | r = SSH_ERR_INVALID_ARGUMENT; | ||
1904 | goto out; | ||
1905 | } | ||
1906 | if (cipher_keylen(cipher) + cipher_ivlen(cipher) > | ||
1907 | ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH)) { | ||
1908 | r = SSH_ERR_INTERNAL_ERROR; | ||
1909 | goto out; | ||
1910 | } | ||
1911 | |||
1912 | /* Prepare a random pre-key, and from it an ephemeral key */ | ||
1913 | if ((prekey = malloc(SSHKEY_SHIELD_PREKEY_LEN)) == NULL) { | ||
1914 | r = SSH_ERR_ALLOC_FAIL; | ||
1915 | goto out; | ||
1916 | } | ||
1917 | arc4random_buf(prekey, SSHKEY_SHIELD_PREKEY_LEN); | ||
1918 | if ((r = ssh_digest_memory(SSHKEY_SHIELD_PREKEY_HASH, | ||
1919 | prekey, SSHKEY_SHIELD_PREKEY_LEN, | ||
1920 | keyiv, SSH_DIGEST_MAX_LENGTH)) != 0) | ||
1921 | goto out; | ||
1922 | #ifdef DEBUG_PK | ||
1923 | fprintf(stderr, "%s: key+iv\n", __func__); | ||
1924 | sshbuf_dump_data(keyiv, ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH), | ||
1925 | stderr); | ||
1926 | #endif | ||
1927 | if ((r = cipher_init(&cctx, cipher, keyiv, cipher_keylen(cipher), | ||
1928 | keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 1)) != 0) | ||
1929 | goto out; | ||
1930 | |||
1931 | /* Serialise and encrypt the private key using the ephemeral key */ | ||
1932 | if ((prvbuf = sshbuf_new()) == NULL) { | ||
1933 | r = SSH_ERR_ALLOC_FAIL; | ||
1934 | goto out; | ||
1935 | } | ||
1936 | if (sshkey_is_shielded(k) && (r = sshkey_unshield_private(k)) != 0) | ||
1937 | goto out; | ||
1938 | if ((r = sshkey_private_serialize_opt(k, prvbuf, | ||
1939 | SSHKEY_SERIALIZE_FULL)) != 0) | ||
1940 | goto out; | ||
1941 | /* pad to cipher blocksize */ | ||
1942 | i = 0; | ||
1943 | while (sshbuf_len(prvbuf) % cipher_blocksize(cipher)) { | ||
1944 | if ((r = sshbuf_put_u8(prvbuf, ++i & 0xff)) != 0) | ||
1945 | goto out; | ||
1946 | } | ||
1947 | #ifdef DEBUG_PK | ||
1948 | fprintf(stderr, "%s: serialised\n", __func__); | ||
1949 | sshbuf_dump(prvbuf, stderr); | ||
1950 | #endif | ||
1951 | /* encrypt */ | ||
1952 | enclen = sshbuf_len(prvbuf); | ||
1953 | if ((enc = malloc(enclen)) == NULL) { | ||
1954 | r = SSH_ERR_ALLOC_FAIL; | ||
1955 | goto out; | ||
1956 | } | ||
1957 | if ((r = cipher_crypt(cctx, 0, enc, | ||
1958 | sshbuf_ptr(prvbuf), sshbuf_len(prvbuf), 0, 0)) != 0) | ||
1959 | goto out; | ||
1960 | #ifdef DEBUG_PK | ||
1961 | fprintf(stderr, "%s: encrypted\n", __func__); | ||
1962 | sshbuf_dump_data(enc, enclen, stderr); | ||
1963 | #endif | ||
1964 | |||
1965 | /* Make a scrubbed, public-only copy of our private key argument */ | ||
1966 | if ((r = sshkey_from_private(k, &kswap)) != 0) | ||
1967 | goto out; | ||
1968 | |||
1969 | /* Swap the private key out (it will be destroyed below) */ | ||
1970 | tmp = *kswap; | ||
1971 | *kswap = *k; | ||
1972 | *k = tmp; | ||
1973 | |||
1974 | /* Insert the shielded key into our argument */ | ||
1975 | k->shielded_private = enc; | ||
1976 | k->shielded_len = enclen; | ||
1977 | k->shield_prekey = prekey; | ||
1978 | k->shield_prekey_len = SSHKEY_SHIELD_PREKEY_LEN; | ||
1979 | enc = prekey = NULL; /* transferred */ | ||
1980 | enclen = 0; | ||
1981 | |||
1982 | /* success */ | ||
1983 | r = 0; | ||
1984 | |||
1985 | out: | ||
1986 | /* XXX behaviour on error - invalidate original private key? */ | ||
1987 | cipher_free(cctx); | ||
1988 | explicit_bzero(enc, enclen); | ||
1989 | explicit_bzero(keyiv, sizeof(keyiv)); | ||
1990 | explicit_bzero(&tmp, sizeof(tmp)); | ||
1991 | freezero(prekey, SSHKEY_SHIELD_PREKEY_LEN); | ||
1992 | sshkey_free(kswap); | ||
1993 | sshbuf_free(prvbuf); | ||
1994 | return r; | ||
1995 | } | ||
1996 | |||
1997 | int | ||
1998 | sshkey_unshield_private(struct sshkey *k) | ||
1999 | { | ||
2000 | struct sshbuf *prvbuf = NULL; | ||
2001 | u_char pad, *cp, keyiv[SSH_DIGEST_MAX_LENGTH]; | ||
2002 | struct sshcipher_ctx *cctx = NULL; | ||
2003 | const struct sshcipher *cipher; | ||
2004 | size_t i; | ||
2005 | struct sshkey *kswap = NULL, tmp; | ||
2006 | int r = SSH_ERR_INTERNAL_ERROR; | ||
2007 | |||
2008 | #ifdef DEBUG_PK | ||
2009 | fprintf(stderr, "%s: entering for %s\n", __func__, sshkey_ssh_name(k)); | ||
2010 | #endif | ||
2011 | if (!sshkey_is_shielded(k)) | ||
2012 | return 0; /* nothing to do */ | ||
2013 | |||
2014 | if ((cipher = cipher_by_name(SSHKEY_SHIELD_CIPHER)) == NULL) { | ||
2015 | r = SSH_ERR_INVALID_ARGUMENT; | ||
2016 | goto out; | ||
2017 | } | ||
2018 | if (cipher_keylen(cipher) + cipher_ivlen(cipher) > | ||
2019 | ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH)) { | ||
2020 | r = SSH_ERR_INTERNAL_ERROR; | ||
2021 | goto out; | ||
2022 | } | ||
2023 | /* check size of shielded key blob */ | ||
2024 | if (k->shielded_len < cipher_blocksize(cipher) || | ||
2025 | (k->shielded_len % cipher_blocksize(cipher)) != 0) { | ||
2026 | r = SSH_ERR_INVALID_FORMAT; | ||
2027 | goto out; | ||
2028 | } | ||
2029 | |||
2030 | /* Calculate the ephemeral key from the prekey */ | ||
2031 | if ((r = ssh_digest_memory(SSHKEY_SHIELD_PREKEY_HASH, | ||
2032 | k->shield_prekey, k->shield_prekey_len, | ||
2033 | keyiv, SSH_DIGEST_MAX_LENGTH)) != 0) | ||
2034 | goto out; | ||
2035 | if ((r = cipher_init(&cctx, cipher, keyiv, cipher_keylen(cipher), | ||
2036 | keyiv + cipher_keylen(cipher), cipher_ivlen(cipher), 0)) != 0) | ||
2037 | goto out; | ||
2038 | #ifdef DEBUG_PK | ||
2039 | fprintf(stderr, "%s: key+iv\n", __func__); | ||
2040 | sshbuf_dump_data(keyiv, ssh_digest_bytes(SSHKEY_SHIELD_PREKEY_HASH), | ||
2041 | stderr); | ||
2042 | #endif | ||
2043 | |||
2044 | /* Decrypt and parse the shielded private key using the ephemeral key */ | ||
2045 | if ((prvbuf = sshbuf_new()) == NULL) { | ||
2046 | r = SSH_ERR_ALLOC_FAIL; | ||
2047 | goto out; | ||
2048 | } | ||
2049 | if ((r = sshbuf_reserve(prvbuf, k->shielded_len, &cp)) != 0) | ||
2050 | goto out; | ||
2051 | /* decrypt */ | ||
2052 | #ifdef DEBUG_PK | ||
2053 | fprintf(stderr, "%s: encrypted\n", __func__); | ||
2054 | sshbuf_dump_data(k->shielded_private, k->shielded_len, stderr); | ||
2055 | #endif | ||
2056 | if ((r = cipher_crypt(cctx, 0, cp, | ||
2057 | k->shielded_private, k->shielded_len, 0, 0)) != 0) | ||
2058 | goto out; | ||
2059 | #ifdef DEBUG_PK | ||
2060 | fprintf(stderr, "%s: serialised\n", __func__); | ||
2061 | sshbuf_dump(prvbuf, stderr); | ||
2062 | #endif | ||
2063 | /* Parse private key */ | ||
2064 | if ((r = sshkey_private_deserialize(prvbuf, &kswap)) != 0) | ||
2065 | goto out; | ||
2066 | /* Check deterministic padding */ | ||
2067 | i = 0; | ||
2068 | while (sshbuf_len(prvbuf)) { | ||
2069 | if ((r = sshbuf_get_u8(prvbuf, &pad)) != 0) | ||
2070 | goto out; | ||
2071 | if (pad != (++i & 0xff)) { | ||
2072 | r = SSH_ERR_INVALID_FORMAT; | ||
2073 | goto out; | ||
2074 | } | ||
2075 | } | ||
2076 | |||
2077 | /* Swap the parsed key back into place */ | ||
2078 | tmp = *kswap; | ||
2079 | *kswap = *k; | ||
2080 | *k = tmp; | ||
2081 | |||
2082 | /* success */ | ||
2083 | r = 0; | ||
2084 | |||
2085 | out: | ||
2086 | cipher_free(cctx); | ||
2087 | explicit_bzero(keyiv, sizeof(keyiv)); | ||
2088 | explicit_bzero(&tmp, sizeof(tmp)); | ||
2089 | sshkey_free(kswap); | ||
2090 | sshbuf_free(prvbuf); | ||
2091 | return r; | ||
2092 | } | ||
2093 | |||
1872 | static int | 2094 | static int |
1873 | cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) | 2095 | cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) |
1874 | { | 2096 | { |
@@ -2373,41 +2595,55 @@ sshkey_check_sigtype(const u_char *sig, size_t siglen, | |||
2373 | } | 2595 | } |
2374 | 2596 | ||
2375 | int | 2597 | int |
2376 | sshkey_sign(const struct sshkey *key, | 2598 | sshkey_sign(struct sshkey *key, |
2377 | u_char **sigp, size_t *lenp, | 2599 | u_char **sigp, size_t *lenp, |
2378 | const u_char *data, size_t datalen, const char *alg, u_int compat) | 2600 | const u_char *data, size_t datalen, const char *alg, u_int compat) |
2379 | { | 2601 | { |
2602 | int was_shielded = sshkey_is_shielded(key); | ||
2603 | int r2, r = SSH_ERR_INTERNAL_ERROR; | ||
2604 | |||
2380 | if (sigp != NULL) | 2605 | if (sigp != NULL) |
2381 | *sigp = NULL; | 2606 | *sigp = NULL; |
2382 | if (lenp != NULL) | 2607 | if (lenp != NULL) |
2383 | *lenp = 0; | 2608 | *lenp = 0; |
2384 | if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) | 2609 | if (datalen > SSH_KEY_MAX_SIGN_DATA_SIZE) |
2385 | return SSH_ERR_INVALID_ARGUMENT; | 2610 | return SSH_ERR_INVALID_ARGUMENT; |
2611 | if ((r = sshkey_unshield_private(key)) != 0) | ||
2612 | return r; | ||
2386 | switch (key->type) { | 2613 | switch (key->type) { |
2387 | #ifdef WITH_OPENSSL | 2614 | #ifdef WITH_OPENSSL |
2388 | case KEY_DSA_CERT: | 2615 | case KEY_DSA_CERT: |
2389 | case KEY_DSA: | 2616 | case KEY_DSA: |
2390 | return ssh_dss_sign(key, sigp, lenp, data, datalen, compat); | 2617 | r = ssh_dss_sign(key, sigp, lenp, data, datalen, compat); |
2618 | break; | ||
2391 | # ifdef OPENSSL_HAS_ECC | 2619 | # ifdef OPENSSL_HAS_ECC |
2392 | case KEY_ECDSA_CERT: | 2620 | case KEY_ECDSA_CERT: |
2393 | case KEY_ECDSA: | 2621 | case KEY_ECDSA: |
2394 | return ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat); | 2622 | r = ssh_ecdsa_sign(key, sigp, lenp, data, datalen, compat); |
2623 | break; | ||
2395 | # endif /* OPENSSL_HAS_ECC */ | 2624 | # endif /* OPENSSL_HAS_ECC */ |
2396 | case KEY_RSA_CERT: | 2625 | case KEY_RSA_CERT: |
2397 | case KEY_RSA: | 2626 | case KEY_RSA: |
2398 | return ssh_rsa_sign(key, sigp, lenp, data, datalen, alg); | 2627 | r = ssh_rsa_sign(key, sigp, lenp, data, datalen, alg); |
2628 | break; | ||
2399 | #endif /* WITH_OPENSSL */ | 2629 | #endif /* WITH_OPENSSL */ |
2400 | case KEY_ED25519: | 2630 | case KEY_ED25519: |
2401 | case KEY_ED25519_CERT: | 2631 | case KEY_ED25519_CERT: |
2402 | return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat); | 2632 | r = ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat); |
2633 | break; | ||
2403 | #ifdef WITH_XMSS | 2634 | #ifdef WITH_XMSS |
2404 | case KEY_XMSS: | 2635 | case KEY_XMSS: |
2405 | case KEY_XMSS_CERT: | 2636 | case KEY_XMSS_CERT: |
2406 | return ssh_xmss_sign(key, sigp, lenp, data, datalen, compat); | 2637 | r = ssh_xmss_sign(key, sigp, lenp, data, datalen, compat); |
2638 | break; | ||
2407 | #endif /* WITH_XMSS */ | 2639 | #endif /* WITH_XMSS */ |
2408 | default: | 2640 | default: |
2409 | return SSH_ERR_KEY_TYPE_UNKNOWN; | 2641 | r = SSH_ERR_KEY_TYPE_UNKNOWN; |
2642 | break; | ||
2410 | } | 2643 | } |
2644 | if (was_shielded && (r2 = sshkey_shield_private(key)) != 0) | ||
2645 | return r2; | ||
2646 | return r; | ||
2411 | } | 2647 | } |
2412 | 2648 | ||
2413 | /* | 2649 | /* |
@@ -2652,7 +2888,7 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg, | |||
2652 | } | 2888 | } |
2653 | 2889 | ||
2654 | static int | 2890 | static int |
2655 | default_key_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, | 2891 | default_key_sign(struct sshkey *key, u_char **sigp, size_t *lenp, |
2656 | const u_char *data, size_t datalen, | 2892 | const u_char *data, size_t datalen, |
2657 | const char *alg, u_int compat, void *ctx) | 2893 | const char *alg, u_int compat, void *ctx) |
2658 | { | 2894 | { |
@@ -2762,15 +2998,21 @@ sshkey_format_cert_validity(const struct sshkey_cert *cert, char *s, size_t l) | |||
2762 | } | 2998 | } |
2763 | 2999 | ||
2764 | int | 3000 | int |
2765 | sshkey_private_serialize_opt(const struct sshkey *key, struct sshbuf *b, | 3001 | sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf, |
2766 | enum sshkey_serialize_rep opts) | 3002 | enum sshkey_serialize_rep opts) |
2767 | { | 3003 | { |
2768 | int r = SSH_ERR_INTERNAL_ERROR; | 3004 | int r = SSH_ERR_INTERNAL_ERROR; |
3005 | int was_shielded = sshkey_is_shielded(key); | ||
3006 | struct sshbuf *b = NULL; | ||
2769 | #ifdef WITH_OPENSSL | 3007 | #ifdef WITH_OPENSSL |
2770 | const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_iqmp, *rsa_p, *rsa_q; | 3008 | const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_iqmp, *rsa_p, *rsa_q; |
2771 | const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key, *dsa_priv_key; | 3009 | const BIGNUM *dsa_p, *dsa_q, *dsa_g, *dsa_pub_key, *dsa_priv_key; |
2772 | #endif /* WITH_OPENSSL */ | 3010 | #endif /* WITH_OPENSSL */ |
2773 | 3011 | ||
3012 | if ((r = sshkey_unshield_private(key)) != 0) | ||
3013 | return r; | ||
3014 | if ((b = sshbuf_new()) == NULL) | ||
3015 | return SSH_ERR_ALLOC_FAIL; | ||
2774 | if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0) | 3016 | if ((r = sshbuf_put_cstring(b, sshkey_ssh_name(key))) != 0) |
2775 | goto out; | 3017 | goto out; |
2776 | switch (key->type) { | 3018 | switch (key->type) { |
@@ -2896,14 +3138,23 @@ sshkey_private_serialize_opt(const struct sshkey *key, struct sshbuf *b, | |||
2896 | r = SSH_ERR_INVALID_ARGUMENT; | 3138 | r = SSH_ERR_INVALID_ARGUMENT; |
2897 | goto out; | 3139 | goto out; |
2898 | } | 3140 | } |
2899 | /* success */ | 3141 | /* |
3142 | * success (but we still need to append the output to buf after | ||
3143 | * possibly re-shielding the private key) | ||
3144 | */ | ||
2900 | r = 0; | 3145 | r = 0; |
2901 | out: | 3146 | out: |
3147 | if (was_shielded) | ||
3148 | r = sshkey_shield_private(key); | ||
3149 | if (r == 0) | ||
3150 | r = sshbuf_putb(buf, b); | ||
3151 | sshbuf_free(b); | ||
3152 | |||
2902 | return r; | 3153 | return r; |
2903 | } | 3154 | } |
2904 | 3155 | ||
2905 | int | 3156 | int |
2906 | sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b) | 3157 | sshkey_private_serialize(struct sshkey *key, struct sshbuf *b) |
2907 | { | 3158 | { |
2908 | return sshkey_private_serialize_opt(key, b, | 3159 | return sshkey_private_serialize_opt(key, b, |
2909 | SSHKEY_SERIALIZE_DEFAULT); | 3160 | SSHKEY_SERIALIZE_DEFAULT); |
@@ -3358,7 +3609,7 @@ sshkey_dump_ec_key(const EC_KEY *key) | |||
3358 | #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ | 3609 | #endif /* WITH_OPENSSL && OPENSSL_HAS_ECC */ |
3359 | 3610 | ||
3360 | static int | 3611 | static int |
3361 | sshkey_private_to_blob2(const struct sshkey *prv, struct sshbuf *blob, | 3612 | sshkey_private_to_blob2(struct sshkey *prv, struct sshbuf *blob, |
3362 | const char *passphrase, const char *comment, const char *ciphername, | 3613 | const char *passphrase, const char *comment, const char *ciphername, |
3363 | int rounds) | 3614 | int rounds) |
3364 | { | 3615 | { |
@@ -3728,20 +3979,28 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, | |||
3728 | #ifdef WITH_OPENSSL | 3979 | #ifdef WITH_OPENSSL |
3729 | /* convert SSH v2 key in OpenSSL PEM format */ | 3980 | /* convert SSH v2 key in OpenSSL PEM format */ |
3730 | static int | 3981 | static int |
3731 | sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *blob, | 3982 | sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *buf, |
3732 | const char *_passphrase, const char *comment) | 3983 | const char *_passphrase, const char *comment) |
3733 | { | 3984 | { |
3985 | int was_shielded = sshkey_is_shielded(key); | ||
3734 | int success, r; | 3986 | int success, r; |
3735 | int blen, len = strlen(_passphrase); | 3987 | int blen, len = strlen(_passphrase); |
3736 | u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; | 3988 | u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; |
3737 | const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; | 3989 | const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; |
3738 | char *bptr; | 3990 | char *bptr; |
3739 | BIO *bio = NULL; | 3991 | BIO *bio = NULL; |
3992 | struct sshbuf *blob; | ||
3740 | 3993 | ||
3741 | if (len > 0 && len <= 4) | 3994 | if (len > 0 && len <= 4) |
3742 | return SSH_ERR_PASSPHRASE_TOO_SHORT; | 3995 | return SSH_ERR_PASSPHRASE_TOO_SHORT; |
3743 | if ((bio = BIO_new(BIO_s_mem())) == NULL) | 3996 | if ((blob = sshbuf_new()) == NULL) |
3744 | return SSH_ERR_ALLOC_FAIL; | 3997 | return SSH_ERR_ALLOC_FAIL; |
3998 | if ((bio = BIO_new(BIO_s_mem())) == NULL) { | ||
3999 | sshbuf_free(blob); | ||
4000 | return SSH_ERR_ALLOC_FAIL; | ||
4001 | } | ||
4002 | if ((r = sshkey_unshield_private(key)) != 0) | ||
4003 | goto out; | ||
3745 | 4004 | ||
3746 | switch (key->type) { | 4005 | switch (key->type) { |
3747 | case KEY_DSA: | 4006 | case KEY_DSA: |
@@ -3774,6 +4033,12 @@ sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *blob, | |||
3774 | goto out; | 4033 | goto out; |
3775 | r = 0; | 4034 | r = 0; |
3776 | out: | 4035 | out: |
4036 | if (was_shielded) | ||
4037 | r = sshkey_shield_private(key); | ||
4038 | if (r == 0) | ||
4039 | r = sshbuf_putb(buf, blob); | ||
4040 | sshbuf_free(blob); | ||
4041 | |||
3777 | BIO_free(bio); | 4042 | BIO_free(bio); |
3778 | return r; | 4043 | return r; |
3779 | } | 4044 | } |
@@ -4102,7 +4367,7 @@ sshkey_set_filename(struct sshkey *k, const char *filename) | |||
4102 | } | 4367 | } |
4103 | #else | 4368 | #else |
4104 | int | 4369 | int |
4105 | sshkey_private_serialize_maxsign(const struct sshkey *k, struct sshbuf *b, | 4370 | sshkey_private_serialize_maxsign(struct sshkey *k, struct sshbuf *b, |
4106 | u_int32_t maxsign, sshkey_printfn *pr) | 4371 | u_int32_t maxsign, sshkey_printfn *pr) |
4107 | { | 4372 | { |
4108 | return sshkey_private_serialize_opt(k, b, SSHKEY_SERIALIZE_DEFAULT); | 4373 | return sshkey_private_serialize_opt(k, b, SSHKEY_SERIALIZE_DEFAULT); |