Compare commits

...
Sign in to create a new pull request.

13 commits

Author SHA1 Message Date
Pauli
a167e8efc2 test: get provider compatibily tests working
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Shane Lontis <shane.lontis@oracle.com>
(Merged from https://github.com/openssl/openssl/pull/26623)
2025-02-04 10:47:24 +11:00
Pauli
b201fc96c8 Add changes entry for LMS verification
Reviewed-by: Hugo Landau <hlandau@devever.net>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/25598)
2025-02-04 08:29:22 +11:00
Pauli
8339b3d753 doc: document the additional LMS self test description
Reviewed-by: Hugo Landau <hlandau@devever.net>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/25598)
2025-02-04 08:29:22 +11:00
Pauli
5edaaac5fa fips: add self test CAST for LMS verify
Reviewed-by: Hugo Landau <hlandau@devever.net>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/25598)
2025-02-04 08:29:22 +11:00
Pauli
ce680a3de0 fips: add LMS description
Reviewed-by: Hugo Landau <hlandau@devever.net>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/25598)
2025-02-04 08:29:22 +11:00
Pauli
6d55700499 Fix indentation
Reviewed-by: Hugo Landau <hlandau@devever.net>
Reviewed-by: Dmitry Belyavskiy <beldmit@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/25598)
2025-02-04 08:29:22 +11:00
slontis
fc875389ee Add LMS documentation
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)
2025-02-04 08:29:22 +11:00
slontis
06937de11d Add LMS to the fips provider.
This required the LMS keymanager to have an export function.
The self test will be provided by HSS, which covers the LMS case.

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)
2025-02-04 08:29:22 +11:00
slontis
c6f68a4213 Allow SHA256-192 to be used internally in the FIPS provider.
Created an internal digest table that contains sha256_192.
Also moved the KECCAK_KMAC_128/256 entries to this internal table
since it is only used by KMAC.

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)
2025-02-04 08:29:22 +11:00
slontis
2ae5fd035a Add LMS Signature verification.
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)
2025-02-04 08:29:22 +11:00
slontis
e9eb032e15 Add LMS public key decoder.
This uses OSSL_DECODER_CTX_new_for_pkey().
"XDR" can be specified for the input type, and the key type is "LMS"

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)
2025-01-27 20:19:14 +11:00
slontis
11551fb38c Add base code to load a LMS public key.
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)
2025-01-27 20:19:14 +11:00
slontis
bfffa8bc02 Add Configurable "lms" option
This option will be used by the base code for enabling
Leighton-Micali Signatures (LMS)

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)
2025-01-27 20:19:14 +11:00
46 changed files with 2991 additions and 32 deletions

View file

@ -37,6 +37,11 @@ OpenSSL 3.5
*Viktor Dukhovni*
* Added LMS signature verification support as per [SP 800-208].
This support is present in both the FIPS and default providers.
*Shane Lontis and Paul Dale*
* All the BIO_meth_get_*() functions allowing reuse of the internal OpenSSL
BIO method implementations were deprecated. The reuse is unsafe due to
dependency on the code of the internal methods not changing.
@ -21202,3 +21207,4 @@ ndif
[CVE-2002-0655]: https://www.openssl.org/news/vulnerabilities.html#CVE-2002-0655
[CMVP]: https://csrc.nist.gov/projects/cryptographic-module-validation-program
[ESV]: https://csrc.nist.gov/Projects/cryptographic-module-validation-program/entropy-validations
[SP 800-208]: https://csrc.nist.gov/pubs/sp/800/208/final

View file

@ -481,6 +481,7 @@ my @disablables = (
"jitter",
"ktls",
"legacy",
"lms",
"loadereng",
"makedepend",
"md2",
@ -621,7 +622,7 @@ my @disable_cascades = (
"des", "dgram", "dh", "dsa",
"ec", "engine",
"filenames",
"idea", "ktls",
"idea", "ktls", "lms",
"md4", "multiblock", "nextprotoneg",
"ocsp", "ocb", "poly1305", "psk",
"rc2", "rc4", "rmd160",

View file

@ -881,6 +881,12 @@ Don't build the legacy provider.
Disabling this also disables the legacy algorithms: MD2 (already disabled by default).
### no-lms
Disable Leighton-Micali Signatures (LMS) support.
Support is currently limited to verification only as per
[SP 800-208](https://csrc.nist.gov/pubs/sp/800/208/final).
### no-makedepend
Don't generate dependencies.

View 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

9
crypto/lms/build.info Normal file
View file

@ -0,0 +1,9 @@
LIBS=../../libcrypto
$COMMON=lms_params.c lms_pubkey_decode.c lms_key.c lm_ots_params.c \
lm_ots_verify.c lms_sig.c lms_sig_decoder.c lms_verify.c
IF[{- !$disabled{'lms'} -}]
SOURCE[../../libcrypto]=$COMMON
SOURCE[../../providers/libfips.a]=$COMMON
ENDIF

View file

@ -0,0 +1,66 @@
/*
* 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"
#include "crypto/lms_sig.h"
#include "crypto/lms_util.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;
}
/* See RFC 8554 Section 4.4 Checksum */
uint16_t ossl_lm_ots_params_checksum(const LM_OTS_PARAMS *params,
const unsigned char *S)
{
uint16_t sum = 0;
uint16_t i;
/* Largest size is 8 * 32 / 1 = 256 (which doesnt quite fit into 8 bits) */
uint16_t bytes = (8 * params->n / params->w);
uint16_t end = (1 << params->w) - 1;
for (i = 0; i < bytes; ++i)
sum += end - coef(S, i, params->w);
return (sum << (8 - params->w));
}

156
crypto/lms/lm_ots_verify.c Normal file
View file

@ -0,0 +1,156 @@
/*
* 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/evp.h>
#include "crypto/lms_sig.h"
#include "crypto/lms_util.h"
static int lm_ots_compute_pubkey_final(EVP_MD_CTX *ctx, EVP_MD_CTX *ctxIq,
const LM_OTS_SIG *sig, unsigned char *Kc);
/**
* @brief OTS Signature verification.
*
* See RFC 8554 Section 4.6 Signature Verification
* Algorithm 4b: Compute a Public Key Candidate |Kc| from a signature, message
* and public key parameters.
*
* @param ctx A temporary working EVP_MD_CTX object.
* @param ctxIq A EVP_MD_CTX object that has been initialised with a digest,
* that returns a non finalized value of H(I || q)
* @param sig An LM_OTS_SIG object that contains C and y
* @param pub The public key LM_OTS_PARAMS
* @param Id A 16 byte indentifier (I) associated with a LMS tree
* @param q The leaf index of the LMS tree.
* @param msg A message to verify
* @param msglen The size of |msg|
* @param Kc The computed public key candidate. It is assumed the size is n.
* @returns 1 on success, or 0 otherwise.
*/
int ossl_lm_ots_compute_pubkey(EVP_MD_CTX *ctx, EVP_MD_CTX *ctxIq,
const LM_OTS_SIG *sig, const LM_OTS_PARAMS *pub,
const unsigned char *Id, uint32_t q,
const unsigned char *msg, size_t msglen,
unsigned char *Kc)
{
int ret = 0;
unsigned char qbuf[LMS_SIZE_q];
unsigned char d_mesg[sizeof(uint16_t)];
if (sig->params != pub)
return 0;
U32STR(qbuf, q);
U16STR(d_mesg, OSSL_LMS_D_MESG);
if (!EVP_DigestUpdate(ctxIq, Id, LMS_SIZE_I)
|| !EVP_DigestUpdate(ctxIq, qbuf, sizeof(qbuf))
|| !EVP_MD_CTX_copy_ex(ctx, ctxIq)
/* Q = H(I || u32str(q) || u16str(D_MESG) || C || msg) */
|| !EVP_DigestUpdate(ctx, d_mesg, sizeof(d_mesg))
|| !EVP_DigestUpdate(ctx, sig->C, sig->params->n)
|| !EVP_DigestUpdate(ctx, msg, msglen)
|| !lm_ots_compute_pubkey_final(ctx, ctxIq, sig, Kc))
goto err;
ret = 1;
err:
return ret;
}
/**
* @brief simple function to increment a 16 bit counter by 1.
* It assumes checking for overflow is not required.
*/
static ossl_inline void INC16(unsigned char *tag)
{
if (++(tag[1]) == 0)
++*tag;
}
/*
* @brief OTS signature verification final phase
* See RFC 8554 Section 4.3 Signature Verification
* Algorithm 4b - Part 3
* Step 3 (Finalizes Q) and 4
*
* @param ctx A EVP_MD_CTX object that contains a non finalized value of
* Q = H(I || u32str(q) || u16str(D_MESG) || C || msg)
* This ctx is reused for other calculations.
* @param ctxIq A EVP_MD_CTX object that contains a non finalized value of H(I || q).
* @param sig An object that containing LM_OTS signature data.
* @param Kc The computed public key. It is assumed the size is n.
* @returns 1 on success, or 0 otherwise.
*/
static int lm_ots_compute_pubkey_final(EVP_MD_CTX *ctx, EVP_MD_CTX *ctxIq,
const LM_OTS_SIG *sig, unsigned char *Kc)
{
int ret = 0, i;
EVP_MD_CTX *ctxKc = NULL;
unsigned char tag[2 + 1], *tag2 = &tag[2];
unsigned char Q[LMS_MAX_DIGEST_SIZE + LMS_SIZE_QSUM], *Qsum;
unsigned char z[LMS_MAX_DIGEST_SIZE];
unsigned char d_pblc[sizeof(uint16_t)];
uint16_t sum;
const LM_OTS_PARAMS *params = sig->params;
int n = params->n;
int p = params->p;
uint8_t j, w = params->w, end = (1 << w) - 1;
int a;
unsigned char *y;
if (!EVP_DigestFinal_ex(ctx, Q, NULL))
goto err;
ctxKc = EVP_MD_CTX_create();
if (ctxKc == NULL)
goto err;
sum = ossl_lm_ots_params_checksum(params, Q);
Qsum = Q + n;
/* Q || Cksm(Q) */
U16STR(Qsum, sum);
U16STR(d_pblc, OSSL_LMS_D_PBLC);
if (!(EVP_MD_CTX_copy_ex(ctxKc, ctxIq))
|| !EVP_DigestUpdate(ctxKc, d_pblc, sizeof(d_pblc)))
goto err;
y = sig->y;
tag[0] = 0;
tag[1] = 0;
/*
* Depending on the lm_ots_type (see lm_ots_params[])
* The outer loop |p| ranges from 26...265 iterations and
* the inner loop |end| is in the range 0...(2^w)-1
*/
for (i = 0; i < p; ++i) {
a = coef(Q, i, w);
memcpy(z, y, n);
y += n;
for (j = a; j < end; ++j) {
*tag2 = (j & 0xFF);
if (!(EVP_MD_CTX_copy_ex(ctx, ctxIq))
|| !EVP_DigestUpdate(ctx, tag, sizeof(tag))
|| !EVP_DigestUpdate(ctx, z, n)
|| !EVP_DigestFinal_ex(ctx, z, NULL))
goto err;
}
INC16(tag);
if (!EVP_DigestUpdate(ctxKc, z, n))
goto err;
}
/* Kc = H(I || u32str(q) || u16str(D_PBLC) || z[0] || ... || z[p-1]) */
if (!EVP_DigestFinal(ctxKc, Kc, NULL))
goto err;
ret = 1;
err:
EVP_MD_CTX_free(ctxKc);
return ret;
}

136
crypto/lms/lms_key.c Normal file
View file

@ -0,0 +1,136 @@
/*
* 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) {
if (!CRYPTO_NEW_REF(&ret->references, 1)) {
OPENSSL_free(ret);
return NULL;
}
ret->libctx = libctx;
}
return ret;
}
/**
* @brief Destroy a LMS_KEY object
*/
void ossl_lms_key_free(LMS_KEY *lmskey)
{
LMS_PUB_KEY *pub;
int i;
if (lmskey == NULL)
return;
CRYPTO_DOWN_REF(&lmskey->references, &i);
REF_PRINT_COUNT("LMS_KEY", i, lmskey);
if (i > 0)
return;
REF_ASSERT_ISNT(i < 0);
pub = &lmskey->pub;
OPENSSL_free(pub->encoded);
CRYPTO_FREE_REF(&lmskey->references);
OPENSSL_free(lmskey);
}
/*
* @brief Increase the reference count for a LMS_KEY object.
* @returns 1 on success or 0 otherwise.
*/
int ossl_lms_key_up_ref(LMS_KEY *key)
{
int i;
if (CRYPTO_UP_REF(&key->references, &i) <= 0)
return 0;
REF_PRINT_COUNT("LMS_KEY", i, key);
REF_ASSERT_ISNT(i < 2);
return ((i > 1) ? 1 : 0);
}
/**
* @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;
}

54
crypto/lms/lms_params.c Normal file
View file

@ -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;
}

View file

@ -0,0 +1,133 @@
/*
* 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 Calculate the size of a public key in XDR format.
*
* @param data A byte array of XDR data for a LMS public key.
* The first 4 bytes are looked at.
* @param datalen The size of |data|.
* @returns The calculated size, or 0 on error.
*/
size_t ossl_lms_pubkey_length(const unsigned char *data, size_t datalen)
{
PACKET pkt;
uint32_t lms_type;
const LMS_PARAMS *params;
if (!PACKET_buf_init(&pkt, data, datalen)
|| !PACKET_get_4_len(&pkt, &lms_type)
|| (params = ossl_lms_params_get(lms_type)) == NULL)
return 0;
return LMS_SIZE_LMS_TYPE + LMS_SIZE_OTS_TYPE + LMS_SIZE_I + params->n;
}
/*
* @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)
*/
int ossl_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) {
OPENSSL_free(pkey->encoded);
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;
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
|| !ossl_lms_pubkey_decode(p->data, p->data_size, lmskey))
return 0;
}
return 1;
}

