summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-06-21 04:21:04 +0000
committerDamien Miller <djm@mindrot.org>2019-06-21 14:24:35 +1000
commit4f7a56d5e02e3d04ab69eac1213817a7536d0562 (patch)
treeb17da67f20831b53f9b00c6647c5eb1bdf88d626
parent4cd6b12cc9c10bf59c8b425041f3ea5091285a0f (diff)
upstream: Add protection for private keys at rest in RAM against
speculation and memory sidechannel attacks like Spectre, Meltdown, Rowhammer and Rambleed. This change encrypts private keys when they are not in use with a symmetic key that is derived from a relatively large "prekey" consisting of random data (currently 16KB). Attackers must recover the entire prekey with high accuracy before they can attempt to decrypt the shielded private key, but the current generation of attacks have bit error rates that, when applied cumulatively to the entire prekey, make this unlikely. Implementation-wise, keys are encrypted "shielded" when loaded and then automatically and transparently unshielded when used for signatures or when being saved/serialised. Hopefully we can remove this in a few years time when computer architecture has become less unsafe. been in snaps for a bit already; thanks deraadt@ ok dtucker@ deraadt@ OpenBSD-Commit-ID: 19767213c312e46f94b303a512ef8e9218a39bd4
-rw-r--r--authfd.c4
-rw-r--r--authfd.h4
-rw-r--r--krl.c4
-rw-r--r--krl.h4
-rw-r--r--ssh-agent.c7
-rw-r--r--ssh-keygen.c4
-rw-r--r--sshconnect.c4
-rw-r--r--sshconnect.h4
-rw-r--r--sshd.c10
-rw-r--r--sshkey.c299
-rw-r--r--sshkey.h21
11 files changed, 324 insertions, 41 deletions
diff --git a/authfd.c b/authfd.c
index 95348abfc..327a333d2 100644
--- a/authfd.c
+++ b/authfd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: authfd.c,v 1.113 2018/12/27 23:02:11 djm Exp $ */ 1/* $OpenBSD: authfd.c,v 1.114 2019/06/21 04:21:04 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -423,7 +423,7 @@ encode_constraints(struct sshbuf *m, u_int life, u_int confirm, u_int maxsign)
423 * This call is intended only for use by ssh-add(1) and like applications. 423 * This call is intended only for use by ssh-add(1) and like applications.
424 */ 424 */
425int 425int
426ssh_add_identity_constrained(int sock, const struct sshkey *key, 426ssh_add_identity_constrained(int sock, struct sshkey *key,
427 const char *comment, u_int life, u_int confirm, u_int maxsign) 427 const char *comment, u_int life, u_int confirm, u_int maxsign)
428{ 428{
429 struct sshbuf *msg; 429 struct sshbuf *msg;
diff --git a/authfd.h b/authfd.h
index a032fd542..060bed63f 100644
--- a/authfd.h
+++ b/authfd.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: authfd.h,v 1.44 2018/07/12 04:35:25 djm Exp $ */ 1/* $OpenBSD: authfd.h,v 1.45 2019/06/21 04:21:04 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -29,7 +29,7 @@ void ssh_close_authentication_socket(int sock);
29int ssh_lock_agent(int sock, int lock, const char *password); 29int ssh_lock_agent(int sock, int lock, const char *password);
30int ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp); 30int ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp);
31void ssh_free_identitylist(struct ssh_identitylist *idl); 31void ssh_free_identitylist(struct ssh_identitylist *idl);
32int ssh_add_identity_constrained(int sock, const struct sshkey *key, 32int ssh_add_identity_constrained(int sock, struct sshkey *key,
33 const char *comment, u_int life, u_int confirm, u_int maxsign); 33 const char *comment, u_int life, u_int confirm, u_int maxsign);
34int ssh_remove_identity(int sock, struct sshkey *key); 34int ssh_remove_identity(int sock, struct sshkey *key);
35int ssh_update_card(int sock, int add, const char *reader_id, 35int ssh_update_card(int sock, int add, const char *reader_id,
diff --git a/krl.c b/krl.c
index 8e2d5d5df..bb960882f 100644
--- a/krl.c
+++ b/krl.c
@@ -14,7 +14,7 @@
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */ 15 */
16 16
17/* $OpenBSD: krl.c,v 1.42 2018/09/12 01:21:34 djm Exp $ */ 17/* $OpenBSD: krl.c,v 1.43 2019/06/21 04:21:04 djm Exp $ */
18 18
19#include "includes.h" 19#include "includes.h"
20 20
@@ -732,7 +732,7 @@ revoked_certs_generate(struct revoked_certs *rc, struct sshbuf *buf)
732 732
733int 733int
734ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf, 734ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf,
735 const struct sshkey **sign_keys, u_int nsign_keys) 735 struct sshkey **sign_keys, u_int nsign_keys)
736{ 736{
737 int r = SSH_ERR_INTERNAL_ERROR; 737 int r = SSH_ERR_INTERNAL_ERROR;
738 struct revoked_certs *rc; 738 struct revoked_certs *rc;
diff --git a/krl.h b/krl.h
index 815a1df4e..ce534a111 100644
--- a/krl.h
+++ b/krl.h
@@ -14,7 +14,7 @@
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */ 15 */
16 16
17/* $OpenBSD: krl.h,v 1.6 2018/09/12 01:21:34 djm Exp $ */ 17/* $OpenBSD: krl.h,v 1.7 2019/06/21 04:21:04 djm Exp $ */
18 18
19#ifndef _KRL_H 19#ifndef _KRL_H
20#define _KRL_H 20#define _KRL_H
@@ -56,7 +56,7 @@ int ssh_krl_revoke_key_sha1(struct ssh_krl *krl, const u_char *p, size_t len);
56int ssh_krl_revoke_key_sha256(struct ssh_krl *krl, const u_char *p, size_t len); 56int ssh_krl_revoke_key_sha256(struct ssh_krl *krl, const u_char *p, size_t len);
57int ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key); 57int ssh_krl_revoke_key(struct ssh_krl *krl, const struct sshkey *key);
58int ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf, 58int ssh_krl_to_blob(struct ssh_krl *krl, struct sshbuf *buf,
59 const struct sshkey **sign_keys, u_int nsign_keys); 59 struct sshkey **sign_keys, u_int nsign_keys);
60int ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp, 60int ssh_krl_from_blob(struct sshbuf *buf, struct ssh_krl **krlp,
61 const struct sshkey **sign_ca_keys, size_t nsign_ca_keys); 61 const struct sshkey **sign_ca_keys, size_t nsign_ca_keys);
62int ssh_krl_check_key(struct ssh_krl *krl, const struct sshkey *key); 62int ssh_krl_check_key(struct ssh_krl *krl, const struct sshkey *key);
diff --git a/ssh-agent.c b/ssh-agent.c
index 4669b679c..4d7ab225f 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-agent.c,v 1.235 2019/06/14 03:51:47 djm Exp $ */ 1/* $OpenBSD: ssh-agent.c,v 1.236 2019/06/21 04:21:04 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -423,7 +423,10 @@ process_add_identity(SocketEntry *e)
423 error("%s: decode private key: %s", __func__, ssh_err(r)); 423 error("%s: decode private key: %s", __func__, ssh_err(r));
424 goto err; 424 goto err;
425 } 425 }
426 426 if ((r = sshkey_shield_private(k)) != 0) {
427 error("%s: shield private key: %s", __func__, ssh_err(r));
428 goto err;
429 }
427 while (sshbuf_len(e->request)) { 430 while (sshbuf_len(e->request)) {
428 if ((r = sshbuf_get_u8(e->request, &ctype)) != 0) { 431 if ((r = sshbuf_get_u8(e->request, &ctype)) != 0) {
429 error("%s: buffer error: %s", __func__, ssh_err(r)); 432 error("%s: buffer error: %s", __func__, ssh_err(r));
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 010667157..c95bc15cf 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh-keygen.c,v 1.331 2019/06/06 05:13:13 otto Exp $ */ 1/* $OpenBSD: ssh-keygen.c,v 1.332 2019/06/21 04:21:04 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1654,7 +1654,7 @@ load_pkcs11_key(char *path)
1654 1654
1655/* Signer for sshkey_certify_custom that uses the agent */ 1655/* Signer for sshkey_certify_custom that uses the agent */
1656static int 1656static int
1657agent_signer(const struct sshkey *key, u_char **sigp, size_t *lenp, 1657agent_signer(struct sshkey *key, u_char **sigp, size_t *lenp,
1658 const u_char *data, size_t datalen, 1658 const u_char *data, size_t datalen,
1659 const char *alg, u_int compat, void *ctx) 1659 const char *alg, u_int compat, void *ctx)
1660{ 1660{
diff --git a/sshconnect.c b/sshconnect.c
index c57f1a0ff..2dc500b47 100644
--- a/sshconnect.c
+++ b/sshconnect.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.c,v 1.315 2019/05/03 03:27:38 dtucker Exp $ */ 1/* $OpenBSD: sshconnect.c,v 1.316 2019/06/21 04:21:04 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1401,7 +1401,7 @@ ssh_local_cmd(const char *args)
1401} 1401}
1402 1402
1403void 1403void
1404maybe_add_key_to_agent(char *authfile, const struct sshkey *private, 1404maybe_add_key_to_agent(char *authfile, struct sshkey *private,
1405 char *comment, char *passphrase) 1405 char *comment, char *passphrase)
1406{ 1406{
1407 int auth_sock = -1, r; 1407 int auth_sock = -1, r;
diff --git a/sshconnect.h b/sshconnect.h
index 6e8989b27..b455d7c20 100644
--- a/sshconnect.h
+++ b/sshconnect.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshconnect.h,v 1.37 2019/01/19 21:36:38 djm Exp $ */ 1/* $OpenBSD: sshconnect.h,v 1.38 2019/06/21 04:21:05 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000 Markus Friedl. All rights reserved.
@@ -52,4 +52,4 @@ void ssh_userauth2(struct ssh *ssh, const char *, const char *,
52 52
53int ssh_local_cmd(const char *); 53int ssh_local_cmd(const char *);
54 54
55void maybe_add_key_to_agent(char *, const struct sshkey *, char *, char *); 55void maybe_add_key_to_agent(char *, struct sshkey *, char *, char *);
diff --git a/sshd.c b/sshd.c
index be23fbc80..735a11060 100644
--- a/sshd.c
+++ b/sshd.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshd.c,v 1.535 2019/06/06 05:13:13 otto Exp $ */ 1/* $OpenBSD: sshd.c,v 1.536 2019/06/21 04:21:05 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1375,7 +1375,7 @@ set_process_rdomain(struct ssh *ssh, const char *name)
1375 1375
1376static void 1376static void
1377accumulate_host_timing_secret(struct sshbuf *server_cfg, 1377accumulate_host_timing_secret(struct sshbuf *server_cfg,
1378 const struct sshkey *key) 1378 struct sshkey *key)
1379{ 1379{
1380 static struct ssh_digest_ctx *ctx; 1380 static struct ssh_digest_ctx *ctx;
1381 u_char *hash; 1381 u_char *hash;
@@ -1723,6 +1723,12 @@ main(int ac, char **av)
1723 &key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR) 1723 &key, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR)
1724 do_log2(ll, "Unable to load host key \"%s\": %s", 1724 do_log2(ll, "Unable to load host key \"%s\": %s",
1725 options.host_key_files[i], ssh_err(r)); 1725 options.host_key_files[i], ssh_err(r));
1726 if (r == 0 && (r = sshkey_shield_private(key)) != 0) {
1727 do_log2(ll, "Unable to shield host key \"%s\": %s",
1728 options.host_key_files[i], ssh_err(r));
1729 sshkey_free(key);
1730 key = NULL;
1731 }
1726 if ((r = sshkey_load_public(options.host_key_files[i], 1732 if ((r = sshkey_load_public(options.host_key_files[i],
1727 &pubkey, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR) 1733 &pubkey, NULL)) != 0 && r != SSH_ERR_SYSTEM_ERROR)
1728 do_log2(ll, "Unable to load host key \"%s\": %s", 1734 do_log2(ll, "Unable to load host key \"%s\": %s",
diff --git a/sshkey.c b/sshkey.c
index 379a579cf..7aa7e772c 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -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
81int 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
89int sshkey_private_serialize_opt(struct sshkey *key,
82 struct sshbuf *buf, enum sshkey_serialize_rep); 90 struct sshbuf *buf, enum sshkey_serialize_rep);
83static int sshkey_from_blob_internal(struct sshbuf *buf, 91static 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
1882int
1883sshkey_is_shielded(struct sshkey *k)
1884{
1885 return k != NULL && k->shielded_private != NULL;
1886}
1887
1888int
1889sshkey_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
1997int
1998sshkey_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
1872static int 2094static int
1873cert_parse(struct sshbuf *b, struct sshkey *key, struct sshbuf *certbuf) 2095cert_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
2375int 2597int
2376sshkey_sign(const struct sshkey *key, 2598sshkey_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
2654static int 2890static int
2655default_key_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, 2891default_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
2764int 3000int
2765sshkey_private_serialize_opt(const struct sshkey *key, struct sshbuf *b, 3001sshkey_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
2905int 3156int
2906sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b) 3157sshkey_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
3360static int 3611static int
3361sshkey_private_to_blob2(const struct sshkey *prv, struct sshbuf *blob, 3612sshkey_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 */
3730static int 3981static int
3731sshkey_private_pem_to_blob(struct sshkey *key, struct sshbuf *blob, 3982sshkey_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
4104int 4369int
4105sshkey_private_serialize_maxsign(const struct sshkey *k, struct sshbuf *b, 4370sshkey_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);
diff --git a/sshkey.h b/sshkey.h
index a91e60436..41d159a1b 100644
--- a/sshkey.h
+++ b/sshkey.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshkey.h,v 1.31 2019/01/20 22:51:37 djm Exp $ */ 1/* $OpenBSD: sshkey.h,v 1.32 2019/06/21 04:21:05 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -123,6 +123,10 @@ struct sshkey {
123 u_char *xmss_sk; 123 u_char *xmss_sk;
124 u_char *xmss_pk; 124 u_char *xmss_pk;
125 struct sshkey_cert *cert; 125 struct sshkey_cert *cert;
126 u_char *shielded_private;
127 size_t shielded_len;
128 u_char *shield_prekey;
129 size_t shield_prekey_len;
126}; 130};
127 131
128#define ED25519_SK_SZ crypto_sign_ed25519_SECRETKEYBYTES 132#define ED25519_SK_SZ crypto_sign_ed25519_SECRETKEYBYTES
@@ -146,6 +150,11 @@ u_int sshkey_size(const struct sshkey *);
146 150
147int sshkey_generate(int type, u_int bits, struct sshkey **keyp); 151int sshkey_generate(int type, u_int bits, struct sshkey **keyp);
148int sshkey_from_private(const struct sshkey *, struct sshkey **); 152int sshkey_from_private(const struct sshkey *, struct sshkey **);
153
154int sshkey_is_shielded(struct sshkey *);
155int sshkey_shield_private(struct sshkey *);
156int sshkey_unshield_private(struct sshkey *);
157
149int sshkey_type_from_name(const char *); 158int sshkey_type_from_name(const char *);
150int sshkey_is_cert(const struct sshkey *); 159int sshkey_is_cert(const struct sshkey *);
151int sshkey_type_is_cert(int); 160int sshkey_type_is_cert(int);
@@ -161,7 +170,7 @@ int sshkey_check_cert_sigtype(const struct sshkey *, const char *);
161 170
162int sshkey_certify(struct sshkey *, struct sshkey *, const char *); 171int sshkey_certify(struct sshkey *, struct sshkey *, const char *);
163/* Variant allowing use of a custom signature function (e.g. for ssh-agent) */ 172/* Variant allowing use of a custom signature function (e.g. for ssh-agent) */
164typedef int sshkey_certify_signer(const struct sshkey *, u_char **, size_t *, 173typedef int sshkey_certify_signer(struct sshkey *, u_char **, size_t *,
165 const u_char *, size_t, const char *, u_int, void *); 174 const u_char *, size_t, const char *, u_int, void *);
166int sshkey_certify_custom(struct sshkey *, struct sshkey *, const char *, 175int sshkey_certify_custom(struct sshkey *, struct sshkey *, const char *,
167 sshkey_certify_signer *, void *); 176 sshkey_certify_signer *, void *);
@@ -192,7 +201,7 @@ int sshkey_puts_opts(const struct sshkey *, struct sshbuf *,
192int sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *); 201int sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *);
193int sshkey_putb_plain(const struct sshkey *, struct sshbuf *); 202int sshkey_putb_plain(const struct sshkey *, struct sshbuf *);
194 203
195int sshkey_sign(const struct sshkey *, u_char **, size_t *, 204int sshkey_sign(struct sshkey *, u_char **, size_t *,
196 const u_char *, size_t, const char *, u_int); 205 const u_char *, size_t, const char *, u_int);
197int sshkey_verify(const struct sshkey *, const u_char *, size_t, 206int sshkey_verify(const struct sshkey *, const u_char *, size_t,
198 const u_char *, size_t, const char *, u_int); 207 const u_char *, size_t, const char *, u_int);
@@ -204,8 +213,8 @@ void sshkey_dump_ec_point(const EC_GROUP *, const EC_POINT *);
204void sshkey_dump_ec_key(const EC_KEY *); 213void sshkey_dump_ec_key(const EC_KEY *);
205 214
206/* private key parsing and serialisation */ 215/* private key parsing and serialisation */
207int sshkey_private_serialize(const struct sshkey *key, struct sshbuf *buf); 216int sshkey_private_serialize(struct sshkey *key, struct sshbuf *buf);
208int sshkey_private_serialize_opt(const struct sshkey *key, struct sshbuf *buf, 217int sshkey_private_serialize_opt(struct sshkey *key, struct sshbuf *buf,
209 enum sshkey_serialize_rep); 218 enum sshkey_serialize_rep);
210int sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **keyp); 219int sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **keyp);
211 220
@@ -231,7 +240,7 @@ int sshkey_set_filename(struct sshkey *, const char *);
231int sshkey_enable_maxsign(struct sshkey *, u_int32_t); 240int sshkey_enable_maxsign(struct sshkey *, u_int32_t);
232u_int32_t sshkey_signatures_left(const struct sshkey *); 241u_int32_t sshkey_signatures_left(const struct sshkey *);
233int sshkey_forward_state(const struct sshkey *, u_int32_t, sshkey_printfn *); 242int sshkey_forward_state(const struct sshkey *, u_int32_t, sshkey_printfn *);
234int sshkey_private_serialize_maxsign(const struct sshkey *key, struct sshbuf *buf, 243int sshkey_private_serialize_maxsign(struct sshkey *key, struct sshbuf *buf,
235 u_int32_t maxsign, sshkey_printfn *pr); 244 u_int32_t maxsign, sshkey_printfn *pr);
236 245
237#ifdef SSHKEY_INTERNAL 246#ifdef SSHKEY_INTERNAL