LMS code review fixups

Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/27885)
This commit is contained in:
slontis 2025-07-07 12:11:52 +10:00 committed by Pauli
parent e6c8110483
commit 6b5fd48ee4
21 changed files with 74 additions and 127 deletions

View File

@ -44,7 +44,7 @@ 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)
for (p = lm_ots_params; p->digestname != NULL; ++p)
if (p->lm_ots_type == ots_type)
return p;
return NULL;
@ -61,6 +61,6 @@ uint16_t ossl_lm_ots_params_checksum(const LM_OTS_PARAMS *params,
uint16_t end = (1 << params->w) - 1;
for (i = 0; i < bytes; ++i)
sum += end - coef(S, i, params->w);
sum += end - lms_ots_coef(S, i, params->w);
return (sum << params->ls);
}

View File

@ -8,6 +8,7 @@
*/
#include <openssl/evp.h>
#include <openssl/byteorder.h>
#include "crypto/lms_sig.h"
#include "crypto/lms_util.h"
@ -39,38 +40,33 @@ int ossl_lm_ots_compute_pubkey(EVP_MD_CTX *ctx, EVP_MD_CTX *ctxIq,
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);
OPENSSL_store_u32_be(qbuf, q);
OPENSSL_store_u16_be(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)
return (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;
&& 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));
}
/**
* @brief simple function to increment a 16 bit counter by 1.
* @brief simple function to increment a big-endian 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;
++tag[0];
}
/*
@ -83,7 +79,7 @@ static ossl_inline void INC16(unsigned char *tag)
* 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 sig An object 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.
*/
@ -104,17 +100,15 @@ static int lm_ots_compute_pubkey_final(EVP_MD_CTX *ctx, EVP_MD_CTX *ctxIq,
int a;
unsigned char *y;
if (!EVP_DigestFinal_ex(ctx, Q, NULL))
goto err;
if (!EVP_DigestFinal_ex(ctx, Q, NULL)
|| (ctxKc = EVP_MD_CTX_create()) == NULL)
return 0;
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);
OPENSSL_store_u16_be(Qsum, sum);
OPENSSL_store_u16_be(d_pblc, OSSL_LMS_D_PBLC);
if (!(EVP_MD_CTX_copy_ex(ctxKc, ctxIq))
|| !EVP_DigestUpdate(ctxKc, d_pblc, sizeof(d_pblc)))
@ -130,7 +124,7 @@ static int lm_ots_compute_pubkey_final(EVP_MD_CTX *ctx, EVP_MD_CTX *ctxIq,
* the inner loop |end| is in the range 0...(2^w)-1
*/
for (i = 0; i < p; ++i) {
a = coef(Q, i, w);
a = lms_ots_coef(Q, i, w);
memcpy(z, y, n);
y += n;
for (j = a; j < end; ++j) {

View File

@ -21,13 +21,8 @@ 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;
}
if (ret != NULL)
ret->libctx = libctx;
}
return ret;
}
@ -37,39 +32,15 @@ LMS_KEY *ossl_lms_key_new(OSSL_LIB_CTX *libctx)
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?
*

View File