26
crypto/lms/lms_sig.c Normal file
View file

@ -0,0 +1,26 @@
/*
* 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_sig.h"
/**
* @brief Create a new LMS_SIG object
*/
LMS_SIG *ossl_lms_sig_new(void)
{
return OPENSSL_zalloc(sizeof(LMS_SIG));
}
/**
* @brief Destroy an existing LMS_SIG object
*/
void ossl_lms_sig_free(LMS_SIG *sig)
{
OPENSSL_free(sig);
}

View file

@ -0,0 +1,103 @@
/*
* 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_sig.h"
#include "crypto/lms_util.h"
/**
* @brief Decode a byte array containing XDR signature data into a LMS_SIG object.
*
* This is used for LMS Signature Verification.
* This function may be called multiple times.
* See RFC 8554 Algorithm 6a: Steps 1 and 2.
* It uses shallow copies for C, y and path.
*
* @param pkt Contains the signature data to decode. There may still be data
* remaining in pkt after decoding.
* @param pub A public key that contains LMS_PARAMS and LM_OTS_PARAMS associated
* with the signature.
* @returns The created LMS_SIG object is successful, or NULL on failure. A
* failure may occur if the passed in LMS public key |pub| is not
* compatible with the decoded LMS_SIG object,
*/
LMS_SIG *ossl_lms_sig_from_pkt(PACKET *pkt, const LMS_KEY *pub)
{
uint32_t sig_ots_type = 0, sig_lms_type = 0;
const LMS_PARAMS *lparams = pub->lms_params;
const LM_OTS_PARAMS *pub_ots_params = pub->ots_params;
const LM_OTS_PARAMS *sig_params;
LMS_SIG *lsig = NULL;
lsig = ossl_lms_sig_new();
if (lsig == NULL)
return NULL;
if (!PACKET_get_4_len(pkt, &lsig->q) /* q = Leaf Index */
|| !PACKET_get_4_len(pkt, &sig_ots_type)
|| pub_ots_params->lm_ots_type != sig_ots_type)
goto err;
sig_params = pub_ots_params;
lsig->sig.params = sig_params;
lsig->params = lparams;
if (!PACKET_get_bytes_shallow(pkt, &lsig->sig.C, sig_params->n)
|| !PACKET_get_bytes_shallow(pkt, &lsig->sig.y,
sig_params->p * sig_params->n)
|| !PACKET_get_4_len(pkt, &sig_lms_type)
|| (lparams->lms_type != sig_lms_type)
|| HASH_NOT_MATCHED(lparams, sig_params)
|| lsig->q >= (uint32_t)(1 << lparams->h)
|| !PACKET_get_bytes_shallow(pkt, &lsig->paths,
lparams->h * lparams->n))
goto err;
return lsig;
err:
ossl_lms_sig_free(lsig);
return NULL;
}
/**
* @brief Decode a byte array of LMS signature data.
*
* This function does not duplicate any of the byte data contained within
* |sig|. So it is expected that |sig| will exist for the duration of the
* returned signature |out|.
*
* @param out Used to return the LMS_SIG object.
* @param pub The root public LMS key
* @param sig A input byte array of signature data.
* @param siglen The size of sig.
* @returns 1 if the signature is successfully decoded,
* otherwise it returns 0.
*/
int ossl_lms_sig_decode(LMS_SIG **out, LMS_KEY *pub,
const unsigned char *sig, size_t siglen)
{
PACKET pkt;
LMS_SIG *s = NULL;
if (pub == NULL)
return 0;
if (!PACKET_buf_init(&pkt, sig, siglen))
return 0;
s = ossl_lms_sig_from_pkt(&pkt, pub);
if (s == NULL)
return 0;
/* Fail if there are trailing bytes */
if (PACKET_remaining(&pkt) > 0)
goto err;
*out = s;
return 1;
err:
ossl_lms_sig_free(s);
return 0;
}

168
crypto/lms/lms_verify.c Normal file
View file

