summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarkus@openbsd.org <markus@openbsd.org>2018-02-23 15:58:37 +0000
committerDamien Miller <djm@mindrot.org>2018-02-26 11:40:41 +1100
commit1b11ea7c58cd5c59838b5fa574cd456d6047b2d4 (patch)
tree7e96cb41b5234b9d327f7c8f41392f09aed0994e
parent7d330a1ac02076de98cfc8fda05353d57b603755 (diff)
upstream: Add experimental support for PQC XMSS keys (Extended
Hash-Based Signatures) The code is not compiled in by default (see WITH_XMSS in Makefile.inc) Joint work with stefan-lukas_gazdag at genua.eu See https://tools.ietf.org/html/draft-irtf-cfrg-xmss-hash-based-signatures-12 ok djm@ OpenBSD-Commit-ID: ef3eccb96762a5d6f135d7daeef608df7776a7ac
-rw-r--r--Makefile.in12
-rw-r--r--authfd.c39
-rw-r--r--authfd.h5
-rw-r--r--authfile.c8
-rw-r--r--cipher.c4
-rw-r--r--dns.c7
-rw-r--r--dns.h5
-rw-r--r--pathnames.h4
-rw-r--r--readconf.c3
-rw-r--r--servconf.c4
-rw-r--r--ssh-add.c74
-rw-r--r--ssh-agent.c24
-rw-r--r--ssh-keygen.c19
-rw-r--r--ssh-keyscan.c12
-rw-r--r--ssh-keysign.c5
-rw-r--r--ssh-xmss.c188
-rw-r--r--ssh.c15
-rw-r--r--sshconnect.c5
-rw-r--r--sshd.c6
-rw-r--r--sshkey-xmss.c1048
-rw-r--r--sshkey-xmss.h56
-rw-r--r--sshkey.c410
-rw-r--r--sshkey.h35
-rw-r--r--xmss_commons.c27
-rw-r--r--xmss_commons.h15
-rw-r--r--xmss_fast.c1099
-rw-r--r--xmss_fast.h109
-rw-r--r--xmss_hash.c133
-rw-r--r--xmss_hash.h19
-rw-r--r--xmss_hash_address.c59
-rw-r--r--xmss_hash_address.h37
-rw-r--r--xmss_wots.c185
-rw-r--r--xmss_wots.h59
33 files changed, 3657 insertions, 73 deletions
diff --git a/Makefile.in b/Makefile.in
index 2d26e83a..25d45eaf 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -62,6 +62,15 @@ MKDIR_P=@MKDIR_P@
TARGETS=ssh$(EXEEXT) sshd$(EXEEXT) ssh-add$(EXEEXT) ssh-keygen$(EXEEXT) ssh-keyscan${EXEEXT} ssh-keysign${EXEEXT} ssh-pkcs11-helper$(EXEEXT) ssh-agent$(EXEEXT) scp$(EXEEXT) sftp-server$(EXEEXT) sftp$(EXEEXT)
+XMSS_OBJS=\
+ ssh-xmss.c \
+ sshkey-xmss.c \
+ xmss_commons.c \
+ xmss_fast.c \
+ xmss_hash.c \
+ xmss_hash_address.c \
+ xmss_wots.c
+
LIBOPENSSH_OBJS=\
ssh_api.o \
ssherr.o \
@@ -71,7 +80,8 @@ LIBOPENSSH_OBJS=\
sshbuf-misc.o \
sshbuf-getput-crypto.o \
krl.o \
- bitmap.o
+ bitmap.o \
+ ${XMSS_OBJS}
LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
authfd.o authfile.o bufaux.o bufbn.o bufec.o buffer.o \
diff --git a/authfd.c b/authfd.c
index 148bc9bf..1eff7ba9 100644
--- a/authfd.c
+++ b/authfd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: authfd.c,v 1.107 2018/02/10 09:25:34 djm Exp $ */
+/* $OpenBSD: authfd.c,v 1.108 2018/02/23 15:58:37 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -129,7 +129,7 @@ ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply)
/* Get the length of the message, and format it in the buffer. */
len = sshbuf_len(request);
- put_u32(buf, len);
+ POKE_U32(buf, len);
/* Send the length and then the packet to the agent. */
if (atomicio(vwrite, sock, buf, 4) != 4 ||
@@ -144,7 +144,7 @@ ssh_request_reply(int sock, struct sshbuf *request, struct sshbuf *reply)
return SSH_ERR_AGENT_COMMUNICATION;
/* Extract the length, and check it for sanity. */
- len = get_u32(buf);
+ len = PEEK_U32(buf);
if (len > MAX_AGENT_REPLY_LEN)
return SSH_ERR_INVALID_FORMAT;
@@ -391,19 +391,7 @@ ssh_agent_sign(int sock, const struct sshkey *key,
static int
-ssh_encode_identity_ssh2(struct sshbuf *b, const struct sshkey *key,
- const char *comment)
-{
- int r;
-
- if ((r = sshkey_private_serialize(key, b)) != 0 ||
- (r = sshbuf_put_cstring(b, comment)) != 0)
- return r;
- return 0;
-}
-
-static int
-encode_constraints(struct sshbuf *m, u_int life, u_int confirm)
+encode_constraints(struct sshbuf *m, u_int life, u_int confirm, u_int maxsign)
{
int r;
@@ -416,6 +404,11 @@ encode_constraints(struct sshbuf *m, u_int life, u_int confirm)
if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_CONFIRM)) != 0)
goto out;
}
+ if (maxsign != 0) {
+ if ((r = sshbuf_put_u8(m, SSH_AGENT_CONSTRAIN_MAXSIGN)) != 0 ||
+ (r = sshbuf_put_u32(m, maxsign)) != 0)
+ goto out;
+ }
r = 0;
out:
return r;
@@ -427,10 +420,10 @@ encode_constraints(struct sshbuf *m, u_int life, u_int confirm)
*/
int
ssh_add_identity_constrained(int sock, const struct sshkey *key,
- const char *comment, u_int life, u_int confirm)
+ const char *comment, u_int life, u_int confirm, u_int maxsign)
{
struct sshbuf *msg;
- int r, constrained = (life || confirm);
+ int r, constrained = (life || confirm || maxsign);
u_char type;
if ((msg = sshbuf_new()) == NULL)
@@ -447,11 +440,15 @@ ssh_add_identity_constrained(int sock, const struct sshkey *key,
#endif
case KEY_ED25519:
case KEY_ED25519_CERT:
+ case KEY_XMSS:
+ case KEY_XMSS_CERT:
type = constrained ?
SSH2_AGENTC_ADD_ID_CONSTRAINED :
SSH2_AGENTC_ADD_IDENTITY;
if ((r = sshbuf_put_u8(msg, type)) != 0 ||
- (r = ssh_encode_identity_ssh2(msg, key, comment)) != 0)
+ (r = sshkey_private_serialize_maxsign(key, msg, maxsign,
+ NULL)) != 0 ||
+ (r = sshbuf_put_cstring(msg, comment)) != 0)
goto out;
break;
default:
@@ -459,7 +456,7 @@ ssh_add_identity_constrained(int sock, const struct sshkey *key,
goto out;
}
if (constrained &&
- (r = encode_constraints(msg, life, confirm)) != 0)
+ (r = encode_constraints(msg, life, confirm, maxsign)) != 0)
goto out;
if ((r = ssh_request_reply(sock, msg, msg)) != 0)
goto out;
@@ -537,7 +534,7 @@ ssh_update_card(int sock, int add, const char *reader_id, const char *pin,
(r = sshbuf_put_cstring(msg, pin)) != 0)
goto out;
if (constrained &&
- (r = encode_constraints(msg, life, confirm)) != 0)
+ (r = encode_constraints(msg, life, confirm, 0)) != 0)
goto out;
if ((r = ssh_request_reply(sock, msg, msg)) != 0)
goto out;
diff --git a/authfd.h b/authfd.h
index 41997ce6..ab954ffc 100644
--- a/authfd.h
+++ b/authfd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: authfd.h,v 1.42 2018/02/10 09:25:34 djm Exp $ */
+/* $OpenBSD: authfd.h,v 1.43 2018/02/23 15:58:37 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -30,7 +30,7 @@ int ssh_lock_agent(int sock, int lock, const char *password);
int ssh_fetch_identitylist(int sock, struct ssh_identitylist **idlp);
void ssh_free_identitylist(struct ssh_identitylist *idl);
int ssh_add_identity_constrained(int sock, const struct sshkey *key,
- const char *comment, u_int life, u_int confirm);
+ const char *comment, u_int life, u_int confirm, u_int maxsign);
int ssh_remove_identity(int sock, struct sshkey *key);
int ssh_update_card(int sock, int add, const char *reader_id,
const char *pin, u_int life, u_int confirm);
@@ -77,6 +77,7 @@ int ssh_agent_sign(int sock, const struct sshkey *key,
#define SSH_AGENT_CONSTRAIN_LIFETIME 1
#define SSH_AGENT_CONSTRAIN_CONFIRM 2
+#define SSH_AGENT_CONSTRAIN_MAXSIGN 3
/* extended failure messages */
#define SSH2_AGENT_FAILURE 30
diff --git a/authfile.c b/authfile.c
index d09b700d..57dcd808 100644
--- a/authfile.c
+++ b/authfile.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: authfile.c,v 1.127 2017/07/01 13:50:45 djm Exp $ */
+/* $OpenBSD: authfile.c,v 1.128 2018/02/23 15:58:37 markus Exp $ */
/*
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
*
@@ -191,6 +191,8 @@ sshkey_load_private_type(int type, const char *filename, const char *passphrase,
*perm_ok = 1;
r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
+ if (r == 0 && keyp && *keyp)
+ r = sshkey_set_filename(*keyp, filename);
out:
close(fd);
return r;
@@ -249,6 +251,9 @@ sshkey_load_private(const char *filename, const char *passphrase,
(r = sshkey_parse_private_fileblob(buffer, passphrase, keyp,
commentp)) != 0)
goto out;
+ if (keyp && *keyp &&
+ (r = sshkey_set_filename(*keyp, filename)) != 0)
+ goto out;
r = 0;
out:
close(fd);
@@ -397,6 +402,7 @@ sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
case KEY_ECDSA:
#endif /* WITH_OPENSSL */
case KEY_ED25519:
+ case KEY_XMSS:
case KEY_UNSPEC:
break;
default:
diff --git a/cipher.c b/cipher.c
index 9f454675..57876361 100644
--- a/cipher.c
+++ b/cipher.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cipher.c,v 1.110 2018/02/13 03:36:56 djm Exp $ */
+/* $OpenBSD: cipher.c,v 1.111 2018/02/23 15:58:37 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -401,7 +401,7 @@ cipher_get_length(struct sshcipher_ctx *cc, u_int *plenp, u_int seqnr,
cp, len);
if (len < 4)
return SSH_ERR_MESSAGE_INCOMPLETE;
- *plenp = get_u32(cp);
+ *plenp = PEEK_U32(cp);
return 0;
}
diff --git a/dns.c b/dns.c
index 6e1abb53..ff1a2c41 100644
--- a/dns.c
+++ b/dns.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.c,v 1.37 2017/09/14 04:32:21 djm Exp $ */
+/* $OpenBSD: dns.c,v 1.38 2018/02/23 15:58:37 markus Exp $ */
/*
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -105,6 +105,11 @@ dns_read_key(u_int8_t *algorithm, u_int8_t *digest_type,
if (!*digest_type)
*digest_type = SSHFP_HASH_SHA256;
break;
+ case KEY_XMSS:
+ *algorithm = SSHFP_KEY_XMSS;
+ if (!*digest_type)
+ *digest_type = SSHFP_HASH_SHA256;
+ break;
default:
*algorithm = SSHFP_KEY_RESERVED; /* 0 */
*digest_type = SSHFP_HASH_RESERVED; /* 0 */
diff --git a/dns.h b/dns.h
index 68443f7c..91f3c632 100644
--- a/dns.h
+++ b/dns.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.h,v 1.17 2017/09/14 04:32:21 djm Exp $ */
+/* $OpenBSD: dns.h,v 1.18 2018/02/23 15:58:37 markus Exp $ */
/*
* Copyright (c) 2003 Wesley Griffin. All rights reserved.
@@ -33,7 +33,8 @@ enum sshfp_types {
SSHFP_KEY_RSA = 1,
SSHFP_KEY_DSA = 2,
SSHFP_KEY_ECDSA = 3,
- SSHFP_KEY_ED25519 = 4
+ SSHFP_KEY_ED25519 = 4,
+ SSHFP_KEY_XMSS = 5
};
enum sshfp_hashes {
diff --git a/pathnames.h b/pathnames.h
index 1c221b01..cb44caa4 100644
--- a/pathnames.h
+++ b/pathnames.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pathnames.h,v 1.27 2017/05/05 10:42:49 naddy Exp $ */
+/* $OpenBSD: pathnames.h,v 1.28 2018/02/23 15:58:37 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -39,6 +39,7 @@
#define _PATH_HOST_DSA_KEY_FILE SSHDIR "/ssh_host_dsa_key"
#define _PATH_HOST_ECDSA_KEY_FILE SSHDIR "/ssh_host_ecdsa_key"
#define _PATH_HOST_ED25519_KEY_FILE SSHDIR "/ssh_host_ed25519_key"
+#define _PATH_HOST_XMSS_KEY_FILE SSHDIR "/ssh_host_xmss_key"
#define _PATH_HOST_RSA_KEY_FILE SSHDIR "/ssh_host_rsa_key"
#define _PATH_DH_MODULI SSHDIR "/moduli"
@@ -75,6 +76,7 @@
#define _PATH_SSH_CLIENT_ID_ECDSA _PATH_SSH_USER_DIR "/id_ecdsa"
#define _PATH_SSH_CLIENT_ID_RSA _PATH_SSH_USER_DIR "/id_rsa"
#define _PATH_SSH_CLIENT_ID_ED25519 _PATH_SSH_USER_DIR "/id_ed25519"
+#define _PATH_SSH_CLIENT_ID_XMSS _PATH_SSH_USER_DIR "/id_xmss"
/*
* Configuration file in user's home directory. This file need not be
diff --git a/readconf.c b/readconf.c
index 56bff850..88051db5 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.282 2018/02/23 02:34:33 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.283 2018/02/23 15:58:37 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -1943,6 +1943,7 @@ fill_default_options(Options * options)
#endif
add_identity_file(options, "~/",
_PATH_SSH_CLIENT_ID_ED25519, 0);
+ add_identity_file(options, "~/", _PATH_SSH_CLIENT_ID_XMSS, 0);
}
if (options->escape_char == -1)
options->escape_char = '~';
diff --git a/servconf.c b/servconf.c
index bf8ad671..c87a9a2b 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: servconf.c,v 1.324 2018/02/16 02:32:40 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.325 2018/02/23 15:58:37 markus Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@@ -253,6 +253,8 @@ fill_default_server_options(ServerOptions *options)
#endif
servconf_add_hostkey("[default]", 0, options,
_PATH_HOST_ED25519_KEY_FILE);
+ servconf_add_hostkey("[default]", 0, options,
+ _PATH_HOST_XMSS_KEY_FILE);
}
/* No certificates by default */
if (options->num_ports == 0)
diff --git a/ssh-add.c b/ssh-add.c
index 2afd4833..adcc4599 100644
--- a/ssh-add.c
+++ b/ssh-add.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-add.c,v 1.134 2017/08/29 09:42:29 dlg Exp $ */
+/* $OpenBSD: ssh-add.c,v 1.135 2018/02/23 15:58:37 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -78,6 +78,7 @@ static char *default_files[] = {
#endif
#endif /* WITH_OPENSSL */
_PATH_SSH_CLIENT_ID_ED25519,
+ _PATH_SSH_CLIENT_ID_XMSS,
NULL
};
@@ -89,6 +90,10 @@ static int lifetime = 0;
/* User has to confirm key use */
static int confirm = 0;
+/* Maximum number of signatures (XMSS) */
+static u_int maxsign = 0;
+static u_int minleft = 0;
+
/* we keep a cache of one passphrase */
static char *pass = NULL;
static void
@@ -190,7 +195,10 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag)
char *comment = NULL;
char msg[1024], *certpath = NULL;
int r, fd, ret = -1;
+ size_t i;
+ u_int32_t left;
struct sshbuf *keyblob;
+ struct ssh_identitylist *idlist;
if (strcmp(filename, "-") == 0) {
fd = STDIN_FILENO;
@@ -268,8 +276,40 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag)
comment = xstrdup(filename);
sshbuf_free(keyblob);
+ /* For XMSS */
+ if ((r = sshkey_set_filename(private, filename)) != 0) {
+ fprintf(stderr, "Could not add filename to private key: %s (%s)\n",
+ filename, comment);
+ goto out;
+ }
+ if (maxsign && minleft &&
+ (r = ssh_fetch_identitylist(agent_fd, &idlist)) == 0) {
+ for (i = 0; i < idlist->nkeys; i++) {
+ if (!sshkey_equal_public(idlist->keys[i], private))
+ continue;
+ left = sshkey_signatures_left(idlist->keys[i]);
+ if (left < minleft) {
+ fprintf(stderr,
+ "Only %d signatures left.\n", left);
+ break;
+ }
+ fprintf(stderr, "Skipping update: ");
+ if (left == minleft) {
+ fprintf(stderr,
+ "required signatures left (%d).\n", left);
+ } else {
+ fprintf(stderr,
+ "more signatures left (%d) than"
+ " required (%d).\n", left, minleft);
+ }
+ ssh_free_identitylist(idlist);
+ goto out;
+ }
+ ssh_free_identitylist(idlist);
+ }
+
if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
- lifetime, confirm)) == 0) {
+ lifetime, confirm, maxsign)) == 0) {
fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
ret = 0;
if (lifetime != 0)
@@ -317,7 +357,7 @@ add_file(int agent_fd, const char *filename, int key_only, int qflag)
sshkey_free(cert);
if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
- lifetime, confirm)) != 0) {
+ lifetime, confirm, maxsign)) != 0) {
error("Certificate %s (%s) add failed: %s", certpath,
private->cert->key_id, ssh_err(r));
goto out;
@@ -368,6 +408,7 @@ list_identities(int agent_fd, int do_fp)
char *fp;
int r;
struct ssh_identitylist *idlist;
+ u_int32_t left;
size_t i;
if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) {
@@ -392,7 +433,12 @@ list_identities(int agent_fd, int do_fp)
ssh_err(r));
continue;
}
- fprintf(stdout, " %s\n", idlist->comments[i]);
+ fprintf(stdout, " %s", idlist->comments[i]);
+ left = sshkey_signatures_left(idlist->keys[i]);
+ if (left > 0)
+ fprintf(stdout,
+ " [signatures left %d]", left);
+ fprintf(stdout, "\n");
}
}
ssh_free_identitylist(idlist);
@@ -454,6 +500,8 @@ usage(void)
fprintf(stderr, " -L List public key parameters of all identities.\n");
fprintf(stderr, " -k Load only keys and not certificates.\n");
fprintf(stderr, " -c Require confirmation to sign using identities\n");
+ fprintf(stderr, " -m minleft Maxsign is only changed if less than minleft are left (for XMSS)\n");
+ fprintf(stderr, " -M maxsign Maximum number of signatures allowed (for XMSS)\n");
fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n");
fprintf(stderr, " -d Delete identity.\n");
fprintf(stderr, " -D Delete all identities.\n");
@@ -500,7 +548,7 @@ main(int argc, char **argv)
exit(2);
}
- while ((ch = getopt(argc, argv, "klLcdDxXE:e:qs:t:")) != -1) {
+ while ((ch = getopt(argc, argv, "klLcdDxXE:e:M:m:qs:t:")) != -1) {
switch (ch) {
case 'E':
fingerprint_hash = ssh_digest_alg_by_name(optarg);
@@ -525,6 +573,22 @@ main(int argc, char **argv)
case 'c':
confirm = 1;
break;
+ case 'm':
+ minleft = (int)strtonum(optarg, 1, UINT_MAX, NULL);
+ if (minleft == 0) {
+ usage();
+ ret = 1;
+ goto done;
+ }
+ break;
+ case 'M':
+ maxsign = (int)strtonum(optarg, 1, UINT_MAX, NULL);
+ if (maxsign == 0) {
+ usage();
+ ret = 1;
+ goto done;
+ }
+ break;
case 'd':
deleting = 1;
break;
diff --git a/ssh-agent.c b/ssh-agent.c
index 39888a72..2a4578b0 100644
--- a/ssh-agent.c
+++ b/ssh-agent.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-agent.c,v 1.227 2018/01/23 05:27:21 djm Exp $ */
+/* $OpenBSD: ssh-agent.c,v 1.228 2018/02/23 15:58:37 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -245,7 +245,8 @@ process_request_identities(SocketEntry *e)
(r = sshbuf_put_u32(msg, idtab->nentries)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
TAILQ_FOREACH(id, &idtab->idlist, next) {
- if ((r = sshkey_puts(id->key, msg)) != 0 ||
+ if ((r = sshkey_puts_opts(id->key, msg, SSHKEY_SERIALIZE_INFO))
+ != 0 ||
(r = sshbuf_put_cstring(msg, id->comment)) != 0) {
error("%s: put key/comment: %s", __func__,
ssh_err(r));
@@ -402,7 +403,7 @@ process_add_identity(SocketEntry *e)
{
Identity *id;
int success = 0, confirm = 0;
- u_int seconds;
+ u_int seconds, maxsign;
char *comment = NULL;
time_t death = 0;
struct sshkey *k = NULL;
@@ -433,6 +434,18 @@ process_add_identity(SocketEntry *e)
case SSH_AGENT_CONSTRAIN_CONFIRM:
confirm = 1;
break;
+ case SSH_AGENT_CONSTRAIN_MAXSIGN:
+ if ((r = sshbuf_get_u32(e->request, &maxsign)) != 0) {
+ error("%s: bad maxsign constraint: %s",
+ __func__, ssh_err(r));
+ goto err;
+ }
+ if ((r = sshkey_enable_maxsign(k, maxsign)) != 0) {
+ error("%s: cannot enable maxsign: %s",
+ __func__, ssh_err(r));
+ goto err;
+ }
+ break;
default:
error("%s: Unknown constraint %d", __func__, ctype);
err:
@@ -448,14 +461,15 @@ process_add_identity(SocketEntry *e)
death = monotime() + lifetime;
if ((id = lookup_identity(k)) == NULL) {
id = xcalloc(1, sizeof(Identity));
- id->key = k;
TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
/* Increment the number of identities. */
idtab->nentries++;
} else {
- sshkey_free(k);
+ /* key state might have been updated */
+ sshkey_free(id->key);
free(id->comment);
}
+ id->key = k;
id->comment = comment;
id->death = death;
id->confirm = confirm;
diff --git a/ssh-keygen.c b/ssh-keygen.c
index 9812c0d2..d80930ee 100644
--- a/ssh-keygen.c
+++ b/ssh-keygen.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keygen.c,v 1.312 2018/02/10 05:48:46 djm Exp $ */
+/* $OpenBSD: ssh-keygen.c,v 1.313 2018/02/23 15:58:38 markus Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -275,6 +275,10 @@ ask_filename(struct passwd *pw, const char *prompt)
case KEY_ED25519_CERT:
name = _PATH_SSH_CLIENT_ID_ED25519;
break;
+ case KEY_XMSS:
+ case KEY_XMSS_CERT:
+ name = _PATH_SSH_CLIENT_ID_XMSS;
+ break;
default:
fatal("bad key type");
}
@@ -969,6 +973,9 @@ do_gen_all_hostkeys(struct passwd *pw)
#endif /* OPENSSL_HAS_ECC */
#endif /* WITH_OPENSSL */
{ "ed25519", "ED25519",_PATH_HOST_ED25519_KEY_FILE },
+#ifdef WITH_XMSS
+ { "xmss", "XMSS",_PATH_HOST_XMSS_KEY_FILE },
+#endif /* WITH_XMSS */
{ NULL, NULL, NULL }
};
@@ -1455,7 +1462,8 @@ do_change_comment(struct passwd *pw)
}
}
- if (private->type != KEY_ED25519 && !use_new_format) {
+ if (private->type != KEY_ED25519 && private->type != KEY_XMSS &&
+ !use_new_format) {
error("Comments are only supported for keys stored in "
"the new format (-o).");
explicit_bzero(passphrase, strlen(passphrase));
@@ -1705,7 +1713,8 @@ do_ca_sign(struct passwd *pw, int argc, char **argv)
fatal("%s: unable to open \"%s\": %s",
__func__, tmp, ssh_err(r));
if (public->type != KEY_RSA && public->type != KEY_DSA &&
- public->type != KEY_ECDSA && public->type != KEY_ED25519)
+ public->type != KEY_ECDSA && public->type != KEY_ED25519 &&
+ public->type != KEY_XMSS)
fatal("%s: key \"%s\" type %s cannot be certified",
__func__, tmp, sshkey_type(public));
@@ -2405,7 +2414,7 @@ main(int argc, char **argv)
gen_all_hostkeys = 1;
break;
case 'b':
- bits = (u_int32_t)strtonum(optarg, 256, 32768, &errstr);
+ bits = (u_int32_t)strtonum(optarg, 10, 32768, &errstr);
if (errstr)
fatal("Bits has bad value %s (%s)",
optarg, errstr);
@@ -2683,6 +2692,8 @@ main(int argc, char **argv)
_PATH_HOST_ECDSA_KEY_FILE, rr_hostname);
n += do_print_resource_record(pw,
_PATH_HOST_ED25519_KEY_FILE, rr_hostname);
+ n += do_print_resource_record(pw,
+ _PATH_HOST_XMSS_KEY_FILE, rr_hostname);
if (n == 0)
fatal("no keys found.");
exit(0);
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
index 15059f6f..53536860 100644
--- a/ssh-keyscan.c
+++ b/ssh-keyscan.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keyscan.c,v 1.117 2018/02/23 05:14:05 djm Exp $ */
+/* $OpenBSD: ssh-keyscan.c,v 1.118 2018/02/23 15:58:38 markus Exp $ */
/*
* Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>.
*
@@ -58,9 +58,10 @@ int ssh_port = SSH_DEFAULT_PORT;
#define KT_RSA (1<<1)
#define KT_ECDSA (1<<2)
#define KT_ED25519 (1<<3)
+#define KT_XMSS (1<<4)
#define KT_MIN KT_DSA
-#define KT_MAX KT_ED25519
+#define KT_MAX KT_XMSS
int get_cert = 0;
int get_keytypes = KT_RSA|KT_ECDSA|KT_ED25519;
@@ -238,6 +239,10 @@ keygrab_ssh2(con *c)
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
"ssh-ed25519-cert-v01@openssh.com" : "ssh-ed25519";
break;
+ case KT_XMSS:
+ myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
+ "ssh-xmss-cert-v01@openssh.com" : "ssh-xmss@openssh.com";
+ break;
case KT_ECDSA:
myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = get_cert ?
"ecdsa-sha2-nistp256-cert-v01@openssh.com,"
@@ -718,6 +723,9 @@ main(int argc, char **argv)
case KEY_ED25519:
get_keytypes |= KT_ED25519;
break;
+ case KEY_XMSS:
+ get_keytypes |= KT_XMSS;
+ break;
case KEY_UNSPEC:
default:
fatal("Unknown key type \"%s\"", tname);
diff --git a/ssh-keysign.c b/ssh-keysign.c
index 17e87a28..78bb66b0 100644
--- a/ssh-keysign.c
+++ b/ssh-keysign.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh-keysign.c,v 1.53 2018/02/07 22:52:45 dtucker Exp $ */
+/* $OpenBSD: ssh-keysign.c,v 1.54 2018/02/23 15:58:38 markus Exp $ */
/*
* Copyright (c) 2002 Markus Friedl. All rights reserved.
*
@@ -171,7 +171,7 @@ main(int argc, char **argv)
{
struct sshbuf *b;
Options options;
-#define NUM_KEYTYPES 4
+#define NUM_KEYTYPES 5
struct sshkey *keys[NUM_KEYTYPES], *key = NULL;
struct passwd *pw;
int r, key_fd[NUM_KEYTYPES], i, found, version = 2, fd;
@@ -198,6 +198,7 @@ main(int argc, char **argv)
key_fd[i++] = open(_PATH_HOST_DSA_KEY_FILE, O_RDONLY);
key_fd[i++] = open(_PATH_HOST_ECDSA_KEY_FILE, O_RDONLY);
key_fd[i++] = open(_PATH_HOST_ED25519_KEY_FILE, O_RDONLY);
+ key_fd[i++] = open(_PATH_HOST_XMSS_KEY_FILE, O_RDONLY);
key_fd[i++] = open(_PATH_HOST_RSA_KEY_FILE, O_RDONLY);
original_real_uid = getuid(); /* XXX readconf.c needs this */
diff --git a/ssh-xmss.c b/ssh-xmss.c
new file mode 100644
index 00000000..d9dafd76
--- /dev/null
+++ b/ssh-xmss.c
@@ -0,0 +1,188 @@
+/* $OpenBSD: ssh-xmss.c,v 1.1 2018/02/23 15:58:38 markus Exp $*/
+/*
+ * Copyright (c) 2017 Stefan-Lukas Gazdag.
+ * Copyright (c) 2017 Markus Friedl.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#define SSHKEY_INTERNAL
+#include <sys/types.h>
+#include <limits.h>
+
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+
+#include "log.h"
+#include "sshbuf.h"
+#include "sshkey.h"
+#include "sshkey-xmss.h"
+#include "ssherr.h"
+#include "ssh.h"
+
+#include "xmss_fast.h"
+
+int
+ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
+ const u_char *data, size_t datalen, u_int compat)
+{
+ u_char *sig = NULL;
+ size_t slen = 0, len = 0, required_siglen;
+ unsigned long long smlen;
+ int r, ret;
+ struct sshbuf *b = NULL;
+
+ if (lenp != NULL)
+ *lenp = 0;
+ if (sigp != NULL)
+ *sigp = NULL;
+
+ if (key == NULL ||
+ sshkey_type_plain(key->type) != KEY_XMSS ||
+ key->xmss_sk == NULL ||
+ sshkey_xmss_params(key) == NULL)
+ return SSH_ERR_INVALID_ARGUMENT;
+ if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
+ return r;
+ if (datalen >= INT_MAX - required_siglen)
+ return SSH_ERR_INVALID_ARGUMENT;
+ smlen = slen = datalen + required_siglen;
+ if ((sig = malloc(slen)) == NULL)
+ return SSH_ERR_ALLOC_FAIL;
+ if ((r = sshkey_xmss_get_state(key, error)) != 0)
+ goto out;
+ if ((ret = xmss_sign(key->xmss_sk, sshkey_xmss_bds_state(key), sig, &smlen,
+ data, datalen, sshkey_xmss_params(key))) != 0 || smlen <= datalen) {