diff options
author | djm@openbsd.org <djm@openbsd.org> | 2019-07-15 13:16:29 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2019-07-15 23:21:18 +1000 |
commit | eb0d8e708a1f958aecd2d6e2ff2450af488d4c2a (patch) | |
tree | c5b7686e1e200aac6f3a742c7b15ed30a2c05067 /sshkey.c | |
parent | e18a27eedccb024acb3cd9820b650a5dff323f01 (diff) |
upstream: support PKCS8 as an optional format for storage of
private keys, enabled via "ssh-keygen -m PKCS8" on operations that save
private keys to disk.
The OpenSSH native key format remains the default, but PKCS8 is a
superior format to PEM if interoperability with non-OpenSSH software
is required, as it may use a less terrible KDF (IIRC PEM uses a single
round of MD5 as a KDF).
adapted from patch by Jakub Jelen via bz3013; ok markus
OpenBSD-Commit-ID: 027824e3bc0b1c243dc5188504526d73a55accb1
Diffstat (limited to 'sshkey.c')
-rw-r--r-- | sshkey.c | 78 |
1 files changed, 56 insertions, 22 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshkey.c,v 1.79 2019/07/07 01:05:00 dtucker Exp $ */ | 1 | /* $OpenBSD: sshkey.c,v 1.80 2019/07/15 13:16:29 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. |
@@ -3975,10 +3975,10 @@ sshkey_parse_private2(struct sshbuf *blob, int type, const char *passphrase, | |||
3975 | 3975 | ||
3976 | 3976 | ||
3977 | #ifdef WITH_OPENSSL | 3977 | #ifdef WITH_OPENSSL |
3978 | /* convert SSH v2 key in OpenSSL PEM format */ | 3978 | /* convert SSH v2 key to PEM or PKCS#8 format */ |
3979 | static int | 3979 | static int |
3980 | sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *buf, | 3980 | sshkey_private_to_blob_pem_pkcs8(struct sshkey *key, struct sshbuf *buf, |
3981 | const char *_passphrase, const char *comment) | 3981 | int format, const char *_passphrase, const char *comment) |
3982 | { | 3982 | { |
3983 | int was_shielded = sshkey_is_shielded(key); | 3983 | int was_shielded = sshkey_is_shielded(key); |
3984 | int success, r; | 3984 | int success, r; |
@@ -3988,32 +3988,49 @@ sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *buf, | |||
3988 | char *bptr; | 3988 | char *bptr; |
3989 | BIO *bio = NULL; | 3989 | BIO *bio = NULL; |
3990 | struct sshbuf *blob; | 3990 | struct sshbuf *blob; |
3991 | EVP_PKEY *pkey = NULL; | ||
3991 | 3992 | ||
3992 | if (len > 0 && len <= 4) | 3993 | if (len > 0 && len <= 4) |
3993 | return SSH_ERR_PASSPHRASE_TOO_SHORT; | 3994 | return SSH_ERR_PASSPHRASE_TOO_SHORT; |
3994 | if ((blob = sshbuf_new()) == NULL) | 3995 | if ((blob = sshbuf_new()) == NULL) |
3995 | return SSH_ERR_ALLOC_FAIL; | 3996 | return SSH_ERR_ALLOC_FAIL; |
3996 | if ((bio = BIO_new(BIO_s_mem())) == NULL) { | 3997 | if ((bio = BIO_new(BIO_s_mem())) == NULL) { |
3997 | sshbuf_free(blob); | 3998 | r = SSH_ERR_ALLOC_FAIL; |
3998 | return SSH_ERR_ALLOC_FAIL; | 3999 | goto out; |
3999 | } | 4000 | } |
4001 | if (format == SSHKEY_PRIVATE_PKCS8 && (pkey = EVP_PKEY_new()) == NULL) { | ||
4002 | r = SSH_ERR_ALLOC_FAIL; | ||
4003 | goto out; | ||
4004 | } | ||
4000 | if ((r = sshkey_unshield_private(key)) != 0) | 4005 | if ((r = sshkey_unshield_private(key)) != 0) |
4001 | goto out; | 4006 | goto out; |
4002 | 4007 | ||
4003 | switch (key->type) { | 4008 | switch (key->type) { |
4004 | case KEY_DSA: | 4009 | case KEY_DSA: |
4005 | success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, | 4010 | if (format == SSHKEY_PRIVATE_PEM) { |
4006 | cipher, passphrase, len, NULL, NULL); | 4011 | success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, |
4012 | cipher, passphrase, len, NULL, NULL); | ||
4013 | } else { | ||
4014 | success = EVP_PKEY_set1_DSA(pkey, key->dsa); | ||
4015 | } | ||
4007 | break; | 4016 | break; |
4008 | #ifdef OPENSSL_HAS_ECC | 4017 | #ifdef OPENSSL_HAS_ECC |
4009 | case KEY_ECDSA: | 4018 | case KEY_ECDSA: |
4010 | success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, | 4019 | if (format == SSHKEY_PRIVATE_PEM) { |
4011 | cipher, passphrase, len, NULL, NULL); | 4020 | success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, |
4021 | cipher, passphrase, len, NULL, NULL); | ||
4022 | } else { | ||
4023 | success = EVP_PKEY_set1_EC_KEY(pkey, key->ecdsa); | ||
4024 | } | ||
4012 | break; | 4025 | break; |
4013 | #endif | 4026 | #endif |
4014 | case KEY_RSA: | 4027 | case KEY_RSA: |
4015 | success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, | 4028 | if (format == SSHKEY_PRIVATE_PEM) { |
4016 | cipher, passphrase, len, NULL, NULL); | 4029 | success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, |
4030 | cipher, passphrase, len, NULL, NULL); | ||
4031 | } else { | ||
4032 | success = EVP_PKEY_set1_RSA(pkey, key->rsa); | ||
4033 | } | ||
4017 | break; | 4034 | break; |
4018 | default: | 4035 | default: |
4019 | success = 0; | 4036 | success = 0; |
@@ -4023,6 +4040,13 @@ sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *buf, | |||
4023 | r = SSH_ERR_LIBCRYPTO_ERROR; | 4040 | r = SSH_ERR_LIBCRYPTO_ERROR; |
4024 | goto out; | 4041 | goto out; |
4025 | } | 4042 | } |
4043 | if (format == SSHKEY_PRIVATE_PKCS8) { | ||
4044 | if ((success = PEM_write_bio_PrivateKey(bio, pkey, cipher, | ||
4045 | passphrase, len, NULL, NULL)) == 0) { | ||
4046 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
4047 | goto out; | ||
4048 | } | ||
4049 | } | ||
4026 | if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) { | 4050 | if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) { |
4027 | r = SSH_ERR_INTERNAL_ERROR; | 4051 | r = SSH_ERR_INTERNAL_ERROR; |
4028 | goto out; | 4052 | goto out; |
@@ -4035,8 +4059,9 @@ sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *buf, | |||
4035 | r = sshkey_shield_private(key); | 4059 | r = sshkey_shield_private(key); |
4036 | if (r == 0) | 4060 | if (r == 0) |
4037 | r = sshbuf_putb(buf, blob); | 4061 | r = sshbuf_putb(buf, blob); |
4038 | sshbuf_free(blob); | ||
4039 | 4062 | ||
4063 | EVP_PKEY_free(pkey); | ||
4064 | sshbuf_free(blob); | ||
4040 | BIO_free(bio); | 4065 | BIO_free(bio); |
4041 | return r; | 4066 | return r; |
4042 | } | 4067 | } |
@@ -4046,29 +4071,38 @@ sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *buf, | |||
4046 | int | 4071 | int |
4047 | sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob, | 4072 | sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob, |
4048 | const char *passphrase, const char *comment, | 4073 | const char *passphrase, const char *comment, |
4049 | int force_new_format, const char *new_format_cipher, int new_format_rounds) | 4074 | int format, const char *openssh_format_cipher, int openssh_format_rounds) |
4050 | { | 4075 | { |
4051 | switch (key->type) { | 4076 | switch (key->type) { |
4052 | #ifdef WITH_OPENSSL | 4077 | #ifdef WITH_OPENSSL |
4053 | case KEY_DSA: | 4078 | case KEY_DSA: |
4054 | case KEY_ECDSA: | 4079 | case KEY_ECDSA: |
4055 | case KEY_RSA: | 4080 | case KEY_RSA: |
4056 | if (force_new_format) { | 4081 | break; /* see below */ |
4057 | return sshkey_private_to_blob2(key, blob, passphrase, | ||
4058 | comment, new_format_cipher, new_format_rounds); | ||
4059 | } | ||
4060 | return sshkey_private_pem_to_blob(key, blob, | ||
4061 | passphrase, comment); | ||
4062 | #endif /* WITH_OPENSSL */ | 4082 | #endif /* WITH_OPENSSL */ |
4063 | case KEY_ED25519: | 4083 | case KEY_ED25519: |
4064 | #ifdef WITH_XMSS | 4084 | #ifdef WITH_XMSS |
4065 | case KEY_XMSS: | 4085 | case KEY_XMSS: |
4066 | #endif /* WITH_XMSS */ | 4086 | #endif /* WITH_XMSS */ |
4067 | return sshkey_private_to_blob2(key, blob, passphrase, | 4087 | return sshkey_private_to_blob2(key, blob, passphrase, |
4068 | comment, new_format_cipher, new_format_rounds); | 4088 | comment, openssh_format_cipher, openssh_format_rounds); |
4069 | default: | 4089 | default: |
4070 | return SSH_ERR_KEY_TYPE_UNKNOWN; | 4090 | return SSH_ERR_KEY_TYPE_UNKNOWN; |
4071 | } | 4091 | } |
4092 | |||
4093 | #ifdef WITH_OPENSSL | ||
4094 | switch (format) { | ||
4095 | case SSHKEY_PRIVATE_OPENSSH: | ||
4096 | return sshkey_private_to_blob2(key, blob, passphrase, | ||
4097 | comment, openssh_format_cipher, openssh_format_rounds); | ||
4098 | case SSHKEY_PRIVATE_PEM: | ||
4099 | case SSHKEY_PRIVATE_PKCS8: | ||
4100 | return sshkey_private_to_blob_pem_pkcs8(key, blob, | ||
4101 | format, passphrase, comment); | ||
4102 | default: | ||
4103 | return SSH_ERR_INVALID_ARGUMENT; | ||
4104 | } | ||
4105 | #endif /* WITH_OPENSSL */ | ||
4072 | } | 4106 | } |
4073 | 4107 | ||
4074 | 4108 | ||