@ -0,0 +1,168 @@
/*
* 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_sig.h"
#include "crypto/lms_util.h"
#include "internal/common.h"
/*
* Constants used for obtaining unique inputs for different hashing operations
* e.g H(I || q || OSSL_LMS_D_LEAF || ... )
*/
const uint16_t OSSL_LMS_D_PBLC = 0x8080;
const uint16_t OSSL_LMS_D_MESG = 0x8181;
const uint16_t OSSL_LMS_D_LEAF = 0x8282;
const uint16_t OSSL_LMS_D_INTR = 0x8383;
/*
* @brief Compute the candidate LMS root value Tc
*
* @param paths An array of bytes representing the hash values associated with
* the path through the tree from the leaf associated with the
* LM-OTS signature to the root public key node.
* @param n The hash output size (The size of each path in |paths|)
* @param nodenum The leaf index node number. The root node had a value of 1
* Each subsequent level has nodes in the range 2^h...2^(h+1)-1
* @param ctx A EVP_MD_CTX object used for calculations
* @param ctxI A EVP_MD_CTX object containing an unfinalised H(I)
* @param Tc Contains H(I || u32str(node_num) || u16str(D_LEAF) || Kc) on input,
* and on output returns the calculated candidate public key.
* @returns 1 on success, or 0 otherwise.
*/
static
int lms_sig_compute_tc_from_path(const unsigned char *paths, uint32_t n,
uint32_t node_num,
EVP_MD_CTX *ctx, EVP_MD_CTX *ctxI,
unsigned char *Tc)
{
int ret = 0;
unsigned char qbuf[4];
unsigned char d_intr[sizeof(uint16_t)];
const unsigned char *path = paths;
U16STR(d_intr, OSSL_LMS_D_INTR);
/*
* Calculate the public key Tc using the path
* The root hash is the hash of its 2 childrens Hash values.
* A child hash for each level is passed in by paths, and we have
* a leaf value that can be used with the path to calculate the parent
* hash.
*/
while (node_num > 1) {
/* At each level the path contains either the left or right child */
int odd = node_num & 1;
node_num = node_num >> 1; /* get the parent node_num */
U32STR(qbuf, node_num);
/*
* Calculate Tc as either
* Tc(parent) = H(I || node_q || 0x8383 || paths[i][n] || Tc(right) OR
* Tc(parent) = H(I || node_q || 0x8383 || Tc(left) || paths[i][n])
*/
if (!EVP_MD_CTX_copy_ex(ctx, ctxI)
|| !EVP_DigestUpdate(ctx, qbuf, sizeof(qbuf))
|| !EVP_DigestUpdate(ctx, d_intr, sizeof(d_intr)))
goto err;
if (odd) {
if (!EVP_DigestUpdate(ctx, path, n)
|| !EVP_DigestUpdate(ctx, Tc, n))
goto err;
} else {
if (!EVP_DigestUpdate(ctx, Tc, n)
|| !EVP_DigestUpdate(ctx, path, n))
goto err;
}
/*
* Tc = parent Hash, which is either the left or right child for the next
* level up (node_num determines if it is left or right).
*/
if (!EVP_DigestFinal_ex(ctx, Tc, NULL))
goto err;
path += n;
}
ret = 1;
err:
return ret;
}
/*
* @brief LMS signature verification.
* See RFC 8554 Section 5.4.2. Algorithm 6: Steps 3 & 4
*
* @param lms_sig Is a valid decoded LMS_SIG signature object.
* @param pub Is a valid LMS public key object.
* @param md Contains the fetched digest to be used for Hash operations
* @param msg A message to verify
* @param msglen The size of |msg|
* @returns 1 if the verification succeeded, or 0 otherwise.
*/
int ossl_lms_sig_verify(const LMS_SIG *lms_sig, const LMS_KEY *pub,
const EVP_MD *md,
const unsigned char *msg, size_t msglen)
{
int ret = 0;
EVP_MD_CTX *ctx = NULL, *ctxIq = NULL;
EVP_MD_CTX *ctxI;
unsigned char Kc[LMS_MAX_DIGEST_SIZE];
unsigned char Tc[LMS_MAX_DIGEST_SIZE];
unsigned char qbuf[4];
unsigned char d_leaf[sizeof(uint16_t)];
const LMS_PARAMS *lms_params = pub->lms_params;
uint32_t n = lms_params->n;
uint32_t node_num;
ctx = EVP_MD_CTX_create();
ctxIq = EVP_MD_CTX_create();
if (ctx == NULL || ctxIq == NULL)
goto err;
if (!evp_md_ctx_init(ctxIq, md, lms_sig->params))
goto err;
/*
* Algorithm 6a: Step 3.
* Calculate a candidate public key |Kc| using the lmots_signature, message,
* and the identifiers I, q
*/
if (!ossl_lm_ots_compute_pubkey(ctx, ctxIq, &lms_sig->sig,
pub->ots_params, pub->Id,
lms_sig->q, msg, msglen, Kc))
goto err;
/*
* Algorithm 6a: Step 4
* Compute the candidate LMS root value Tc
*/
if (!ossl_assert(lms_sig->q < (uint32_t)(1 << lms_params->h)))
return 0;
node_num = (1 << lms_params->h) + lms_sig->q;
U32STR(qbuf, node_num);
U16STR(d_leaf, OSSL_LMS_D_LEAF);
ctxI = ctxIq;
/* Tc = H(I || u32str(node_num) || u16str(D_LEAF) || Kc) */
if (!EVP_DigestInit_ex2(ctx, NULL, NULL)
|| !EVP_DigestUpdate(ctx, pub->Id, LMS_SIZE_I)
|| !EVP_MD_CTX_copy_ex(ctxI, ctx)
|| !EVP_DigestUpdate(ctx, qbuf, sizeof(qbuf))
|| !EVP_DigestUpdate(ctx, d_leaf, sizeof(d_leaf))
|| !EVP_DigestUpdate(ctx, Kc, n)
|| !EVP_DigestFinal_ex(ctx, Tc, NULL)
|| !lms_sig_compute_tc_from_path(lms_sig->paths, n, node_num,
ctx, ctxI, Tc))
goto err;
/* Algorithm 6: Step 4 */
ret = (memcmp(pub->pub.K, Tc, n) == 0);
err:
EVP_MD_CTX_free(ctxIq);
EVP_MD_CTX_free(ctx);
return ret;
}

View 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
@ -4805,6 +4809,10 @@ DEPEND[html/man7/EVP_SIGNATURE-HMAC.html]=man7/EVP_SIGNATURE-HMAC.pod
GENERATE[html/man7/EVP_SIGNATURE-HMAC.html]=man7/EVP_SIGNATURE-HMAC.pod
DEPEND[man/man7/EVP_SIGNATURE-HMAC.7]=man7/EVP_SIGNATURE-HMAC.pod
GENERATE[man/man7/EVP_SIGNATURE-HMAC.7]=man7/EVP_SIGNATURE-HMAC.pod
DEPEND[html/man7/EVP_SIGNATURE-LMS.html]=man7/EVP_SIGNATURE-LMS.pod
GENERATE[html/man7/EVP_SIGNATURE-LMS.html]=man7/EVP_SIGNATURE-LMS.pod
DEPEND[man/man7/EVP_SIGNATURE-LMS.7]=man7/EVP_SIGNATURE-LMS.pod
GENERATE[man/man7/EVP_SIGNATURE-LMS.7]=man7/EVP_SIGNATURE-LMS.pod
DEPEND[html/man7/EVP_SIGNATURE-RSA.html]=man7/EVP_SIGNATURE-RSA.pod
GENERATE[html/man7/EVP_SIGNATURE-RSA.html]=man7/EVP_SIGNATURE-RSA.pod
DEPEND[man/man7/EVP_SIGNATURE-RSA.7]=man7/EVP_SIGNATURE-RSA.pod
@ -5140,6 +5148,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 \
@ -5155,6 +5164,7 @@ html/man7/EVP_SIGNATURE-DSA.html \
html/man7/EVP_SIGNATURE-ECDSA.html \
html/man7/EVP_SIGNATURE-ED25519.html \
html/man7/EVP_SIGNATURE-HMAC.html \
html/man7/EVP_SIGNATURE-LMS.html \
html/man7/EVP_SIGNATURE-RSA.html \
html/man7/OSSL_PROVIDER-FIPS.html \
html/man7/OSSL_PROVIDER-base.html \
@ -5287,6 +5297,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 \
@ -5302,6 +5313,7 @@ man/man7/EVP_SIGNATURE-DSA.7 \
man/man7/EVP_SIGNATURE-ECDSA.7 \
man/man7/EVP_SIGNATURE-ED25519.7 \
man/man7/EVP_SIGNATURE-HMAC.7 \
man/man7/EVP_SIGNATURE-LMS.7 \
man/man7/EVP_SIGNATURE-RSA.7 \
man/man7/OSSL_PROVIDER-FIPS.7 \
man/man7/OSSL_PROVIDER-base.7 \

View file

@ -57,6 +57,7 @@ L<EVP_PKEY-DH(7)/DH parameters>
L<EVP_PKEY-DH(7)/DH key generation parameters>
L<EVP_PKEY-EC(7)/Common EC parameters>
L<EVP_PKEY-X25519(7)/Common X25519, X448, ED25519 and ED448 parameters>
L<EVP_PKEY-LMS(7)/Common LMS parameters>
=head1 RETURN VALUES

View file

@ -261,7 +261,7 @@ L<EVP_PKEY_CTX_new(3)>, L<provider(7)>, L<EVP_PKEY_gettable_params(3)>,
L<OSSL_PARAM(3)>, L<EVP_PKEY_todata(3)>,
L<EVP_PKEY-RSA(7)>, L<EVP_PKEY-DSA(7)>, L<EVP_PKEY-DH(7)>, L<EVP_PKEY-EC(7)>,
L<EVP_PKEY-ED448(7)>, L<EVP_PKEY-X25519(7)>, L<EVP_PKEY-X448(7)>,
L<EVP_PKEY-ED25519(7)>
L<EVP_PKEY-ED25519(7)>, L<EVP_PKEY-LMS(7)>
=head1 HISTORY

View file

@ -45,7 +45,7 @@ L<OSSL_PARAM(3)>, L<openssl-core.h(7)>,
L<EVP_PKEY_fromdata(3)>,
L<EVP_PKEY-RSA(7)>, L<EVP_PKEY-DSA(7)>, L<EVP_PKEY-DH(7)>, L<EVP_PKEY-EC(7)>,
L<EVP_PKEY-ED448(7)>, L<EVP_PKEY-X25519(7)>, L<EVP_PKEY-X448(7)>,
L<EVP_PKEY-ED25519(7)>
L<EVP_PKEY-ED25519(7)>, L<EVP_PKEY-LMS(7)>
=head1 HISTORY

99
doc/man7/EVP_PKEY-LMS.pod Normal file
View file

