]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add base code to load a LMS public key.
authorslontis <shane.lontis@oracle.com>
Thu, 3 Oct 2024 01:16:15 +0000 (11:16 +1000)
committerPauli <ppzgs1@gmail.com>
Mon, 27 Jan 2025 09:19:14 +0000 (20:19 +1100)
This loads a XDR encoded LMS public key.
It adds a simple LMS keymanager to import this key.

Reviewed-by: Hugo Landau <hlandau@devever.net>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/25598)

21 files changed:
crypto/build.info
crypto/lms/build.info [new file with mode: 0644]
crypto/lms/lm_ots_params.c [new file with mode: 0644]
crypto/lms/lms_key.c [new file with mode: 0644]
crypto/lms/lms_params.c [new file with mode: 0644]
crypto/lms/lms_pubkey_decode.c [new file with mode: 0644]
doc/build.info
doc/man7/EVP_PKEY-LMS.pod [new file with mode: 0644]
include/crypto/lms.h [new file with mode: 0644]
include/crypto/lms_util.h [new file with mode: 0644]
include/crypto/types.h
providers/defltprov.c
providers/implementations/include/prov/implementations.h
providers/implementations/include/prov/names.h
providers/implementations/keymgmt/build.info
providers/implementations/keymgmt/lms_kmgmt.c [new file with mode: 0644]
test/build.info
test/lms.inc [new file with mode: 0644]
test/lms_common.inc [new file with mode: 0644]
test/lms_test.c [new file with mode: 0644]
test/recipes/30-test_lms.t [new file with mode: 0644]

index 2642d30754b585214d2bc888451eaa141c7467d2..cb43cbfe34576590f6d8aa2f438acca34c981d3e 100644 (file)
@@ -6,7 +6,7 @@ SUBDIRS=objects buffer bio stack lhash hashtable rand evp asn1 pem x509 conf \
         siphash sm3 des aes rc2 rc4 rc5 idea aria bf cast camellia \
         seed sm4 chacha modes bn ec rsa dsa dh sm2 dso engine \
         err comp http ocsp cms ts srp cmac ct async ess crmf cmp encode_decode \
-        ffc hpke thread
+        ffc hpke thread lms
 
 LIBS=../libcrypto
 
diff --git a/crypto/lms/build.info b/crypto/lms/build.info
new file mode 100644 (file)
index 0000000..e6bf504
--- /dev/null
@@ -0,0 +1,7 @@
+LIBS=../../libcrypto
+
+$COMMON=lms_params.c lms_pubkey_decode.c lms_key.c lm_ots_params.c
+
+IF[{- !$disabled{'lms'} -}]
+SOURCE[../../libcrypto]=$COMMON
+ENDIF
diff --git a/crypto/lms/lm_ots_params.c b/crypto/lms/lm_ots_params.c
new file mode 100644 (file)
index 0000000..9777d0e
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "crypto/lms.h"
+
+/* Refer to SP800-208 Section 4 LM-OTS parameter sets */
+static const LM_OTS_PARAMS lm_ots_params[] = {
+    { OSSL_LM_OTS_TYPE_SHA256_N32_W1, 32, 1, 265, "SHA256"},
+    { OSSL_LM_OTS_TYPE_SHA256_N32_W2, 32, 2, 133, "SHA256"},
+    { OSSL_LM_OTS_TYPE_SHA256_N32_W4, 32, 4,  67, "SHA256"},
+    { OSSL_LM_OTS_TYPE_SHA256_N32_W8, 32, 8,  34, "SHA256"},
+    { OSSL_LM_OTS_TYPE_SHA256_N24_W1, 24, 1, 200, "SHA256-192"},
+    { OSSL_LM_OTS_TYPE_SHA256_N24_W2, 24, 2, 101, "SHA256-192"},
+    { OSSL_LM_OTS_TYPE_SHA256_N24_W4, 24, 4,  51, "SHA256-192"},
+    { OSSL_LM_OTS_TYPE_SHA256_N24_W8, 24, 8,  26, "SHA256-192"},
+    { OSSL_LM_OTS_TYPE_SHAKE_N32_W1,  32, 1, 265, "SHAKE-256"},
+    { OSSL_LM_OTS_TYPE_SHAKE_N32_W2,  32, 2, 133, "SHAKE-256"},
+    { OSSL_LM_OTS_TYPE_SHAKE_N32_W4,  32, 4,  67, "SHAKE-256"},
+    { OSSL_LM_OTS_TYPE_SHAKE_N32_W8,  32, 8,  34, "SHAKE-256"},
+    /* SHAKE-256/192 - OpenSSL does not support this as a name */
+    { OSSL_LM_OTS_TYPE_SHAKE_N24_W1,  24, 1, 200, "SHAKE-256"},
+    { OSSL_LM_OTS_TYPE_SHAKE_N24_W2,  24, 2, 101, "SHAKE-256"},
+    { OSSL_LM_OTS_TYPE_SHAKE_N24_W4,  24, 4,  51, "SHAKE-256"},
+    { OSSL_LM_OTS_TYPE_SHAKE_N24_W8,  24, 8,  26, "SHAKE-256"},
+    { 0, 0, 0, 0, NULL },
+};
+
+/**
+ * @brief A getter to convert an |ots_type| into a LM_OTS_PARAMS object.
+ *
+ * @param ots_type The type such as OSSL_LM_OTS_TYPE_SHA256_N32_W1
+ * @returns The LM_OTS_PARAMS object associated with the |ots_type|, or
+ *          NULL if |ots_type| is undefined.
+ */
+const LM_OTS_PARAMS *ossl_lm_ots_params_get(uint32_t ots_type)
+{
+    const LM_OTS_PARAMS *p;
+
+    for (p = lm_ots_params; p->lm_ots_type != 0; ++p)
+        if (p->lm_ots_type == ots_type)
+            return p;
+    return NULL;
+}
diff --git a/crypto/lms/lms_key.c b/crypto/lms/lms_key.c
new file mode 100644 (file)
index 0000000..6f35a5a
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_dispatch.h>
+#include "crypto/lms.h"
+#include <string.h>
+
+/**
+ * @brief Create a new LMS_KEY object
+ *
+ * @param libctx A OSSL_LIB_CTX object used for fetching algorithms.
+ * @returns The new LMS_KEY object on success, or NULL on malloc failure
+ */
+LMS_KEY *ossl_lms_key_new(OSSL_LIB_CTX *libctx)
+{
+    LMS_KEY *ret = OPENSSL_zalloc(sizeof(LMS_KEY));
+
+    if (ret != NULL)
+        ret->libctx = libctx;
+    return ret;
+}
+
+/**
+ * @brief Destroy a LMS_KEY object
+ */
+void ossl_lms_key_free(LMS_KEY *lmskey)
+{
+    LMS_PUB_KEY *pub;
+
+    if (lmskey == NULL)
+        return;
+
+    pub = &lmskey->pub;
+    if (pub->allocated)
+        OPENSSL_free(pub->encoded);
+    OPENSSL_free(lmskey);
+}
+
+/**
+ * @brief Are 2 LMS public keys equal?
+ *
+ * To be equal the keys must have the same LMS_PARAMS, LM_OTS_PARAMS and
+ * encoded public keys.
+ *
+ * @param key1 A LMS_KEY object
+ * @param key2 A LMS_KEY object
+ * @param selection Only OSSL_KEYMGMT_SELECT_PUBLIC_KEY is supported
+ * @returns 1 if the keys are equal otherwise it returns 0.
+ */
+int ossl_lms_key_equal(const LMS_KEY *key1, const LMS_KEY *key2, int selection)
+{
+    int ok = 1;
+
+    if (key1->lms_params != key2->lms_params
+            || key1->ots_params != key2->ots_params)
+        return 0;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
+        if (key1->pub.encodedlen != key2->pub.encodedlen)
+            return 0;
+        ok = (key1->pub.encodedlen == 0)
+            || (memcmp(key1->pub.encoded, key2->pub.encoded,
+                       key1->pub.encodedlen) == 0);
+    }
+    return ok;
+}
+
+/**
+ * @brief Is a LMS_KEY valid.
+ *
+ * @param key A LMS_KEY object
+ * @param selection Currently only supports |OSSL_KEYMGMT_SELECT_PUBLIC_KEY|
+ * @returns 1 if a LMS_KEY contains valid key data.
+ */
+int ossl_lms_key_valid(const LMS_KEY *key, int selection)
+{
+    if (key == NULL)
+        return 0;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+        if (key->pub.encoded == NULL || key->pub.encodedlen == 0)
+            return 0;
+    /* There is no private key currently */
+    return 1;
+}
+
+/**
+ * @brief Does a LMS_KEY object contain a public key.
+ *
+ * @param key A LMS_KEY object
+ * @param selection Currently only supports |OSSL_KEYMGMT_SELECT_PUBLIC_KEY|
+ * @returns 1 if a LMS_KEY contains public key data, or 0 otherwise.
+ */
+int ossl_lms_key_has(const LMS_KEY *key, int selection)
+{
+    int ok = 1;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+        ok = (key != NULL && key->pub.K != NULL);
+    /* There is no private key currently */
+    return ok;
+}
diff --git a/crypto/lms/lms_params.c b/crypto/lms/lms_params.c
new file mode 100644 (file)
index 0000000..b8c3470
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "crypto/lms.h"
+
+/* Refer to SP800-208 Section 4 LMS Parameter Sets */
+static const LMS_PARAMS lms_params[] = {
+    {OSSL_LMS_TYPE_SHA256_N32_H5,  "SHA256", 32, 5},
+    {OSSL_LMS_TYPE_SHA256_N32_H10, "SHA256", 32, 10},
+    {OSSL_LMS_TYPE_SHA256_N32_H15, "SHA256", 32, 15},
+    {OSSL_LMS_TYPE_SHA256_N32_H20, "SHA256", 32, 20},
+    {OSSL_LMS_TYPE_SHA256_N32_H25, "SHA256", 32, 25},
+    {OSSL_LMS_TYPE_SHA256_N24_H5,  "SHA256-192", 24, 5},
+    {OSSL_LMS_TYPE_SHA256_N24_H10, "SHA256-192", 24, 10},
+    {OSSL_LMS_TYPE_SHA256_N24_H15, "SHA256-192", 24, 15},
+    {OSSL_LMS_TYPE_SHA256_N24_H20, "SHA256-192", 24, 20},
+    {OSSL_LMS_TYPE_SHA256_N24_H25, "SHA256-192", 24, 25},
+    {OSSL_LMS_TYPE_SHAKE_N32_H5,   "SHAKE-256", 32, 5},
+    {OSSL_LMS_TYPE_SHAKE_N32_H10,  "SHAKE-256", 32, 10},
+    {OSSL_LMS_TYPE_SHAKE_N32_H15,  "SHAKE-256", 32, 15},
+    {OSSL_LMS_TYPE_SHAKE_N32_H20,  "SHAKE-256", 32, 20},
+    {OSSL_LMS_TYPE_SHAKE_N32_H25,  "SHAKE-256", 32, 25},
+    /* SHAKE-256/192 */
+    {OSSL_LMS_TYPE_SHAKE_N24_H5,   "SHAKE-256", 24, 5},
+    {OSSL_LMS_TYPE_SHAKE_N24_H10,  "SHAKE-256", 24, 10},
+    {OSSL_LMS_TYPE_SHAKE_N24_H15,  "SHAKE-256", 24, 15},
+    {OSSL_LMS_TYPE_SHAKE_N24_H20,  "SHAKE-256", 24, 20},
+    {OSSL_LMS_TYPE_SHAKE_N24_H25,  "SHAKE-256", 24, 25},
+
+    {0, NULL, 0, 0}
+};
+
+/**
+ * @brief A getter to convert a |lms_type| into a LMS_PARAMS object.
+ *
+ * @param lms_type The type such as OSSL_LMS_TYPE_SHA256_N32_H5.
+ * @returns The LMS_PARAMS object associated with the |lms_type|, or
+ *          NULL if |lms_type| is undefined.
+ */
+const LMS_PARAMS *ossl_lms_params_get(uint32_t lms_type)
+{
+    const LMS_PARAMS *p;
+
+    for (p = lms_params; p->lms_type != 0; ++p)
+        if (p->lms_type == lms_type)
+            return p;
+    return NULL;
+}
diff --git a/crypto/lms/lms_pubkey_decode.c b/crypto/lms/lms_pubkey_decode.c
new file mode 100644 (file)
index 0000000..59e4e92
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_names.h>
+#include "crypto/lms.h"
+#include "crypto/lms_util.h"
+
+/*
+ * @brief Decode LMS public key data in XDR format into a LMS_KEY object.
+ *
+ * See RFC 8554 Algorithm 6: Steps 1 & 2.
+ * The XDR format is lms_type[4] || ots_type[4] || I[16] || K[n]
+ * Steps that involve checking the size of the public key data are
+ * done indirectly by checking the return result of PACKET_get API's.
+ * This function may be called multiple times.
+ *
+ * @param pkt The packet to read public key data in XDR format from.
+ * @param lmskey The object to store the public key into
+ * @return 1 on success or 0 otherwise.
+ */
+static
+int lms_pubkey_from_pkt(PACKET *pkt, LMS_KEY *lmskey)
+{
+    uint32_t lms_type;
+    uint32_t ots_type;
+    LMS_PUB_KEY *key = &lmskey->pub;
+
+    key->encoded = (unsigned char *)pkt->curr;
+    if (!PACKET_get_4_len(pkt, &lms_type))
+        goto err;
+    lmskey->lms_params = ossl_lms_params_get(lms_type);
+    if (lmskey->lms_params == NULL
+            || !PACKET_get_4_len(pkt, &ots_type))
+        goto err;
+    lmskey->ots_params = ossl_lm_ots_params_get(ots_type);
+    if (lmskey->ots_params == NULL)
+        goto err;
+
+    /* The digest used must be the same */
+    if (HASH_NOT_MATCHED(lmskey->ots_params, lmskey->lms_params)
+            || !PACKET_get_bytes_shallow(pkt, &lmskey->Id, LMS_SIZE_I)
+            || !PACKET_get_bytes_shallow(pkt, &key->K, lmskey->lms_params->n))
+        goto err;
+    key->encodedlen = pkt->curr - key->encoded;
+    return 1;
+err:
+    return 0;
+}
+
+/*
+ * @brief Decode LMS public key data in XDR format into a LMS_KEY object.
+ * Used by the LMS public key decoder.
+ * The XDR format is lms_type[4] || ots_type[4] || I[16] || K[n]
+ *
+ * @param pub byte array of public key data in XDR format.
+ * @param publen is the size of |pub|.
+ * @param lmskey The LMS_KEY object to store the public key into.
+ * @returns 1 on success, or 0 otherwise. 0 is returned if either |pub| is
+ * invalid or |publen| is not the correct size (i.e. trailing data is not allowed)
+ */
+static
+int lms_pubkey_decode(const unsigned char *pub, size_t publen, LMS_KEY *lmskey)
+{
+    PACKET pkt;
+    LMS_PUB_KEY *pkey = &lmskey->pub;
+
+    if (pkey->encoded != NULL && pkey->encodedlen != publen) {
+        if (pkey->allocated) {
+            OPENSSL_free(pkey->encoded);
+            pkey->allocated = 0;
+        }
+        pkey->encodedlen = 0;
+    }
+    pkey->encoded = OPENSSL_memdup(pub, publen);
+    if (pkey->encoded == NULL)
+        return 0;
+
+    if (!PACKET_buf_init(&pkt, pkey->encoded, publen)
+            || !lms_pubkey_from_pkt(&pkt, lmskey)
+            || (PACKET_remaining(&pkt) > 0))
+        goto err;
+    pkey->encodedlen = publen;
+    pkey->allocated = 1;
+    return 1;
+err:
+    OPENSSL_free(pkey->encoded);
+    pkey->encoded = NULL;
+    return 0;
+}
+
+/**
+ * @brief Load a LMS public key from OSSL_PARAM data.
+ *
+ * @param params An array of OSSL_PARAM
+ * @param lmskey The LMS_KEY to load the public key data into.
+ * @returns 1 on success, or 0 otherwise.
+ */
+int ossl_lms_pubkey_from_params(const OSSL_PARAM params[], LMS_KEY *lmskey)
+{
+    const OSSL_PARAM *p = NULL;
+
+    p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY);
+    if (p != NULL) {
+        if (p->data == NULL || p->data_type != OSSL_PARAM_OCTET_STRING)
+            return 0;
+        if (!lms_pubkey_decode(p->data, p->data_size, lmskey))
+            return 0;
+    }
+    return 1;
+}
index 9003540be42e41385420ac2adc00ffcce1956641..44e6ca27c07abb971625513c423eb28d1e05dac6 100644 (file)
@@ -4745,6 +4745,10 @@ DEPEND[html/man7/EVP_PKEY-HMAC.html]=man7/EVP_PKEY-HMAC.pod
 GENERATE[html/man7/EVP_PKEY-HMAC.html]=man7/EVP_PKEY-HMAC.pod
 DEPEND[man/man7/EVP_PKEY-HMAC.7]=man7/EVP_PKEY-HMAC.pod
 GENERATE[man/man7/EVP_PKEY-HMAC.7]=man7/EVP_PKEY-HMAC.pod