@ -47,7 +47,7 @@ const LMS_PARAMS *ossl_lms_params_get(uint32_t lms_type)
{
const LMS_PARAMS *p;
for (p = lms_params; p->lms_type != 0; ++p)
for (p = lms_params; p->digestname != NULL; ++p)
if (p->lms_type == lms_type)
return p;
return NULL;

View File

@ -26,7 +26,7 @@ size_t ossl_lms_pubkey_length(const unsigned char *data, size_t datalen)
const LMS_PARAMS *params;
if (!PACKET_buf_init(&pkt, data, datalen)
|| !PACKET_get_4_len(&pkt, &lms_type)
|| !PACKET_get_net_4_len_u32(&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;
@ -56,12 +56,12 @@ int lms_pubkey_from_pkt(LMS_KEY *lmskey, const unsigned char *pubkeydata,
if (!PACKET_buf_init(&pkt, pubkeydata, publen))
goto err;
key->encoded = (unsigned char *)pkt.curr;
if (!PACKET_get_4_len(&pkt, &lms_type))
key->encoded = (unsigned char *)PACKET_data(&pkt);
if (!PACKET_get_net_4_len_u32(&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))
|| !PACKET_get_net_4_len_u32(&pkt, &ots_type))
goto err;
lmskey->ots_params = ossl_lm_ots_params_get(ots_type);
if (lmskey->ots_params == NULL)
@ -74,7 +74,7 @@ int lms_pubkey_from_pkt(LMS_KEY *lmskey, const unsigned char *pubkeydata,
|| !PACKET_get_bytes(&pkt, (const unsigned char **)&key->K,
lmskey->lms_params->n))
goto err;
key->encodedlen = pkt.curr - key->encoded;
key->encodedlen = (unsigned char *)PACKET_data(&pkt) - key->encoded;
return PACKET_remaining(&pkt) == 0;
err:
return 0;

View File

@ -20,9 +20,9 @@
*
* @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
* @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
* @returns The created LMS_SIG object if 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,
*/
@ -38,8 +38,8 @@ LMS_SIG *ossl_lms_sig_from_pkt(PACKET *pkt, const LMS_KEY *pub)
if (lsig == NULL)
return NULL;
if (!PACKET_get_4_len(pkt, &lsig->q) /* q = Leaf Index */
|| !PACKET_get_4_len(pkt, &sig_ots_type)
if (!PACKET_get_net_4_len_u32(pkt, &lsig->q) /* q = Leaf Index */
|| !PACKET_get_net_4_len_u32(pkt, &sig_ots_type)
|| pub_ots_params->lm_ots_type != sig_ots_type)
goto err;
sig_params = pub_ots_params;
@ -50,7 +50,7 @@ LMS_SIG *ossl_lms_sig_from_pkt(PACKET *pkt, const LMS_KEY *pub)
sig_params->n)
|| !PACKET_get_bytes(pkt, (const unsigned char **)&lsig->sig.y,
sig_params->p * sig_params->n)
|| !PACKET_get_4_len(pkt, &sig_lms_type)
|| !PACKET_get_net_4_len_u32(pkt, &sig_lms_type)
|| (lparams->lms_type != sig_lms_type)
|| HASH_NOT_MATCHED(lparams, sig_params)
|| lsig->q >= (uint32_t)(1 << lparams->h)

View File

@ -7,6 +7,7 @@
* https://www.openssl.org/source/license.html
*/
#include <openssl/byteorder.h>
#include "crypto/lms_sig.h"
#include "crypto/lms_util.h"
#include "internal/common.h"
@ -46,7 +47,7 @@ int lms_sig_compute_tc_from_path(const unsigned char *paths, uint32_t n,
unsigned char d_intr[sizeof(uint16_t)];
const unsigned char *path = paths;
U16STR(d_intr, OSSL_LMS_D_INTR);
OPENSSL_store_u16_be(d_intr, OSSL_LMS_D_INTR);
/*
* Calculate the public key Tc using the path
@ -60,7 +61,7 @@ int lms_sig_compute_tc_from_path(const unsigned char *paths, uint32_t n,
int odd = node_num & 1;
node_num = node_num >> 1; /* get the parent node_num */
U32STR(qbuf, node_num);
OPENSSL_store_u32_be(qbuf, node_num);
/*
* Calculate Tc as either
@ -125,7 +126,7 @@ int ossl_lms_sig_verify(const LMS_SIG *lms_sig, const LMS_KEY *pub,
if (ctx == NULL || ctxIq == NULL)
goto err;
if (!evp_md_ctx_init(ctxIq, md, lms_sig->params))
if (!lms_evp_md_ctx_init(ctxIq, md, lms_sig->params))
goto err;
/*
* Algorithm 6a: Step 3.
@ -145,8 +146,8 @@ int ossl_lms_sig_verify(const LMS_SIG *lms_sig, const LMS_KEY *pub,
return 0;
node_num = (1 << lms_params->h) + lms_sig->q;
U32STR(qbuf, node_num);
U16STR(d_leaf, OSSL_LMS_D_LEAF);
OPENSSL_store_u32_be(qbuf, node_num);
OPENSSL_store_u16_be(d_leaf, OSSL_LMS_D_LEAF);
ctxI = ctxIq;
/*
* Tc = H(I || u32str(node_num) || u16str(D_LEAF) || Kc)

View File

@ -10,7 +10,7 @@ EVP_PKEY-LMS, EVP_KEYMGMT-LMS, LMS
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.
FIPS software modules.
=head2 Common LMS parameters
@ -39,7 +39,7 @@ Leighton-Micali Hash-Based Signatures
Recommendation for Stateful Hash-Based Signature Schemes
=item CSNA 2.0
=item CNSA 2.0
Commercial National Security Algorithm Suite

View File

@ -10,9 +10,9 @@ EVP_SIGNATURE-LMS
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.
[SP 800-208](https://csrc.nist.gov/pubs/sp/800/208/final) requirement for
FIPS 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,
@ -24,6 +24,10 @@ that specify the digest name are not necessary.
LMS support is disabled by default at compile-time.
To enable, specify the B<enable-lms> build configuration option.
LMS should only be used for older deployments.
New deployments should use either L<EVP_SIGNATURE-ML-DSA(7)>
or <L/EVP_SIGNATURE-SLH-DSA(7)>.
=head1 EXAMPLES
Error checking has been omitted from the following examples

View File

@ -67,12 +67,8 @@ 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)>
KECCAK-KMAC is only used internally as a sub algorithm of KMAC.
=back
=head2 Symmetric Ciphers

View File

@ -18,7 +18,6 @@
# ifndef OPENSSL_NO_LMS
# include "types.h"
# include <openssl/params.h>
# include "internal/refcount.h"
/*
* Numeric identifiers associated with Leighton-Micali Signatures (LMS)
@ -135,20 +134,18 @@ typedef struct lms_pub_key_st {
unsigned char *K;
} LMS_PUB_KEY;
struct lms_key_st {
typedef 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;
};
} LMS_KEY;
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);

View File

@ -23,24 +23,12 @@
#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)
/*
* 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 lms_ots_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);
@ -50,8 +38,8 @@ uint8_t coef(const unsigned char *S, uint16_t i, uint8_t w)
}
static ossl_unused ossl_inline
int evp_md_ctx_init(EVP_MD_CTX *ctx, const EVP_MD *md,
const LMS_PARAMS *lms_params)
int lms_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;

View File

@ -31,8 +31,4 @@ typedef struct ecx_key_st ECX_KEY;
typedef struct prov_skey_st PROV_SKEY;
# ifndef OPENSSL_NO_LMS
typedef struct lms_key_st LMS_KEY;
# endif
#endif

View File

@ -103,7 +103,7 @@ static const OSSL_ALGORITHM deflt_digests[] = {
{ PROV_NAMES_SHA1, "provider=default", ossl_sha1_functions },
{ PROV_NAMES_SHA2_224, "provider=default", ossl_sha224_functions },
{ PROV_NAMES_SHA2_256, "provider=default", ossl_sha256_functions },
{ PROV_NAMES_SHA2_256_192, "provider=default", ossl_sha256_192_functions },
{ PROV_NAMES_SHA2_256_192, "provider=default", ossl_sha256_192_internal_functions },
{ PROV_NAMES_SHA2_384, "provider=default", ossl_sha384_functions },
{ PROV_NAMES_SHA2_512, "provider=default", ossl_sha512_functions },
{ PROV_NAMES_SHA2_512_224, "provider=default", ossl_sha512_224_functions },

View File

@ -295,7 +295,7 @@ 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 },
ossl_sha256_192_internal_functions },
/*
* KECCAK-KMAC-128 and KECCAK-KMAC-256 as hashes are mostly useful for
* KMAC128 and KMAC256.

View File

@ -71,8 +71,8 @@ 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)
/* ossl_sha256_192_functions */
IMPLEMENT_digest_functions(sha256_192, SHA256_CTX,
/* ossl_sha256_192_internal_functions */
IMPLEMENT_digest_functions(sha256_192_internal, SHA256_CTX,
SHA256_CBLOCK, SHA256_192_DIGEST_LENGTH, SHA2_FLAGS,
ossl_sha256_192_init, SHA256_Update, SHA256_Final)
/* ossl_sha384_functions */

View File

@ -63,24 +63,33 @@ static int lmsxdr2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
LMS_KEY *key = NULL;
unsigned char buf[LMS_MAX_PUBKEY];
size_t length;
int ok = 0;
int ok = 0, inlen, readlen;
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)
ERR_set_mark();
readlen = BIO_read(in, buf, 4);
ERR_pop_to_mark();
if (readlen != 4)
goto next;
length = ossl_lms_pubkey_length(buf, 4);
if (length == 0)
if (length <= 4)
goto next;
if (BIO_read(in, buf + 4, length - 4) != (int)(length - 4))
inlen = (int)length - 4;
ERR_set_mark();
readlen = BIO_read(in, buf + 4, inlen);
ERR_pop_to_mark();
if (readlen != inlen)
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)) {
@ -89,7 +98,6 @@ static int lmsxdr2key_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
}
}
next:
ERR_clear_last_mark();
/*
* Indicated that we successfully decoded something, or not at all.
* Ending up "empty handed" is not an error.

View File

@ -14,7 +14,7 @@
extern const OSSL_DISPATCH ossl_sha1_functions[];
extern const OSSL_DISPATCH ossl_sha224_functions[];
extern const OSSL_DISPATCH ossl_sha256_functions[];
extern const OSSL_DISPATCH ossl_sha256_192_functions[];
extern const OSSL_DISPATCH ossl_sha256_192_internal_functions[];
extern const OSSL_DISPATCH ossl_sha384_functions[];
extern const OSSL_DISPATCH ossl_sha512_functions[];
extern const OSSL_DISPATCH ossl_sha512_224_functions[];

View File

@ -60,8 +60,6 @@ static int lms_match(const void *keydata1, const void *keydata2, int selection)
if (!ossl_prov_is_running())
return 0;
if (key1 == NULL || key2 == NULL)
return 0;
return ossl_lms_key_equal(key1, key2, selection);
}

View File

@ -13,6 +13,7 @@
#include <openssl/proverr.h>
#include <openssl/params.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include "prov/providercommon.h"
#include "prov/provider_ctx.h"
#include "prov/implementations.h"
@ -56,7 +57,6 @@ static void lms_freectx(void *vctx)
if (ctx == NULL)
return;
ossl_lms_key_free(ctx->key);
OPENSSL_free(ctx->propq);
EVP_MD_free(ctx->md);
OPENSSL_free(ctx);
@ -97,14 +97,8 @@ static int lms_verify_msg_init(void *vctx, void *vkey, const OSSL_PARAM params[]
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;
return setdigest(ctx, NULL);
}
static int lms_verify(void *vctx, const unsigned char *sigbuf, size_t sigbuf_len,

View File

@ -151,7 +151,7 @@ static EVP_PKEY *key_decode_from_data(const unsigned char *data, size_t datalen,
BIO *bio;
EVP_PKEY *key = NULL;
if (!TEST_ptr(bio = BIO_new_mem_buf(data, datalen)))
if (!TEST_ptr(bio = BIO_new_mem_buf(data, (int)datalen)))
return NULL;
key = key_decode_from_bio(bio, keytype);
BIO_free(bio);