@ -0,0 +1,99 @@
=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 and FIPS providers.
The OpenSSL providers only support LMS signature verification, as this is a
[SP 800-208](https://csrc.nist.gov/pubs/sp/800/208/final) requirement for
software modules.
=head2 Common LMS parameters
LMS public keys are encoded in XDR format (i.e. not ASN1 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 SP800-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(libctx, "LMS", propq);
An B<LMS> public key can be loaded simply like this:
EVP_PKEY *pkey = NULL;
OSSL_DECODER_CTX *dctx = NULL;
int selection = OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "XDR", NULL,
"LMS", selection, libctx, propq);
ret = OSSL_DECODER_from_bio(dctx, bio);
OSSL_DECODER_CTX_free(dctx);
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<EVP_SIGNATURE-LMS(7)>,
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

View file

@ -0,0 +1,60 @@
=pod
=head1 NAME
EVP_SIGNATURE-LMS
- The EVP_PKEY Leighton-Micali Signature (LMS) implementation
=head1 DESCRIPTION
The B<LMS> EVP_PKEY implementation supports Leighton-Micali Signatures (LMS)
described in [RFC 8554](https://datatracker.ietf.org/doc/html/rfc8854)
and [SP 800-208](https://csrc.nist.gov/pubs/sp/800/208/final).
The OpenSSL providers only support LMS signature verification, as this is a
SP 800-208 requirement for software modules.
EVP_PKEY_verify_message_init() and EVP_PKEY_verify() are the only supported
functions used for LMS signatures. Streaming is not currently supported,
and since the signature data contains data related to the digest used, functions
that specify the digest name are not necessary.
=head1 EXAMPLES
Error checking has been omitted from the following examples
=head2 LMS signature verification
/* See L<EVP_PKEY-LMS(7)/EXAMPLES for an example of loading a LMS |pub| key */
ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pub, propq);
sig = EVP_SIGNATURE_fetch(libctx, "LMS", propq);
EVP_PKEY_verify_message_init(ctx, sig, NULL);
/*
* EVP_PKEY_verify_message_update() and EVP_PKEY_verify_message_final()
* are not supported
*/
ret = EVP_PKEY_verify(ctx, sigdata, sigdata_len, msg, msglen);
/*
* ret == 1 indicates success, 0 verify failure and < 0 for some
* other error.
*/
=head1 SEE ALSO
L<EVP_PKEY-LMS(7)>,
L<provider-signature(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

View file

@ -70,9 +70,11 @@ The OpenSSL FIPS provider supports these operations and algorithms:
=item SHA3, see L<EVP_MD-SHA3(7)>
=item SHAKE, see L<EVP_MD-SHAKE(7)>
=item KECCAK-KMAC, see L<EVP_MD-KECCAK-KMAC(7)>
=item SHAKE, see L<EVP_MD-SHAKE(7)>
KECCAK-KMAC is only used internally as a sub algorithm of KMAC.
=back
@ -168,6 +170,8 @@ for signature generation, but may be used for verification for legacy use cases.
=item CMAC, see L<EVP_SIGNATURE-CMAC(7)>
=item LMS, see L<EVP_SIGNATURE-LMS(7)>
=back
=head2 Asymmetric Cipher
@ -381,6 +385,8 @@ Digest tests used with the "KAT_Digest" type.
=item "EDDSA" (B<OSSL_SELF_TEST_DESC_SIGN_EDDSA>)
=item "LMS" (B<OSSL_SELF_TEST_DESC_SIGN_LMS>)
Signature tests used with the "KAT_Signature" type.
=item "ECDH" (B<OSSL_SELF_TEST_DESC_KA_ECDH>)

View file

@ -199,6 +199,8 @@ The OpenSSL default provider supports these operations and algorithms:
=item CMAC, see L<EVP_SIGNATURE-CMAC(7)>
=item LMS, see L<EVP_SIGNATURE-LMS(7)>
=back
=head2 Asymmetric Cipher

View file

@ -502,7 +502,8 @@ L<EVP_PKEY_get_security_bits(3)>,
L<provider(7)>,
L<EVP_PKEY-X25519(7)>, L<EVP_PKEY-X448(7)>, L<EVP_PKEY-ED25519(7)>,
L<EVP_PKEY-ED448(7)>, L<EVP_PKEY-EC(7)>, L<EVP_PKEY-RSA(7)>,
L<EVP_PKEY-DSA(7)>, L<EVP_PKEY-DH(7)>
L<EVP_PKEY-DSA(7)>, L<EVP_PKEY-DH(7)>,
L<EVP_PKEY-LMS(7)>
=head1 HISTORY

157
include/crypto/lms.h Normal file
View file

@ -0,0 +1,157 @@
/*
* 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>
# include "internal/refcount.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
/* Constants used for verifying */
# define LMS_SIZE_q 4
/* XDR sizes when encoding and decoding */
# define LMS_SIZE_I 16
# define LMS_SIZE_LMS_TYPE 4
# define LMS_SIZE_OTS_TYPE 4
# define LMS_MAX_DIGEST_SIZE 32
# define LMS_MAX_PUBKEY \
(LMS_SIZE_LMS_TYPE + LMS_SIZE_OTS_TYPE + LMS_SIZE_I + LMS_MAX_DIGEST_SIZE)
/*
* 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;
} 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;
CRYPTO_REF_COUNT references;
};
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);
int ossl_lms_key_up_ref(LMS_KEY *key);
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);
int ossl_lms_pubkey_decode(const unsigned char *pub, size_t publen,
LMS_KEY *lmskey);
size_t ossl_lms_pubkey_length(const unsigned char *data, size_t datalen);
# endif /* OPENSSL_NO_LMS */
#endif /* OSSL_CRYPTO_LMS_H */

75
include/crypto/lms_sig.h Normal file
View file

@ -0,0 +1,75 @@
/*
* 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
*
* Refer to RFC 8554 Sections 5.4 & 4.5 for information related to
* LMS Signatures & LM_OTS Signature Generation respectively.
*/
#ifndef OSSL_CRYPTO_LMS_SIG_H
# define OSSL_CRYPTO_LMS_SIG_H
# pragma once
# ifndef OPENSSL_NO_LMS
# include "lms.h"
# include "internal/packet.h"
/* The values defined for 8 byte TAGS */
extern const uint16_t OSSL_LMS_D_PBLC; /* 8080 */
extern const uint16_t OSSL_LMS_D_MESG; /* 8181 */
extern const uint16_t OSSL_LMS_D_LEAF; /* 8282 */
extern const uint16_t OSSL_LMS_D_INTR; /* 8383 */
/* Used by OTS signature when calculating Q || Cksm(Q) */
# define LMS_SIZE_CHECKSUM 2
# define LMS_SIZE_QSUM 2
/*
* An object for storing a One-Time Signature
* See RFC 8554 Section 4.5
*/
typedef struct lm_ots_sig_st {
const LM_OTS_PARAMS *params;
/* For verify operations the following pointers are not allocated */
unsigned char *C; /* A salt value of size n */
unsigned char *y; /* The trailing part of a signature of size p * n */
} LM_OTS_SIG;
/*
* An object for storing a LMS signature
* See RFC 8554 Section 5.4
*/
typedef struct lms_signature_st {
uint32_t q;
LM_OTS_SIG sig;
const LMS_PARAMS *params; /* contains the LMS type */
unsigned char *paths; /* size is h * m */
} LMS_SIG;
LMS_SIG *ossl_lms_sig_new(void);
void ossl_lms_sig_free(LMS_SIG *sig);
LMS_SIG *ossl_lms_sig_from_pkt(PACKET *pkt, const LMS_KEY *pub);
int ossl_lms_sig_decode(LMS_SIG **out, LMS_KEY *pub,
const unsigned char *sig, size_t siglen);
int ossl_lms_sig_verify(const LMS_SIG *lms_sig, const LMS_KEY *pub,
const EVP_MD *md,
const unsigned char *msg, size_t msglen);
int ossl_lm_ots_compute_pubkey(EVP_MD_CTX *ctx, EVP_MD_CTX *ctxIq,
const LM_OTS_SIG *sig, const LM_OTS_PARAMS *pub,
const unsigned char *Id, uint32_t q,
const unsigned char *msg, size_t msglen,
unsigned char *Kc);
uint16_t ossl_lm_ots_params_checksum(const LM_OTS_PARAMS *params,
const unsigned char *S);
# endif /* OPENSSL_NO_LMS */
#endif /* OSSL_CRYPTO_LMS_SIG_H */

108
include/crypto/lms_util.h Normal file
View file

@ -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
*/
/* @brief Internal LMS internal helper functions */
#include "internal/packet.h"
#include <openssl/params.h>
#include <openssl/core_names.h>
#include <openssl/evp.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)
/* Convert a 32 bit value |in| to 4 bytes |out| */
#define U32STR(out, in) \
(out)[0] = (unsigned char)(((in) >> 24) & 0xff); \
(out)[1] = (unsigned char)(((in) >> 16) & 0xff); \
(out)[2] = (unsigned char)(((in) >> 8) & 0xff); \
(out)[3] = (unsigned char)((in) & 0xff)
/* Convert a 16 bit value |in| to 2 bytes |out| */
#define U16STR(out, in) \
(out)[0] = (unsigned char)(((in) >> 8) & 0xff); \
(out)[1] = (unsigned char)((in) & 0xff)
/**
* @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;
}
/*
* See RFC 8554 Section 3.1.3: Strings of w-bit Elements
* w: Is one of {1,2,4,8}
*/
static ossl_unused ossl_inline
uint8_t coef(const unsigned char *S, uint16_t i, uint8_t w)
{
uint8_t bitmask = (1 << w) - 1;
uint8_t shift = 8 - (w * (i % (8 / w)) + w);
int id = (i * w) / 8;
return (S[id] >> shift) & bitmask;
}
static ossl_unused ossl_inline
int evp_md_ctx_init(EVP_MD_CTX *ctx, const EVP_MD *md,
const LMS_PARAMS *lms_params)
{
OSSL_PARAM params[2] = { OSSL_PARAM_END, OSSL_PARAM_END };
OSSL_PARAM *p = NULL;
/* The OpenSSL SHAKE implementation requires the xoflen to be set */
if (strncmp(lms_params->digestname, "SHAKE", 5) == 0) {
params[0] = OSSL_PARAM_construct_uint32(OSSL_DIGEST_PARAM_XOFLEN,
(uint32_t *)&lms_params->n);
p = params;
}
return EVP_DigestInit_ex2(ctx, md, p);
}

View 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

View file

@ -61,6 +61,7 @@ extern "C" {
# define OSSL_SELF_TEST_DESC_SIGN_RSA "RSA"
# define OSSL_SELF_TEST_DESC_SIGN_ECDSA "ECDSA"
# define OSSL_SELF_TEST_DESC_SIGN_EDDSA "EDDSA"
# define OSSL_SELF_TEST_DESC_SIGN_LMS "LMS"
# define OSSL_SELF_TEST_DESC_DRBG_CTR "CTR"
# define OSSL_SELF_TEST_DESC_DRBG_HASH "HASH"
# define OSSL_SELF_TEST_DESC_DRBG_HMAC "HMAC"

View file

@ -95,3 +95,7 @@ DECODER("DER", pem, der, yes),
* form to the next decoder.
*/
DECODER_w_structure("DER", der, EncryptedPrivateKeyInfo, der, yes),
#ifndef OPENSSL_NO_LMS
DECODER("LMS", xdr, lms, yes),
#endif

View file

@ -456,6 +456,9 @@ static const OSSL_ALGORITHM deflt_signature[] = {
#endif
#ifndef OPENSSL_NO_CMAC
{ PROV_NAMES_CMAC, "provider=default", ossl_mac_legacy_cmac_signature_functions },
#endif
#ifndef OPENSSL_NO_LMS
{ PROV_NAMES_LMS, "provider=default", ossl_lms_signature_functions },
#endif
{ NULL, NULL, NULL }
};
@ -530,6 +533,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 }
};

View file

@ -253,27 +253,33 @@ static int fips_self_test(void *provctx)
* NIST uses, or that are used for ASN.1 OBJECT IDENTIFIERs, or names
* we have used historically.
*/
#define FIPS_DIGESTS_COMMON() \
{ PROV_NAMES_SHA1, FIPS_DEFAULT_PROPERTIES, ossl_sha1_functions }, \
{ PROV_NAMES_SHA2_224, FIPS_DEFAULT_PROPERTIES, ossl_sha224_functions }, \
{ PROV_NAMES_SHA2_256, FIPS_DEFAULT_PROPERTIES, ossl_sha256_functions }, \
{ PROV_NAMES_SHA2_384, FIPS_DEFAULT_PROPERTIES, ossl_sha384_functions }, \
{ PROV_NAMES_SHA2_512, FIPS_DEFAULT_PROPERTIES, ossl_sha512_functions }, \
{ PROV_NAMES_SHA2_512_224, FIPS_DEFAULT_PROPERTIES, \
ossl_sha512_224_functions }, \
{ PROV_NAMES_SHA2_512_256, FIPS_DEFAULT_PROPERTIES, \
ossl_sha512_256_functions }, \
{ PROV_NAMES_SHA3_224, FIPS_DEFAULT_PROPERTIES, ossl_sha3_224_functions }, \
{ PROV_NAMES_SHA3_256, FIPS_DEFAULT_PROPERTIES, ossl_sha3_256_functions }, \
{ PROV_NAMES_SHA3_384, FIPS_DEFAULT_PROPERTIES, ossl_sha3_384_functions }, \
{ PROV_NAMES_SHA3_512, FIPS_DEFAULT_PROPERTIES, ossl_sha3_512_functions }, \
{ PROV_NAMES_SHAKE_128, FIPS_DEFAULT_PROPERTIES, ossl_shake_128_functions }, \
{ PROV_NAMES_SHAKE_256, FIPS_DEFAULT_PROPERTIES, ossl_shake_256_functions }
static const OSSL_ALGORITHM fips_digests[] = {
/* Our primary name:NiST name[:our older names] */
{ PROV_NAMES_SHA1, FIPS_DEFAULT_PROPERTIES, ossl_sha1_functions },
{ PROV_NAMES_SHA2_224, FIPS_DEFAULT_PROPERTIES, ossl_sha224_functions },
{ PROV_NAMES_SHA2_256, FIPS_DEFAULT_PROPERTIES, ossl_sha256_functions },
{ PROV_NAMES_SHA2_384, FIPS_DEFAULT_PROPERTIES, ossl_sha384_functions },
{ PROV_NAMES_SHA2_512, FIPS_DEFAULT_PROPERTIES, ossl_sha512_functions },
{ PROV_NAMES_SHA2_512_224, FIPS_DEFAULT_PROPERTIES,
ossl_sha512_224_functions },
{ PROV_NAMES_SHA2_512_256, FIPS_DEFAULT_PROPERTIES,
ossl_sha512_256_functions },
/* We agree with NIST here, so one name only */
{ PROV_NAMES_SHA3_224, FIPS_DEFAULT_PROPERTIES, ossl_sha3_224_functions },
{ PROV_NAMES_SHA3_256, FIPS_DEFAULT_PROPERTIES, ossl_sha3_256_functions },
{ PROV_NAMES_SHA3_384, FIPS_DEFAULT_PROPERTIES, ossl_sha3_384_functions },
{ PROV_NAMES_SHA3_512, FIPS_DEFAULT_PROPERTIES, ossl_sha3_512_functions },
{ PROV_NAMES_SHAKE_128, FIPS_DEFAULT_PROPERTIES, ossl_shake_128_functions },
{ PROV_NAMES_SHAKE_256, FIPS_DEFAULT_PROPERTIES, ossl_shake_256_functions },
FIPS_DIGESTS_COMMON(),
{ NULL, NULL, NULL }
};
static const OSSL_ALGORITHM fips_digests_internal[] = {
FIPS_DIGESTS_COMMON(),
/* Used by LMS/HSS */
{ PROV_NAMES_SHA2_256_192, FIPS_DEFAULT_PROPERTIES,
ossl_sha256_192_functions },
/*
* KECCAK-KMAC-128 and KECCAK-KMAC-256 as hashes are mostly useful for
* KMAC128 and KMAC256.
@ -479,6 +485,9 @@ static const OSSL_ALGORITHM fips_signature[] = {
#ifndef OPENSSL_NO_CMAC
{ PROV_NAMES_CMAC, FIPS_DEFAULT_PROPERTIES,
ossl_mac_legacy_cmac_signature_functions },
#endif
#ifndef OPENSSL_NO_LMS
{ PROV_NAMES_LMS, FIPS_DEFAULT_PROPERTIES, ossl_lms_signature_functions },
#endif
{ NULL, NULL, NULL }
};
@ -531,6 +540,10 @@ static const OSSL_ALGORITHM fips_keymgmt[] = {
#ifndef OPENSSL_NO_CMAC
{ PROV_NAMES_CMAC, FIPS_DEFAULT_PROPERTIES,
ossl_cmac_legacy_keymgmt_functions, PROV_DESCS_CMAC_SIGN },
#endif
#ifndef OPENSSL_NO_LMS
{ PROV_NAMES_LMS, FIPS_DEFAULT_PROPERTIES, ossl_lms_keymgmt_functions,
PROV_DESCS_LMS },
#endif
{ NULL, NULL, NULL }
};
@ -571,11 +584,14 @@ static const OSSL_ALGORITHM *fips_query(void *provctx, int operation_id,
static const OSSL_ALGORITHM *fips_query_internal(void *provctx, int operation_id,
int *no_cache)
{
if (operation_id == OSSL_OP_MAC) {
int is_digest_op = (operation_id == OSSL_OP_DIGEST);
if (is_digest_op
|| operation_id == OSSL_OP_MAC) {
*no_cache = 0;
if (!ossl_prov_is_running())
return NULL;
return fips_macs_internal;
return is_digest_op ? fips_digests_internal : fips_macs_internal;
}
return fips_query(provctx, operation_id, no_cache);
}

View file

@ -307,6 +307,148 @@ static const ST_KAT_CIPHER st_kat_cipher_tests[] = {
#endif
};
#ifndef OPENSSL_NO_LMS
typedef struct st_kat_lms_s {
const unsigned char *pub;
size_t publen;
const unsigned char *msg;
size_t msglen;
const unsigned char *sig;
size_t siglen;
} ST_KAT_LMS;
/*
* Test vector 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, 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_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, 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 ST_KAT_LMS st_kat_lms_test = {
ITM(sha256_192_pub),
ITM(sha256_192_msg),
ITM(sha256_192_sig)
};
#endif /* OPENSSL_NO_LMS */
static const char hkdf_digest[] = "SHA256";
/*
* Input parameters and expected result are from RFC 5869 test case 1, which is

View file

@ -446,6 +446,52 @@ err:
}
#endif /* !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_EC) */
#ifndef OPENSSL_NO_LMS
static int self_test_LMS(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
{
int ret = 0;
OSSL_PARAM pm[2];
const ST_KAT_LMS *t = &st_kat_lms_test;
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *pkey = NULL;
EVP_SIGNATURE *sig = NULL;
OSSL_SELF_TEST_onbegin(st, OSSL_SELF_TEST_TYPE_KAT_SIGNATURE,
OSSL_SELF_TEST_DESC_SIGN_LMS);
pm[0] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
(unsigned char *)t->pub,
t->publen);
pm[1] = OSSL_PARAM_construct_end();
ctx = EVP_PKEY_CTX_new_from_name(libctx, "LMS", "");
if (ctx == NULL
|| EVP_PKEY_fromdata_init(ctx) <= 0
|| EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, pm) <= 0)
goto err;
EVP_PKEY_CTX_free(ctx);
ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, "");
if (ctx == NULL)
goto err;
sig = EVP_SIGNATURE_fetch(libctx, "LMS", NULL);
if (sig == NULL
|| EVP_PKEY_verify_message_init(ctx, sig, NULL) <= 0
|| EVP_PKEY_verify(ctx, t->sig, t->siglen,
t->msg, t->msglen) <= 0)
goto err;
ret = 1;
err:
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
EVP_SIGNATURE_free(sig);
OSSL_SELF_TEST_onend(st, ret);
return ret;
}
#endif /* OPENSSL_NO_LMS */
static int self_test_digest_sign(const ST_KAT_SIGN *t,
OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
{
@ -799,6 +845,19 @@ int SELF_TEST_kats(OSSL_SELF_TEST *st, OSSL_LIB_CTX *libctx)
ret = 0;
if (!self_test_ciphers(st, libctx))
ret = 0;
#ifndef OPENSSL_NO_LMS
/*
* FIPS 140-3 IG 10.3.A Note 5 mandates a CAST for LMS.
*
* It permits this to be omitted if HSS is also implemented and has
* the relevant self tests. One HSS is implemented, this test can be
* removed. This IG permits the digest's CAST to be subsumed into this
* test, however, because this will be removed, the underlying digest
* test has been retained elsewhere lest it is accidentally omitted.
*/
if (!self_test_LMS(st, libctx))
ret = 0;
#endif /* OPENSSL_NO_LMS */
if (!self_test_signatures(st, libctx))
ret = 0;
if (!self_test_kdfs(st, libctx))

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019-2023 The OpenSSL Project Authors. All Rights Reserved.
* Copyright 2019-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
@ -71,12 +71,10 @@ IMPLEMENT_digest_functions(sha224, SHA256_CTX,
IMPLEMENT_digest_functions(sha256, SHA256_CTX,
SHA256_CBLOCK, SHA256_DIGEST_LENGTH, SHA2_FLAGS,
SHA256_Init, SHA256_Update, SHA256_Final)
#ifndef FIPS_MODULE
/* ossl_sha256_192_functions */
IMPLEMENT_digest_functions(sha256_192, SHA256_CTX,
SHA256_CBLOCK, SHA256_192_DIGEST_LENGTH, SHA2_FLAGS,
ossl_sha256_192_init, SHA256_Update, SHA256_Final)
#endif
/* ossl_sha384_functions */
IMPLEMENT_digest_functions(sha384, SHA512_CTX,
SHA512_CBLOCK, SHA384_DIGEST_LENGTH, SHA2_FLAGS,

View file

@ -18,3 +18,7 @@ IF[{- !$disabled{ec} -}]
SOURCE[$ENCODER_GOAL]=encode_key2blob.c
ENDIF
DEPEND[encode_key2any.o]=../../common/include/prov/der_rsa.h
IF[{- !$disabled{lms} -}]
SOURCE[$DECODER_GOAL]=decode_lmsxdr2key.c
ENDIF

View file

@ -0,0 +1,162 @@
/*
* 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_object.h>
#include <openssl/core_names.h>
#include <openssl/crypto.h>
#include <openssl/err.h>
#include <openssl/params.h>
#include "endecoder_local.h"
#include "crypto/lms.h"
#include "prov/bio.h"
#include "prov/implementations.h"
static OSSL_FUNC_decoder_newctx_fn lmsxdr2key_newctx;
static OSSL_FUNC_decoder_freectx_fn lmsxdr2key_freectx;
static OSSL_FUNC_decoder_decode_fn lmsxdr2key_decode;
static OSSL_FUNC_decoder_export_object_fn lmsxdr2key_export_object;
/* Context used for xdr to key decoding. */
struct lmsxdr2key_ctx_st {
PROV_CTX *provctx;
int selection; /* The selection that is passed to lmsxdr2key_decode() */
};
static void *lmsxdr2key_newctx(void *provctx)
{
struct lmsxdr2key_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
if (ctx != NULL)
ctx->provctx = provctx;
return ctx;
}
static void lmsxdr2key_freectx(void *vctx)
{
struct lmsxdr2key_ctx_st *ctx = vctx;
OPENSSL_free(ctx);
}
static int lmsxdr2key_does_selection(void *provctx, int selection)
{
if (selection == 0)
return 1;
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0)
return 1;
return 0;
}
static int lmsxdr2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
OSSL_CALLBACK *data_cb, void *data_cbarg,
OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
{
struct lmsxdr2key_ctx_st *ctx = vctx;
LMS_KEY *key = NULL;
unsigned char buf[LMS_MAX_PUBKEY];
size_t length;
int ok = 0;
BIO *in;
in = ossl_bio_new_from_core_bio(ctx->provctx, cin);
if (in == NULL)
return 0;
ERR_set_mark();
ctx->selection = selection;
/* Read the header to determine the size */
if (BIO_read(in, buf, 4) != 4)
goto next;
length = ossl_lms_pubkey_length(buf, 4);
if (length == 0)
goto next;
if (BIO_read(in, buf + 4, length - 4) != (int)(length - 4))
goto next;
if (selection == 0 || (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
key = ossl_lms_key_new(PROV_LIBCTX_OF(ctx->provctx));
if (key == NULL || !ossl_lms_pubkey_decode(buf, length, key)) {
ossl_lms_key_free(key);
key = NULL;
}
}
next:
ERR_clear_last_mark();
/*
* Indicated that we successfully decoded something, or not at all.
* Ending up "empty handed" is not an error.
*/
ok = 1;
/*
* We free resources here so it's not held up during the callback, because
* we know the process is recursive and the allocated chunks of memory
* add up.
*/
BIO_free(in);
in = NULL;
if (key != NULL) {
OSSL_PARAM params[4];
int object_type = OSSL_OBJECT_PKEY;
params[0] =
OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type);
params[1] =
OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
(char *)"lms", 0);
/* The address of the key becomes the octet string */
params[2] =
OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE,
&key, sizeof(key));
params[3] = OSSL_PARAM_construct_end();
ok = data_cb(params, data_cbarg);
}
BIO_free(in);
ossl_lms_key_free(key);
return ok;
}
static int lmsxdr2key_export_object(void *vctx,
const void *reference, size_t reference_sz,
OSSL_CALLBACK *export_cb,
void *export_cbarg)
{
struct lmsxdr2key_ctx_st *ctx = vctx;
OSSL_FUNC_keymgmt_export_fn *export =
ossl_prov_get_keymgmt_export(ossl_lms_keymgmt_functions);
void *keydata;
if (reference_sz == sizeof(keydata) && export != NULL) {
int selection = ctx->selection;
if (selection == 0)
selection = OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
/* The contents of the reference is the address to our object */
keydata = *(void **)reference;
return export(keydata, selection, export_cb, export_cbarg);
}
return 0;
}
const OSSL_DISPATCH ossl_xdr_to_lms_decoder_functions[] = {
{ OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))lmsxdr2key_newctx },
{ OSSL_FUNC_DECODER_FREECTX, (void (*)(void))lmsxdr2key_freectx },
{ OSSL_FUNC_DECODER_DOES_SELECTION,
(void (*)(void))lmsxdr2key_does_selection },
{ OSSL_FUNC_DECODER_DECODE, (void (*)(void))lmsxdr2key_decode },
{ OSSL_FUNC_DECODER_EXPORT_OBJECT,
(void (*)(void))lmsxdr2key_export_object },
OSSL_DISPATCH_END
};