+DEPEND[html/man7/EVP_PKEY-LMS.html]=man7/EVP_PKEY-LMS.pod
+GENERATE[html/man7/EVP_PKEY-LMS.html]=man7/EVP_PKEY-LMS.pod
+DEPEND[man/man7/EVP_PKEY-LMS.7]=man7/EVP_PKEY-LMS.pod
+GENERATE[man/man7/EVP_PKEY-LMS.7]=man7/EVP_PKEY-LMS.pod
 DEPEND[html/man7/EVP_PKEY-RSA.html]=man7/EVP_PKEY-RSA.pod
 GENERATE[html/man7/EVP_PKEY-RSA.html]=man7/EVP_PKEY-RSA.pod
 DEPEND[man/man7/EVP_PKEY-RSA.7]=man7/EVP_PKEY-RSA.pod
@@ -5140,6 +5144,7 @@ html/man7/EVP_PKEY-DSA.html \
 html/man7/EVP_PKEY-EC.html \
 html/man7/EVP_PKEY-FFC.html \
 html/man7/EVP_PKEY-HMAC.html \
+html/man7/EVP_PKEY-LMS.html \
 html/man7/EVP_PKEY-RSA.html \
 html/man7/EVP_PKEY-SM2.html \
 html/man7/EVP_PKEY-X25519.html \
@@ -5287,6 +5292,7 @@ man/man7/EVP_PKEY-DSA.7 \
 man/man7/EVP_PKEY-EC.7 \
 man/man7/EVP_PKEY-FFC.7 \
 man/man7/EVP_PKEY-HMAC.7 \
+man/man7/EVP_PKEY-LMS.7 \
 man/man7/EVP_PKEY-RSA.7 \
 man/man7/EVP_PKEY-SM2.7 \
 man/man7/EVP_PKEY-X25519.7 \
diff --git a/doc/man7/EVP_PKEY-LMS.pod b/doc/man7/EVP_PKEY-LMS.pod
new file mode 100644 (file)
index 0000000..9f16d15
--- /dev/null
@@ -0,0 +1,83 @@
+=pod
+
+=head1 NAME
+
+EVP_PKEY-LMS, EVP_KEYMGMT-LMS, LMS
+- EVP_PKEY Leighton-Micali Signature (LMS) keytype and algorithm support
+
+=head1 DESCRIPTION
+
+The B<LMS> keytype is implemented in OpenSSL's default provider.
+
+=head2 Common LMS parameters
+
+LMS public keys are encoded in XDR format (i.e. not ANS1 format),
+The following parameters are used by EVP_PKEY_fromdata() and by the
+LMS keymanager for import and export.
+
+=over 4
+
+=item "encoded-pub-key" (B<OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY>) <octet string>
+
+Used for getting and setting the encoding of an LMS public key. The public key
+is expected to be in XDR format.
+
+=back
+
+=head1 CONFORMING TO
+
+=over 4
+
+=item RFC 8554
+
+Leighton-Micali Hash-Based Signatures
+
+=item NIST SP 800-208
+
+Recommendation for Stateful Hash-Based Signature Schemes
+
+=item CSNA 2.0
+
+Commercial National Security Algorithm Suite
+
+=back
+
+=head1 EXAMPLES
+
+NOTE error checking has been omitted in these examples
+
+An B<EVP_PKEY> context can be obtained by calling:
+    EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name(NULL, "LMS", NULL);
+
+To load a LMS key from XDR encoded "data" of size "datalen":
+
+    EVP_PKEY *key = NULL;
+    OSSL_PARAM params[2];
+
+    params[0] =
+        OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+                                          (unsigned char *)data, datalen);
+    params[1] = OSSL_PARAM_construct_end();
+    ret = EVP_PKEY_fromdata_init(ctx)
+    ret = EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_PUBLIC_KEY, params);
+
+=head1 SEE ALSO
+
+L<EVP_KEYMGMT(3)>,
+L<EVP_PKEY(3)>,
+L<provider-keymgmt(7)>
+
+=head1 HISTORY
+
+This functionality was added in OpenSSL 3.5.0
+
+=head1 COPYRIGHT
+
+Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
diff --git a/include/crypto/lms.h b/include/crypto/lms.h
new file mode 100644 (file)
index 0000000..bea0909
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * Internal LMS/LM_OTS functions for other submodules,
+ * not for application use
+ */
+
+#ifndef OSSL_CRYPTO_LMS_H
+# define OSSL_CRYPTO_LMS_H
+# pragma once
+# ifndef OPENSSL_NO_LMS
+#  include "types.h"
+#  include <openssl/params.h>
+
+/*
+ * Numeric identifiers associated with Leighton-Micali Signatures (LMS)
+ * parameter sets are defined in
+ * https://www.iana.org/assignments/leighton-micali-signatures/leighton-micali-signatures.xhtml
+ * which is referenced from SP800-208.
+ */
+#  define OSSL_LMS_TYPE_SHA256_N32_H5   0x00000005
+#  define OSSL_LMS_TYPE_SHA256_N32_H10  0x00000006
+#  define OSSL_LMS_TYPE_SHA256_N32_H15  0x00000007
+#  define OSSL_LMS_TYPE_SHA256_N32_H20  0x00000008
+#  define OSSL_LMS_TYPE_SHA256_N32_H25  0x00000009
+#  define OSSL_LMS_TYPE_SHA256_N24_H5   0x0000000A
+#  define OSSL_LMS_TYPE_SHA256_N24_H10  0x0000000B
+#  define OSSL_LMS_TYPE_SHA256_N24_H15  0x0000000C
+#  define OSSL_LMS_TYPE_SHA256_N24_H20  0x0000000D
+#  define OSSL_LMS_TYPE_SHA256_N24_H25  0x0000000E
+#  define OSSL_LMS_TYPE_SHAKE_N32_H5    0x0000000F
+#  define OSSL_LMS_TYPE_SHAKE_N32_H10   0x00000010
+#  define OSSL_LMS_TYPE_SHAKE_N32_H15   0x00000011
+#  define OSSL_LMS_TYPE_SHAKE_N32_H20   0x00000012
+#  define OSSL_LMS_TYPE_SHAKE_N32_H25   0x00000013
+#  define OSSL_LMS_TYPE_SHAKE_N24_H5    0x00000014
+#  define OSSL_LMS_TYPE_SHAKE_N24_H10   0x00000015
+#  define OSSL_LMS_TYPE_SHAKE_N24_H15   0x00000016
+#  define OSSL_LMS_TYPE_SHAKE_N24_H20   0x00000017
+#  define OSSL_LMS_TYPE_SHAKE_N24_H25   0x00000018
+
+#  define OSSL_LM_OTS_TYPE_SHA256_N32_W1 0x00000001
+#  define OSSL_LM_OTS_TYPE_SHA256_N32_W2 0x00000002
+#  define OSSL_LM_OTS_TYPE_SHA256_N32_W4 0x00000003
+#  define OSSL_LM_OTS_TYPE_SHA256_N32_W8 0x00000004
+#  define OSSL_LM_OTS_TYPE_SHA256_N24_W1 0x00000005
+#  define OSSL_LM_OTS_TYPE_SHA256_N24_W2 0x00000006
+#  define OSSL_LM_OTS_TYPE_SHA256_N24_W4 0x00000007
+#  define OSSL_LM_OTS_TYPE_SHA256_N24_W8 0x00000008
+#  define OSSL_LM_OTS_TYPE_SHAKE_N32_W1  0x00000009
+#  define OSSL_LM_OTS_TYPE_SHAKE_N32_W2  0x0000000A
+#  define OSSL_LM_OTS_TYPE_SHAKE_N32_W4  0x0000000B
+#  define OSSL_LM_OTS_TYPE_SHAKE_N32_W8  0x0000000C
+#  define OSSL_LM_OTS_TYPE_SHAKE_N24_W1  0x0000000D
+#  define OSSL_LM_OTS_TYPE_SHAKE_N24_W2  0x0000000E
+#  define OSSL_LM_OTS_TYPE_SHAKE_N24_W4  0x0000000F
+#  define OSSL_LM_OTS_TYPE_SHAKE_N24_W8  0x00000010
+
+/* XDR sizes when encoding and decoding */
+#  define LMS_SIZE_I 16
+#  define LMS_SIZE_LMS_TYPE 4
+#  define LMS_SIZE_OTS_TYPE 4
+
+/*
+ * Refer to RFC 8554 Section 4.1.
+ * See also lm_ots_params[]
+ */
+typedef struct lm_ots_params_st {
+    /*
+     * The OTS type associates an id with a set of OTS parameters
+     * e.g. OSSL_LM_OTS_TYPE_SHAKE_N32_W1
+     */
+    uint32_t lm_ots_type;
+    uint32_t n;              /* Hash output size in bytes (32 or 24) */
+    /*
+     * The width of the Winternitz coefficients in bits. One of (1, 2, 4, 8)
+     * Higher values of w are slower (~2^w computations) but have smaller
+     * signatures.
+     */
+    uint32_t w;
+    /*
+     * The number of n-byte elements used for an LMOTS signature.
+     * One of (265, 133, 67, 34) for n = 32, for w=1,2,4,8
+     * One of (200, 101, 51, 26) for n = 24, for w=1,2,4,8
+     */
+    uint32_t p;
+    const char *digestname; /* Hash Name */
+} LM_OTS_PARAMS;
+
+/* See lms_params[] */
+typedef struct lms_params_st {
+    /*
+     * The lms type associates an id with a set of parameters to define the
+     * Digest and Height of a LMS tree.
+     * e.g, OSSL_LMS_TYPE_SHA256_N24_H25
+     */
+    uint32_t lms_type;
+    const char *digestname; /* One of SHA256, SHA256-192, or SHAKE256 */
+    uint32_t n; /* The Digest size (either 24 or 32), Useful for setting up SHAKE */
+    uint32_t h; /* The height of a LMS tree which is one of 5, 10, 15, 20, 25) */
+} LMS_PARAMS;
+
+typedef struct lms_pub_key_st {
+    /*
+     * A buffer containing an encoded public key of the form
+     * u32str(lmstype) || u32str(otstype) || I[16] || K[n]
+     */
+    unsigned char *encoded;         /* encoded public key data */
+    size_t encodedlen;
+    /*
+     * K is the LMS tree's root public key (Called T(1))
+     * It is n bytes long (the hash size).
+     * It is a pointer into the encoded buffer
+     */
+    unsigned char *K;
+    uint32_t allocated;             /* If 1 then encoded needs to be freed */
+} LMS_PUB_KEY;
+
+struct lms_key_st {
+    const LMS_PARAMS *lms_params;
+    const LM_OTS_PARAMS *ots_params;
+    OSSL_LIB_CTX *libctx;
+    unsigned char *Id;        /* A pointer to 16 bytes (I[16]) */
+    LMS_PUB_KEY pub;
+};
+
+const LMS_PARAMS *ossl_lms_params_get(uint32_t lms_type);
+const LM_OTS_PARAMS *ossl_lm_ots_params_get(uint32_t ots_type);
+
+LMS_KEY *ossl_lms_key_new(OSSL_LIB_CTX *libctx);
+void ossl_lms_key_free(LMS_KEY *lmskey);
+int ossl_lms_key_equal(const LMS_KEY *key1, const LMS_KEY *key2, int selection);
+int ossl_lms_key_valid(const LMS_KEY *key, int selection);
+int ossl_lms_key_has(const LMS_KEY *key, int selection);
+
+int ossl_lms_pubkey_from_params(const OSSL_PARAM params[], LMS_KEY *lmskey);
+
+# endif /* OPENSSL_NO_LMS */
+#endif /* OSSL_CRYPTO_LMS_H */
diff --git a/include/crypto/lms_util.h b/include/crypto/lms_util.h
new file mode 100644 (file)
index 0000000..690a0eb
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* @brief Internal LMS internal helper functions */
+
+#include "internal/packet.h"
+
+/*
+ * This LMS implementation assumes that the hash algorithm must be the same for
+ * LMS params and OTS params. Since OpenSSL does not have a "SHAKE256-192"
+ * algorithm, we have to check the digest size as well as the name.
+ * This macro can be used to compare 2 LMS_PARAMS, LMS_PARAMS and LM_OTS_PARAMS.
+ */
+#define HASH_NOT_MATCHED(a, b) \
+    (a)->n != (b)->n || (strcmp((a)->digestname, (b)->digestname) != 0)
+
+/**
+ * @brief Helper function to return a ptr to a pkt buffer and move forward.
+ * Used when decoding byte array XDR data.
+ *
+ * @param pkt A PACKET object that needs to have at least len bytes remaining.
+ * @param out The returned ptr to the current position in the pkt buffer.
+ * @param len The amount that we will move forward in the pkt buffer.
+ * @returns 1 if there is enough bytes remaining to be able to skip forward,
+ *          or 0 otherwise.
+ */
+static ossl_unused ossl_inline
+int PACKET_get_bytes_shallow(PACKET *pkt, unsigned char **out, size_t len)
+{
+    const unsigned char **data = (const unsigned char **)out;
+
+    if (!PACKET_peek_bytes(pkt, data, len))
+        return 0;
+
+    packet_forward(pkt, len);
+
+    return 1;
+}
+
+/**
+ * @brief Get 4 bytes in network order from |pkt| and store the value in |*data|
+ * Similar to PACKET_get_net_4() except the data is uint32_t
+ *
+ * @param pkt Contains a buffer to read from
+ * @param data The object to write the data to.
+ * @returns 1 on success, or 0 otherwise.
+ */
+static ossl_unused ossl_inline
+int PACKET_get_4_len(PACKET *pkt, uint32_t *data)
+{
+    size_t i = 0;
+    int ret = PACKET_get_net_4_len(pkt, &i);
+
+    if (ret)
+        *data = (uint32_t)i;
+    return ret;
+}
index ad17f052e45f5047ad498fa1c55538ee33bc93c4..b79d9b7e4a1c3953a1ef18dc371dc0abf9384da3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
  *
  * Licensed under the Apache License 2.0 (the "License").  You may not use
  * this file except in compliance with the License.  You can obtain a copy
@@ -29,4 +29,8 @@ typedef struct dsa_st DSA;
 typedef struct ecx_key_st ECX_KEY;
 # endif
 
+# ifndef OPENSSL_NO_LMS
+typedef struct lms_key_st LMS_KEY;
+# endif
+
 #endif
index e30256cbaa43e61c945eb9545a4123d1ebc48899..e869110b351e849b7efc8712dc0299b5a3b01556 100644 (file)
@@ -530,6 +530,10 @@ static const OSSL_ALGORITHM deflt_keymgmt[] = {
 #ifndef OPENSSL_NO_SM2
     { PROV_NAMES_SM2, "provider=default", ossl_sm2_keymgmt_functions,
       PROV_DESCS_SM2 },
+#endif
+#ifndef OPENSSL_NO_LMS
+    { PROV_NAMES_LMS, "provider=default", ossl_lms_keymgmt_functions,
+      PROV_DESCS_LMS },
 #endif
     { NULL, NULL, NULL }
 };
index 5b9190565775bc439861b69019c2f73be9487fb4..0555ddee8c3a224d0ba9d5db39ecf852d95710ac 100644 (file)
@@ -321,6 +321,9 @@ extern const OSSL_DISPATCH ossl_cmac_legacy_keymgmt_functions[];
 #ifndef OPENSSL_NO_SM2
 extern const OSSL_DISPATCH ossl_sm2_keymgmt_functions[];
 #endif
+#ifndef OPENSSL_NO_LMS
+extern const OSSL_DISPATCH ossl_lms_keymgmt_functions[];
+#endif
 
 /* Key Exchange */
 extern const OSSL_DISPATCH ossl_dh_keyexch_functions[];
index d422dbac296ef6583ac692b3ca93a487456f75ed..3010b04bdfd007bf15fa6b56f78fc59c5d945b93 100644 (file)
 #define PROV_DESCS_RSA_PSS "OpenSSL RSA-PSS implementation"
 #define PROV_NAMES_SM2 "SM2:1.2.156.10197.1.301"
 #define PROV_DESCS_SM2 "OpenSSL SM2 implementation"
+#define PROV_NAMES_LMS "LMS"
+#define PROV_DESCS_LMS "OpenSSL LMS implementation"
index f2cbb3dfe8da2f28a3e60bb92574204401cd6920..a4e03b4f6a1c480ff60ad004bac3807599537b22 100644 (file)
@@ -8,6 +8,7 @@ $ECX_GOAL=../../libdefault.a ../../libfips.a
 $KDF_GOAL=../../libdefault.a ../../libfips.a
 $MAC_GOAL=../../libdefault.a ../../libfips.a
 $RSA_GOAL=../../libdefault.a ../../libfips.a
+$LMS_GOAL=../../libdefault.a
 $TEMPLATE_GOAL=../../libtemplate.a
 
 IF[{- !$disabled{dh} -}]
@@ -43,4 +44,8 @@ SOURCE[$KDF_GOAL]=kdf_legacy_kmgmt.c
 
 SOURCE[$MAC_GOAL]=mac_legacy_kmgmt.c
 
+IF[{- !$disabled{lms} -}]
+  SOURCE[$LMS_GOAL]=lms_kmgmt.c
+ENDIF
+
 SOURCE[$TEMPLATE_GOAL]=template_kmgmt.c
diff --git a/providers/implementations/keymgmt/lms_kmgmt.c b/providers/implementations/keymgmt/lms_kmgmt.c
new file mode 100644 (file)
index 0000000..ac97646
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_dispatch.h>
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#include "crypto/lms.h"
+#include "prov/implementations.h"
+#include "prov/providercommon.h"
+#include "prov/provider_ctx.h"
+
+static OSSL_FUNC_keymgmt_new_fn lms_new_key;
+static OSSL_FUNC_keymgmt_free_fn lms_free_key;
+static OSSL_FUNC_keymgmt_has_fn lms_has;
+static OSSL_FUNC_keymgmt_match_fn lms_match;
+static OSSL_FUNC_keymgmt_validate_fn lms_validate;
+static OSSL_FUNC_keymgmt_import_fn lms_import;
+static OSSL_FUNC_keymgmt_import_types_fn lms_imexport_types;
+
+#define LMS_POSSIBLE_SELECTIONS (OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
+
+static void *lms_new_key(void *provctx)
+{
+    if (!ossl_prov_is_running())
+        return 0;
+    return ossl_lms_key_new(PROV_LIBCTX_OF(provctx));
+}
+
+static void lms_free_key(void *keydata)
+{
+    ossl_lms_key_free((LMS_KEY *)keydata);
+}
+
+static int lms_has(const void *keydata, int selection)
+{
+    const LMS_KEY *key = keydata;
+
+    if (!ossl_prov_is_running() || key == NULL)
+        return 0;
+    if ((selection & LMS_POSSIBLE_SELECTIONS) == 0)
+        return 1; /* the selection is not missing */
+
+    return ossl_lms_key_has(key, selection);
+}
+
+static int lms_match(const void *keydata1, const void *keydata2, int selection)
+{
+    const LMS_KEY *key1 = keydata1;
+    const LMS_KEY *key2 = keydata2;
+
+    if (!ossl_prov_is_running())
+        return 0;
+    if (key1 == NULL || key2 == NULL)
+        return 0;
+    return ossl_lms_key_equal(key1, key2, selection);
+}
+
+static int lms_import(void *keydata, int selection, const OSSL_PARAM params[])
+{
+    LMS_KEY *key = keydata;
+
+    if (!ossl_prov_is_running() || key == NULL)
+        return 0;
+
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) == 0)
+        return 0;
+
+    return ossl_lms_pubkey_from_params(params, key);
+}
+
+static const OSSL_PARAM lms_key_types[] = {
+    OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0),
+    OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_PROPERTIES, NULL, 0),
+    OSSL_PARAM_END
+};
+static const OSSL_PARAM *lms_imexport_types(int selection)
+{
+    if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
+        return lms_key_types;
+    return NULL;
+}
+
+static int lms_validate(const void *keydata, int selection, int checktype)
+{
+    const LMS_KEY *lmskey = keydata;
+
+    if (!ossl_prov_is_running())
+        return 0;
+
+    if ((selection & LMS_POSSIBLE_SELECTIONS) == 0)
+        return 1; /* nothing to validate */
+
+    return ossl_lms_key_valid(lmskey, selection);
+}
+
+const OSSL_DISPATCH ossl_lms_keymgmt_functions[] = {
+    { OSSL_FUNC_KEYMGMT_NEW, (void (*)(void))lms_new_key },
+    { OSSL_FUNC_KEYMGMT_FREE, (void (*)(void))lms_free_key },
+    { OSSL_FUNC_KEYMGMT_HAS, (void (*)(void))lms_has },
+    { OSSL_FUNC_KEYMGMT_MATCH, (void (*)(void))lms_match },
+    { OSSL_FUNC_KEYMGMT_VALIDATE, (void (*)(void))lms_validate },
+    { OSSL_FUNC_KEYMGMT_IMPORT, (void (*)(void))lms_import },
+    { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void (*)(void))lms_imexport_types },
+    OSSL_DISPATCH_END
+};
index 71ae915253f31269312c8c7da9075d90bef37461..2d38724393ec86e983ba72dc46df97a04b4e768f 100644 (file)
@@ -209,6 +209,13 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[hpke_test]=../include ../apps/include
   DEPEND[hpke_test]=../libcrypto.a libtestutil.a
 
+  IF[{- !$disabled{'lms'} -}]
+    PROGRAMS{noinst}=lms_test
+    SOURCE[lms_test]=lms_test.c
+    INCLUDE[lms_test]=../include ../apps/include
+    DEPEND[lms_test]=../libcrypto.a libtestutil.a
+  ENDIF
+
   SOURCE[evp_extra_test2]=evp_extra_test2.c $INITSRC tls-provider.c
   INCLUDE[evp_extra_test2]=../include ../apps/include
   DEPEND[evp_extra_test2]=../libcrypto libtestutil.a
diff --git a/test/lms.inc b/test/lms.inc
new file mode 100644 (file)
index 0000000..6507eec
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include "lms_common.inc"
+
+typedef struct LMS_ACVP_TEST_DATA_st {
+    const unsigned char *pub;
+    size_t publen;
+    const unsigned char *priv;
+    size_t privlen;
+    const unsigned char *msg;
+    size_t msglen;
+    const unsigned char *sig;
+    size_t siglen;
+} LMS_ACVP_TEST_DATA;
+
+/*
+ * The data for HSS with a single level is almost identical
+ * to LMS data, except the public key & signature have extra 4 byte headers.
+ */
+#define LMS_ACVP_ITEM(name) {                \
+    name##_pub + 4, sizeof(name##_pub) - 4,  \
+    name##_priv, sizeof(name##_priv),        \
+    name##_msg, sizeof(name##_msg),          \
+    name##_sig + 4, sizeof(name##_sig) - 4 }
+
+/* We can only use the hss tests that have a single level here */
+static LMS_ACVP_TEST_DATA lms_testdata[] = {
+    LMS_ACVP_ITEM(sha256_192),
+    LMS_ACVP_ITEM(shake256_192),
+    LMS_ACVP_ITEM(shake256_256)
+};
diff --git a/test/lms_common.inc b/test/lms_common.inc
new file mode 100644 (file)
index 0000000..829ef12
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/*
+ * Test vectors from
+ * https://datatracker.ietf.org/doc/html/draft-fluhrer-lms-more-parm-sets-15#name-test-cases
+ */
+static const unsigned char sha256_192_pub[] = {
+0x00,0x00,0x00,0x01,
+0x00,0x00,0x00,0x0A,
+0x00,0x00,0x00,0x08,
+0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
+0x2c,0x57,0x14,0x50,0xae,0xd9,0x9c,0xfb,0x4f,0x4a,0xc2,0x85,0xda,0x14,0x88,0x27,
+0x96,0x61,0x83,0x14,0x50,0x8b,0x12,0xd2
+};
+static const unsigned char sha256_192_priv[] = {
+0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
+0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
+};
+static const unsigned char sha256_192_msg[] = {
+0x54,0x65,0x73,0x74,0x20,0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x20,0x66,0x6f,0x72,
+0x20,0x53,0x48,0x41,0x32,0x35,0x36,0x2d,0x31,0x39,0x32,0x0a
+};
+static const unsigned char sha256_192_sig[] = {
+/* L = 1, q = 5 */
+0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x05,
+0x00,0x00,0x00,0x08,
+0x0b,0x50,0x40,0xa1,0x8c,0x1b,0x5c,0xab,0xcb,0xc8,0x5b,0x04,0x74,0x02,0xec,0x62,0x94,0xa3,0x0d,0xd8,0xda,0x8f,0xc3,0xda,
+0xe1,0x3b,0x9f,0x08,0x75,0xf0,0x93,0x61,0xdc,0x77,0xfc,0xc4,0x48,0x1e,0xa4,0x63,0xc0,0x73,0x71,0x62,0x49,0x71,0x91,0x93,
+0x61,0x4b,0x83,0x5b,0x46,0x94,0xc0,0x59,0xf1,0x2d,0x3a,0xed,0xd3,0x4f,0x3d,0xb9,0x3f,0x35,0x80,0xfb,0x88,0x74,0x3b,0x8b,
+0x3d,0x06,0x48,0xc0,0x53,0x7b,0x7a,0x50,0xe4,0x33,0xd7,0xea,0x9d,0x66,0x72,0xff,0xfc,0x5f,0x42,0x77,0x0f,0xea,0xb4,0xf9,
+0x8e,0xb3,0xf3,0xb2,0x3f,0xd2,0x06,0x1e,0x4d,0x0b,0x38,0xf8,0x32,0x86,0x0a,0xe7,0x66,0x73,0xad,0x1a,0x1a,0x52,0xa9,0x00,
+0x5d,0xcf,0x1b,0xfb,0x56,0xfe,0x16,0xff,0x72,0x36,0x27,0x61,0x2f,0x9a,0x48,0xf7,0x90,0xf3,0xc4,0x7a,0x67,0xf8,0x70,0xb8,
+0x1e,0x91,0x9d,0x99,0x91,0x9c,0x8d,0xb4,0x81,0x68,0x83,0x8c,0xec,0xe0,0xab,0xfb,0x68,0x3d,0xa4,0x8b,0x92,0x09,0x86,0x8b,
+0xe8,0xec,0x10,0xc6,0x3d,0x8b,0xf8,0x0d,0x36,0x49,0x8d,0xfc,0x20,0x5d,0xc4,0x5d,0x0d,0xd8,0x70,0x57,0x2d,0x6d,0x8f,0x1d,
+0x90,0x17,0x7c,0xf5,0x13,0x7b,0x8b,0xbf,0x7b,0xcb,0x67,0xa4,0x6f,0x86,0xf2,0x6c,0xfa,0x5a,0x44,0xcb,0xca,0xa4,0xe1,0x8d,
+0xa0,0x99,0xa9,0x8b,0x0b,0x3f,0x96,0xd5,0xac,0x8a,0xc3,0x75,0xd8,0xda,0x2a,0x7c,0x24,0x80,0x04,0xba,0x11,0xd7,0xac,0x77,
+0x5b,0x92,0x18,0x35,0x9c,0xdd,0xab,0x4c,0xf8,0xcc,0xc6,0xd5,0x4c,0xb7,0xe1,0xb3,0x5a,0x36,0xdd,0xc9,0x26,0x5c,0x08,0x70,
+0x63,0xd2,0xfc,0x67,0x42,0xa7,0x17,0x78,0x76,0x47,0x6a,0x32,0x4b,0x03,0x29,0x5b,0xfe,0xd9,0x9f,0x2e,0xaf,0x1f,0x38,0x97,
+0x05,0x83,0xc1,0xb2,0xb6,0x16,0xaa,0xd0,0xf3,0x1c,0xd7,0xa4,0xb1,0xbb,0x0a,0x51,0xe4,0x77,0xe9,0x4a,0x01,0xbb,0xb4,0xd6,
+0xf8,0x86,0x6e,0x25,0x28,0xa1,0x59,0xdf,0x3d,0x6c,0xe2,0x44,0xd2,0xb6,0x51,0x8d,0x1f,0x02,0x12,0x28,0x5a,0x3c,0x2d,0x4a,
+0x92,0x70,0x54,0xa1,0xe1,0x62,0x0b,0x5b,0x02,0xaa,0xb0,0xc8,0xc1,0x0e,0xd4,0x8a,0xe5,0x18,0xea,0x73,0xcb,0xa8,0x1f,0xcf,
+0xff,0x88,0xbf,0xf4,0x61,0xda,0xc5,0x1e,0x7a,0xb4,0xca,0x75,0xf4,0x7a,0x62,0x59,0xd2,0x48,0x20,0xb9,0x99,0x57,0x92,0xd1,
+0x39,0xf6,0x1a,0xe2,0xa8,0x18,0x6a,0xe4,0xe3,0xc9,0xbf,0xe0,0xaf,0x2c,0xc7,0x17,0xf4,0x24,0xf4,0x1a,0xa6,0x7f,0x03,0xfa,
+0xed,0xb0,0x66,0x51,0x15,0xf2,0x06,0x7a,0x46,0x84,0x3a,0x4c,0xbb,0xd2,0x97,0xd5,0xe8,0x3b,0xc1,0xaa,0xfc,0x18,0xd1,0xd0,
+0x3b,0x3d,0x89,0x4e,0x85,0x95,0xa6,0x52,0x60,0x73,0xf0,0x2a,0xb0,0xf0,0x8b,0x99,0xfd,0x9e,0xb2,0x08,0xb5,0x9f,0xf6,0x31,
+0x7e,0x55,0x45,0xe6,0xf9,0xad,0x5f,0x9c,0x18,0x3a,0xbd,0x04,0x3d,0x5a,0xcd,0x6e,0xb2,0xdd,0x4d,0xa3,0xf0,0x2d,0xbc,0x31,
+0x67,0xb4,0x68,0x72,0x0a,0x4b,0x8b,0x92,0xdd,0xfe,0x79,0x60,0x99,0x8b,0xb7,0xa0,0xec,0xf2,0xa2,0x6a,0x37,0x59,0x82,0x99,
+0x41,0x3f,0x7b,0x2a,0xec,0xd3,0x9a,0x30,0xce,0xc5,0x27,0xb4,0xd9,0x71,0x0c,0x44,0x73,0x63,0x90,0x22,0x45,0x1f,0x50,0xd0,
+0x1c,0x04,0x57,0x12,0x5d,0xa0,0xfa,0x44,0x29,0xc0,0x7d,0xad,0x85,0x9c,0x84,0x6c,0xbb,0xd9,0x3a,0xb5,0xb9,0x1b,0x01,0xbc,
+0x77,0x0b,0x08,0x9c,0xfe,0xde,0x6f,0x65,0x1e,0x86,0xdd,0x7c,0x15,0x98,0x9c,0x8b,0x53,0x21,0xde,0xa9,0xca,0x60,0x8c,0x71,
+0xfd,0x86,0x23,0x23,0x07,0x2b,0x82,0x7c,0xee,0x7a,0x7e,0x28,0xe4,0xe2,0xb9,0x99,0x64,0x72,0x33,0xc3,0x45,0x69,0x44,0xbb,
+0x7a,0xef,0x91,0x87,0xc9,0x6b,0x3f,0x5b,0x79,0xfb,0x98,0xbc,0x76,0xc3,0x57,0x4d,0xd0,0x6f,0x0e,0x95,0x68,0x5e,0x5b,0x3a,
+0xef,0x3a,0x54,0xc4,0x15,0x5f,0xe3,0xad,0x81,0x77,0x49,0x62,0x9c,0x30,0xad,0xbe,0x89,0x7c,0x4f,0x44,0x54,0xc8,0x6c,0x49,
+0x00,0x00,0x00,0x0a,
+0xe9,0xca,0x10,0xea,0xa8,0x11,0xb2,0x2a,0xe0,0x7f,0xb1,0x95,0xe3,0x59,0x0a,0x33,0x4e,0xa6,0x42,0x09,0x94,0x2f,0xba,0xe3,
+0x38,0xd1,0x9f,0x15,0x21,0x82,0xc8,0x07,0xd3,0xc4,0x0b,0x18,0x9d,0x3f,0xcb,0xea,0x94,0x2f,0x44,0x68,0x24,0x39,0xb1,0x91,
+0x33,0x2d,0x33,0xae,0x0b,0x76,0x1a,0x2a,0x8f,0x98,0x4b,0x56,0xb2,0xac,0x2f,0xd4,0xab,0x08,0x22,0x3a,0x69,0xed,0x1f,0x77,
+0x19,0xc7,0xaa,0x7e,0x9e,0xee,0x96,0x50,0x4b,0x0e,0x60,0xc6,0xbb,0x5c,0x94,0x2d,0x69,0x5f,0x04,0x93,0xeb,0x25,0xf8,0x0a,
+0x58,0x71,0xcf,0xfd,0x13,0x1d,0x0e,0x04,0xff,0xe5,0x06,0x5b,0xc7,0x87,0x5e,0x82,0xd3,0x4b,0x40,0xb6,0x9d,0xd9,0xf3,0xc1
+};
+
+static const unsigned char shake256_192_pub[] = {
+0x00,0x00,0x00,0x01,
+0x00,0x00,0x00,0x14,
+0x00,0x00,0x00,0x10,
+0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
+0xdb,0x54,0xa4,0x50,0x99,0x01,0x05,0x1c,0x01,0xe2,0x6d,0x99,0x90,0xe5,0x50,0x34,
+0x79,0x86,0xda,0x87,0x92,0x4f,0xf0,0xb1
+};
+static const unsigned char shake256_192_priv[] = {
+/* SEED */
+0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
+0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,
+/* I */
+0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
+};
+static const unsigned char shake256_192_msg[] = {
+0x54,0x65,0x73,0x74,0x20,0x6d,0x65,0x73,0x73,0x61,0x67,0x65,0x20,0x66,0x6f,0x72,
+0x20,0x53,0x48,0x41,0x4b,0x45,0x32,0x35,0x36,0x2d,0x31,0x39,0x32,0x0a
+};
+static const unsigned char shake256_192_sig[] = {
+/* L = 1, q = 6 */
+0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x06,
+0x00,0x00,0x00,0x10,
+0x84,0x21,0x9d,0xa9,0xce,0x9f,0xff,0xb1,0x6e,0xdb,0x94,0x52,0x7c,0x6d,0x10,0x56,0x55,0x87,0xdb,0x28,0x06,0x2d,0xea,0xc4,
+0x20,0x8e,0x62,0xfc,0x4f,0xbe,0x9d,0x85,0xde,0xb3,0xc6,0xbd,0x2c,0x01,0x64,0x0a,0xcc,0xb3,0x87,0xd8,0xa6,0x09,0x3d,0x68,
+0x51,0x12,0x34,0xa6,0xa1,0xa5,0x01,0x08,0x09,0x1c,0x03,0x4c,0xb1,0x77,0x7e,0x02,0xb5,0xdf,0x46,0x61,0x49,0xa6,0x69,0x69,
+0xa4,0x98,0xe4,0x20,0x0c,0x0a,0x0c,0x1b,0xf5,0xd1,0x00,0xcd,0xb9,0x7d,0x2d,0xd4,0x0e,0xfd,0x3c,0xad,0xa2,0x78,0xac,0xc5,
+0xa5,0x70,0x07,0x1a,0x04,0x39,0x56,0x11,0x2c,0x6d,0xee,0xbd,0x1e,0xb3,0xa7,0xb5,0x6f,0x5f,0x67,0x91,0x51,0x5a,0x7b,0x5f,
+0xfd,0xdb,0x0e,0xc2,0xd9,0x09,0x4b,0xfb,0xc8,0x89,0xea,0x15,0xc3,0xc7,0xb9,0xbe,0xa9,0x53,0xef,0xb7,0x5e,0xd6,0x48,0xf5,
+0x35,0xb9,0xac,0xab,0x66,0xa2,0xe9,0x63,0x1e,0x42,0x6e,0x4e,0x99,0xb7,0x33,0xca,0xa6,0xc5,0x59,0x63,0x92,0x9b,0x77,0xfe,
+0xc5,0x4a,0x7e,0x70,0x3d,0x81,0x62,0xe7,0x36,0x87,0x5c,0xb6,0xa4,0x55,0xd4,0xa9,0x01,0x5c,0x7a,0x6d,0x8f,0xd5,0xfe,0x75,
+0xe4,0x02,0xb4,0x70,0x36,0xdc,0x37,0x70,0xf4,0xa1,0xdd,0x0a,0x55,0x9c,0xb4,0x78,0xc7,0xfb,0x17,0x26,0x00,0x53,0x21,0xbe,
+0x9d,0x1a,0xc2,0xde,0x94,0xd7,0x31,0xee,0x4c,0xa7,0x9c,0xff,0x45,0x4c,0x81,0x1f,0x46,0xd1,0x19,0x80,0x90,0x9f,0x04,0x7b,
+0x20,0x05,0xe8,0x4b,0x6e,0x15,0x37,0x84,0x46,0xb1,0xca,0x69,0x1e,0xfe,0x49,0x1e,0xa9,0x8a,0xcc,0x9d,0x3c,0x0f,0x78,0x5c,
+0xab,0xa5,0xe2,0xeb,0x3c,0x30,0x68,0x11,0xc2,0x40,0xba,0x22,0x80,0x29,0x23,0x82,0x7d,0x58,0x26,0x39,0x30,0x4a,0x1e,0x97,
+0x83,0xba,0x5b,0xc9,0xd6,0x9d,0x99,0x9a,0x7d,0xb8,0xf7,0x49,0x77,0x0c,0x3c,0x04,0xa1,0x52,0x85,0x6d,0xc7,0x26,0xd8,0x06,
+0x79,0x21,0x46,0x5b,0x61,0xb3,0xf8,0x47,0xb1,0x3b,0x26,0x35,0xa4,0x53,0x79,0xe5,0xad,0xc6,0xff,0x58,0xa9,0x9b,0x00,0xe6,
+0x0a,0xc7,0x67,0xf7,0xf3,0x01,0x75,0xf9,0xf7,0xa1,0x40,0x25,0x7e,0x21,0x8b,0xe3,0x07,0x95,0x4b,0x12,0x50,0xc9,0xb4,0x19,
+0x02,0xc4,0xfa,0x7c,0x90,0xd8,0xa5,0x92,0x94,0x5c,0x66,0xe8,0x6a,0x76,0xde,0xfc,0xb8,0x45,0x00,0xb5,0x55,0x98,0xa1,0x99,
+0x0f,0xaa,0xa1,0x00,0x77,0xc7,0x4c,0x94,0x89,0x57,0x31,0x58,0x5c,0x8f,0x90,0x0d,0xe1,0xa1,0xc6,0x75,0xbd,0x8b,0x0c,0x18,
+0x0e,0xbe,0x2b,0x5e,0xb3,0xef,0x80,0x19,0xec,0xe3,0xe1,0xea,0x72,0x23,0xeb,0x79,0x06,0xa2,0x04,0x2b,0x62,0x62,0xb4,0xaa,
+0x25,0xc4,0xb8,0xa0,0x5f,0x20,0x5c,0x8b,0xef,0xee,0xf1,0x1c,0xef,0xf1,0x28,0x25,0x08,0xd7,0x1b,0xc2,0xa8,0xcf,0xa0,0xa9,
+0x9f,0x73,0xf3,0xe3,0xa7,0x4b,0xb4,0xb3,0xc0,0xd8,0xca,0x2a,0xbd,0x0e,0x1c,0x2c,0x17,0xda,0xfe,0x18,0xb4,0xee,0x22,0x98,
+0xe8,0x7b,0xcf,0xb1,0x30,0x5b,0x3c,0x06,0x9e,0x6d,0x38,0x55,0x69,0xa4,0x06,0x7e,0xd5,0x47,0x48,0x6d,0xd1,0xa5,0x0d,0x6f,
+0x4a,0x58,0xaa,0xb9,0x6e,0x2f,0xa8,0x83,0xa9,0xa3,0x9e,0x1b,0xd4,0x55,0x41,0xee,0xe9,0x4e,0xfc,0x32,0xfa,0xa9,0xa9,0x4b,
+0xe6,0x6d,0xc8,0x53,0x8b,0x2d,0xab,0x05,0xae,0xe5,0xef,0xa6,0xb3,0xb2,0xef,0xb3,0xfd,0x02,0x0f,0xe7,0x89,0x47,0x7a,0x93,
+0xaf,0xff,0x9a,0x3e,0x63,0x6d,0xbb,0xa8,0x64,0xa5,0xbf,0xfa,0x3e,0x28,0xd1,0x3d,0x49,0xbb,0x59,0x7d,0x94,0x86,0x5b,0xde,
+0x88,0xc4,0x62,0x7f,0x20,0x6a,0xb2,0xb4,0x65,0x08,0x4d,0x6b,0x78,0x06,0x66,0xe9,0x52,0xf8,0x71,0x0e,0xfd,0x74,0x8b,0xd0,
+0xf1,0xae,0x8f,0x10,0x35,0x08,0x7f,0x50,0x28,0xf1,0x4a,0xff,0xcc,0x5f,0xff,0xe3,0x32,0x12,0x1a,0xe4,0xf8,0x7a,0xc5,0xf1,
+0xea,0xc9,0x06,0x26,0x08,0xc7,0xd8,0x77,0x08,0xf1,0x72,0x3f,0x38,0xb2,0x32,0x37,0xa4,0xed,0xf4,0xb4,0x9a,0x5c,0xd3,0xd7,
+0x00,0x00,0x00,0x14,
+0xdd,0x4b,0xdc,0x8f,0x92,0x8f,0xb5,0x26,0xf6,0xfb,0x7c,0xdb,0x94,0x4a,0x7e,0xba,0xa7,0xfb,0x05,0xd9,0x95,0xb5,0x72,0x1a,
+0x27,0x09,0x6a,0x50,0x07,0xd8,0x2f,0x79,0xd0,0x63,0xac,0xd4,0x34,0xa0,0x4e,0x97,0xf6,0x15,0x52,0xf7,0xf8,0x1a,0x93,0x17,
+0xb4,0xec,0x7c,0x87,0xa5,0xed,0x10,0xc8,0x81,0x92,0x8f,0xc6,0xeb,0xce,0x6d,0xfc,0xe9,0xda,0xae,0x9c,0xc9,0xdb,0xa6,0x90,
+0x7c,0xa9,0xa9,0xdd,0x5f,0x9f,0x57,0x37,0x04,0xd5,0xe6,0xcf,0x22,0xa4,0x3b,0x04,0xe6,0x4c,0x1f,0xfc,0x7e,0x1c,0x44,0x2e,
+0xcb,0x49,0x5b,0xa2,0x65,0xf4,0x65,0xc5,0x62,0x91,0xa9,0x02,0xe6,0x2a,0x46,0x1f,0x6d,0xfd,0xa2,0x32,0x45,0x7f,0xad,0x14
+};
+
+static const unsigned char shake256_256_pub[] = {
+0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x0F,0x00,0x00,0x00,0x0C,
+0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
+0x9b,0xb7,0xfa,0xee,0x41,0x1c,0xae,0x80,0x6c,0x16,0xa4,0x66,0xc3,0x19,0x1a,0x8b,
+0x65,0xd0,0xac,0x31,0x93,0x2b,0xbf,0x0c,0x2d,0x07,0xc7,0xa4,0xa3,0x63,0x79,0xfe
+};
+static const unsigned char shake256_256_priv[] = {
+/* SEED */
+0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
+0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
+/* I */
+0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
+};
+static const unsigned char shake256_256_msg[] = {
+0x54,0x65,0x73,0x74,0x20,0x6d,0x65,0x73,0x61,0x67,0x65,0x20,0x66,0x6f,0x72,0x20,
+0x53,0x48,0x41,0x4b,0x45,0x32,0x35,0x36,0x2d,0x32,0x35,0x36,0x0a
+};
+static const unsigned char shake256_256_sig[] = {
+/* L = 1, q = 7 */
+0x00,0x00,0x00,0x00,
+0x00,0x00,0x00,0x07,
+0x00,0x00,0x00,0x0c,
+0xb8,0x27,0x09,0xf0,0xf0,0x0e,0x83,0x75,0x91,0x90,0x99,0x62,0x33,0xd1,0xee,0x4f,
+0x4e,0xc5,0x05,0x34,0x47,0x3c,0x02,0xff,0xa1,0x45,0xe8,0xca,0x28,0x74,0xe3,0x2b,
+0x16,0xb2,0x28,0x11,0x8c,0x62,0xb9,0x6c,0x9c,0x77,0x67,0x8b,0x33,0x18,0x37,0x30,
+0xde,0xba,0xad,0xe8,0xfe,0x60,0x7f,0x05,0xc6,0x69,0x7b,0xc9,0x71,0x51,0x9a,0x34,
+0x1d,0x69,0xc0,0x01,0x29,0x68,0x0b,0x67,0xe7,0x5b,0x3b,0xd7,0xd8,0xaa,0x5c,0x8b,
+0x71,0xf0,0x26,0x69,0xd1,0x77,0xa2,0xa0,0xee,0xa8,0x96,0xdc,0xd1,0x66,0x0f,0x16,
+0x86,0x4b,0x30,0x2f,0xf3,0x21,0xf9,0xc4,0xb8,0x35,0x44,0x08,0xd0,0x67,0x60,0x50,
+0x4f,0x76,0x8e,0xbd,0x4e,0x54,0x5a,0x9b,0x0a,0xc0,0x58,0xc5,0x75,0x07,0x8e,0x6c,
+0x14,0x03,0x16,0x0f,0xb4,0x54,0x50,0xd6,0x1a,0x9c,0x8c,0x81,0xf6,0xbd,0x69,0xbd,
+0xfa,0x26,0xa1,0x6e,0x12,0xa2,0x65,0xba,0xf7,0x9e,0x9e,0x23,0x3e,0xb7,0x1a,0xf6,
+0x34,0xec,0xc6,0x6d,0xc8,0x8e,0x10,0xc6,0xe0,0x14,0x29,0x42,0xd4,0x84,0x3f,0x70,
+0xa0,0x24,0x27,0x27,0xbc,0x5a,0x2a,0xab,0xf7,0xb0,0xec,0x12,0xa9,0x90,0x90,0xd8,
+0xca,0xee,0xf2,0x13,0x03,0xf8,0xac,0x58,0xb9,0xf2,0x00,0x37,0x1d,0xc9,0xe4,0x1a,
+0xb9,0x56,0xe1,0xa3,0xef,0xed,0x9d,0x4b,0xbb,0x38,0x97,0x5b,0x46,0xc2,0x8d,0x5f,
+0x5b,0x3e,0xd1,0x9d,0x84,0x7b,0xd0,0xa7,0x37,0x17,0x72,0x63,0xcb,0xc1,0xa2,0x26,
+0x2d,0x40,0xe8,0x08,0x15,0xee,0x14,0x9b,0x6c,0xce,0x27,0x14,0x38,0x4c,0x9b,0x7f,
+0xce,0xb3,0xbb,0xcb,0xd2,0x52,0x28,0xdd,0xa8,0x30,0x65,0x36,0x37,0x6f,0x87,0x93,
+0xec,0xad,0xd6,0x02,0x02,0x65,0xda,0xb9,0x07,0x5f,0x64,0xc7,0x73,0xef,0x97,0xd0,
+0x73,0x52,0x91,0x99,0x95,0xb7,0x44,0x04,0xcc,0x69,0xa6,0xf3,0xb4,0x69,0x44,0x5c,
+0x92,0x86,0xa6,0xb2,0xc9,0xf6,0xdc,0x83,0x9b,0xe7,0x66,0x18,0xf0,0x53,0xde,0x76,
+0x3d,0xa3,0x57,0x1e,0xf7,0x0f,0x80,0x5c,0x9c,0xc5,0x4b,0x8e,0x50,0x1a,0x98,0xb9,
+0x8c,0x70,0x78,0x5e,0xeb,0x61,0x73,0x7e,0xce,0xd7,0x8b,0x0e,0x38,0x0d,0xed,0x4f,
+0x76,0x9a,0x9d,0x42,0x27,0x86,0xde,0xf5,0x97,0x00,0xee,0xf3,0x27,0x80,0x17,0xba,
+0xbb,0xe5,0xf9,0x06,0x3b,0x46,0x8a,0xe0,0xdd,0x61,0xd9,0x4f,0x9f,0x99,0xd5,0xcc,
+0x36,0xfb,0xec,0x41,0x78,0xd2,0xbd,0xa3,0xad,0x31,0xe1,0x64,0x4a,0x2b,0xcc,0xe2,
+0x08,0xd7,0x2d,0x50,0xa7,0x63,0x78,0x51,0xaa,0x90,0x8b,0x94,0xdc,0x43,0x76,0x12,
+0x0d,0x5b,0xea,0xb0,0xfb,0x80,0x5e,0x19,0x45,0xc4,0x18,0x34,0xdd,0x60,0x85,0xe6,
+0xdb,0x1a,0x3a,0xa7,0x8f,0xcb,0x59,0xf6,0x2b,0xde,0x68,0x23,0x6a,0x10,0x61,0x8c,
+0xff,0x12,0x3a,0xbe,0x64,0xda,0xe8,0xda,0xbb,0x2e,0x84,0xca,0x70,0x53,0x09,0xc2,
+0xab,0x98,0x6d,0x4f,0x83,0x26,0xba,0x06,0x42,0x27,0x2c,0xb3,0x90,0x4e,0xb9,0x6f,
+0x6f,0x5e,0x3b,0xb8,0x81,0x39,0x97,0x88,0x1b,0x6a,0x33,0xca,0xc0,0x71,0x4e,0x4b,
+0x5e,0x7a,0x88,0x2a,0xd8,0x7e,0x14,0x19,0x31,0xf9,0x7d,0x61,0x2b,0x84,0xe9,0x03,
+0xe7,0x73,0x13,0x9a,0xe3,0x77,0xf5,0xba,0x19,0xac,0x86,0x19,0x8d,0x48,0x5f,0xca,
+0x97,0x74,0x25,0x68,0xf6,0xff,0x75,0x81,0x20,0xa8,0x9b,0xf1,0x90,0x59,0xb8,0xa6,
+0xbf,0xe2,0xd8,0x6b,0x12,0x77,0x81,0x64,0x43,0x6a,0xb2,0x65,0x9b,0xa8,0x66,0x76,
+0x7f,0xcc,0x43,0x55,0x84,0x12,0x5f,0xb7,0x92,0x42,0x01,0xee,0x67,0xb5,0x35,0xda,
+0xf7,0x2c,0x5c,0xb3,0x1f,0x5a,0x0b,0x1d,0x92,0x63,0x24,0xc2,0x6e,0x67,0xd4,0xc3,
+0x83,0x6e,0x30,0x1a,0xa0,0x9b,0xae,0x8f,0xb3,0xf9,0x1f,0x16,0x22,0xb1,0x81,0x8c,
+0xcf,0x44,0x0f,0x52,0xca,0x9b,0x5b,0x9b,0x99,0xab,0xa8,0xa6,0x75,0x4a,0xae,0x2b,
+0x96,0x7c,0x49,0x54,0xfa,0x85,0x29,0x8a,0xd9,0xb1,0xe7,0x4f,0x27,0xa4,0x61,0x27,
+0xc3,0x61,0x31,0xc8,0x99,0x1f,0x0c,0xc2,0xba,0x57,0xa1,0x5d,0x35,0xc9,0x1c,0xf8,
+0xbc,0x48,0xe8,0xe2,0x0d,0x62,0x5a,0xf4,0xe8,0x5d,0x8f,0x94,0x02,0xec,0x44,0xaf,
+0xbd,0x47,0x92,0xb9,0x24,0xb8,0x39,0x33,0x2a,0x64,0x78,0x8a,0x77,0x01,0xa3,0x00,
+0x94,0xb9,0xec,0x4b,0x9f,0x4b,0x64,0x8f,0x16,0x8b,0xf4,0x57,0xfb,0xb3,0xc9,0x59,
+0x4f,0xa8,0x79,0x20,0xb6,0x45,0xe4,0x2a,0xa2,0xfe,0xcc,0x9e,0x21,0xe0,0x00,0xca,
+0x7d,0x3f,0xf9,0x14,0xe1,0x5c,0x40,0xa8,0xbc,0x53,0x31,0x29,0xa7,0xfd,0x39,0x52,
+0x93,0x76,0x43,0x0f,0x35,0x5a,0xaf,0x96,0xa0,0xa1,0x3d,0x13,0xf2,0x41,0x91,0x41,
+0xb3,0xcc,0x25,0x84,0x3e,0x8c,0x90,0xd0,0xe5,0x51,0xa3,0x55,0xdd,0x90,0xad,0x77,
+0x0e,0xa7,0x25,0x52,0x14,0xce,0x11,0x23,0x86,0x05,0xde,0x2f,0x00,0x0d,0x20,0x01,
+0x04,0xd0,0xc3,0xa3,0xe3,0x5a,0xe6,0x4e,0xa1,0x0a,0x3e,0xff,0x37,0xac,0x7e,0x95,
+0x49,0x21,0x7c,0xdf,0x52,0xf3,0x07,0x17,0x2e,0x2f,0x6c,0x7a,0x2a,0x45,0x43,0xe1,
+0x43,0x14,0x03,0x65,0x25,0xb1,0xad,0x53,0xee,0xad,0xdf,0x0e,0x24,0xb1,0xf3,0x69,
+0x14,0xed,0x22,0x48,0x3f,0x28,0x89,0xf6,0x1e,0x62,0xb6,0xfb,0x78,0xf5,0x64,0x5b,
+0xdb,0xb0,0x2c,0x9e,0x5b,0xf9,0x7d,0xb7,0xa0,0x00,0x4e,0x87,0xc2,0xa5,0x53,0x99,
+0xb6,0x19,0x58,0x78,0x6c,0x97,0xbd,0x52,0xfa,0x19,0x9c,0x27,0xf6,0xbb,0x4d,0x68,
+0xc4,0x90,0x79,0x33,0x56,0x27,0x55,0xbf,0xec,0x5d,0x4f,0xb5,0x2f,0x06,0xc2,0x89,
+0xd6,0xe8,0x52,0xcf,0x6b,0xc7,0x73,0xff,0xd4,0xc0,0x7e,0xe2,0xd6,0xcc,0x55,0xf5,
+0x7e,0xdc,0xfb,0xc8,0xe8,0x69,0x2a,0x49,0xad,0x47,0xa1,0x21,0xfe,0x3c,0x1b,0x16,
+0xca,0xb1,0xcc,0x28,0x5f,0xaf,0x67,0x93,0xff,0xad,0x7a,0x8c,0x34,0x1a,0x49,0xc5,
+0xd2,0xdc,0xe7,0x06,0x9e,0x46,0x4c,0xb9,0x0a,0x00,0xb2,0x90,0x36,0x48,0xb2,0x3c,
+0x81,0xa6,0x8e,0x21,0xd7,0x48,0xa7,0xe7,0xb1,0xdf,0x8a,0x59,0x3f,0x38,0x94,0xb2,
+0x47,0x7e,0x83,0x16,0x94,0x7c,0xa7,0x25,0xd1,0x41,0x13,0x52,0x02,0xa9,0x44,0x2e,
+0x1d,0xb3,0x3b,0xbd,0x39,0x0d,0x2c,0x04,0x40,0x1c,0x39,0xb2,0x53,0xb7,0x8c,0xe2,
+0x97,0xb0,0xe1,0x47,0x55,0xe4,0x6e,0xc0,0x8a,0x14,0x6d,0x27,0x9c,0x67,0xaf,0x70,
+0xde,0x25,0x68,0x90,0x80,0x4d,0x83,0xd6,0xec,0x5c,0xa3,0x28,0x6f,0x1f,0xca,0x9c,
+0x72,0xab,0xf6,0xef,0x86,0x8e,0x7f,0x6e,0xb0,0xfd,0xdd,0xa1,0xb0,0x40,0xec,0xec,
+0x9b,0xbc,0x69,0xe2,0xfd,0x86,0x18,0xe9,0xdb,0x3b,0xdb,0x0a,0xf1,0x3d,0xda,0x06,
+0xc6,0x61,0x7e,0x95,0xaf,0xa5,0x22,0xd6,0xa2,0x55,0x2d,0xe1,0x53,0x24,0xd9,0x91,
+0x19,0xf5,0x5e,0x9a,0xf1,0x1a,0xe3,0xd5,0x61,0x4b,0x56,0x4c,0x64,0x2d,0xbf,0xec,
+0x6c,0x64,0x41,0x98,0xce,0x80,0xd2,0x43,0x3a,0xc8,0xee,0x73,0x8f,0x9d,0x82,0x5e,
+0x00,0x00,0x00,0x0f,
+0x71,0xd5,0x85,0xa3,0x5c,0x3a,0x90,0x83,0x79,0xf4,0x07,0x2d,0x07,0x03,0x11,0xdb,
+0x5d,0x65,0xb2,0x42,0xb7,0x14,0xbc,0x5a,0x75,0x6b,0xa5,0xe2,0x28,0xab,0xfa,0x0d,
+0x13,0x29,0x97,0x8a,0x05,0xd5,0xe8,0x15,0xcf,0x4d,0x74,0xc1,0xe5,0x47,0xec,0x4a,
+0xa3,0xca,0x95,0x6a,0xe9,0x27,0xdf,0x8b,0x29,0xfb,0x9f,0xab,0x39,0x17,0xa7,0xa4,
+0xae,0x61,0xba,0x57,0xe5,0x34,0x2e,0x9d,0xb1,0x2c,0xaf,0x6f,0x6d,0xbc,0x52,0x53,
+0xde,0x52,0x68,0xd4,0xb0,0xc4,0xce,0x4e,0xbe,0x68,0x52,0xf0,0x12,0xb1,0x62,0xfc,
+0x1c,0x12,0xb9,0xff,0xc3,0xbc,0xb1,0xd3,0xac,0x85,0x89,0x77,0x76,0x55,0xe2,0x2c,
+0xd9,0xb9,0x9f,0xf1,0xe4,0x34,0x6f,0xd0,0xef,0xea,0xa1,0xda,0x04,0x46,0x92,0xe7,
+0xad,0x6b,0xfc,0x33,0x7d,0xb6,0x98,0x49,0xe5,0x44,0x11,0xdf,0x89,0x20,0xc2,0x28,
+0xa2,0xb7,0x76,0x2c,0x11,0xe4,0xb1,0xc4,0x9e,0xfb,0x74,0x48,0x6d,0x39,0x31,0xea,
+};
diff --git a/test/lms_test.c b/test/lms_test.c
new file mode 100644 (file)
index 0000000..6c90b6f
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <openssl/core_names.h>
+#include <openssl/evp.h>
+#include "crypto/lms.h"
+#include "internal/nelem.h"
+#include "testutil.h"
+#include "lms.inc"
+
+static OSSL_LIB_CTX *libctx = NULL;
+
+static EVP_PKEY *lms_pubkey_from_data(const unsigned char *data, size_t datalen)
+{
+    int ret;
+    EVP_PKEY_CTX *ctx = NULL;
+    EVP_PKEY *key = NULL;
+    OSSL_PARAM params[2];
+
+    params[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+                                                  (unsigned char *)data, datalen);
+    params[1] = OSSL_PARAM_construct_end();
+    ret = TEST_ptr(ctx = EVP_PKEY_CTX_new_from_name(libctx, "LMS", NULL))
+        && TEST_int_eq(EVP_PKEY_fromdata_init(ctx), 1)
+        && (EVP_PKEY_fromdata(ctx, &key, EVP_PKEY_PUBLIC_KEY, params) == 1);
+    if (ret == 0) {
+        EVP_PKEY_free(key);
+        key = NULL;
+    }
+    EVP_PKEY_CTX_free(ctx);
+    return key;
+}
+
+static int lms_bad_pub_len_test(void)
+{
+    int ret = 0;
+    LMS_ACVP_TEST_DATA *td = &lms_testdata[1];
+    EVP_PKEY *pkey = NULL;
+    size_t publen = 0;
+    unsigned char pubdata[128];
+
+    if (!TEST_size_t_le(td->publen + 16, sizeof(pubdata)))
+        goto end;
+
+    OPENSSL_cleanse(pubdata, sizeof(pubdata));
+    memcpy(pubdata, td->pub, td->publen);
+
+    for (publen = 0; publen <= td->publen + 16; publen += 3) {
+        if (publen == td->publen)
+            continue;
+        if (!TEST_ptr_null(pkey = lms_pubkey_from_data(pubdata, publen)))
+            goto end;
+    }
+    ret = 1;
+end:
+    if (ret == 0)
+        TEST_note("Incorrectly accepted public key of length %u (expected %u)",
+                  (unsigned)publen, (unsigned)td->publen);
+    EVP_PKEY_free(pkey);
+
+    return ret == 1;
+}
+
+static int lms_key_eq_test(void)
+{
+    int ret = 0;
+    EVP_PKEY *key[3] = { NULL, NULL, NULL };
+    LMS_ACVP_TEST_DATA *td1 = &lms_testdata[0];
+    LMS_ACVP_TEST_DATA *td2 = &lms_testdata[1];
+#ifndef OPENSSL_NO_EC
+    EVP_PKEY *eckey = NULL;
+#endif
+
+    if (!TEST_ptr(key[0] = lms_pubkey_from_data(td1->pub, td1->publen))
+            || !TEST_ptr(key[1] = lms_pubkey_from_data(td1->pub, td1->publen))
+            || !TEST_ptr(key[2] = lms_pubkey_from_data(td2->pub, td2->publen)))
+        goto end;
+
+    ret = TEST_int_eq(EVP_PKEY_eq(key[0], key[1]), 1)
+        && TEST_int_ne(EVP_PKEY_eq(key[0], key[2]), 1);
+    if (ret == 0)
+        goto end;
+
+#ifndef OPENSSL_NO_EC
+    if (!TEST_ptr(eckey = EVP_PKEY_Q_keygen(libctx, NULL, "EC", "P-256")))
+        goto end;
+    ret = TEST_int_ne(EVP_PKEY_eq(key[0], eckey), 1);
+    EVP_PKEY_free(eckey);
+#endif
+end:
+    EVP_PKEY_free(key[2]);
+    EVP_PKEY_free(key[1]);
+    EVP_PKEY_free(key[0]);
+    return ret;
+}
+
+static int lms_key_validate_test(void)
+{
+    int ret = 0;
+    LMS_ACVP_TEST_DATA *td = &lms_testdata[0];
+    EVP_PKEY_CTX *vctx = NULL;
+    EVP_PKEY *key = NULL;
+
+    if (!TEST_ptr(key = lms_pubkey_from_data(td->pub, td->publen)))
+        return 0;
+    if (!TEST_ptr(vctx = EVP_PKEY_CTX_new_from_pkey(libctx, key, NULL)))
+        goto end;
+    ret = TEST_int_eq(EVP_PKEY_check(vctx), 1);
+    EVP_PKEY_CTX_free(vctx);
+end:
+    EVP_PKEY_free(key);
+    return ret;
+}
+
+int setup_tests(void)
+{
+    ADD_TEST(lms_bad_pub_len_test);
+    ADD_TEST(lms_key_validate_test);
+    ADD_TEST(lms_key_eq_test);
+    return 1;
+}
diff --git a/test/recipes/30-test_lms.t b/test/recipes/30-test_lms.t
new file mode 100644 (file)
index 0000000..ada1ab0
--- /dev/null
@@ -0,0 +1,26 @@
+#! /usr/bin/env perl
+# Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
+#
+# Licensed under the Apache License 2.0 (the "License").  You may not use
+# this file except in compliance with the License.  You can obtain a copy
+# in the file LICENSE in the source distribution or at
+# https://www.openssl.org/source/license.html
+
+use strict;
+use warnings;
+
+use OpenSSL::Test qw(:DEFAULT srctop_dir bldtop_dir);
+use OpenSSL::Test::Utils;
+
+BEGIN {
+    setup("test_lms");
+}
+
+use lib srctop_dir('Configurations');
+use lib bldtop_dir('.');
+
+plan skip_all => 'LMS is not supported in this build' if disabled('lms');
+plan tests => 1;
+
+ok(run(test(["lms_test"])), "running lms_test");
+