summaryrefslogtreecommitdiff
path: root/sshkey.c
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-07-15 13:16:29 +0000
committerDamien Miller <djm@mindrot.org>2019-07-15 23:21:18 +1000
commiteb0d8e708a1f958aecd2d6e2ff2450af488d4c2a (patch)
treec5b7686e1e200aac6f3a742c7b15ed30a2c05067 /sshkey.c
parente18a27eedccb024acb3cd9820b650a5dff323f01 (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.c78
1 files changed, 56 insertions, 22 deletions
diff --git a/sshkey.c b/sshkey.c
index 6b5ff0485..a0cea9257 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -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 */
3979static int 3979static int
3980sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *buf, 3980sshkey_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,
4046int 4071int
4047sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob, 4072sshkey_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