View 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[];
@ -383,6 +386,7 @@ extern const OSSL_DISPATCH ossl_mac_legacy_siphash_signature_functions[];
extern const OSSL_DISPATCH ossl_mac_legacy_poly1305_signature_functions[];
extern const OSSL_DISPATCH ossl_mac_legacy_cmac_signature_functions[];
extern const OSSL_DISPATCH ossl_sm2_signature_functions[];
extern const OSSL_DISPATCH ossl_lms_signature_functions[];
/* Asym Cipher */
extern const OSSL_DISPATCH ossl_rsa_asym_cipher_functions[];
@ -587,3 +591,5 @@ extern const OSSL_DISPATCH ossl_pem_to_der_decoder_functions[];
extern const OSSL_DISPATCH ossl_file_store_functions[];
extern const OSSL_DISPATCH ossl_winstore_store_functions[];
extern const OSSL_DISPATCH ossl_xdr_to_lms_decoder_functions[];

View file

@ -384,3 +384,5 @@
#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"

View 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 ../../libfips.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

View file

@ -0,0 +1,167 @@
/*
* 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 "internal/param_build_set.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_export_fn lms_export;
static OSSL_FUNC_keymgmt_import_types_fn lms_imexport_types;
static OSSL_FUNC_keymgmt_export_types_fn lms_imexport_types;
static OSSL_FUNC_keymgmt_load_fn lms_load;
#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_export(void *keydata, int selection, OSSL_CALLBACK *param_cb,
void *cbarg)
{
LMS_KEY *lmskey = keydata;
OSSL_PARAM_BLD *tmpl;
OSSL_PARAM *params = NULL;
int ret = 0;
if (!ossl_prov_is_running() || lmskey == NULL)
return 0;
if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) == 0)
return 0;
tmpl = OSSL_PARAM_BLD_new();
if (tmpl == NULL)
return 0;
if (!ossl_param_build_set_octet_string(tmpl, params,
OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
lmskey->pub.encoded,
lmskey->pub.encodedlen))
goto err;
params = OSSL_PARAM_BLD_to_param(tmpl);
if (params == NULL)
goto err;
ret = param_cb(params, cbarg);
OSSL_PARAM_free(params);
err:
OSSL_PARAM_BLD_free(tmpl);
return ret;
}
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);
}
static void *lms_load(const void *reference, size_t reference_sz)
{
LMS_KEY *key = NULL;
if (ossl_prov_is_running() && reference_sz == sizeof(key)) {
/* The contents of the reference is the address to our object */
key = *(LMS_KEY **)reference;
/* We grabbed, so we detach it */
*(LMS_KEY **)reference = NULL;
return key;
}
return NULL;
}
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_FUNC_KEYMGMT_EXPORT, (void (*)(void))lms_export },
{ OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void (*)(void))lms_imexport_types },
{ OSSL_FUNC_KEYMGMT_LOAD, (void (*)(void))lms_load },
OSSL_DISPATCH_END
};

