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
This commit is contained in:
parent
7d330a1ac0
commit
1b11ea7c58
12
Makefile.in
12
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 \
|
||||
|
|
39
authfd.c
39
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;
|
||||
|
|
5
authfd.h
5
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
|
||||
|
|
|
@ -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:
|
||||
|
|
4
cipher.c
4
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;
|
||||
}
|
||||
|
||||
|
|
7
dns.c
7
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 */
|
||||
|
|
5
dns.h
5
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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = '~';
|
||||
|
|
|
@ -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)
|
||||
|
|
74
ssh-add.c
74
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;
|
||||
|
|
24
ssh-agent.c
24
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;
|
||||
|
|
19
ssh-keygen.c
19
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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) {
|
||||
r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
|
||||
goto out;
|
||||
}
|
||||
/* encode signature */
|
||||
if ((b = sshbuf_new()) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshbuf_put_cstring(b, "ssh-xmss@openssh.com")) != 0 ||
|
||||
(r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
|
||||
goto out;
|
||||
len = sshbuf_len(b);
|
||||
if (sigp != NULL) {
|
||||
if ((*sigp = malloc(len)) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(*sigp, sshbuf_ptr(b), len);
|
||||
}
|
||||
if (lenp != NULL)
|
||||
*lenp = len;
|
||||
/* success */
|
||||
r = 0;
|
||||
out:
|
||||
if ((ret = sshkey_xmss_update_state(key, error)) != 0) {
|
||||
/* discard signature since we cannot update the state */
|
||||
if (r == 0 && sigp != NULL && *sigp != NULL) {
|
||||
explicit_bzero(*sigp, len);
|
||||
free(*sigp);
|
||||
}
|
||||
if (sigp != NULL)
|
||||
*sigp = NULL;
|
||||
if (lenp != NULL)
|
||||
*lenp = 0;
|
||||
r = ret;
|
||||
}
|
||||
sshbuf_free(b);
|
||||
if (sig != NULL) {
|
||||
explicit_bzero(sig, slen);
|
||||
free(sig);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
ssh_xmss_verify(const struct sshkey *key,
|
||||
const u_char *signature, size_t signaturelen,
|
||||
const u_char *data, size_t datalen, u_int compat)
|
||||
{
|
||||
struct sshbuf *b = NULL;
|
||||
char *ktype = NULL;
|
||||
const u_char *sigblob;
|
||||
u_char *sm = NULL, *m = NULL;
|
||||
size_t len, required_siglen;
|
||||
unsigned long long smlen = 0, mlen = 0;
|
||||
int r, ret;
|
||||
|
||||
if (key == NULL ||
|
||||
sshkey_type_plain(key->type) != KEY_XMSS ||
|
||||
key->xmss_pk == NULL ||
|
||||
sshkey_xmss_params(key) == NULL ||
|
||||
signature == NULL || signaturelen == 0)
|
||||
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;
|
||||
|
||||
if ((b = sshbuf_from(signature, signaturelen)) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
|
||||
(r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
|
||||
goto out;
|
||||
if (strcmp("ssh-xmss@openssh.com", ktype) != 0) {
|
||||
r = SSH_ERR_KEY_TYPE_MISMATCH;
|
||||
goto out;
|
||||
}
|
||||
if (sshbuf_len(b) != 0) {
|
||||
r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
|
||||
goto out;
|
||||
}
|
||||
if (len != required_siglen) {
|
||||
r = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
if (datalen >= SIZE_MAX - len) {
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
smlen = len + datalen;
|
||||
mlen = smlen;
|
||||
if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
memcpy(sm, sigblob, len);
|
||||
memcpy(sm+len, data, datalen);
|
||||
if ((ret = xmss_sign_open(m, &mlen, sm, smlen,
|
||||
key->xmss_pk, sshkey_xmss_params(key))) != 0) {
|
||||
debug2("%s: crypto_sign_xmss_open failed: %d",
|
||||
__func__, ret);
|
||||
}
|
||||
if (ret != 0 || mlen != datalen) {
|
||||
r = SSH_ERR_SIGNATURE_INVALID;
|
||||
goto out;
|
||||
}
|
||||
/* XXX compare 'm' and 'data' ? */
|
||||
/* success */
|
||||
r = 0;
|
||||
out:
|
||||
if (sm != NULL) {
|
||||
explicit_bzero(sm, smlen);
|
||||
free(sm);
|
||||
}
|
||||
if (m != NULL) {
|
||||
explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */
|
||||
free(m);
|
||||
}
|
||||
sshbuf_free(b);
|
||||
free(ktype);
|
||||
return r;
|
||||
}
|
15
ssh.c
15
ssh.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: ssh.c,v 1.474 2018/02/23 02:34:33 djm Exp $ */
|
||||
/* $OpenBSD: ssh.c,v 1.475 2018/02/23 15:58:38 markus Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -1384,7 +1384,7 @@ main(int ac, char **av)
|
|||
sensitive_data.keys = NULL;
|
||||
sensitive_data.external_keysign = 0;
|
||||
if (options.hostbased_authentication) {
|
||||
sensitive_data.nkeys = 9;
|
||||
sensitive_data.nkeys = 11;
|
||||
sensitive_data.keys = xcalloc(sensitive_data.nkeys,
|
||||
sizeof(struct sshkey)); /* XXX */
|
||||
for (i = 0; i < sensitive_data.nkeys; i++)
|
||||
|
@ -1411,6 +1411,10 @@ main(int ac, char **av)
|
|||
_PATH_HOST_RSA_KEY_FILE, "", NULL, NULL);
|
||||
sensitive_data.keys[8] = key_load_private_type(KEY_DSA,
|
||||
_PATH_HOST_DSA_KEY_FILE, "", NULL, NULL);
|
||||
sensitive_data.keys[9] = key_load_private_cert(KEY_XMSS,
|
||||
_PATH_HOST_XMSS_KEY_FILE, "", NULL);
|
||||
sensitive_data.keys[10] = key_load_private_type(KEY_XMSS,
|
||||
_PATH_HOST_XMSS_KEY_FILE, "", NULL, NULL);
|
||||
PRIV_END;
|
||||
|
||||
if (options.hostbased_authentication == 1 &&
|
||||
|
@ -1418,7 +1422,8 @@ main(int ac, char **av)
|
|||
sensitive_data.keys[5] == NULL &&
|
||||
sensitive_data.keys[6] == NULL &&
|
||||
sensitive_data.keys[7] == NULL &&
|
||||
sensitive_data.keys[8] == NULL) {
|
||||
sensitive_data.keys[8] == NULL &&
|
||||
sensitive_data.keys[9] == NULL) {
|
||||
#ifdef OPENSSL_HAS_ECC
|
||||
sensitive_data.keys[1] = key_load_cert(
|
||||
_PATH_HOST_ECDSA_KEY_FILE);
|
||||
|
@ -1439,6 +1444,10 @@ main(int ac, char **av)
|
|||
_PATH_HOST_RSA_KEY_FILE, NULL);
|
||||
sensitive_data.keys[8] = key_load_public(
|
||||
_PATH_HOST_DSA_KEY_FILE, NULL);
|
||||
sensitive_data.keys[9] = key_load_cert(
|
||||
_PATH_HOST_XMSS_KEY_FILE);
|
||||
sensitive_data.keys[10] = key_load_public(
|
||||
_PATH_HOST_XMSS_KEY_FILE, NULL);
|
||||
sensitive_data.external_keysign = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshconnect.c,v 1.296 2018/02/23 04:18:46 dtucker Exp $ */
|
||||
/* $OpenBSD: sshconnect.c,v 1.297 2018/02/23 15:58:38 markus Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -1475,6 +1475,7 @@ show_other_keys(struct hostkeys *hostkeys, struct sshkey *key)
|
|||
KEY_DSA,
|
||||
KEY_ECDSA,
|
||||
KEY_ED25519,
|
||||
KEY_XMSS,
|
||||
-1
|
||||
};
|
||||
int i, ret = 0;
|
||||
|
@ -1592,7 +1593,7 @@ maybe_add_key_to_agent(char *authfile, const struct sshkey *private,
|
|||
}
|
||||
|
||||
if ((r = ssh_add_identity_constrained(auth_sock, private, comment, 0,
|
||||
(options.add_keys_to_agent == 3))) == 0)
|
||||
(options.add_keys_to_agent == 3), 0)) == 0)
|
||||
debug("identity added to agent: %s", authfile);
|
||||
else
|
||||
debug("could not add identity to agent: %s (%d)", authfile, r);
|
||||
|
|
6
sshd.c
6
sshd.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshd.c,v 1.504 2018/02/11 21:16:56 dtucker Exp $ */
|
||||
/* $OpenBSD: sshd.c,v 1.505 2018/02/23 15:58:38 markus Exp $ */
|
||||
/*
|
||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||
|
@ -705,6 +705,7 @@ list_hostkey_types(void)
|
|||
case KEY_DSA:
|
||||
case KEY_ECDSA:
|
||||
case KEY_ED25519:
|
||||
case KEY_XMSS:
|
||||
if (buffer_len(&b) > 0)
|
||||
buffer_append(&b, ",", 1);
|
||||
p = key_ssh_name(key);
|
||||
|
@ -726,6 +727,7 @@ list_hostkey_types(void)
|
|||
case KEY_DSA_CERT:
|
||||
case KEY_ECDSA_CERT:
|
||||
case KEY_ED25519_CERT:
|
||||
case KEY_XMSS_CERT:
|
||||
if (buffer_len(&b) > 0)
|
||||
buffer_append(&b, ",", 1);
|
||||
p = key_ssh_name(key);
|
||||
|
@ -752,6 +754,7 @@ get_hostkey_by_type(int type, int nid, int need_private, struct ssh *ssh)
|
|||
case KEY_DSA_CERT:
|
||||
case KEY_ECDSA_CERT:
|
||||
case KEY_ED25519_CERT:
|
||||
case KEY_XMSS_CERT:
|
||||
key = sensitive_data.host_certificates[i];
|
||||
break;
|
||||
default:
|
||||
|
@ -1734,6 +1737,7 @@ main(int ac, char **av)
|
|||
case KEY_DSA:
|
||||
case KEY_ECDSA:
|
||||
case KEY_ED25519:
|
||||
case KEY_XMSS:
|
||||
if (have_agent || key != NULL)
|
||||
sensitive_data.have_ssh2_key = 1;
|
||||
break;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,56 @@
|
|||
/* $OpenBSD: sshkey-xmss.h,v 1.1 2018/02/23 15:58:38 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2017 Markus Friedl. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef SSHKEY_XMSS_H
|
||||
#define SSHKEY_XMSS_H
|
||||
|
||||
#define XMSS_SHA2_256_W16_H10_NAME "XMSS_SHA2-256_W16_H10"
|
||||
#define XMSS_SHA2_256_W16_H16_NAME "XMSS_SHA2-256_W16_H16"
|
||||
#define XMSS_SHA2_256_W16_H20_NAME "XMSS_SHA2-256_W16_H20"
|
||||
#define XMSS_DEFAULT_NAME XMSS_SHA2_256_W16_H10_NAME
|
||||
|
||||
size_t sshkey_xmss_pklen(const struct sshkey *);
|
||||
size_t sshkey_xmss_sklen(const struct sshkey *);
|
||||
int sshkey_xmss_init(struct sshkey *, const char *);
|
||||
void sshkey_xmss_free_state(struct sshkey *);
|
||||
int sshkey_xmss_generate_private_key(struct sshkey *, u_int);
|
||||
int sshkey_xmss_serialize_state(const struct sshkey *, struct sshbuf *);
|
||||
int sshkey_xmss_serialize_state_opt(const struct sshkey *, struct sshbuf *,
|
||||
enum sshkey_serialize_rep);
|
||||
int sshkey_xmss_serialize_pk_info(const struct sshkey *, struct sshbuf *,
|
||||
enum sshkey_serialize_rep);
|
||||
int sshkey_xmss_deserialize_state(struct sshkey *, struct sshbuf *);
|
||||
int sshkey_xmss_deserialize_state_opt(struct sshkey *, struct sshbuf *);
|
||||
int sshkey_xmss_deserialize_pk_info(struct sshkey *, struct sshbuf *);
|
||||
|
||||
int sshkey_xmss_siglen(const struct sshkey *, size_t *);
|
||||
void *sshkey_xmss_params(const struct sshkey *);
|
||||
void *sshkey_xmss_bds_state(const struct sshkey *);
|
||||
int sshkey_xmss_get_state(const struct sshkey *, sshkey_printfn *);
|
||||
int sshkey_xmss_enable_maxsign(struct sshkey *, u_int32_t);
|
||||
int sshkey_xmss_forward_state(const struct sshkey *, u_int32_t);
|
||||
int sshkey_xmss_update_state(const struct sshkey *, sshkey_printfn *);
|
||||
u_int32_t sshkey_xmss_signatures_left(const struct sshkey *);
|
||||
|
||||
#endif /* SSHKEY_XMSS_H */
|
410
sshkey.c
410
sshkey.c
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshkey.c,v 1.61 2018/02/14 16:03:32 jsing Exp $ */
|
||||
/* $OpenBSD: sshkey.c,v 1.62 2018/02/23 15:58:38 markus Exp $ */
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
* Copyright (c) 2008 Alexander von Gernler. All rights reserved.
|
||||
|
@ -55,8 +55,11 @@
|
|||
#include "digest.h"
|
||||
#define SSHKEY_INTERNAL
|
||||
#include "sshkey.h"
|
||||
#include "sshkey-xmss.h"
|
||||
#include "match.h"
|
||||
|
||||
#include "xmss_fast.h"
|
||||
|
||||
/* openssh private key file format */
|
||||
#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n"
|
||||
#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n"
|
||||
|
@ -71,6 +74,8 @@
|
|||
/* Version identification string for SSH v1 identity files. */
|
||||
#define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n"
|
||||
|
||||
int sshkey_private_serialize_opt(const struct sshkey *key,
|
||||
struct sshbuf *buf, enum sshkey_serialize_rep);
|
||||
static int sshkey_from_blob_internal(struct sshbuf *buf,
|
||||
struct sshkey **keyp, int allow_cert);
|
||||
|
||||
|
@ -87,6 +92,11 @@ static const struct keytype keytypes[] = {
|
|||
{ "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0, 0 },
|
||||
{ "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT",
|
||||
KEY_ED25519_CERT, 0, 1, 0 },
|
||||
#ifdef WITH_XMSS
|
||||
{ "ssh-xmss@openssh.com", "XMSS", KEY_XMSS, 0, 0, 0 },
|
||||
{ "ssh-xmss-cert-v01@openssh.com", "XMSS-CERT",
|
||||
KEY_XMSS_CERT, 0, 1, 0 },
|
||||
#endif /* WITH_XMSS */
|
||||
#ifdef WITH_OPENSSL
|
||||
{ "ssh-rsa", "RSA", KEY_RSA, 0, 0, 0 },
|
||||
{ "rsa-sha2-256", "RSA", KEY_RSA, 0, 0, 1 },
|
||||
|
@ -274,6 +284,8 @@ sshkey_size(const struct sshkey *k)
|
|||
#endif /* WITH_OPENSSL */
|
||||
case KEY_ED25519:
|
||||
case KEY_ED25519_CERT:
|
||||
case KEY_XMSS:
|
||||
case KEY_XMSS_CERT:
|
||||
return 256; /* XXX */
|
||||
}
|
||||
return 0;
|
||||
|
@ -287,6 +299,7 @@ sshkey_type_is_valid_ca(int type)
|
|||
case KEY_DSA:
|
||||
case KEY_ECDSA:
|
||||
case KEY_ED25519:
|
||||
case KEY_XMSS:
|
||||
return 1;
|
||||
default:
|
||||
return 0;
|
||||
|
@ -314,6 +327,8 @@ sshkey_type_plain(int type)
|
|||
return KEY_ECDSA;
|
||||
case KEY_ED25519_CERT:
|
||||
return KEY_ED25519;
|
||||
case KEY_XMSS_CERT:
|
||||
return KEY_XMSS;
|
||||
default:
|
||||
return type;
|
||||
}
|
||||
|
@ -461,6 +476,8 @@ sshkey_new(int type)
|
|||
k->cert = NULL;
|
||||
k->ed25519_sk = NULL;
|
||||
k->ed25519_pk = NULL;
|
||||
k->xmss_sk = NULL;
|
||||
k->xmss_pk = NULL;
|
||||
switch (k->type) {
|
||||
#ifdef WITH_OPENSSL
|
||||
case KEY_RSA:
|
||||
|
@ -494,6 +511,8 @@ sshkey_new(int type)
|
|||
#endif /* WITH_OPENSSL */
|
||||
case KEY_ED25519:
|
||||
case KEY_ED25519_CERT:
|
||||
case KEY_XMSS:
|
||||
case KEY_XMSS_CERT:
|
||||
/* no need to prealloc */
|
||||
break;
|
||||
case KEY_UNSPEC:
|
||||
|
@ -542,6 +561,8 @@ sshkey_add_private(struct sshkey *k)
|
|||
#endif /* WITH_OPENSSL */
|
||||
case KEY_ED25519:
|
||||
case KEY_ED25519_CERT:
|
||||
case KEY_XMSS:
|
||||
case KEY_XMSS_CERT:
|
||||
/* no need to prealloc */
|
||||
break;
|
||||
case KEY_UNSPEC:
|
||||
|
@ -598,6 +619,20 @@ sshkey_free(struct sshkey *k)
|
|||
freezero(k->ed25519_sk, ED25519_SK_SZ);
|
||||
k->ed25519_sk = NULL;
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
case KEY_XMSS_CERT:
|
||||
freezero(k->xmss_pk, sshkey_xmss_pklen(k));
|
||||
k->xmss_pk = NULL;
|
||||
freezero(k->xmss_sk, sshkey_xmss_sklen(k));
|
||||
k->xmss_sk = NULL;
|
||||
sshkey_xmss_free_state(k);
|
||||
free(k->xmss_name);
|
||||
k->xmss_name = NULL;
|
||||
free(k->xmss_filename);
|
||||
k->xmss_filename = NULL;
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
case KEY_UNSPEC:
|
||||
break;
|
||||
default:
|
||||
|
@ -677,6 +712,13 @@ sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
|
|||
case KEY_ED25519_CERT:
|
||||
return a->ed25519_pk != NULL && b->ed25519_pk != NULL &&
|
||||
memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
case KEY_XMSS_CERT:
|
||||
return a->xmss_pk != NULL && b->xmss_pk != NULL &&
|
||||
sshkey_xmss_pklen(a) == sshkey_xmss_pklen(b) &&
|
||||
memcmp(a->xmss_pk, b->xmss_pk, sshkey_xmss_pklen(a)) == 0;
|
||||
#endif /* WITH_XMSS */
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
@ -696,7 +738,8 @@ sshkey_equal(const struct sshkey *a, const struct sshkey *b)
|
|||
}
|
||||
|
||||
static int
|
||||
to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain)
|
||||
to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain,
|
||||
enum sshkey_serialize_rep opts)
|
||||
{
|
||||
int type, ret = SSH_ERR_INTERNAL_ERROR;
|
||||
const char *typename;
|
||||
|
@ -720,6 +763,9 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain)
|
|||
case KEY_RSA_CERT:
|
||||
#endif /* WITH_OPENSSL */
|
||||
case KEY_ED25519_CERT:
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS_CERT:
|
||||
#endif /* WITH_XMSS */
|
||||
/* Use the existing blob */
|
||||
/* XXX modified flag? */
|
||||
if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0)
|
||||
|
@ -764,6 +810,19 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain)
|
|||
key->ed25519_pk, ED25519_PK_SZ)) != 0)
|
||||
return ret;
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
if (key->xmss_name == NULL || key->xmss_pk == NULL ||
|
||||
sshkey_xmss_pklen(key) == 0)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
|
||||
(ret = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
|
||||
(ret = sshbuf_put_string(b,
|
||||
key->xmss_pk, sshkey_xmss_pklen(key))) != 0 ||
|
||||
(ret = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0)
|
||||
return ret;
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
default:
|
||||
return SSH_ERR_KEY_TYPE_UNKNOWN;
|
||||
}
|
||||
|
@ -773,32 +832,40 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain)
|
|||
int
|
||||
sshkey_putb(const struct sshkey *key, struct sshbuf *b)
|
||||
{
|
||||
return to_blob_buf(key, b, 0);
|
||||
return to_blob_buf(key, b, 0, SSHKEY_SERIALIZE_DEFAULT);
|
||||
}
|
||||
|
||||
int
|
||||
sshkey_puts(const struct sshkey *key, struct sshbuf *b)
|
||||
sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b,
|
||||
enum sshkey_serialize_rep opts)
|
||||
{
|
||||
struct sshbuf *tmp;
|
||||
int r;
|
||||
|
||||
if ((tmp = sshbuf_new()) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
r = to_blob_buf(key, tmp, 0);
|
||||
r = to_blob_buf(key, tmp, 0, opts);
|
||||
if (r == 0)
|
||||
r = sshbuf_put_stringb(b, tmp);
|
||||
sshbuf_free(tmp);
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
sshkey_puts(const struct sshkey *key, struct sshbuf *b)
|
||||
{
|
||||
return sshkey_puts_opts(key, b, SSHKEY_SERIALIZE_DEFAULT);
|
||||
}
|
||||
|
||||
int
|
||||
sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b)
|
||||
{
|
||||
return to_blob_buf(key, b, 1);
|
||||
return to_blob_buf(key, b, 1, SSHKEY_SERIALIZE_DEFAULT);
|
||||
}
|
||||
|
||||
static int
|
||||
to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain)
|
||||
to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain,
|
||||
enum sshkey_serialize_rep opts)
|
||||
{
|
||||
int ret = SSH_ERR_INTERNAL_ERROR;
|
||||
size_t len;
|
||||
|
@ -810,7 +877,7 @@ to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain)
|
|||
*blobp = NULL;
|
||||
if ((b = sshbuf_new()) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((ret = to_blob_buf(key, b, force_plain)) != 0)
|
||||
if ((ret = to_blob_buf(key, b, force_plain, opts)) != 0)
|
||||
goto out;
|
||||
len = sshbuf_len(b);
|
||||
if (lenp != NULL)
|
||||
|
@ -831,13 +898,13 @@ to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain)
|
|||
int
|
||||
sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
|
||||
{
|
||||
return to_blob(key, blobp, lenp, 0);
|
||||
return to_blob(key, blobp, lenp, 0, SSHKEY_SERIALIZE_DEFAULT);
|
||||
}
|
||||
|
||||
int
|
||||
sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
|
||||
{
|
||||
return to_blob(key, blobp, lenp, 1);
|
||||
return to_blob(key, blobp, lenp, 1, SSHKEY_SERIALIZE_DEFAULT);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -856,7 +923,8 @@ sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
|
|||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
if ((r = to_blob(k, &blob, &blob_len, 1)) != 0)
|
||||
if ((r = to_blob(k, &blob, &blob_len, 1, SSHKEY_SERIALIZE_DEFAULT))
|
||||
!= 0)
|
||||
goto out;
|
||||
if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
|
@ -1173,6 +1241,10 @@ sshkey_read(struct sshkey *ret, char **cpp)
|
|||
case KEY_ECDSA_CERT:
|
||||
case KEY_RSA_CERT:
|
||||
case KEY_ED25519_CERT:
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
case KEY_XMSS_CERT:
|
||||
#endif /* WITH_XMSS */
|
||||
space = strchr(cp, ' ');
|
||||
if (space == NULL)
|
||||
return SSH_ERR_INVALID_FORMAT;
|
||||
|
@ -1270,6 +1342,25 @@ sshkey_read(struct sshkey *ret, char **cpp)
|
|||
/* XXX */
|
||||
#endif
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
free(ret->xmss_pk);
|
||||
ret->xmss_pk = k->xmss_pk;
|
||||
k->xmss_pk = NULL;
|
||||
free(ret->xmss_state);
|
||||
ret->xmss_state = k->xmss_state;
|
||||
k->xmss_state = NULL;
|
||||
free(ret->xmss_name);
|
||||
ret->xmss_name = k->xmss_name;
|
||||
k->xmss_name = NULL;
|
||||
free(ret->xmss_filename);
|
||||
ret->xmss_filename = k->xmss_filename;
|
||||
k->xmss_filename = NULL;
|
||||
#ifdef DEBUG_PK
|
||||
/* XXX */
|
||||
#endif
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
}
|
||||
*cpp = ep;
|
||||
retval = 0;
|
||||
|
@ -1528,6 +1619,11 @@ sshkey_generate(int type, u_int bits, struct sshkey **keyp)
|
|||
crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk);
|
||||
ret = 0;
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
ret = sshkey_xmss_generate_private_key(k, bits);
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
#ifdef WITH_OPENSSL
|
||||
case KEY_DSA:
|
||||
ret = dsa_generate_private_key(bits, &k->dsa);
|
||||
|
@ -1671,6 +1767,29 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
|
|||
memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
|
||||
}
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
case KEY_XMSS_CERT:
|
||||
if ((n = sshkey_new(k->type)) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
if ((ret = sshkey_xmss_init(n, k->xmss_name)) != 0) {
|
||||
sshkey_free(n);
|
||||
return ret;
|
||||
}
|
||||
if (k->xmss_pk != NULL) {
|
||||
size_t pklen = sshkey_xmss_pklen(k);
|
||||
if (pklen == 0 || sshkey_xmss_pklen(n) != pklen) {
|
||||
sshkey_free(n);
|
||||
return SSH_ERR_INTERNAL_ERROR;
|
||||
}
|
||||
if ((n->xmss_pk = malloc(pklen)) == NULL) {
|
||||
sshkey_free(n);
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
}
|
||||
memcpy(n->xmss_pk, k->xmss_pk, pklen);
|
||||
}
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
default:
|
||||
return SSH_ERR_KEY_TYPE_UNKNOWN;
|
||||
}
|
||||
|
@ -1812,7 +1931,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
|
|||
int allow_cert)
|
||||
{
|
||||
int type, ret = SSH_ERR_INTERNAL_ERROR;
|
||||
char *ktype = NULL, *curve = NULL;
|
||||
char *ktype = NULL, *curve = NULL, *xmss_name = NULL;
|
||||
struct sshkey *key = NULL;
|
||||
size_t len;
|
||||
u_char *pk = NULL;
|
||||
|
@ -1963,6 +2082,36 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
|
|||
key->ed25519_pk = pk;
|
||||
pk = NULL;
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS_CERT:
|
||||
/* Skip nonce */
|
||||
if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
|
||||
ret = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
/* FALLTHROUGH */
|
||||
case KEY_XMSS:
|
||||
if ((ret = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0)
|
||||
goto out;
|
||||
if ((key = sshkey_new(type)) == NULL) {
|
||||
ret = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if ((ret = sshkey_xmss_init(key, xmss_name)) != 0)
|
||||
goto out;
|
||||
if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
|
||||
goto out;
|
||||
if (len == 0 || len != sshkey_xmss_pklen(key)) {
|
||||
ret = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
key->xmss_pk = pk;
|
||||
pk = NULL;
|
||||
if (type != KEY_XMSS_CERT &&
|
||||
(ret = sshkey_xmss_deserialize_pk_info(key, b)) != 0)
|
||||
goto out;
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
case KEY_UNSPEC:
|
||||
default:
|
||||
ret = SSH_ERR_KEY_TYPE_UNKNOWN;
|
||||
|
@ -1985,6 +2134,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
|
|||
out:
|
||||
sshbuf_free(copy);
|
||||
sshkey_free(key);
|
||||
free(xmss_name);
|
||||
free(ktype);
|
||||
free(curve);
|
||||
free(pk);
|
||||
|
@ -2079,6 +2229,11 @@ sshkey_sign(const struct sshkey *key,
|
|||
case KEY_ED25519:
|
||||
case KEY_ED25519_CERT:
|
||||
return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat);
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
case KEY_XMSS_CERT:
|
||||
return ssh_xmss_sign(key, sigp, lenp, data, datalen, compat);
|
||||
#endif /* WITH_XMSS */
|
||||
default:
|
||||
return SSH_ERR_KEY_TYPE_UNKNOWN;
|
||||
}
|
||||
|
@ -2112,6 +2267,11 @@ sshkey_verify(const struct sshkey *key,
|
|||
case KEY_ED25519:
|
||||
case KEY_ED25519_CERT:
|
||||
return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat);
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
case KEY_XMSS_CERT:
|
||||
return ssh_xmss_verify(key, sig, siglen, data, dlen, compat);
|
||||
#endif /* WITH_XMSS */
|
||||
default:
|
||||
return SSH_ERR_KEY_TYPE_UNKNOWN;
|
||||
}
|
||||
|
@ -2135,6 +2295,8 @@ sshkey_demote(const struct sshkey *k, struct sshkey **dkp)
|
|||
pk->rsa = NULL;
|
||||
pk->ed25519_pk = NULL;
|
||||
pk->ed25519_sk = NULL;
|
||||
pk->xmss_pk = NULL;
|
||||
pk->xmss_sk = NULL;
|
||||
|
||||
switch (k->type) {
|
||||
#ifdef WITH_OPENSSL
|
||||
|
@ -2196,6 +2358,29 @@ sshkey_demote(const struct sshkey *k, struct sshkey **dkp)
|
|||
memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
|
||||
}
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS_CERT:
|
||||
if ((ret = sshkey_cert_copy(k, pk)) != 0)
|
||||
goto fail;
|
||||
/* FALLTHROUGH */
|
||||
case KEY_XMSS:
|
||||
if ((ret = sshkey_xmss_init(pk, k->xmss_name)) != 0)
|
||||
goto fail;
|
||||
if (k->xmss_pk != NULL) {
|
||||
size_t pklen = sshkey_xmss_pklen(k);
|
||||
|
||||
if (pklen == 0 || sshkey_xmss_pklen(pk) != pklen) {
|
||||
ret = SSH_ERR_INTERNAL_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
if ((pk->xmss_pk = malloc(pklen)) == NULL) {
|
||||
ret = SSH_ERR_ALLOC_FAIL;
|
||||
goto fail;
|
||||
}
|
||||
memcpy(pk->xmss_pk, k->xmss_pk, pklen);
|
||||
}
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
default:
|
||||
ret = SSH_ERR_KEY_TYPE_UNKNOWN;
|
||||
fail:
|
||||
|
@ -2227,6 +2412,11 @@ sshkey_to_certified(struct sshkey *k)
|
|||
case KEY_ED25519:
|
||||
newtype = KEY_ED25519_CERT;
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
newtype = KEY_XMSS_CERT;
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
default:
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
@ -2311,6 +2501,18 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
|
|||
k->ed25519_pk, ED25519_PK_SZ)) != 0)
|
||||
goto out;
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS_CERT:
|
||||
if (k->xmss_name == NULL) {
|
||||
ret = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
if ((ret = sshbuf_put_cstring(cert, k->xmss_name)) ||
|
||||
(ret = sshbuf_put_string(cert,
|
||||
k->xmss_pk, sshkey_xmss_pklen(k))) != 0)
|
||||
goto out;
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
default:
|
||||
ret = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
|
@ -2468,7 +2670,8 @@ sshkey_format_cert_validity(const struct sshkey_cert *cert, char *s, size_t l)
|
|||
}
|
||||
|
||||
int
|
||||
sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
|
||||
sshkey_private_serialize_opt(const struct sshkey *key, struct sshbuf *b,
|
||||
enum sshkey_serialize_rep opts)
|
||||
{
|
||||
int r = SSH_ERR_INTERNAL_ERROR;
|
||||
|
||||
|
@ -2554,6 +2757,36 @@ sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
|
|||
ED25519_SK_SZ)) != 0)
|
||||
goto out;
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
if (key->xmss_name == NULL) {
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
|
||||
(r = sshbuf_put_string(b, key->xmss_pk,
|
||||
sshkey_xmss_pklen(key))) != 0 ||
|
||||
(r = sshbuf_put_string(b, key->xmss_sk,
|
||||
sshkey_xmss_sklen(key))) != 0 ||
|
||||
(r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0)
|
||||
goto out;
|
||||
break;
|
||||
case KEY_XMSS_CERT:
|
||||
if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0 ||
|
||||
key->xmss_name == NULL) {
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
|
||||
(r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
|
||||
(r = sshbuf_put_string(b, key->xmss_pk,
|
||||
sshkey_xmss_pklen(key))) != 0 ||
|
||||
(r = sshbuf_put_string(b, key->xmss_sk,
|
||||
sshkey_xmss_sklen(key))) != 0 ||
|
||||
(r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0)
|
||||
goto out;
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
default:
|
||||
r = SSH_ERR_INVALID_ARGUMENT;
|
||||
goto out;
|
||||
|
@ -2564,14 +2797,22 @@ sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
|
|||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
|
||||
{
|
||||
return sshkey_private_serialize_opt(key, b,
|
||||
SSHKEY_SERIALIZE_DEFAULT);
|
||||
}
|
||||
|
||||
int
|
||||
sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
|
||||
{
|
||||
char *tname = NULL, *curve = NULL;
|
||||
char *tname = NULL, *curve = NULL, *xmss_name = NULL;
|
||||
struct sshkey *k = NULL;
|
||||
size_t pklen = 0, sklen = 0;
|
||||
int type, r = SSH_ERR_INTERNAL_ERROR;
|
||||
u_char *ed25519_pk = NULL, *ed25519_sk = NULL;
|
||||
u_char *xmss_pk = NULL, *xmss_sk = NULL;
|
||||
#ifdef WITH_OPENSSL
|
||||
BIGNUM *exponent = NULL;
|
||||
#endif /* WITH_OPENSSL */
|
||||
|
@ -2716,6 +2957,48 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
|
|||
k->ed25519_sk = ed25519_sk;
|
||||
ed25519_pk = ed25519_sk = NULL;
|
||||
break;
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
if ((k = sshkey_new_private(type)) == NULL) {
|
||||
r = SSH_ERR_ALLOC_FAIL;
|
||||
goto out;
|
||||
}
|
||||
if ((r = sshbuf_get_cstring(buf, &xmss_name, NULL)) != 0 ||
|
||||
(r = sshkey_xmss_init(k, xmss_name)) != 0 ||
|
||||
(r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 ||
|
||||
(r = sshbuf_get_string(buf, &xmss_sk, &sklen)) != 0)
|
||||
goto out;
|
||||
if (pklen != sshkey_xmss_pklen(k) ||
|
||||
sklen != sshkey_xmss_sklen(k)) {
|
||||
r = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
k->xmss_pk = xmss_pk;
|
||||
k->xmss_sk = xmss_sk;
|
||||
xmss_pk = xmss_sk = NULL;
|
||||
/* optional internal state */
|
||||
if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0)
|
||||
goto out;
|
||||
break;
|
||||
case KEY_XMSS_CERT:
|
||||
if ((r = sshkey_froms(buf, &k)) != 0 ||
|
||||
(r = sshkey_add_private(k)) != 0 ||
|
||||
(r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 ||
|
||||
(r = sshbuf_get_string(buf, &xmss_sk, &sklen)) != 0)
|
||||
goto out;
|
||||
if (pklen != sshkey_xmss_pklen(k) ||
|
||||
sklen != sshkey_xmss_sklen(k)) {
|
||||
r = SSH_ERR_INVALID_FORMAT;
|
||||
goto out;
|
||||
}
|
||||
k->xmss_pk = xmss_pk;
|
||||
k->xmss_sk = xmss_sk;
|
||||
xmss_pk = xmss_sk = NULL;
|
||||
/* optional internal state */
|
||||
if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0)
|
||||
goto out;
|
||||
break;
|
||||
#endif /* WITH_XMSS */
|
||||
default:
|
||||
r = SSH_ERR_KEY_TYPE_UNKNOWN;
|
||||
goto out;
|
||||
|
@ -2747,6 +3030,9 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
|
|||
sshkey_free(k);
|
||||
freezero(ed25519_pk, pklen);
|
||||
freezero(ed25519_sk, sklen);
|
||||
free(xmss_name);
|
||||
freezero(xmss_pk, pklen);
|
||||
freezero(xmss_sk, sklen);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -3001,7 +3287,8 @@ sshkey_private_to_blob2(const struct sshkey *prv, struct sshbuf *blob,
|
|||
goto out;
|
||||
|
||||
/* append private key and comment*/
|
||||
if ((r = sshkey_private_serialize(prv, encrypted)) != 0 ||
|
||||
if ((r = sshkey_private_serialize_opt(prv, encrypted,
|
||||
SSHKEY_SERIALIZE_FULL)) != 0 ||
|
||||
(r = sshbuf_put_cstring(encrypted, comment)) != 0)
|
||||
goto out;
|
||||
|
||||
|
@ -3362,6 +3649,9 @@ sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
|
|||
passphrase, comment);
|
||||
#endif /* WITH_OPENSSL */
|
||||
case KEY_ED25519:
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
#endif /* WITH_XMSS */
|
||||
return sshkey_private_to_blob2(key, blob, passphrase,
|
||||
comment, new_format_cipher, new_format_rounds);
|
||||
default:
|
||||
|
@ -3545,6 +3835,9 @@ sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
|
|||
passphrase, keyp);
|
||||
#endif /* WITH_OPENSSL */
|
||||
case KEY_ED25519:
|
||||
#ifdef WITH_XMSS
|
||||
case KEY_XMSS:
|
||||
#endif /* WITH_XMSS */
|
||||
return sshkey_parse_private2(blob, type, passphrase,
|
||||
keyp, commentp);
|
||||
case KEY_UNSPEC:
|
||||
|
@ -3576,3 +3869,90 @@ sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase,
|
|||
return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,
|
||||
passphrase, keyp, commentp);
|
||||
}
|
||||
|
||||
#ifdef WITH_XMSS
|
||||
/*
|
||||
* serialize the key with the current state and forward the state
|
||||
* maxsign times.
|
||||
*/
|
||||
int
|
||||
sshkey_private_serialize_maxsign(const struct sshkey *k, struct sshbuf *b,
|
||||
u_int32_t maxsign, sshkey_printfn *pr)
|
||||
{
|
||||
int r, rupdate;
|
||||
|
||||
if (maxsign == 0 ||
|
||||
sshkey_type_plain(k->type) != KEY_XMSS)
|
||||
return sshkey_private_serialize_opt(k, b,
|
||||
SSHKEY_SERIALIZE_DEFAULT);
|
||||
if ((r = sshkey_xmss_get_state(k, pr)) != 0 ||
|
||||
(r = sshkey_private_serialize_opt(k, b,
|
||||
SSHKEY_SERIALIZE_STATE)) != 0 ||
|
||||
(r = sshkey_xmss_forward_state(k, maxsign)) != 0)
|
||||
goto out;
|
||||
r = 0;
|
||||
out:
|
||||
if ((rupdate = sshkey_xmss_update_state(k, pr)) != 0) {
|
||||
if (r == 0)
|
||||
r = rupdate;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
sshkey_signatures_left(const struct sshkey *k)
|
||||
{
|
||||
if (sshkey_type_plain(k->type) == KEY_XMSS)
|
||||
return sshkey_xmss_signatures_left(k);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
|
||||
{
|
||||
if (sshkey_type_plain(k->type) != KEY_XMSS)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
return sshkey_xmss_enable_maxsign(k, maxsign);
|
||||
}
|
||||
|
||||
int
|
||||
sshkey_set_filename(struct sshkey *k, const char *filename)
|
||||
{
|
||||
if (k == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if (sshkey_type_plain(k->type) != KEY_XMSS)
|
||||
return 0;
|
||||
if (filename == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
if ((k->xmss_filename = strdup(filename)) == NULL)
|
||||
return SSH_ERR_ALLOC_FAIL;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int
|
||||
sshkey_private_serialize_maxsign(const struct sshkey *k, struct sshbuf *b,
|
||||
u_int32_t maxsign, sshkey_printfn *pr)
|
||||
{
|
||||
return sshkey_private_serialize_opt(k, b, SSHKEY_SERIALIZE_DEFAULT);
|
||||
}
|
||||
|
||||
u_int32_t
|
||||
sshkey_signatures_left(const struct sshkey *k)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
|
||||
{
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
int
|
||||
sshkey_set_filename(struct sshkey *k, const char *filename)
|
||||
{
|
||||
if (k == NULL)
|
||||
return SSH_ERR_INVALID_ARGUMENT;
|
||||
return 0;
|
||||
}
|
||||
#endif /* WITH_XMSS */
|
||||
|
|
35
sshkey.h
35
sshkey.h
|
@ -1,4 +1,4 @@
|
|||
/* $OpenBSD: sshkey.h,v 1.23 2017/12/18 02:25:15 djm Exp $ */
|
||||
/* $OpenBSD: sshkey.h,v 1.24 2018/02/23 15:58:38 markus Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||
|
@ -61,6 +61,8 @@ enum sshkey_types {
|
|||
KEY_DSA_CERT,
|
||||
KEY_ECDSA_CERT,
|
||||
KEY_ED25519_CERT,
|
||||
KEY_XMSS,
|
||||
KEY_XMSS_CERT,
|
||||
KEY_UNSPEC
|
||||
};
|
||||
|
||||
|
@ -76,6 +78,14 @@ enum sshkey_fp_rep {
|
|||
SSH_FP_RANDOMART
|
||||
};
|
||||
|
||||
/* Private key serialisation formats, used on the wire */
|
||||
enum sshkey_serialize_rep {
|
||||
SSHKEY_SERIALIZE_DEFAULT = 0,
|
||||
SSHKEY_SERIALIZE_STATE = 1,
|
||||
SSHKEY_SERIALIZE_FULL = 2,
|
||||
SSHKEY_SERIALIZE_INFO = 254,
|
||||
};
|
||||
|
||||
/* key is stored in external hardware */
|
||||
#define SSHKEY_FLAG_EXT 0x0001
|
||||
|
||||
|
@ -104,6 +114,11 @@ struct sshkey {
|
|||
EC_KEY *ecdsa;
|
||||
u_char *ed25519_sk;
|
||||
u_char *ed25519_pk;
|
||||
char *xmss_name;
|
||||
char *xmss_filename; /* for state file updates */
|
||||
void *xmss_state; /* depends on xmss_name, opaque */
|
||||
u_char *xmss_sk;
|
||||
u_char *xmss_pk;
|
||||
struct sshkey_cert *cert;
|
||||
};
|
||||
|
||||
|
@ -171,6 +186,8 @@ int sshkey_to_blob(const struct sshkey *, u_char **, size_t *);
|
|||
int sshkey_to_base64(const struct sshkey *, char **);
|
||||
int sshkey_putb(const struct sshkey *, struct sshbuf *);
|
||||
int sshkey_puts(const struct sshkey *, struct sshbuf *);
|
||||
int sshkey_puts_opts(const struct sshkey *, struct sshbuf *,
|
||||
enum sshkey_serialize_rep);
|
||||
int sshkey_plain_to_blob(const struct sshkey *, u_char **, size_t *);
|
||||
int sshkey_putb_plain(const struct sshkey *, struct sshbuf *);
|
||||
|
||||
|
@ -186,6 +203,8 @@ void sshkey_dump_ec_key(const EC_KEY *);
|
|||
|
||||
/* private key parsing and serialisation */
|
||||
int sshkey_private_serialize(const struct sshkey *key, struct sshbuf *buf);
|
||||
int sshkey_private_serialize_opt(const struct sshkey *key, struct sshbuf *buf,
|
||||
enum sshkey_serialize_rep);
|
||||
int sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **keyp);
|
||||
|
||||
/* private key file format parsing and serialisation */
|
||||
|
@ -200,6 +219,15 @@ int sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
|
|||
/* XXX should be internal, but used by ssh-keygen */
|
||||
int ssh_rsa_generate_additional_parameters(struct sshkey *);
|
||||
|
||||
/* stateful keys (e.g. XMSS) */
|
||||
typedef void sshkey_printfn(const char *, ...) __attribute__((format(printf, 1, 2)));
|
||||
int sshkey_set_filename(struct sshkey *, const char *);
|
||||
int sshkey_enable_maxsign(struct sshkey *, u_int32_t);
|
||||
u_int32_t sshkey_signatures_left(const struct sshkey *);
|
||||
int sshkey_forward_state(const struct sshkey *, u_int32_t, sshkey_printfn *);
|
||||
int sshkey_private_serialize_maxsign(const struct sshkey *key, struct sshbuf *buf,
|
||||
u_int32_t maxsign, sshkey_printfn *pr);
|
||||
|
||||
#ifdef SSHKEY_INTERNAL
|
||||
int ssh_rsa_sign(const struct sshkey *key,
|
||||
u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
|
||||
|
@ -222,6 +250,11 @@ int ssh_ed25519_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
|
|||
int ssh_ed25519_verify(const struct sshkey *key,
|
||||
const u_char *signature, size_t signaturelen,
|
||||
const u_char *data, size_t datalen, u_int compat);
|
||||
int ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
|
||||
const u_char *data, size_t datalen, u_int compat);
|
||||
int ssh_xmss_verify(const struct sshkey *key,
|
||||
const u_char *signature, size_t signaturelen,
|
||||
const u_char *data, size_t datalen, u_int compat);
|
||||
#endif
|
||||
|
||||
#if !defined(WITH_OPENSSL)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
xmss_commons.c 20160722
|
||||
Andreas Hülsing
|
||||
Joost Rijneveld
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include "xmss_commons.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void to_byte(unsigned char *out, unsigned long long in, uint32_t bytes)
|
||||
{
|
||||
int32_t i;
|
||||
for (i = bytes-1; i >= 0; i--) {
|
||||
out[i] = in & 0xff;
|
||||
in = in >> 8;
|
||||
}
|
||||
}
|
||||
|
||||
void hexdump(const unsigned char *a, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < len; i++)
|
||||
printf("%02x", a[i]);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
xmss_commons.h 20160722
|
||||
Andreas Hülsing
|
||||
Joost Rijneveld
|
||||
Public domain.
|
||||
*/
|
||||
#ifndef XMSS_COMMONS_H
|
||||
#define XMSS_COMMONS_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void to_byte(unsigned char *output, unsigned long long in, uint32_t bytes);
|
||||
void hexdump(const unsigned char *a, size_t len);
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
xmss_fast.h version 20160722
|
||||
Andreas Hülsing
|
||||
Joost Rijneveld
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include "xmss_wots.h"
|
||||
|
||||
#ifndef XMSS_H
|
||||
#define XMSS_H
|
||||
typedef struct{
|
||||
unsigned int level;
|
||||
unsigned long long subtree;
|
||||
unsigned int subleaf;
|
||||
} leafaddr;
|
||||
|
||||
typedef struct{
|
||||
wots_params wots_par;
|
||||
unsigned int n;
|
||||
unsigned int h;
|
||||
unsigned int k;
|
||||
} xmss_params;
|
||||
|
||||
typedef struct{
|
||||
xmss_params xmss_par;
|
||||
unsigned int n;
|
||||
unsigned int h;
|
||||
unsigned int d;
|
||||
unsigned int index_len;
|
||||
} xmssmt_params;
|
||||
|
||||
typedef struct{
|
||||
unsigned int h;
|
||||
unsigned int next_idx;
|
||||
unsigned int stackusage;
|
||||
unsigned char completed;
|
||||
unsigned char *node;
|
||||
} treehash_inst;
|
||||
|
||||
typedef struct {
|
||||
unsigned char *stack;
|
||||
unsigned int stackoffset;
|
||||
unsigned char *stacklevels;
|
||||
unsigned char *auth;
|
||||
unsigned char *keep;
|
||||
treehash_inst *treehash;
|
||||
unsigned char *retain;
|
||||
unsigned int next_leaf;
|
||||
} bds_state;
|
||||
|
||||
/**
|
||||
* Initialize BDS state struct
|
||||
* parameter names are the same as used in the description of the BDS traversal
|
||||
*/
|
||||
void xmss_set_bds_state(bds_state *state, unsigned char *stack, int stackoffset, unsigned char *stacklevels, unsigned char *auth, unsigned char *keep, treehash_inst *treehash, unsigned char *retain, int next_leaf);
|
||||
/**
|
||||
* Initializes parameter set.
|
||||
* Needed, for any of the other methods.
|
||||
*/
|
||||
int xmss_set_params(xmss_params *params, int n, int h, int w, int k);
|
||||
/**
|
||||
* Initialize xmssmt_params struct
|
||||
* parameter names are the same as in the draft
|
||||
*
|
||||
* Especially h is the total tree height, i.e. the XMSS trees have height h/d
|
||||
*/
|
||||
int xmssmt_set_params(xmssmt_params *params, int n, int h, int d, int w, int k);
|
||||
/**
|
||||
* Generates a XMSS key pair for a given parameter set.
|
||||
* Format sk: [(32bit) idx || SK_SEED || SK_PRF || PUB_SEED || root]
|
||||
* Format pk: [root || PUB_SEED] omitting algo oid.
|
||||
*/
|
||||
int xmss_keypair(unsigned char *pk, unsigned char *sk, bds_state *state, xmss_params *params);
|
||||
/**
|
||||
* Signs a message.
|
||||
* Returns
|
||||
* 1. an array containing the signature followed by the message AND
|
||||
* 2. an updated secret key!
|
||||
*
|
||||
*/
|
||||
int xmss_sign(unsigned char *sk, bds_state *state, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg,unsigned long long msglen, const xmss_params *params);
|
||||
/**
|
||||
* Verifies a given message signature pair under a given public key.
|
||||
*
|
||||
* Note: msg and msglen are pure outputs which carry the message in case verification succeeds. The (input) message is assumed to be within sig_msg which has the form (sig||msg).
|
||||
*/
|
||||
int xmss_sign_open(unsigned char *msg,unsigned long long *msglen, const unsigned char *sig_msg,unsigned long long sig_msg_len, const unsigned char *pk, const xmss_params *params);
|
||||
|
||||
/*
|
||||
* Generates a XMSSMT key pair for a given parameter set.
|
||||
* Format sk: [(ceil(h/8) bit) idx || SK_SEED || SK_PRF || PUB_SEED || root]
|
||||
* Format pk: [root || PUB_SEED] omitting algo oid.
|
||||
*/
|
||||
int xmssmt_keypair(unsigned char *pk, unsigned char *sk, bds_state *states, unsigned char *wots_sigs, xmssmt_params *params);
|
||||
/**
|
||||
* Signs a message.
|
||||
* Returns
|
||||
* 1. an array containing the signature followed by the message AND
|
||||
* 2. an updated secret key!
|
||||
*
|
||||
*/
|
||||
int xmssmt_sign(unsigned char *sk, bds_state *state, unsigned char *wots_sigs, unsigned char *sig_msg, unsigned long long *sig_msg_len, const unsigned char *msg, unsigned long long msglen, const xmssmt_params *params);
|
||||
/**
|
||||
* Verifies a given message signature pair under a given public key.
|
||||
*/
|
||||
int xmssmt_sign_open(unsigned char *msg, unsigned long long *msglen, const unsigned char *sig_msg, unsigned long long sig_msg_len, const unsigned char *pk, const xmssmt_params *params);
|
||||
#endif
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
hash.c version 20160722
|
||||
Andreas Hülsing
|
||||
Joost Rijneveld
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include "xmss_hash_address.h"
|
||||
#include "xmss_commons.h"
|
||||
#include "xmss_hash.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
int core_hash_SHA2(unsigned char *, const unsigned int, const unsigned char *,
|
||||
unsigned int, const unsigned char *, unsigned long long, unsigned int);
|
||||
|
||||
unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]){
|
||||
#if IS_LITTLE_ENDIAN==1
|
||||
int i = 0;
|
||||
for(i=0;i<8;i++)
|
||||
to_byte(bytes+i*4, addr[i],4);
|
||||
return bytes;
|
||||
#else
|
||||
memcpy(bytes, addr, 32);
|
||||
return bytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
int core_hash_SHA2(unsigned char *out, const unsigned int type, const unsigned char *key, unsigned int keylen, const unsigned char *in, unsigned long long inlen, unsigned int n){
|
||||
unsigned long long i = 0;
|
||||
unsigned char buf[inlen + n + keylen];
|
||||
|
||||
// Input is (toByte(X, 32) || KEY || M)
|
||||
|
||||
// set toByte
|
||||
to_byte(buf, type, n);
|
||||
|
||||
for (i=0; i < keylen; i++) {
|
||||
buf[i+n] = key[i];
|
||||
}
|
||||
|
||||
for (i=0; i < inlen; i++) {
|
||||
buf[keylen + n + i] = in[i];
|
||||
}
|
||||
|
||||
if (n == 32) {
|
||||
SHA256(buf, inlen + keylen + n, out);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
if (n == 64) {
|
||||
SHA512(buf, inlen + keylen + n, out);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements PRF
|
||||
*/
|
||||
int prf(unsigned char *out, const unsigned char *in, const unsigned char *key, unsigned int keylen)
|
||||
{
|
||||
return core_hash_SHA2(out, 3, key, keylen, in, 32, keylen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Implemts H_msg
|
||||
*/
|
||||
int h_msg(unsigned char *out, const unsigned char *in, unsigned long long inlen, const unsigned char *key, const unsigned int keylen, const unsigned int n)
|
||||
{
|
||||
if (keylen != 3*n){
|
||||
// H_msg takes 3n-bit keys, but n does not match the keylength of keylen
|
||||
return -1;
|
||||
}
|
||||
return core_hash_SHA2(out, 2, key, keylen, in, inlen, n);
|
||||
}
|
||||
|
||||
/**
|
||||
* We assume the left half is in in[0]...in[n-1]
|
||||
*/
|
||||
int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n)
|
||||
{
|
||||
|
||||
unsigned char buf[2*n];
|
||||
unsigned char key[n];
|
||||
unsigned char bitmask[2*n];
|
||||
unsigned char byte_addr[32];
|
||||
unsigned int i;
|
||||
|
||||
setKeyAndMask(addr, 0);
|
||||
addr_to_byte(byte_addr, addr);
|
||||
prf(key, byte_addr, pub_seed, n);
|
||||
// Use MSB order
|
||||
setKeyAndMask(addr, 1);
|
||||
addr_to_byte(byte_addr, addr);
|
||||
prf(bitmask, byte_addr, pub_seed, n);
|
||||
setKeyAndMask(addr, 2);
|
||||
addr_to_byte(byte_addr, addr);
|
||||
prf(bitmask+n, byte_addr, pub_seed, n);
|
||||
for (i = 0; i < 2*n; i++) {
|
||||
buf[i] = in[i] ^ bitmask[i];
|
||||
}
|
||||
return core_hash_SHA2(out, 1, key, n, buf, 2*n, n);
|
||||
}
|
||||
|
||||
int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n)
|
||||
{
|
||||
unsigned char buf[n];
|
||||
unsigned char key[n];
|
||||
unsigned char bitmask[n];
|
||||
unsigned char byte_addr[32];
|
||||
unsigned int i;
|
||||
|
||||
setKeyAndMask(addr, 0);
|
||||
addr_to_byte(byte_addr, addr);
|
||||
prf(key, byte_addr, pub_seed, n);
|
||||
|
||||
setKeyAndMask(addr, 1);
|
||||
addr_to_byte(byte_addr, addr);
|
||||
prf(bitmask, byte_addr, pub_seed, n);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
buf[i] = in[i] ^ bitmask[i];
|
||||
}
|
||||
return core_hash_SHA2(out, 0, key, n, buf, n, n);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
hash.h version 20160722
|
||||
Andreas Hülsing
|
||||
Joost Rijneveld
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#ifndef HASH_H
|
||||
#define HASH_H
|
||||
|
||||
#define IS_LITTLE_ENDIAN 1
|
||||
|
||||
unsigned char* addr_to_byte(unsigned char *bytes, const uint32_t addr[8]);
|
||||
int prf(unsigned char *out, const unsigned char *in, const unsigned char *key, unsigned int keylen);
|
||||
int h_msg(unsigned char *out,const unsigned char *in,unsigned long long inlen, const unsigned char *key, const unsigned int keylen, const unsigned int n);
|
||||
int hash_h(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n);
|
||||
int hash_f(unsigned char *out, const unsigned char *in, const unsigned char *pub_seed, uint32_t addr[8], const unsigned int n);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
hash_address.c version 20160722
|
||||
Andreas Hülsing
|
||||
Joost Rijneveld
|
||||
Public domain.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include "xmss_hash_address.h" /* prototypes */
|
||||
|
||||
void setLayerADRS(uint32_t adrs[8], uint32_t layer){
|
||||
adrs[0] = layer;
|
||||
}
|
||||
|
||||
void setTreeADRS(uint32_t adrs[8], uint64_t tree){
|
||||
adrs[1] = (uint32_t) (tree >> 32);
|
||||
adrs[2] = (uint32_t) tree;
|
||||
}
|
||||
|
||||
void setType(uint32_t adrs[8], uint32_t type){
|
||||
adrs[3] = type;
|
||||
int i;
|
||||
for(i = 4; i < 8; i++){
|
||||
adrs[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void setKeyAndMask(uint32_t adrs[8], uint32_t keyAndMask){
|
||||
adrs[7] = keyAndMask;
|
||||
}
|
||||
|
||||
// OTS
|
||||
|
||||
void setOTSADRS(uint32_t adrs[8], uint32_t ots){
|
||||
adrs[4] = ots;
|
||||
}
|
||||
|
||||
void setChainADRS(uint32_t adrs[8], uint32_t chain){
|
||||
adrs[5] = chain;
|
||||
}
|
||||
|
||||
void setHashADRS(uint32_t adrs[8], uint32_t hash){
|
||||
adrs[6] = hash;
|
||||
}
|
||||
|
||||
// L-tree
|
||||
|
||||
void setLtreeADRS(uint32_t adrs[8], uint32_t ltree){
|
||||
adrs[4] = ltree;
|
||||
}
|
||||
|
||||
// Hash Tree & L-tree
|
||||
|
||||
void setTreeHeight(uint32_t adrs[8], uint32_t treeHeight){
|
||||
adrs[5] = treeHeight;
|
||||
}
|
||||
|
||||
void setTreeIndex(uint32_t adrs[8], uint32_t treeIndex){
|
||||
adrs[6] = treeIndex;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
hash_address.h version 20160722
|
||||
Andreas Hülsing
|
||||
Joost Rijneveld
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void setLayerADRS(uint32_t adrs[8], uint32_t layer);
|
||||
|
||||
void setTreeADRS(uint32_t adrs[8], uint64_t tree);
|
||||
|
||||
void setType(uint32_t adrs[8], uint32_t type);
|
||||
|
||||
void setKeyAndMask(uint32_t adrs[8], uint32_t keyAndMask);
|
||||
|
||||
// OTS
|
||||
|
||||
void setOTSADRS(uint32_t adrs[8], uint32_t ots);
|
||||
|
||||
void setChainADRS(uint32_t adrs[8], uint32_t chain);
|
||||
|
||||
void setHashADRS(uint32_t adrs[8], uint32_t hash);
|
||||
|
||||
// L-tree
|
||||
|
||||
void setLtreeADRS(uint32_t adrs[8], uint32_t ltree);
|
||||
|
||||
// Hash Tree & L-tree
|
||||
|
||||
void setTreeHeight(uint32_t adrs[8], uint32_t treeHeight);
|
||||
|
||||
void setTreeIndex(uint32_t adrs[8], uint32_t treeIndex);
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
wots.c version 20160722
|
||||
Andreas Hülsing
|
||||
Joost Rijneveld
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "xmss_commons.h"
|
||||
#include "xmss_hash.h"
|
||||
#include "xmss_wots.h"
|
||||
#include "xmss_hash_address.h"
|
||||
|
||||
|
||||
/* libm-free version of log2() for wots */
|
||||
static inline int
|
||||
wots_log2(uint32_t v)
|
||||
{
|
||||
int b;
|
||||
|
||||
for (b = sizeof (v) * CHAR_BIT - 1; b >= 0; b--) {
|
||||
if ((1U << b) & v) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
wots_set_params(wots_params *params, int n, int w)
|
||||
{
|
||||
params->n = n;
|
||||
params->w = w;
|
||||
params->log_w = wots_log2(params->w);
|
||||
params->len_1 = (CHAR_BIT * n) / params->log_w;
|
||||
params->len_2 = (wots_log2(params->len_1 * (w - 1)) / params->log_w) + 1;
|
||||
params->len = params->len_1 + params->len_2;
|
||||
params->keysize = params->len * params->n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method for pseudorandom key generation
|
||||
* Expands an n-byte array into a len*n byte array
|
||||
* this is done using PRF
|
||||
*/
|
||||
static void expand_seed(unsigned char *outseeds, const unsigned char *inseed, const wots_params *params)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
unsigned char ctr[32];
|
||||
for(i = 0; i < params->len; i++){
|
||||
to_byte(ctr, i, 32);
|
||||
prf((outseeds + (i*params->n)), ctr, inseed, params->n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the chaining function.
|
||||
* out and in have to be n-byte arrays
|
||||
*
|
||||
* interpretes in as start-th value of the chain
|
||||
* addr has to contain the address of the chain
|
||||
*/
|
||||
static void gen_chain(unsigned char *out, const unsigned char *in, unsigned int start, unsigned int steps, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8])
|
||||
{
|
||||
uint32_t i, j;
|
||||
for (j = 0; j < params->n; j++)
|
||||
out[j] = in[j];
|
||||
|
||||
for (i = start; i < (start+steps) && i < params->w; i++) {
|
||||
setHashADRS(addr, i);
|
||||
hash_f(out, out, pub_seed, addr, params->n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* base_w algorithm as described in draft.
|
||||
*
|
||||
*
|
||||
*/
|
||||
static void base_w(int *output, const int out_len, const unsigned char *input, const wots_params *params)
|
||||
{
|
||||
int in = 0;
|
||||
int out = 0;
|
||||
uint32_t total = 0;
|
||||
int bits = 0;
|
||||
int consumed = 0;
|
||||
|
||||
for (consumed = 0; consumed < out_len; consumed++) {
|
||||
if (bits == 0) {
|
||||
total = input[in];
|
||||
in++;
|
||||
bits += 8;
|
||||
}
|
||||
bits -= params->log_w;
|
||||
output[out] = (total >> bits) & (params->w - 1);
|
||||
out++;
|
||||
}
|
||||
}
|
||||
|
||||
void wots_pkgen(unsigned char *pk, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8])
|
||||
{
|
||||
uint32_t i;
|
||||
expand_seed(pk, sk, params);
|
||||
for (i=0; i < params->len; i++) {
|
||||
setChainADRS(addr, i);
|
||||
gen_chain(pk+i*params->n, pk+i*params->n, 0, params->w-1, params, pub_seed, addr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int wots_sign(unsigned char *sig, const unsigned char *msg, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8])
|
||||
{
|
||||
//int basew[params->len];
|
||||
int csum = 0;
|
||||
uint32_t i = 0;
|
||||
int *basew = calloc(params->len, sizeof(int));
|
||||
if (basew == NULL)
|
||||
return -1;
|
||||
|
||||
base_w(basew, params->len_1, msg, params);
|
||||
|
||||
for (i=0; i < params->len_1; i++) {
|
||||
csum += params->w - 1 - basew[i];
|
||||
}
|
||||
|
||||
csum = csum << (8 - ((params->len_2 * params->log_w) % 8));
|
||||
|
||||
int len_2_bytes = ((params->len_2 * params->log_w) + 7) / 8;
|
||||
|
||||
unsigned char csum_bytes[len_2_bytes];
|
||||
to_byte(csum_bytes, csum, len_2_bytes);
|
||||
|
||||
int csum_basew[params->len_2];
|
||||
base_w(csum_basew, params->len_2, csum_bytes, params);
|
||||
|
||||
for (i = 0; i < params->len_2; i++) {
|
||||
basew[params->len_1 + i] = csum_basew[i];
|
||||
}
|
||||
|
||||
expand_seed(sig, sk, params);
|
||||
|
||||
for (i = 0; i < params->len; i++) {
|
||||
setChainADRS(addr, i);
|
||||
gen_chain(sig+i*params->n, sig+i*params->n, 0, basew[i], params, pub_seed, addr);
|
||||
}
|
||||
free(basew);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wots_pkFromSig(unsigned char *pk, const unsigned char *sig, const unsigned char *msg, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8])
|
||||
{
|
||||
int csum = 0;
|
||||
uint32_t i = 0;
|
||||
int *basew = calloc(params->len, sizeof(int));
|
||||
if (basew == NULL)
|
||||
return -1;
|
||||
|
||||
base_w(basew, params->len_1, msg, params);
|
||||
|
||||
for (i=0; i < params->len_1; i++) {
|
||||
csum += params->w - 1 - basew[i];
|
||||
}
|
||||
|
||||
csum = csum << (8 - ((params->len_2 * params->log_w) % 8));
|
||||
|
||||
int len_2_bytes = ((params->len_2 * params->log_w) + 7) / 8;
|
||||
|
||||
unsigned char csum_bytes[len_2_bytes];
|
||||
to_byte(csum_bytes, csum, len_2_bytes);
|
||||
|
||||
int csum_basew[params->len_2];
|
||||
base_w(csum_basew, params->len_2, csum_bytes, params);
|
||||
|
||||
for (i = 0; i < params->len_2; i++) {
|
||||
basew[params->len_1 + i] = csum_basew[i];
|
||||
}
|
||||
for (i=0; i < params->len; i++) {
|
||||
setChainADRS(addr, i);
|
||||
gen_chain(pk+i*params->n, sig+i*params->n, basew[i], params->w-1-basew[i], params, pub_seed, addr);
|
||||
}
|
||||
free(basew);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
wots.h version 20160722
|
||||
Andreas Hülsing
|
||||
Joost Rijneveld
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#ifndef WOTS_H
|
||||
#define WOTS_H
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
/**
|
||||
* WOTS parameter set
|
||||
*
|
||||
* Meaning as defined in draft-irtf-cfrg-xmss-hash-based-signatures-02
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t len_1;
|
||||
uint32_t len_2;
|
||||
uint32_t len;
|
||||
uint32_t n;
|
||||
uint32_t w;
|
||||
uint32_t log_w;
|
||||
uint32_t keysize;
|
||||
} wots_params;
|
||||
|
||||
/**
|
||||
* Set the WOTS parameters,
|
||||
* only m, n, w are required as inputs,
|
||||
* len, len_1, and len_2 are computed from those.
|
||||
*
|
||||
* Assumes w is a power of 2
|
||||
*/
|
||||
void wots_set_params(wots_params *params, int n, int w);
|
||||
|
||||
/**
|
||||
* WOTS key generation. Takes a 32byte seed for the secret key, expands it to a full WOTS secret key and computes the corresponding public key.
|
||||
* For this it takes the seed pub_seed which is used to generate bitmasks and hash keys and the address of this WOTS key pair addr
|
||||
*
|
||||
* params, must have been initialized before using wots_set params for params ! This is not done in this function
|
||||
*
|
||||
* Places the computed public key at address pk.
|
||||
*/
|
||||
void wots_pkgen(unsigned char *pk, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]);
|
||||
|
||||
/**
|
||||
* Takes a m-byte message and the 32-byte seed for the secret key to compute a signature that is placed at "sig".
|
||||
*
|
||||
*/
|
||||
int wots_sign(unsigned char *sig, const unsigned char *msg, const unsigned char *sk, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]);
|
||||
|
||||
/**
|
||||
* Takes a WOTS signature, a m-byte message and computes a WOTS public key that it places at pk.
|
||||
*
|
||||
*/
|
||||
int wots_pkFromSig(unsigned char *pk, const unsigned char *sig, const unsigned char *msg, const wots_params *params, const unsigned char *pub_seed, uint32_t addr[8]);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue