summaryrefslogtreecommitdiff
path: root/sshkey.c
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 /sshkey.c
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
Diffstat (limited to 'sshkey.c')
-rw-r--r--sshkey.c410
1 files changed, 395 insertions, 15 deletions
diff --git a/sshkey.c b/sshkey.c
index 0e146d4d6..d8ee70ca0 100644
--- a/sshkey.c
+++ b/sshkey.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: sshkey.c,v 1.61 2018/02/14 16:03:32 jsing Exp $ */ 1/* $OpenBSD: sshkey.c,v 1.62 2018/02/23 15:58:38 markus Exp $ */
2/* 2/*
3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 3 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
4 * Copyright (c) 2008 Alexander von Gernler. All rights reserved. 4 * Copyright (c) 2008 Alexander von Gernler. All rights reserved.
@@ -55,8 +55,11 @@
55#include "digest.h" 55#include "digest.h"
56#define SSHKEY_INTERNAL 56#define SSHKEY_INTERNAL
57#include "sshkey.h" 57#include "sshkey.h"
58#include "sshkey-xmss.h"
58#include "match.h" 59#include "match.h"
59 60
61#include "xmss_fast.h"
62
60/* openssh private key file format */ 63/* openssh private key file format */
61#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" 64#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n"
62#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" 65#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n"
@@ -71,6 +74,8 @@
71/* Version identification string for SSH v1 identity files. */ 74/* Version identification string for SSH v1 identity files. */
72#define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n" 75#define LEGACY_BEGIN "SSH PRIVATE KEY FILE FORMAT 1.1\n"
73 76
77int sshkey_private_serialize_opt(const struct sshkey *key,
78 struct sshbuf *buf, enum sshkey_serialize_rep);
74static int sshkey_from_blob_internal(struct sshbuf *buf, 79static int sshkey_from_blob_internal(struct sshbuf *buf,
75 struct sshkey **keyp, int allow_cert); 80 struct sshkey **keyp, int allow_cert);
76 81
@@ -87,6 +92,11 @@ static const struct keytype keytypes[] = {
87 { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0, 0 }, 92 { "ssh-ed25519", "ED25519", KEY_ED25519, 0, 0, 0 },
88 { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT", 93 { "ssh-ed25519-cert-v01@openssh.com", "ED25519-CERT",
89 KEY_ED25519_CERT, 0, 1, 0 }, 94 KEY_ED25519_CERT, 0, 1, 0 },
95#ifdef WITH_XMSS
96 { "ssh-xmss@openssh.com", "XMSS", KEY_XMSS, 0, 0, 0 },
97 { "ssh-xmss-cert-v01@openssh.com", "XMSS-CERT",
98 KEY_XMSS_CERT, 0, 1, 0 },
99#endif /* WITH_XMSS */
90#ifdef WITH_OPENSSL 100#ifdef WITH_OPENSSL
91 { "ssh-rsa", "RSA", KEY_RSA, 0, 0, 0 }, 101 { "ssh-rsa", "RSA", KEY_RSA, 0, 0, 0 },
92 { "rsa-sha2-256", "RSA", KEY_RSA, 0, 0, 1 }, 102 { "rsa-sha2-256", "RSA", KEY_RSA, 0, 0, 1 },
@@ -274,6 +284,8 @@ sshkey_size(const struct sshkey *k)
274#endif /* WITH_OPENSSL */ 284#endif /* WITH_OPENSSL */
275 case KEY_ED25519: 285 case KEY_ED25519:
276 case KEY_ED25519_CERT: 286 case KEY_ED25519_CERT:
287 case KEY_XMSS:
288 case KEY_XMSS_CERT:
277 return 256; /* XXX */ 289 return 256; /* XXX */
278 } 290 }
279 return 0; 291 return 0;
@@ -287,6 +299,7 @@ sshkey_type_is_valid_ca(int type)
287 case KEY_DSA: 299 case KEY_DSA:
288 case KEY_ECDSA: 300 case KEY_ECDSA:
289 case KEY_ED25519: 301 case KEY_ED25519:
302 case KEY_XMSS:
290 return 1; 303 return 1;
291 default: 304 default:
292 return 0; 305 return 0;
@@ -314,6 +327,8 @@ sshkey_type_plain(int type)
314 return KEY_ECDSA; 327 return KEY_ECDSA;
315 case KEY_ED25519_CERT: 328 case KEY_ED25519_CERT:
316 return KEY_ED25519; 329 return KEY_ED25519;
330 case KEY_XMSS_CERT:
331 return KEY_XMSS;
317 default: 332 default:
318 return type; 333 return type;
319 } 334 }
@@ -461,6 +476,8 @@ sshkey_new(int type)
461 k->cert = NULL; 476 k->cert = NULL;
462 k->ed25519_sk = NULL; 477 k->ed25519_sk = NULL;
463 k->ed25519_pk = NULL; 478 k->ed25519_pk = NULL;
479 k->xmss_sk = NULL;
480 k->xmss_pk = NULL;
464 switch (k->type) { 481 switch (k->type) {
465#ifdef WITH_OPENSSL 482#ifdef WITH_OPENSSL
466 case KEY_RSA: 483 case KEY_RSA:
@@ -494,6 +511,8 @@ sshkey_new(int type)
494#endif /* WITH_OPENSSL */ 511#endif /* WITH_OPENSSL */
495 case KEY_ED25519: 512 case KEY_ED25519:
496 case KEY_ED25519_CERT: 513 case KEY_ED25519_CERT:
514 case KEY_XMSS:
515 case KEY_XMSS_CERT:
497 /* no need to prealloc */ 516 /* no need to prealloc */
498 break; 517 break;
499 case KEY_UNSPEC: 518 case KEY_UNSPEC:
@@ -542,6 +561,8 @@ sshkey_add_private(struct sshkey *k)
542#endif /* WITH_OPENSSL */ 561#endif /* WITH_OPENSSL */
543 case KEY_ED25519: 562 case KEY_ED25519:
544 case KEY_ED25519_CERT: 563 case KEY_ED25519_CERT:
564 case KEY_XMSS:
565 case KEY_XMSS_CERT:
545 /* no need to prealloc */ 566 /* no need to prealloc */
546 break; 567 break;
547 case KEY_UNSPEC: 568 case KEY_UNSPEC:
@@ -598,6 +619,20 @@ sshkey_free(struct sshkey *k)
598 freezero(k->ed25519_sk, ED25519_SK_SZ); 619 freezero(k->ed25519_sk, ED25519_SK_SZ);
599 k->ed25519_sk = NULL; 620 k->ed25519_sk = NULL;
600 break; 621 break;
622#ifdef WITH_XMSS
623 case KEY_XMSS:
624 case KEY_XMSS_CERT:
625 freezero(k->xmss_pk, sshkey_xmss_pklen(k));
626 k->xmss_pk = NULL;
627 freezero(k->xmss_sk, sshkey_xmss_sklen(k));
628 k->xmss_sk = NULL;
629 sshkey_xmss_free_state(k);
630 free(k->xmss_name);
631 k->xmss_name = NULL;
632 free(k->xmss_filename);
633 k->xmss_filename = NULL;
634 break;
635#endif /* WITH_XMSS */
601 case KEY_UNSPEC: 636 case KEY_UNSPEC:
602 break; 637 break;
603 default: 638 default:
@@ -677,6 +712,13 @@ sshkey_equal_public(const struct sshkey *a, const struct sshkey *b)
677 case KEY_ED25519_CERT: 712 case KEY_ED25519_CERT:
678 return a->ed25519_pk != NULL && b->ed25519_pk != NULL && 713 return a->ed25519_pk != NULL && b->ed25519_pk != NULL &&
679 memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0; 714 memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0;
715#ifdef WITH_XMSS
716 case KEY_XMSS:
717 case KEY_XMSS_CERT:
718 return a->xmss_pk != NULL && b->xmss_pk != NULL &&
719 sshkey_xmss_pklen(a) == sshkey_xmss_pklen(b) &&
720 memcmp(a->xmss_pk, b->xmss_pk, sshkey_xmss_pklen(a)) == 0;
721#endif /* WITH_XMSS */
680 default: 722 default:
681 return 0; 723 return 0;
682 } 724 }
@@ -696,7 +738,8 @@ sshkey_equal(const struct sshkey *a, const struct sshkey *b)
696} 738}
697 739
698static int 740static int
699to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain) 741to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain,
742 enum sshkey_serialize_rep opts)
700{ 743{
701 int type, ret = SSH_ERR_INTERNAL_ERROR; 744 int type, ret = SSH_ERR_INTERNAL_ERROR;
702 const char *typename; 745 const char *typename;
@@ -720,6 +763,9 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain)
720 case KEY_RSA_CERT: 763 case KEY_RSA_CERT:
721#endif /* WITH_OPENSSL */ 764#endif /* WITH_OPENSSL */
722 case KEY_ED25519_CERT: 765 case KEY_ED25519_CERT:
766#ifdef WITH_XMSS
767 case KEY_XMSS_CERT:
768#endif /* WITH_XMSS */
723 /* Use the existing blob */ 769 /* Use the existing blob */
724 /* XXX modified flag? */ 770 /* XXX modified flag? */
725 if ((ret = sshbuf_putb(b, key->cert->certblob)) != 0) 771 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)
764 key->ed25519_pk, ED25519_PK_SZ)) != 0) 810 key->ed25519_pk, ED25519_PK_SZ)) != 0)
765 return ret; 811 return ret;
766 break; 812 break;
813#ifdef WITH_XMSS
814 case KEY_XMSS:
815 if (key->xmss_name == NULL || key->xmss_pk == NULL ||
816 sshkey_xmss_pklen(key) == 0)
817 return SSH_ERR_INVALID_ARGUMENT;
818 if ((ret = sshbuf_put_cstring(b, typename)) != 0 ||
819 (ret = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
820 (ret = sshbuf_put_string(b,
821 key->xmss_pk, sshkey_xmss_pklen(key))) != 0 ||
822 (ret = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0)
823 return ret;
824 break;
825#endif /* WITH_XMSS */
767 default: 826 default:
768 return SSH_ERR_KEY_TYPE_UNKNOWN; 827 return SSH_ERR_KEY_TYPE_UNKNOWN;
769 } 828 }
@@ -773,18 +832,19 @@ to_blob_buf(const struct sshkey *key, struct sshbuf *b, int force_plain)
773int 832int
774sshkey_putb(const struct sshkey *key, struct sshbuf *b) 833sshkey_putb(const struct sshkey *key, struct sshbuf *b)
775{ 834{
776 return to_blob_buf(key, b, 0); 835 return to_blob_buf(key, b, 0, SSHKEY_SERIALIZE_DEFAULT);
777} 836}
778 837
779int 838int
780sshkey_puts(const struct sshkey *key, struct sshbuf *b) 839sshkey_puts_opts(const struct sshkey *key, struct sshbuf *b,
840 enum sshkey_serialize_rep opts)
781{ 841{
782 struct sshbuf *tmp; 842 struct sshbuf *tmp;
783 int r; 843 int r;
784 844
785 if ((tmp = sshbuf_new()) == NULL) 845 if ((tmp = sshbuf_new()) == NULL)
786 return SSH_ERR_ALLOC_FAIL; 846 return SSH_ERR_ALLOC_FAIL;
787 r = to_blob_buf(key, tmp, 0); 847 r = to_blob_buf(key, tmp, 0, opts);
788 if (r == 0) 848 if (r == 0)
789 r = sshbuf_put_stringb(b, tmp); 849 r = sshbuf_put_stringb(b, tmp);
790 sshbuf_free(tmp); 850 sshbuf_free(tmp);
@@ -792,13 +852,20 @@ sshkey_puts(const struct sshkey *key, struct sshbuf *b)
792} 852}
793 853
794int 854int
855sshkey_puts(const struct sshkey *key, struct sshbuf *b)
856{
857 return sshkey_puts_opts(key, b, SSHKEY_SERIALIZE_DEFAULT);
858}
859
860int
795sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b) 861sshkey_putb_plain(const struct sshkey *key, struct sshbuf *b)
796{ 862{
797 return to_blob_buf(key, b, 1); 863 return to_blob_buf(key, b, 1, SSHKEY_SERIALIZE_DEFAULT);
798} 864}
799 865
800static int 866static int
801to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain) 867to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain,
868 enum sshkey_serialize_rep opts)
802{ 869{
803 int ret = SSH_ERR_INTERNAL_ERROR; 870 int ret = SSH_ERR_INTERNAL_ERROR;
804 size_t len; 871 size_t len;
@@ -810,7 +877,7 @@ to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain)
810 *blobp = NULL; 877 *blobp = NULL;
811 if ((b = sshbuf_new()) == NULL) 878 if ((b = sshbuf_new()) == NULL)
812 return SSH_ERR_ALLOC_FAIL; 879 return SSH_ERR_ALLOC_FAIL;
813 if ((ret = to_blob_buf(key, b, force_plain)) != 0) 880 if ((ret = to_blob_buf(key, b, force_plain, opts)) != 0)
814 goto out; 881 goto out;
815 len = sshbuf_len(b); 882 len = sshbuf_len(b);
816 if (lenp != NULL) 883 if (lenp != NULL)
@@ -831,13 +898,13 @@ to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp, int force_plain)
831int 898int
832sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) 899sshkey_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
833{ 900{
834 return to_blob(key, blobp, lenp, 0); 901 return to_blob(key, blobp, lenp, 0, SSHKEY_SERIALIZE_DEFAULT);
835} 902}
836 903
837int 904int
838sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp) 905sshkey_plain_to_blob(const struct sshkey *key, u_char **blobp, size_t *lenp)
839{ 906{
840 return to_blob(key, blobp, lenp, 1); 907 return to_blob(key, blobp, lenp, 1, SSHKEY_SERIALIZE_DEFAULT);
841} 908}
842 909
843int 910int
@@ -856,7 +923,8 @@ sshkey_fingerprint_raw(const struct sshkey *k, int dgst_alg,
856 r = SSH_ERR_INVALID_ARGUMENT; 923 r = SSH_ERR_INVALID_ARGUMENT;
857 goto out; 924 goto out;
858 } 925 }
859 if ((r = to_blob(k, &blob, &blob_len, 1)) != 0) 926 if ((r = to_blob(k, &blob, &blob_len, 1, SSHKEY_SERIALIZE_DEFAULT))
927 != 0)
860 goto out; 928 goto out;
861 if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) { 929 if ((ret = calloc(1, SSH_DIGEST_MAX_LENGTH)) == NULL) {
862 r = SSH_ERR_ALLOC_FAIL; 930 r = SSH_ERR_ALLOC_FAIL;
@@ -1173,6 +1241,10 @@ sshkey_read(struct sshkey *ret, char **cpp)
1173 case KEY_ECDSA_CERT: 1241 case KEY_ECDSA_CERT:
1174 case KEY_RSA_CERT: 1242 case KEY_RSA_CERT:
1175 case KEY_ED25519_CERT: 1243 case KEY_ED25519_CERT:
1244#ifdef WITH_XMSS
1245 case KEY_XMSS:
1246 case KEY_XMSS_CERT:
1247#endif /* WITH_XMSS */
1176 space = strchr(cp, ' '); 1248 space = strchr(cp, ' ');
1177 if (space == NULL) 1249 if (space == NULL)
1178 return SSH_ERR_INVALID_FORMAT; 1250 return SSH_ERR_INVALID_FORMAT;
@@ -1270,6 +1342,25 @@ sshkey_read(struct sshkey *ret, char **cpp)
1270 /* XXX */ 1342 /* XXX */
1271#endif 1343#endif
1272 break; 1344 break;
1345#ifdef WITH_XMSS
1346 case KEY_XMSS:
1347 free(ret->xmss_pk);
1348 ret->xmss_pk = k->xmss_pk;
1349 k->xmss_pk = NULL;
1350 free(ret->xmss_state);
1351 ret->xmss_state = k->xmss_state;
1352 k->xmss_state = NULL;
1353 free(ret->xmss_name);
1354 ret->xmss_name = k->xmss_name;
1355 k->xmss_name = NULL;
1356 free(ret->xmss_filename);
1357 ret->xmss_filename = k->xmss_filename;
1358 k->xmss_filename = NULL;
1359#ifdef DEBUG_PK
1360 /* XXX */
1361#endif
1362 break;
1363#endif /* WITH_XMSS */
1273 } 1364 }
1274 *cpp = ep; 1365 *cpp = ep;
1275 retval = 0; 1366 retval = 0;
@@ -1528,6 +1619,11 @@ sshkey_generate(int type, u_int bits, struct sshkey **keyp)
1528 crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk); 1619 crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk);
1529 ret = 0; 1620 ret = 0;
1530 break; 1621 break;
1622#ifdef WITH_XMSS
1623 case KEY_XMSS:
1624 ret = sshkey_xmss_generate_private_key(k, bits);
1625 break;
1626#endif /* WITH_XMSS */
1531#ifdef WITH_OPENSSL 1627#ifdef WITH_OPENSSL
1532 case KEY_DSA: 1628 case KEY_DSA:
1533 ret = dsa_generate_private_key(bits, &k->dsa); 1629 ret = dsa_generate_private_key(bits, &k->dsa);
@@ -1671,6 +1767,29 @@ sshkey_from_private(const struct sshkey *k, struct sshkey **pkp)
1671 memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); 1767 memcpy(n->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
1672 } 1768 }
1673 break; 1769 break;
1770#ifdef WITH_XMSS
1771 case KEY_XMSS:
1772 case KEY_XMSS_CERT:
1773 if ((n = sshkey_new(k->type)) == NULL)
1774 return SSH_ERR_ALLOC_FAIL;
1775 if ((ret = sshkey_xmss_init(n, k->xmss_name)) != 0) {
1776 sshkey_free(n);
1777 return ret;
1778 }
1779 if (k->xmss_pk != NULL) {
1780 size_t pklen = sshkey_xmss_pklen(k);
1781 if (pklen == 0 || sshkey_xmss_pklen(n) != pklen) {
1782 sshkey_free(n);
1783 return SSH_ERR_INTERNAL_ERROR;
1784 }
1785 if ((n->xmss_pk = malloc(pklen)) == NULL) {
1786 sshkey_free(n);
1787 return SSH_ERR_ALLOC_FAIL;
1788 }
1789 memcpy(n->xmss_pk, k->xmss_pk, pklen);
1790 }
1791 break;
1792#endif /* WITH_XMSS */
1674 default: 1793 default:
1675 return SSH_ERR_KEY_TYPE_UNKNOWN; 1794 return SSH_ERR_KEY_TYPE_UNKNOWN;
1676 } 1795 }
@@ -1812,7 +1931,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
1812 int allow_cert) 1931 int allow_cert)
1813{ 1932{
1814 int type, ret = SSH_ERR_INTERNAL_ERROR; 1933 int type, ret = SSH_ERR_INTERNAL_ERROR;
1815 char *ktype = NULL, *curve = NULL; 1934 char *ktype = NULL, *curve = NULL, *xmss_name = NULL;
1816 struct sshkey *key = NULL; 1935 struct sshkey *key = NULL;
1817 size_t len; 1936 size_t len;
1818 u_char *pk = NULL; 1937 u_char *pk = NULL;
@@ -1963,6 +2082,36 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
1963 key->ed25519_pk = pk; 2082 key->ed25519_pk = pk;
1964 pk = NULL; 2083 pk = NULL;
1965 break; 2084 break;
2085#ifdef WITH_XMSS
2086 case KEY_XMSS_CERT:
2087 /* Skip nonce */
2088 if (sshbuf_get_string_direct(b, NULL, NULL) != 0) {
2089 ret = SSH_ERR_INVALID_FORMAT;
2090 goto out;
2091 }
2092 /* FALLTHROUGH */
2093 case KEY_XMSS:
2094 if ((ret = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0)
2095 goto out;
2096 if ((key = sshkey_new(type)) == NULL) {
2097 ret = SSH_ERR_ALLOC_FAIL;
2098 goto out;
2099 }
2100 if ((ret = sshkey_xmss_init(key, xmss_name)) != 0)
2101 goto out;
2102 if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
2103 goto out;
2104 if (len == 0 || len != sshkey_xmss_pklen(key)) {
2105 ret = SSH_ERR_INVALID_FORMAT;
2106 goto out;
2107 }
2108 key->xmss_pk = pk;
2109 pk = NULL;
2110 if (type != KEY_XMSS_CERT &&
2111 (ret = sshkey_xmss_deserialize_pk_info(key, b)) != 0)
2112 goto out;
2113 break;
2114#endif /* WITH_XMSS */
1966 case KEY_UNSPEC: 2115 case KEY_UNSPEC:
1967 default: 2116 default:
1968 ret = SSH_ERR_KEY_TYPE_UNKNOWN; 2117 ret = SSH_ERR_KEY_TYPE_UNKNOWN;
@@ -1985,6 +2134,7 @@ sshkey_from_blob_internal(struct sshbuf *b, struct sshkey **keyp,
1985 out: 2134 out:
1986 sshbuf_free(copy); 2135 sshbuf_free(copy);
1987 sshkey_free(key); 2136 sshkey_free(key);
2137 free(xmss_name);
1988 free(ktype); 2138 free(ktype);
1989 free(curve); 2139 free(curve);
1990 free(pk); 2140 free(pk);
@@ -2079,6 +2229,11 @@ sshkey_sign(const struct sshkey *key,
2079 case KEY_ED25519: 2229 case KEY_ED25519:
2080 case KEY_ED25519_CERT: 2230 case KEY_ED25519_CERT:
2081 return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat); 2231 return ssh_ed25519_sign(key, sigp, lenp, data, datalen, compat);
2232#ifdef WITH_XMSS
2233 case KEY_XMSS:
2234 case KEY_XMSS_CERT:
2235 return ssh_xmss_sign(key, sigp, lenp, data, datalen, compat);
2236#endif /* WITH_XMSS */
2082 default: 2237 default:
2083 return SSH_ERR_KEY_TYPE_UNKNOWN; 2238 return SSH_ERR_KEY_TYPE_UNKNOWN;
2084 } 2239 }
@@ -2112,6 +2267,11 @@ sshkey_verify(const struct sshkey *key,
2112 case KEY_ED25519: 2267 case KEY_ED25519:
2113 case KEY_ED25519_CERT: 2268 case KEY_ED25519_CERT:
2114 return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat); 2269 return ssh_ed25519_verify(key, sig, siglen, data, dlen, compat);
2270#ifdef WITH_XMSS
2271 case KEY_XMSS:
2272 case KEY_XMSS_CERT:
2273 return ssh_xmss_verify(key, sig, siglen, data, dlen, compat);
2274#endif /* WITH_XMSS */
2115 default: 2275 default:
2116 return SSH_ERR_KEY_TYPE_UNKNOWN; 2276 return SSH_ERR_KEY_TYPE_UNKNOWN;
2117 } 2277 }
@@ -2135,6 +2295,8 @@ sshkey_demote(const struct sshkey *k, struct sshkey **dkp)
2135 pk->rsa = NULL; 2295 pk->rsa = NULL;
2136 pk->ed25519_pk = NULL; 2296 pk->ed25519_pk = NULL;
2137 pk->ed25519_sk = NULL; 2297 pk->ed25519_sk = NULL;
2298 pk->xmss_pk = NULL;
2299 pk->xmss_sk = NULL;
2138 2300
2139 switch (k->type) { 2301 switch (k->type) {
2140#ifdef WITH_OPENSSL 2302#ifdef WITH_OPENSSL
@@ -2196,6 +2358,29 @@ sshkey_demote(const struct sshkey *k, struct sshkey **dkp)
2196 memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ); 2358 memcpy(pk->ed25519_pk, k->ed25519_pk, ED25519_PK_SZ);
2197 } 2359 }
2198 break; 2360 break;
2361#ifdef WITH_XMSS
2362 case KEY_XMSS_CERT:
2363 if ((ret = sshkey_cert_copy(k, pk)) != 0)
2364 goto fail;
2365 /* FALLTHROUGH */
2366 case KEY_XMSS:
2367 if ((ret = sshkey_xmss_init(pk, k->xmss_name)) != 0)
2368 goto fail;
2369 if (k->xmss_pk != NULL) {
2370 size_t pklen = sshkey_xmss_pklen(k);
2371
2372 if (pklen == 0 || sshkey_xmss_pklen(pk) != pklen) {
2373 ret = SSH_ERR_INTERNAL_ERROR;
2374 goto fail;
2375 }
2376 if ((pk->xmss_pk = malloc(pklen)) == NULL) {
2377 ret = SSH_ERR_ALLOC_FAIL;
2378 goto fail;
2379 }
2380 memcpy(pk->xmss_pk, k->xmss_pk, pklen);
2381 }
2382 break;
2383#endif /* WITH_XMSS */
2199 default: 2384 default:
2200 ret = SSH_ERR_KEY_TYPE_UNKNOWN; 2385 ret = SSH_ERR_KEY_TYPE_UNKNOWN;
2201 fail: 2386 fail:
@@ -2227,6 +2412,11 @@ sshkey_to_certified(struct sshkey *k)
2227 case KEY_ED25519: 2412 case KEY_ED25519:
2228 newtype = KEY_ED25519_CERT; 2413 newtype = KEY_ED25519_CERT;
2229 break; 2414 break;
2415#ifdef WITH_XMSS
2416 case KEY_XMSS:
2417 newtype = KEY_XMSS_CERT;
2418 break;
2419#endif /* WITH_XMSS */
2230 default: 2420 default:
2231 return SSH_ERR_INVALID_ARGUMENT; 2421 return SSH_ERR_INVALID_ARGUMENT;
2232 } 2422 }
@@ -2311,6 +2501,18 @@ sshkey_certify_custom(struct sshkey *k, struct sshkey *ca, const char *alg,
2311 k->ed25519_pk, ED25519_PK_SZ)) != 0) 2501 k->ed25519_pk, ED25519_PK_SZ)) != 0)
2312 goto out; 2502 goto out;
2313 break; 2503 break;
2504#ifdef WITH_XMSS
2505 case KEY_XMSS_CERT:
2506 if (k->xmss_name == NULL) {
2507 ret = SSH_ERR_INVALID_ARGUMENT;
2508 goto out;
2509 }
2510 if ((ret = sshbuf_put_cstring(cert, k->xmss_name)) ||
2511 (ret = sshbuf_put_string(cert,
2512 k->xmss_pk, sshkey_xmss_pklen(k))) != 0)
2513 goto out;
2514 break;
2515#endif /* WITH_XMSS */
2314 default: 2516 default:
2315 ret = SSH_ERR_INVALID_ARGUMENT; 2517 ret = SSH_ERR_INVALID_ARGUMENT;
2316 goto out; 2518 goto out;
@@ -2468,7 +2670,8 @@ sshkey_format_cert_validity(const struct sshkey_cert *cert, char *s, size_t l)
2468} 2670}
2469 2671
2470int 2672int
2471sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b) 2673sshkey_private_serialize_opt(const struct sshkey *key, struct sshbuf *b,
2674 enum sshkey_serialize_rep opts)
2472{ 2675{
2473 int r = SSH_ERR_INTERNAL_ERROR; 2676 int r = SSH_ERR_INTERNAL_ERROR;
2474 2677
@@ -2554,6 +2757,36 @@ sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
2554 ED25519_SK_SZ)) != 0) 2757 ED25519_SK_SZ)) != 0)
2555 goto out; 2758 goto out;
2556 break; 2759 break;
2760#ifdef WITH_XMSS
2761 case KEY_XMSS:
2762 if (key->xmss_name == NULL) {
2763 r = SSH_ERR_INVALID_ARGUMENT;
2764 goto out;
2765 }
2766 if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
2767 (r = sshbuf_put_string(b, key->xmss_pk,
2768 sshkey_xmss_pklen(key))) != 0 ||
2769 (r = sshbuf_put_string(b, key->xmss_sk,
2770 sshkey_xmss_sklen(key))) != 0 ||
2771 (r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0)
2772 goto out;
2773 break;
2774 case KEY_XMSS_CERT:
2775 if (key->cert == NULL || sshbuf_len(key->cert->certblob) == 0 ||
2776 key->xmss_name == NULL) {
2777 r = SSH_ERR_INVALID_ARGUMENT;
2778 goto out;
2779 }
2780 if ((r = sshbuf_put_stringb(b, key->cert->certblob)) != 0 ||
2781 (r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
2782 (r = sshbuf_put_string(b, key->xmss_pk,
2783 sshkey_xmss_pklen(key))) != 0 ||
2784 (r = sshbuf_put_string(b, key->xmss_sk,
2785 sshkey_xmss_sklen(key))) != 0 ||
2786 (r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0)
2787 goto out;
2788 break;
2789#endif /* WITH_XMSS */
2557 default: 2790 default:
2558 r = SSH_ERR_INVALID_ARGUMENT; 2791 r = SSH_ERR_INVALID_ARGUMENT;
2559 goto out; 2792 goto out;
@@ -2565,13 +2798,21 @@ sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
2565} 2798}
2566 2799
2567int 2800int
2801sshkey_private_serialize(const struct sshkey *key, struct sshbuf *b)
2802{
2803 return sshkey_private_serialize_opt(key, b,
2804 SSHKEY_SERIALIZE_DEFAULT);
2805}
2806
2807int
2568sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp) 2808sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
2569{ 2809{
2570 char *tname = NULL, *curve = NULL; 2810 char *tname = NULL, *curve = NULL, *xmss_name = NULL;
2571 struct sshkey *k = NULL; 2811 struct sshkey *k = NULL;
2572 size_t pklen = 0, sklen = 0; 2812 size_t pklen = 0, sklen = 0;
2573 int type, r = SSH_ERR_INTERNAL_ERROR; 2813 int type, r = SSH_ERR_INTERNAL_ERROR;
2574 u_char *ed25519_pk = NULL, *ed25519_sk = NULL; 2814 u_char *ed25519_pk = NULL, *ed25519_sk = NULL;
2815 u_char *xmss_pk = NULL, *xmss_sk = NULL;
2575#ifdef WITH_OPENSSL 2816#ifdef WITH_OPENSSL
2576 BIGNUM *exponent = NULL; 2817 BIGNUM *exponent = NULL;
2577#endif /* WITH_OPENSSL */ 2818#endif /* WITH_OPENSSL */
@@ -2716,6 +2957,48 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
2716 k->ed25519_sk = ed25519_sk; 2957 k->ed25519_sk = ed25519_sk;
2717 ed25519_pk = ed25519_sk = NULL; 2958 ed25519_pk = ed25519_sk = NULL;
2718 break; 2959 break;
2960#ifdef WITH_XMSS
2961 case KEY_XMSS:
2962 if ((k = sshkey_new_private(type)) == NULL) {
2963 r = SSH_ERR_ALLOC_FAIL;
2964 goto out;
2965 }
2966 if ((r = sshbuf_get_cstring(buf, &xmss_name, NULL)) != 0 ||
2967 (r = sshkey_xmss_init(k, xmss_name)) != 0 ||
2968 (r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 ||
2969 (r = sshbuf_get_string(buf, &xmss_sk, &sklen)) != 0)
2970 goto out;
2971 if (pklen != sshkey_xmss_pklen(k) ||
2972 sklen != sshkey_xmss_sklen(k)) {
2973 r = SSH_ERR_INVALID_FORMAT;
2974 goto out;
2975 }
2976 k->xmss_pk = xmss_pk;
2977 k->xmss_sk = xmss_sk;
2978 xmss_pk = xmss_sk = NULL;
2979 /* optional internal state */
2980 if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0)
2981 goto out;
2982 break;
2983 case KEY_XMSS_CERT:
2984 if ((r = sshkey_froms(buf, &k)) != 0 ||
2985 (r = sshkey_add_private(k)) != 0 ||
2986 (r = sshbuf_get_string(buf, &xmss_pk, &pklen)) != 0 ||
2987 (r = sshbuf_get_string(buf, &xmss_sk, &sklen)) != 0)
2988 goto out;
2989 if (pklen != sshkey_xmss_pklen(k) ||
2990 sklen != sshkey_xmss_sklen(k)) {
2991 r = SSH_ERR_INVALID_FORMAT;
2992 goto out;
2993 }
2994 k->xmss_pk = xmss_pk;
2995 k->xmss_sk = xmss_sk;
2996 xmss_pk = xmss_sk = NULL;
2997 /* optional internal state */
2998 if ((r = sshkey_xmss_deserialize_state_opt(k, buf)) != 0)
2999 goto out;
3000 break;
3001#endif /* WITH_XMSS */
2719 default: 3002 default:
2720 r = SSH_ERR_KEY_TYPE_UNKNOWN; 3003 r = SSH_ERR_KEY_TYPE_UNKNOWN;
2721 goto out; 3004 goto out;
@@ -2747,6 +3030,9 @@ sshkey_private_deserialize(struct sshbuf *buf, struct sshkey **kp)
2747 sshkey_free(k); 3030 sshkey_free(k);
2748 freezero(ed25519_pk, pklen); 3031 freezero(ed25519_pk, pklen);
2749 freezero(ed25519_sk, sklen); 3032 freezero(ed25519_sk, sklen);
3033 free(xmss_name);
3034 freezero(xmss_pk, pklen);
3035 freezero(xmss_sk, sklen);
2750 return r; 3036 return r;
2751} 3037}
2752 3038
@@ -3001,7 +3287,8 @@ sshkey_private_to_blob2(const struct sshkey *prv, struct sshbuf *blob,
3001 goto out; 3287 goto out;
3002 3288
3003 /* append private key and comment*/ 3289 /* append private key and comment*/
3004 if ((r = sshkey_private_serialize(prv, encrypted)) != 0 || 3290 if ((r = sshkey_private_serialize_opt(prv, encrypted,
3291 SSHKEY_SERIALIZE_FULL)) != 0 ||
3005 (r = sshbuf_put_cstring(encrypted, comment)) != 0) 3292 (r = sshbuf_put_cstring(encrypted, comment)) != 0)
3006 goto out; 3293 goto out;
3007 3294
@@ -3362,6 +3649,9 @@ sshkey_private_to_fileblob(struct sshkey *key, struct sshbuf *blob,
3362 passphrase, comment); 3649 passphrase, comment);
3363#endif /* WITH_OPENSSL */ 3650#endif /* WITH_OPENSSL */
3364 case KEY_ED25519: 3651 case KEY_ED25519:
3652#ifdef WITH_XMSS
3653 case KEY_XMSS:
3654#endif /* WITH_XMSS */
3365 return sshkey_private_to_blob2(key, blob, passphrase, 3655 return sshkey_private_to_blob2(key, blob, passphrase,
3366 comment, new_format_cipher, new_format_rounds); 3656 comment, new_format_cipher, new_format_rounds);
3367 default: 3657 default:
@@ -3545,6 +3835,9 @@ sshkey_parse_private_fileblob_type(struct sshbuf *blob, int type,
3545 passphrase, keyp); 3835 passphrase, keyp);
3546#endif /* WITH_OPENSSL */ 3836#endif /* WITH_OPENSSL */
3547 case KEY_ED25519: 3837 case KEY_ED25519:
3838#ifdef WITH_XMSS
3839 case KEY_XMSS:
3840#endif /* WITH_XMSS */
3548 return sshkey_parse_private2(blob, type, passphrase, 3841 return sshkey_parse_private2(blob, type, passphrase,
3549 keyp, commentp); 3842 keyp, commentp);
3550 case KEY_UNSPEC: 3843 case KEY_UNSPEC:
@@ -3576,3 +3869,90 @@ sshkey_parse_private_fileblob(struct sshbuf *buffer, const char *passphrase,
3576 return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC, 3869 return sshkey_parse_private_fileblob_type(buffer, KEY_UNSPEC,
3577 passphrase, keyp, commentp); 3870 passphrase, keyp, commentp);
3578} 3871}
3872
3873#ifdef WITH_XMSS
3874/*
3875 * serialize the key with the current state and forward the state
3876 * maxsign times.
3877 */
3878int
3879sshkey_private_serialize_maxsign(const struct sshkey *k, struct sshbuf *b,
3880 u_int32_t maxsign, sshkey_printfn *pr)
3881{
3882 int r, rupdate;
3883
3884 if (maxsign == 0 ||
3885 sshkey_type_plain(k->type) != KEY_XMSS)
3886 return sshkey_private_serialize_opt(k, b,
3887 SSHKEY_SERIALIZE_DEFAULT);
3888 if ((r = sshkey_xmss_get_state(k, pr)) != 0 ||
3889 (r = sshkey_private_serialize_opt(k, b,
3890 SSHKEY_SERIALIZE_STATE)) != 0 ||
3891 (r = sshkey_xmss_forward_state(k, maxsign)) != 0)
3892 goto out;
3893 r = 0;
3894out:
3895 if ((rupdate = sshkey_xmss_update_state(k, pr)) != 0) {
3896 if (r == 0)
3897 r = rupdate;
3898 }
3899 return r;
3900}
3901
3902u_int32_t
3903sshkey_signatures_left(const struct sshkey *k)
3904{
3905 if (sshkey_type_plain(k->type) == KEY_XMSS)
3906 return sshkey_xmss_signatures_left(k);
3907 return 0;
3908}
3909
3910int
3911sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
3912{
3913 if (sshkey_type_plain(k->type) != KEY_XMSS)
3914 return SSH_ERR_INVALID_ARGUMENT;
3915 return sshkey_xmss_enable_maxsign(k, maxsign);
3916}
3917
3918int
3919sshkey_set_filename(struct sshkey *k, const char *filename)
3920{
3921 if (k == NULL)
3922 return SSH_ERR_INVALID_ARGUMENT;
3923 if (sshkey_type_plain(k->type) != KEY_XMSS)
3924 return 0;
3925 if (filename == NULL)
3926 return SSH_ERR_INVALID_ARGUMENT;
3927 if ((k->xmss_filename = strdup(filename)) == NULL)
3928 return SSH_ERR_ALLOC_FAIL;
3929 return 0;
3930}
3931#else
3932int
3933sshkey_private_serialize_maxsign(const struct sshkey *k, struct sshbuf *b,
3934 u_int32_t maxsign, sshkey_printfn *pr)
3935{
3936 return sshkey_private_serialize_opt(k, b, SSHKEY_SERIALIZE_DEFAULT);
3937}
3938
3939u_int32_t
3940sshkey_signatures_left(const struct sshkey *k)
3941{
3942 return 0;
3943}
3944
3945int
3946sshkey_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
3947{
3948 return SSH_ERR_INVALID_ARGUMENT;
3949}
3950
3951int
3952sshkey_set_filename(struct sshkey *k, const char *filename)
3953{
3954 if (k == NULL)
3955 return SSH_ERR_INVALID_ARGUMENT;
3956 return 0;
3957}
3958#endif /* WITH_XMSS */