View file

@ -6,6 +6,7 @@ $EC_GOAL=../../libdefault.a ../../libfips.a
$MAC_GOAL=../../libdefault.a ../../libfips.a
$RSA_GOAL=../../libdefault.a ../../libfips.a
$SM2_GOAL=../../libdefault.a
$LMS_GOAL=../../libdefault.a ../../libfips.a
IF[{- !$disabled{dsa} -}]
SOURCE[$DSA_GOAL]=dsa_sig.c
@ -31,3 +32,7 @@ DEPEND[eddsa_sig.o]=../../common/include/prov/der_ecx.h
DEPEND[sm2_sig.o]=../../common/include/prov/der_sm2.h
SOURCE[$MAC_GOAL]=mac_legacy_sig.c
IF[{- !$disabled{lms} -}]
SOURCE[$LMS_GOAL]=lms_signature.c
ENDIF

View file

@ -0,0 +1,138 @@
/*
* 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.h>
#include <openssl/core_dispatch.h>
#include <openssl/core_names.h>
#include <openssl/proverr.h>
#include <openssl/params.h>
#include <openssl/evp.h>
#include "prov/providercommon.h"
#include "prov/provider_ctx.h"
#include "prov/implementations.h"
#include "crypto/lms_sig.h"
static OSSL_FUNC_signature_newctx_fn lms_newctx;
static OSSL_FUNC_signature_freectx_fn lms_freectx;
static OSSL_FUNC_signature_verify_message_init_fn lms_verify_msg_init;
static OSSL_FUNC_signature_verify_fn lms_verify;
typedef struct {
OSSL_LIB_CTX *libctx;
char *propq;
LMS_KEY *key;
EVP_MD *md;
} PROV_LMS_CTX;
static void *lms_newctx(void *provctx, const char *propq)
{
PROV_LMS_CTX *ctx;
if (!ossl_prov_is_running())
return NULL;
ctx = OPENSSL_zalloc(sizeof(PROV_LMS_CTX));
if (ctx == NULL)
return NULL;
if (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL)
goto err;
ctx->libctx = PROV_LIBCTX_OF(provctx);
return ctx;
err:
OPENSSL_free(ctx);
return NULL;
}
static void lms_freectx(void *vctx)
{
PROV_LMS_CTX *ctx = (PROV_LMS_CTX *)vctx;
if (ctx == NULL)
return;
ossl_lms_key_free(ctx->key);
OPENSSL_free(ctx->propq);
EVP_MD_free(ctx->md);
OPENSSL_free(ctx);
}
static int setdigest(PROV_LMS_CTX *ctx, const char *digestname)
{
/*
* Assume that only one digest can be used by LMS.
* Set the digest to the one contained in the public key.
* If the optional digestname passed in by the user is different
* then return an error.
*/
LMS_KEY *key = ctx->key;
const char *pub_digestname = key->ots_params->digestname;
if (ctx->md != NULL) {
if (EVP_MD_is_a(ctx->md, pub_digestname))
goto end;
EVP_MD_free(ctx->md);
}
ctx->md = EVP_MD_fetch(ctx->libctx, pub_digestname, ctx->propq);
if (ctx->md == NULL)
return 0;
end:
return digestname == NULL || EVP_MD_is_a(ctx->md, digestname);
}
static int lms_verify_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[])
{
PROV_LMS_CTX *ctx = (PROV_LMS_CTX *)vctx;
LMS_KEY *key = (LMS_KEY *)vkey;
if (!ossl_prov_is_running() || ctx == NULL)
return 0;
if (key == NULL && ctx->key == NULL) {
ERR_raise(ERR_LIB_PROV, PROV_R_NO_KEY_SET);
return 0;
}
if (!ossl_lms_key_up_ref(key))
return 0;
ossl_lms_key_free(ctx->key);
ctx->key = key;
if (!setdigest(ctx, NULL))
return 0;
return 1;
}
static int lms_verify(void *vctx, const unsigned char *sigbuf, size_t sigbuf_len,
const unsigned char *msg, size_t msglen)
{
int ret = 0;
PROV_LMS_CTX *ctx = (PROV_LMS_CTX *)vctx;
LMS_KEY *pub = ctx->key;
LMS_SIG *sig = NULL;
/* A root public key is required to perform a verify operation */
if (pub == NULL)
return 0;
/* Decode the LMS signature data into a LMS_SIG object */
if (!ossl_lms_sig_decode(&sig, pub, sigbuf, sigbuf_len))
return 0;
ret = ossl_lms_sig_verify(sig, pub, ctx->md, msg, msglen);
ossl_lms_sig_free(sig);
return ret;
}
const OSSL_DISPATCH ossl_lms_signature_functions[] = {
{ OSSL_FUNC_SIGNATURE_NEWCTX, (void (*)(void))lms_newctx },
{ OSSL_FUNC_SIGNATURE_FREECTX, (void (*)(void))lms_freectx },
{ OSSL_FUNC_SIGNATURE_VERIFY_MESSAGE_INIT,
(void (*)(void))lms_verify_msg_init },
{ OSSL_FUNC_SIGNATURE_VERIFY, (void (*)(void))lms_verify },
OSSL_DISPATCH_END
};

View 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

38
test/lms.inc Normal file
View file

@ -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)
};

233
test/lms_common.inc Normal file
View file

@ -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,
};

538
test/lms_test.c Normal file
View file

@ -0,0 +1,538 @@
/*
* 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/decoder.h>
#include <openssl/evp.h>
#include "crypto/lms.h"
#include "internal/nelem.h"
#include "testutil.h"
#include "lms.inc"
typedef enum OPTION_choice {
OPT_ERR = -1,
OPT_EOF = 0,
OPT_CONFIG_FILE,
OPT_TEST_ENUM
} OPTION_CHOICE;
static OSSL_LIB_CTX *libctx = NULL;
static char *propq = NULL;
static OSSL_PROVIDER *nullprov = NULL;
static OSSL_PROVIDER *libprov = 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", propq))
&& 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_pubkey_decoder_fail_test(void)
{
int ret = 0;
EVP_PKEY *pkey = NULL;
OSSL_DECODER_CTX *dctx = NULL;
int selection = 0;
LMS_ACVP_TEST_DATA *td = &lms_testdata[0];
const unsigned char *pdata;
size_t pdatalen;
static const unsigned char pub_bad_LMSType[] = {
0x00, 0x00, 0x00, 0xAA
};
static const unsigned char pub_bad_OTSType[] = {
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xAA
};
if (!TEST_ptr(dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, NULL, NULL, "LMS",
selection,
libctx, NULL)))
return 0;
pdata = td->pub;
pdatalen = 3;
if (!TEST_false(OSSL_DECODER_from_data(dctx, &pdata, &pdatalen)))
goto end;
pdatalen = SIZE_MAX;
if (!TEST_false(OSSL_DECODER_from_data(dctx, &pdata, &pdatalen)))
goto end;
pdata = pub_bad_LMSType;
pdatalen = sizeof(pub_bad_LMSType);
if (!TEST_false(OSSL_DECODER_from_data(dctx, &pdata, &pdatalen)))
goto end;
pdata = pub_bad_OTSType;
pdatalen = sizeof(pub_bad_OTSType);
if (!TEST_false(OSSL_DECODER_from_data(dctx, &pdata, &pdatalen)))
goto end;
ret = 1;
end:
EVP_PKEY_free(pkey);
OSSL_DECODER_CTX_free(dctx);
return ret;
}
static EVP_PKEY *key_decode_from_bio(BIO *bio, const char *keytype)
{
EVP_PKEY *pkey = NULL;
OSSL_DECODER_CTX *dctx = NULL;
int selection = 0;
if (!TEST_ptr(dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, NULL, NULL,
keytype,
selection,
libctx, NULL)))
return NULL;
if (!TEST_true(OSSL_DECODER_from_bio(dctx, bio))) {
EVP_PKEY_free(pkey);
pkey = NULL;
}
OSSL_DECODER_CTX_free(dctx);
return pkey;
}
static EVP_PKEY *key_decode_from_data(const unsigned char *data, size_t datalen,
const char *keytype)
{
BIO *bio;
EVP_PKEY *key = NULL;
if (!TEST_ptr(bio = BIO_new_mem_buf(data, datalen)))
return NULL;
key = key_decode_from_bio(bio, keytype);
BIO_free(bio);
return key;
}
static int lms_key_decode_test(void)
{
int ret = 0;
LMS_ACVP_TEST_DATA *td1 = &lms_testdata[0];
EVP_PKEY *key = NULL;
ret = TEST_ptr(key = key_decode_from_data(td1->pub, td1->publen, NULL));
EVP_PKEY_free(key);
return ret;
}
static int lms_pubkey_decoder_test(void)
{
int ret = 0;
LMS_ACVP_TEST_DATA *td = &lms_testdata[0];
EVP_PKEY *pub = NULL;
OSSL_DECODER_CTX *dctx = NULL;
const unsigned char *data;
size_t data_len;
if (!TEST_ptr(dctx = OSSL_DECODER_CTX_new_for_pkey(&pub, "xdr", NULL,
"LMS",
OSSL_KEYMGMT_SELECT_PUBLIC_KEY,
libctx, NULL)))
goto err;
data = td->pub;
data_len = td->publen;
if (!TEST_true(OSSL_DECODER_from_data(dctx, &data, &data_len)))
goto err;
ret = 1;
err:
EVP_PKEY_free(pub);
OSSL_DECODER_CTX_free(dctx);
return ret;
}
static int lms_key_eq_test(void)
{
int ret = 0;
EVP_PKEY *key[4];
LMS_ACVP_TEST_DATA *td1 = &lms_testdata[0];
LMS_ACVP_TEST_DATA *td2 = &lms_testdata[1];
size_t i;
#ifndef OPENSSL_NO_EC
EVP_PKEY *eckey = NULL;
#endif
for (i = 0; i < OSSL_NELEM(key); i++)
key[i] = NULL;
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))
|| !TEST_ptr(key[3] = key_decode_from_data(td1->pub, td1->publen,
NULL)))
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)
&& TEST_int_eq(EVP_PKEY_eq(key[0], key[3]), 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[3]);
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;
}
static int lms_verify_test(int tst)
{
int ret = 0;
LMS_ACVP_TEST_DATA *td = &lms_testdata[tst];
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *pkey = NULL;
EVP_SIGNATURE *sig = NULL;
ret = TEST_ptr(pkey = lms_pubkey_from_data(td->pub, td->publen))
&& TEST_ptr(sig = EVP_SIGNATURE_fetch(libctx, "LMS", NULL))
&& TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, NULL))
&& TEST_int_eq(EVP_PKEY_verify_message_init(ctx, sig, NULL), 1)
&& TEST_int_eq(EVP_PKEY_verify(ctx, td->sig, td->siglen,
td->msg, td->msglen), 1);
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
EVP_SIGNATURE_free(sig);
return ret;
}
static int lms_digest_verify_fail_test(void)
{
int ret = 0;
LMS_ACVP_TEST_DATA *td = &lms_testdata[0];
EVP_PKEY *pub = NULL;
EVP_MD_CTX *vctx = NULL;
if (!TEST_ptr(pub = lms_pubkey_from_data(td->pub, td->publen)))
return 0;
if (!TEST_ptr(vctx = EVP_MD_CTX_new()))
goto err;
if (!TEST_int_eq(EVP_DigestVerifyInit_ex(vctx, NULL, NULL, libctx, NULL,
pub, NULL), 0))
goto err;
ret = 1;
err:
EVP_PKEY_free(pub);
EVP_MD_CTX_free(vctx);
return ret;
}
static int lms_verify_fail_test(void)
{
int ret = 0;
LMS_ACVP_TEST_DATA *td = &lms_testdata[0];
EVP_PKEY_CTX *ctx = NULL;
EVP_PKEY *pkey = NULL;
if (!TEST_ptr(pkey = lms_pubkey_from_data(td->pub, td->publen))
|| !TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, NULL)))
goto end;
if (!TEST_int_eq(EVP_PKEY_verify_init(ctx), -2))
goto end;
ret = 1;
end:
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return ret;
}
static int lms_verify_bad_sig_test(void)
{
int ret = 0, i = 0;
LMS_ACVP_TEST_DATA *td = &lms_testdata[1];
EVP_PKEY *pkey = NULL;
EVP_SIGNATURE *sig = NULL;
EVP_PKEY_CTX *ctx = NULL;
unsigned char *sig_data = NULL, corrupt_mask = 0x01;
/*
* Corrupt every 3rd byte to run less tests. The smallest element of an XDR
* encoding is 4 bytes, so this will corrupt every element.
* Memory sanitisation is slow, so a larger step size is used for this.
*/
#if defined(OSSL_SANITIZE_MEMORY)
const int step = (int)(td->siglen >> 1);
#else
const int step = 3;
#endif
/* Copy the signature so that we can corrupt it */
sig_data = OPENSSL_memdup(td->sig, td->siglen);
if (sig_data == NULL)
return 0;
if (!TEST_ptr(pkey = lms_pubkey_from_data(td->pub, td->publen))
|| !TEST_ptr(sig = EVP_SIGNATURE_fetch(libctx, "LMS", NULL))
|| !TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, NULL)))
goto end;
if (!TEST_int_eq(EVP_PKEY_verify_message_init(ctx, sig, NULL), 1))
goto end;
for (i = 0; i < (int)td->siglen; i += step) {
sig_data[i] ^= corrupt_mask; /* corrupt a byte */
if (i > 0)
sig_data[i - step] ^= corrupt_mask; /* Reset the previously corrupt byte */
if (!TEST_int_eq(EVP_PKEY_verify(ctx, sig_data, td->siglen,
td->msg, td->msglen), 0)) {
ret = -1;
goto end;
}
}
ret = 1;
end:
if (ret == -1)
TEST_note("Incorrectly passed when %dth byte of signature"
" was corrupted", i);
EVP_SIGNATURE_free(sig);
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
OPENSSL_free(sig_data);
return ret == 1;
}
/*
* Test that using the incorrect signature lengths (both shorter and longer)
* fail.
* NOTE: It does not get an out of bounds read due to the signature
* knowing how large it should be
*/
static int lms_verify_bad_sig_len_test(void)
{
int ret = 0;
LMS_ACVP_TEST_DATA *td = &lms_testdata[1];
EVP_PKEY *pkey = NULL;
EVP_SIGNATURE *sig = NULL;
EVP_PKEY_CTX *ctx = NULL;
size_t siglen = 0;
const int step = 3;
unsigned char sigdata[4096];
if (!TEST_ptr(pkey = lms_pubkey_from_data(td->pub, td->publen))
|| !TEST_ptr(sig = EVP_SIGNATURE_fetch(libctx, "LMS", NULL))
|| !TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, NULL)))
goto end;
if (!TEST_size_t_le(td->siglen + 16, sizeof(sigdata)))
goto end;
OPENSSL_cleanse(sigdata, sizeof(sigdata));
memcpy(sigdata, td->sig, td->siglen);
ret = 0;
for (siglen = 0; siglen < td->siglen + 16; siglen += step) {
if (siglen == td->siglen) /* ignore the size that should pass */
continue;
if (!TEST_int_eq(EVP_PKEY_verify_message_init(ctx, sig, NULL), 1))
goto end;
if (!TEST_int_eq(EVP_PKEY_verify(ctx, sigdata, siglen,
td->msg, td->msglen), 0)) {
ret = -1;
goto end;
}
}
ret = 1;
end:
if (ret == -1)
TEST_note("Incorrectly accepted signature key of length"
" %u (expected %u)", (unsigned)siglen, (unsigned)td->siglen);
EVP_SIGNATURE_free(sig);
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
return ret == 1;
}
static int lms_verify_bad_pub_sig_test(void)
{
LMS_ACVP_TEST_DATA *td = &lms_testdata[1];
int ret = 0, i = 0;
EVP_PKEY *pkey = NULL;
EVP_SIGNATURE *sig = NULL;
EVP_PKEY_CTX *ctx = NULL;
unsigned char *pub = NULL;
const int step = 1;
/* Copy the public key data so that we can corrupt it */
if (!TEST_ptr(pub = OPENSSL_memdup(td->pub, td->publen)))
return 0;
if (!TEST_ptr(sig = EVP_SIGNATURE_fetch(libctx, "LMS", NULL)))
goto end;
for (i = 0; i < (int)td->publen; i += step) {
if (i > 0) {
EVP_PKEY_free(pkey);
EVP_PKEY_CTX_free(ctx);
pkey = NULL;
ctx = NULL;
pub[i - step] ^= 1;
}
pub[3] ^= 1;
/* Corrupting the public key may cause the key load to fail */
pkey = lms_pubkey_from_data(pub, td->publen);
if (pkey == NULL)
continue;
if (!TEST_ptr(ctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, NULL)))
continue;
if (!TEST_int_eq(EVP_PKEY_verify_message_init(ctx, sig, NULL), 1))
continue;
/* We expect the verify to fail */
if (!TEST_int_eq(EVP_PKEY_verify(ctx, td->sig, td->siglen,
td->msg, td->msglen), 0)) {
ret = -1;
goto end;
}
}
ret = 1;
end:
if (ret == -1)
TEST_note("Incorrectly passed when byte %d of the public key"
" was corrupted", i);
EVP_SIGNATURE_free(sig);
EVP_PKEY_CTX_free(ctx);
EVP_PKEY_free(pkey);
OPENSSL_free(pub);
return ret == 1;
}
const OPTIONS *test_get_options(void)
{
static const OPTIONS options[] = {
OPT_TEST_OPTIONS_DEFAULT_USAGE,
{ "config", OPT_CONFIG_FILE, '<',
"The configuration file to use for the libctx" },
{ NULL }
};
return options;
}
int setup_tests(void)
{
OPTION_CHOICE o;
char *config_file = NULL;
/* Swap the libctx to test non-default context only */
propq = "provider=default";
while ((o = opt_next()) != OPT_EOF) {
switch (o) {
case OPT_CONFIG_FILE:
config_file = opt_arg();
propq = "";
break;
case OPT_TEST_CASES:
break;
default:
case OPT_ERR:
return 0;
}
}
if (!test_get_libctx(&libctx, &nullprov, config_file, &libprov, NULL))
return 0;
ADD_TEST(lms_bad_pub_len_test);
ADD_TEST(lms_key_validate_test);
ADD_TEST(lms_key_eq_test);
ADD_TEST(lms_key_decode_test);
ADD_TEST(lms_pubkey_decoder_test);
ADD_TEST(lms_pubkey_decoder_fail_test);
ADD_ALL_TESTS(lms_verify_test, OSSL_NELEM(lms_testdata));
ADD_TEST(lms_verify_fail_test);
ADD_TEST(lms_digest_verify_fail_test);
ADD_TEST(lms_verify_bad_sig_test);
ADD_TEST(lms_verify_bad_sig_len_test);
ADD_TEST(lms_verify_bad_pub_sig_test);
return 1;
}
void cleanup_tests(void)
{
OSSL_PROVIDER_unload(nullprov);
OSSL_PROVIDER_unload(libprov);
OSSL_LIB_CTX_free(libctx);
}

View file

@ -0,0 +1,38 @@
#! /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_file srctop_dir bldtop_dir);
use OpenSSL::Test::Utils;
BEGIN {
setup("test_lms");
}
my $provconf = srctop_file("test", "fips-and-base.cnf");
my $no_fips = disabled('fips') || ($ENV{NO_FIPS} // 0);
run(test(["fips_version_test", "-config", $provconf, ">=3.5.0"]),
capture => 1, statusvar => \my $exit);
plan skip_all => "FIPS provider does not support LMS" if !$exit;
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 + + ($no_fips ? 0 : 1);
ok(run(test(["lms_test"])), "running lms_test");
unless ($no_fips) {
ok(run(test(["lms_test", "-config", $provconf])),
"running lms_test with fips");
}