]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add ML_DSA encoders
authorslontis <shane.lontis@oracle.com>
Fri, 10 Jan 2025 01:41:12 +0000 (12:41 +1100)
committerTomas Mraz <tomas@openssl.org>
Fri, 14 Feb 2025 09:46:03 +0000 (10:46 +0100)
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
Reviewed-by: Paul Dale <ppzgs1@gmail.com>
(Merged from https://github.com/openssl/openssl/pull/26451)

15 files changed:
crypto/err/openssl.txt
crypto/ml_dsa/ml_dsa_key.c
crypto/ml_dsa/ml_dsa_local.h
include/crypto/ml_dsa.h
include/openssl/evp.h
include/openssl/proverr.h
providers/common/include/prov/proverr.h
providers/common/provider_err.c
providers/decoders.inc
providers/encoders.inc
providers/implementations/encode_decode/decode_der2key.c
providers/implementations/encode_decode/encode_key2any.c
providers/implementations/encode_decode/encode_key2text.c
providers/implementations/include/prov/implementations.h
test/endecode_test.c

index decf2d6f2ec42dbded5f8d45dde1a08d84b3c143..3b8183da4f5e8c0549860e50194ecb8f5cfd13d0 100644 (file)
@@ -1172,6 +1172,8 @@ PROV_R_UNABLE_TO_INITIALISE_CIPHERS:208:unable to initialise ciphers
 PROV_R_UNABLE_TO_LOAD_SHA256:147:unable to load sha256
 PROV_R_UNABLE_TO_LOCK_PARENT:201:unable to lock parent
 PROV_R_UNABLE_TO_RESEED:204:unable to reseed
+PROV_R_UNEXPECTED_KEY_OID:245:unexpected key oid
+PROV_R_UNEXPECTED_KEY_PARAMETERS:246:unexpected key parameters
 PROV_R_UNSUPPORTED_CEK_ALG:145:unsupported cek alg
 PROV_R_UNSUPPORTED_KEY_SIZE:153:unsupported key size
 PROV_R_UNSUPPORTED_MAC_TYPE:137:unsupported mac type
index ff9728f964d207eb90b3e2dfbbc027c350c5e43a..00f1dc4a3678f10d13698dc7be49ee864a6345b7 100644 (file)
@@ -205,7 +205,7 @@ err:
     return 1;
 }
 
-static int ml_dsa_key_public_from_private(ML_DSA_KEY *key)
+int ossl_ml_dsa_key_public_from_private(ML_DSA_KEY *key)
 {
     int ret = 0;
     VECTOR t0;
@@ -263,7 +263,7 @@ int ossl_ml_dsa_key_fromdata(ML_DSA_KEY *key, const OSSL_PARAM params[],
                     || !ossl_ml_dsa_sk_decode(key, priv_data, priv_data_len))
                 return 0;
             /* Always generate the public key from the private key */
-            if (!ml_dsa_key_public_from_private(key))
+            if (!ossl_ml_dsa_key_public_from_private(key))
                 return 0;
             /* Error if the supplied public key does not match the generated key */
             if (pub != NULL
index a93b6b64fc53b1576a68bdbc1de82bb3290add82..9bc56f562bd4c376303cb367a8ddf40c1a122e0c 100644 (file)
@@ -93,9 +93,7 @@ uint32_t ossl_ml_dsa_key_compress_use_hint(uint32_t hint, uint32_t r,
                                            uint32_t gamma2);
 
 int ossl_ml_dsa_pk_encode(ML_DSA_KEY *key);
-int ossl_ml_dsa_pk_decode(ML_DSA_KEY *key, const uint8_t *in, size_t in_len);
 int ossl_ml_dsa_sk_encode(ML_DSA_KEY *key);
-int ossl_ml_dsa_sk_decode(ML_DSA_KEY *key, const uint8_t *in, size_t in_len);
 
 int ossl_ml_dsa_sig_encode(const ML_DSA_SIG *sig, const ML_DSA_PARAMS *params,
                            uint8_t *out);
index 0434a2baf80a1898235987259f13c72b3239708b..2008da796833ab38ffeb41be5336b7bdefc779b1 100644 (file)
@@ -41,9 +41,12 @@ __owur size_t ossl_ml_dsa_key_get_priv_len(const ML_DSA_KEY *key);
 __owur size_t ossl_ml_dsa_key_get_sig_len(const ML_DSA_KEY *key);
 __owur const char *ossl_ml_dsa_key_get_name(const ML_DSA_KEY *key);
 __owur int ossl_ml_dsa_key_matches(const ML_DSA_KEY *key, const char *alg);
-__owur int ossl_ml_dsa_key_to_text(BIO *out, const ML_DSA_KEY *key, int selection);
 void ossl_ml_dsa_key_set0_libctx(ML_DSA_KEY *key, OSSL_LIB_CTX *lib_ctx);
 
+__owur int ossl_ml_dsa_key_public_from_private(ML_DSA_KEY *key);
+__owur int ossl_ml_dsa_pk_decode(ML_DSA_KEY *key, const uint8_t *in, size_t in_len);
+__owur int ossl_ml_dsa_sk_decode(ML_DSA_KEY *key, const uint8_t *in, size_t in_len);
+
 __owur int ossl_ml_dsa_sign(const ML_DSA_KEY *priv,
                             const uint8_t *msg, size_t msg_len,
                             const uint8_t *context, size_t context_len,
index 01caaadcde0527ba05a4e3ba4940c46b0c1e67c0..00570edc17e81e82381da74fcc155c0de599224c 100644 (file)
 # define EVP_PKEY_ED25519 NID_ED25519
 # define EVP_PKEY_X448 NID_X448
 # define EVP_PKEY_ED448 NID_ED448
+# define EVP_PKEY_ML_DSA_44 NID_ML_DSA_44
+# define EVP_PKEY_ML_DSA_65 NID_ML_DSA_65
+# define EVP_PKEY_ML_DSA_87 NID_ML_DSA_87
+
 /* Special indicator that the object is uniquely provider side */
 # define EVP_PKEY_KEYMGMT -1
 
index d10b653152ec70adecb495f5c1f5eb539783e4b6..091549ddd8c3161a8789938389795c06c20931b3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2025 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
 # define PROV_R_UNABLE_TO_LOAD_SHA256                     147
 # define PROV_R_UNABLE_TO_LOCK_PARENT                     201
 # define PROV_R_UNABLE_TO_RESEED                          204
+# define PROV_R_UNEXPECTED_KEY_OID                        245
+# define PROV_R_UNEXPECTED_KEY_PARAMETERS                 246
 # define PROV_R_UNSUPPORTED_CEK_ALG                       145
 # define PROV_R_UNSUPPORTED_KEY_SIZE                      153
 # define PROV_R_UNSUPPORTED_MAC_TYPE                      137
index 34247ed2f7e0119d1589b89dd16aaad2324f9177..87a84e9c21f8b64a9e5f11b2178c882f55810d05 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 2020-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 2020-2025 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
index df4bab0966d8c4f07f95ce0aa30dc4edf5453eac..03375d6bbd23fcc758e409b82658948906da8e71 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Generated by util/mkerr.pl DO NOT EDIT
- * Copyright 1995-2024 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright 1995-2025 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
@@ -215,6 +215,10 @@ static const ERR_STRING_DATA PROV_str_reasons[] = {
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_UNABLE_TO_LOCK_PARENT),
      "unable to lock parent"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_UNABLE_TO_RESEED), "unable to reseed"},
+    {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_UNEXPECTED_KEY_OID),
+     "unexpected key oid"},
+    {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_UNEXPECTED_KEY_PARAMETERS),
+     "unexpected key parameters"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_UNSUPPORTED_CEK_ALG),
      "unsupported cek alg"},
     {ERR_PACK(ERR_LIB_PROV, 0, PROV_R_UNSUPPORTED_KEY_SIZE),
index 0191aa771ea6cec63bdd8cc23c1cd2120a522ee5..9effdd083592029f9b6646775b0aa704a170f22b 100644 (file)
@@ -82,6 +82,14 @@ DECODER_w_structure("RSA-PSS", der, PrivateKeyInfo, rsapss, yes),
 DECODER_w_structure("RSA-PSS", der, SubjectPublicKeyInfo, rsapss, yes),
 DECODER("RSA", msblob, rsa, yes),
 DECODER("RSA", pvk, rsa, yes),
+#ifndef OPENSSL_NO_ML_DSA
+DECODER_w_structure("ML-DSA-44", der, PrivateKeyInfo, ml_dsa_44, no),
+DECODER_w_structure("ML-DSA-65", der, PrivateKeyInfo, ml_dsa_65, no),
+DECODER_w_structure("ML-DSA-87", der, PrivateKeyInfo, ml_dsa_87, no),
+DECODER_w_structure("ML-DSA-44", der, SubjectPublicKeyInfo, ml_dsa_44, no),
+DECODER_w_structure("ML-DSA-65", der, SubjectPublicKeyInfo, ml_dsa_65, no),
+DECODER_w_structure("ML-DSA-87", der, SubjectPublicKeyInfo, ml_dsa_87, no),
+#endif /* OPENSSL_NO_ML_DSA */
 
 /*
  * A decoder that takes a SubjectPublicKeyInfo and figures out the types of key
index cd0d1137bb697858fd943f2d98098fb581236107..10a838c0a7940bd953ffda53ee484c11b8db2387 100644 (file)
@@ -68,6 +68,12 @@ ENCODER_TEXT("SM2", sm2, no),
 # endif
 #endif
 
+# ifndef OPENSSL_NO_ML_DSA
+ENCODER_TEXT("ML-DSA-44", ml_dsa_44, no),
+ENCODER_TEXT("ML-DSA-65", ml_dsa_65, no),
+ENCODER_TEXT("ML-DSA-87", ml_dsa_87, no),
+# endif
+
 /*
  * Entries for key type specific output formats.  The structure name on these
  * is the same as the key type name.  This allows us to say something like:
@@ -223,6 +229,29 @@ ENCODER_w_structure("SM2", sm2, no, pem, SubjectPublicKeyInfo),
 # endif
 #endif
 
+# ifndef OPENSSL_NO_ML_DSA
+ENCODER_w_structure("ML-DSA-44", ml_dsa_44, no, der, EncryptedPrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-44", ml_dsa_44, no, pem, EncryptedPrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-44", ml_dsa_44, no, der, PrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-44", ml_dsa_44, no, pem, PrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-44", ml_dsa_44, no, der, SubjectPublicKeyInfo),
+ENCODER_w_structure("ML-DSA-44", ml_dsa_44, no, pem, SubjectPublicKeyInfo),
+
+ENCODER_w_structure("ML-DSA-65", ml_dsa_65, no, der, EncryptedPrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-65", ml_dsa_65, no, pem, EncryptedPrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-65", ml_dsa_65, no, der, PrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-65", ml_dsa_65, no, pem, PrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-65", ml_dsa_65, no, der, SubjectPublicKeyInfo),
+ENCODER_w_structure("ML-DSA-65", ml_dsa_65, no, pem, SubjectPublicKeyInfo),
+
+ENCODER_w_structure("ML-DSA-87", ml_dsa_87, no, der, EncryptedPrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-87", ml_dsa_87, no, pem, EncryptedPrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-87", ml_dsa_87, no, der, PrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-87", ml_dsa_87, no, pem, PrivateKeyInfo),
+ENCODER_w_structure("ML-DSA-87", ml_dsa_87, no, der, SubjectPublicKeyInfo),
+ENCODER_w_structure("ML-DSA-87", ml_dsa_87, no, pem, SubjectPublicKeyInfo),
+# endif /* OPENSSL_NO_ML_DSA */
+
 /*
  * Entries for key type specific output formats.  These are exactly the
  * same as the type specific above, except that they use the key type
index e33ae49b51f53d25ad396bc4ec962361270bb99b..e52fa5c9304a78195b3b1f90a69aedcb8e70a86c 100644 (file)
@@ -23,6 +23,7 @@
 #include <openssl/pkcs12.h>
 #include <openssl/x509.h>
 #include <openssl/proverr.h>
+#include <openssl/asn1t.h>
 #include "internal/cryptlib.h"   /* ossl_assert() */
 #include "internal/asn1.h"
 #include "crypto/dh.h"
@@ -31,6 +32,7 @@
 #include "crypto/evp.h"
 #include "crypto/ecx.h"
 #include "crypto/rsa.h"
+#include "crypto/ml_dsa.h"
 #include "crypto/x509.h"
 #include "openssl/obj_mac.h"
 #include "prov/bio.h"
 #include "endecoder_local.h"
 #include "internal/nelem.h"
 
+#ifndef OPENSSL_NO_ML_DSA
+typedef struct {
+    ASN1_OBJECT *oid;
+} BARE_ALGOR;
+
+typedef struct {
+    BARE_ALGOR algor;
+    ASN1_BIT_STRING *pubkey;
+} BARE_PUBKEY;
+
+ASN1_SEQUENCE(BARE_ALGOR) = {
+    ASN1_SIMPLE(BARE_ALGOR, oid, ASN1_OBJECT),
+} static_ASN1_SEQUENCE_END(BARE_ALGOR)
+
+ASN1_SEQUENCE(BARE_PUBKEY) = {
+    ASN1_EMBED(BARE_PUBKEY, algor, BARE_ALGOR),
+    ASN1_SIMPLE(BARE_PUBKEY, pubkey, ASN1_BIT_STRING)
+} static_ASN1_SEQUENCE_END(BARE_PUBKEY)
+#endif /* OPENSSL_NO_ML_DSA */
+
 struct der2key_ctx_st;           /* Forward declaration */
 typedef int check_key_fn(void *, struct der2key_ctx_st *ctx);
 typedef void adjust_key_fn(void *, struct der2key_ctx_st *ctx);
@@ -614,6 +636,169 @@ static void rsa_adjust(void *key, struct der2key_ctx_st *ctx)
 
 /* ---------------------------------------------------------------------- */
 
+#ifndef OPENSSL_NO_ML_DSA
+static void *
+ml_dsa_d2i_PKCS8(const uint8_t **der, long der_len, struct der2key_ctx_st *ctx)
+{
+    ML_DSA_KEY *key = NULL, *ret = NULL;
+    OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
+    PKCS8_PRIV_KEY_INFO *p8inf = NULL;
+    const unsigned char *p;
+    const X509_ALGOR *alg = NULL;
+    int plen, ptype;
+
+    /*
+     * The private key format in PKCS8 is the 64-bytes (d, z) seed pair.
+     * Algorithm parameters must be absent.
+     */
+    if ((p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, der, der_len)) == NULL
+        || !PKCS8_pkey_get0(NULL, &p, &plen, &alg, p8inf))
+        goto end;
+
+    if ((X509_ALGOR_get0(NULL, &ptype, NULL, alg), ptype != V_ASN1_UNDEF)) {
+        ERR_raise_data(ERR_LIB_PROV, PROV_R_UNEXPECTED_KEY_PARAMETERS,
+                       "unexpected parameters with a PKCS#8 %s private key",
+                       ctx->desc->keytype_name);
+        goto end;
+    }
+    if (OBJ_obj2nid(alg->algorithm) != ctx->desc->evp_type) {
+        ERR_raise_data(ERR_LIB_PROV, PROV_R_UNEXPECTED_KEY_OID,
+                       "unexpected algorithm OID for a PKCS#8 %s private key",
+                       ctx->desc->keytype_name);
+        goto end;
+    }
+    if ((key = ossl_ml_dsa_key_new(libctx, ctx->propq,
+                                   ctx->desc->keytype_name)) == NULL)
+        goto end;
+
+    if (!ossl_ml_dsa_sk_decode(key, p, plen)
+            || !ossl_ml_dsa_key_public_from_private(key))
+        goto end;
+    ret = key;
+ end:
+    PKCS8_PRIV_KEY_INFO_free(p8inf);
+    if (ret == NULL)
+        ossl_ml_dsa_key_free(key);
+    return ret;
+}
+
+static ossl_inline void * ml_dsa_d2i_PUBKEY(const uint8_t **der, long der_len,
+                                            struct der2key_ctx_st *ctx)
+{
+    int ok = 0;
+    OSSL_LIB_CTX *libctx = PROV_LIBCTX_OF(ctx->provctx);
+    ML_DSA_KEY *ret = NULL;
+    BARE_PUBKEY *spki = NULL;
+    const uint8_t *end = *der;
+    size_t len;
+
+    ret = ossl_ml_dsa_key_new(libctx, ctx->propq, ctx->desc->keytype_name);
+    if (ret == NULL)
+        return NULL;
+    len = ossl_ml_dsa_key_get_pub_len(ret);
+
+    /*-
+     * The DER ASN.1 encoding of ML-DSA public keys prepends 22 bytes to the
+     * encoded public key:
+     *
+     * - 4 byte outer sequence tag and length
+     * -  2 byte algorithm sequence tag and length
+     * -    2 byte algorithm OID tag and length
+     * -      9 byte algorithm OID
+     * -  4 byte bit string tag and length
+     * -    1 bitstring lead byte
+     *
+     * Check that we have the right OID, the bit string has no "bits left" and
+     * that we consume all the input exactly.
+     */
+    if (der_len != 22 + (long)len) {
+        ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_ENCODING,
+                       "unexpected %s public key length: %ld != %ld",
+                       ctx->desc->keytype_name, der_len,
+                       22 + (long)len);
+        goto err;
+    }
+
+    if ((spki = OPENSSL_zalloc(sizeof(*spki))) == NULL)
+        goto err;
+
+    /* The spki storage is freed on error */
+    if (ASN1_item_d2i_ex((ASN1_VALUE **)&spki, &end, der_len,
+                         ASN1_ITEM_rptr(BARE_PUBKEY), NULL, NULL) == NULL) {
+        ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_ENCODING,
+                       "malformed %s public key ASN.1 encoding",
+                       ossl_ml_dsa_key_get_name(ret));
+        goto err;
+    }
+
+    /* The spki structure now owns some memory */
+    if ((spki->pubkey->flags & 0x7) != 0 || end != *der + der_len) {
+        ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_ENCODING,
+                       "malformed %s public key ASN.1 encoding",
+                       ossl_ml_dsa_key_get_name(ret));
+        goto err;
+    }
+    if (OBJ_cmp(OBJ_nid2obj(ctx->desc->evp_type), spki->algor.oid) != 0) {
+        ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_ENCODING,
+                       "unexpected algorithm OID for an %s public key",
+                       ossl_ml_dsa_key_get_name(ret));
+        goto err;
+    }
+
+    if (!ossl_ml_dsa_pk_decode(ret, spki->pubkey->data, spki->pubkey->length)) {
+        ERR_raise_data(ERR_LIB_PROV, PROV_R_BAD_ENCODING,
+                       "failed to parse %s public key from the input data",
+                       ossl_ml_dsa_key_get_name(ret));
+        goto err;
+    }
+    ok = 1;
+ err:
+    if (spki != NULL) {
+        ASN1_OBJECT_free(spki->algor.oid);
+        ASN1_BIT_STRING_free(spki->pubkey);
+        OPENSSL_free(spki);
+    }
+    if (!ok) {
+        ossl_ml_dsa_key_free(ret);
+        ret = NULL;
+    }
+    return ret;
+}
+
+# define ml_dsa_44_evp_type                EVP_PKEY_ML_DSA_44
+# define ml_dsa_44_d2i_private_key         NULL
+# define ml_dsa_44_d2i_public_key          NULL
+# define ml_dsa_44_d2i_key_params          NULL
+# define ml_dsa_44_d2i_PUBKEY              ml_dsa_d2i_PUBKEY
+# define ml_dsa_44_d2i_PKCS8               ml_dsa_d2i_PKCS8
+# define ml_dsa_44_free                    (free_key_fn *)ossl_ml_dsa_key_free
+# define ml_dsa_44_check                   NULL
+# define ml_dsa_44_adjust                  NULL
+
+# define ml_dsa_65_evp_type                EVP_PKEY_ML_DSA_65
+# define ml_dsa_65_d2i_private_key         NULL
+# define ml_dsa_65_d2i_public_key          NULL
+# define ml_dsa_65_d2i_key_params          NULL
+# define ml_dsa_65_d2i_PUBKEY              ml_dsa_d2i_PUBKEY
+# define ml_dsa_65_d2i_PKCS8               ml_dsa_d2i_PKCS8
+# define ml_dsa_65_free                    (free_key_fn *)ossl_ml_dsa_key_free
+# define ml_dsa_65_check                   NULL
+# define ml_dsa_65_adjust                  NULL
+
+# define ml_dsa_87_evp_type               EVP_PKEY_ML_DSA_87
+# define ml_dsa_87_d2i_private_key        NULL
+# define ml_dsa_87_d2i_public_key         NULL
+# define ml_dsa_87_d2i_PUBKEY             ml_dsa_d2i_PUBKEY
+# define ml_dsa_87_d2i_PKCS8              ml_dsa_d2i_PKCS8
+# define ml_dsa_87_d2i_key_params         NULL
+# define ml_dsa_87_free                   (free_key_fn *)ossl_ml_dsa_key_free
+# define ml_dsa_87_check                  NULL
+# define ml_dsa_87_adjust                 NULL
+
+#endif
+
+/* ---------------------------------------------------------------------- */
+
 /*
  * The DO_ macros help define the selection mask and the method functions
  * for each kind of object we want to decode.
@@ -872,3 +1057,12 @@ MAKE_DECODER("RSA", rsa, rsa, type_specific_keypair);
 MAKE_DECODER("RSA", rsa, rsa, RSA);
 MAKE_DECODER("RSA-PSS", rsapss, rsapss, PrivateKeyInfo);
 MAKE_DECODER("RSA-PSS", rsapss, rsapss, SubjectPublicKeyInfo);
+
+#ifndef OPENSSL_NO_ML_DSA
+MAKE_DECODER("ML-DSA-44", ml_dsa_44, ml_dsa_44, PrivateKeyInfo);
+MAKE_DECODER("ML-DSA-44", ml_dsa_44, ml_dsa_44, SubjectPublicKeyInfo);
+MAKE_DECODER("ML-DSA-65", ml_dsa_65, ml_dsa_65, PrivateKeyInfo);
+MAKE_DECODER("ML-DSA-65", ml_dsa_65, ml_dsa_65, SubjectPublicKeyInfo);
+MAKE_DECODER("ML-DSA-87", ml_dsa_87, ml_dsa_87, PrivateKeyInfo);
+MAKE_DECODER("ML-DSA-87", ml_dsa_87, ml_dsa_87, SubjectPublicKeyInfo);
+#endif
index 846f936f8115b969bfe0bc2d492076e85022adab..d2c4ccaa23035f8081acdac1f25ef742bc404497 100644 (file)
@@ -30,6 +30,7 @@
 #include "internal/cryptlib.h"
 #include "crypto/ecx.h"
 #include "crypto/rsa.h"
+#include "crypto/ml_dsa.h"
 #include "prov/implementations.h"
 #include "prov/bio.h"
 #include "prov/provider_ctx.h"
@@ -846,6 +847,58 @@ static int ecx_pki_priv_to_der(const void *vecxkey, unsigned char **pder,
 
 /* ---------------------------------------------------------------------- */
 
+#ifndef OPENSSL_NO_ML_DSA
+static int ml_dsa_spki_pub_to_der(const void *vkey, unsigned char **pder)
+{
+    const ML_DSA_KEY *key = vkey;
+    size_t publen;
+
+    if (ossl_ml_dsa_key_get_pub(key) == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    publen = ossl_ml_dsa_key_get_pub_len(key);
+
+    if (pder != NULL
+            && ((*pder = OPENSSL_memdup(ossl_ml_dsa_key_get_pub(key),
+                                        publen)) == NULL))
+        return 0;
+
+    return publen;
+}
+
+static int ml_dsa_pki_priv_to_der(const void *vkey, unsigned char **pder)
+{
+    const ML_DSA_KEY *key = vkey;
+    size_t len;
+
+    if (ossl_ml_dsa_key_get_priv(key) == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    len = ossl_ml_dsa_key_get_priv_len(key);
+
+    if (pder != NULL
+            && ((*pder = OPENSSL_memdup(ossl_ml_dsa_key_get_priv(key), len)) == NULL))
+        return 0;
+
+    return len;
+}
+
+# define ml_dsa_epki_priv_to_der ml_dsa_pki_priv_to_der
+# define prepare_ml_dsa_params   NULL
+# define ml_dsa_check_key_type   NULL
+
+# define ml_dsa_44_evp_type        EVP_PKEY_ML_DSA_44
+# define ml_dsa_44_pem_type        "ML-DSA-44"
+# define ml_dsa_65_evp_type        EVP_PKEY_ML_DSA_65
+# define ml_dsa_65_pem_type        "ML-DSA-65"
+# define ml_dsa_87_evp_type        EVP_PKEY_ML_DSA_87
+# define ml_dsa_87_pem_type        "ML-DSA-87"
+#endif /* OPENSSL_NO_ML_DSA */
+
+/* ---------------------------------------------------------------------- */
+
 /*
  * Helper functions to prepare RSA-PSS params for encoding.  We would
  * have simply written the whole AlgorithmIdentifier, but existing libcrypto
@@ -1491,3 +1544,26 @@ MAKE_ENCODER(dhx, dh, X9_42, pem); /* parameters only */
 MAKE_ENCODER(ec, ec, X9_62, der);
 MAKE_ENCODER(ec, ec, X9_62, pem);
 #endif
+
+#ifndef OPENSSL_NO_ML_DSA
+MAKE_ENCODER(ml_dsa_44, ml_dsa, EVP_PKEY_ML_DSA_44, EncryptedPrivateKeyInfo, der);
+MAKE_ENCODER(ml_dsa_44, ml_dsa, EVP_PKEY_ML_DSA_44, EncryptedPrivateKeyInfo, pem);
+MAKE_ENCODER(ml_dsa_44, ml_dsa, EVP_PKEY_ML_DSA_44, PrivateKeyInfo, der);
+MAKE_ENCODER(ml_dsa_44, ml_dsa, EVP_PKEY_ML_DSA_44, PrivateKeyInfo, pem);
+MAKE_ENCODER(ml_dsa_44, ml_dsa, EVP_PKEY_ML_DSA_44, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(ml_dsa_44, ml_dsa, EVP_PKEY_ML_DSA_44, SubjectPublicKeyInfo, pem);
+
+MAKE_ENCODER(ml_dsa_65, ml_dsa, EVP_PKEY_ML_DSA_65, EncryptedPrivateKeyInfo, der);
+MAKE_ENCODER(ml_dsa_65, ml_dsa, EVP_PKEY_ML_DSA_65, EncryptedPrivateKeyInfo, pem);
+MAKE_ENCODER(ml_dsa_65, ml_dsa, EVP_PKEY_ML_DSA_65, PrivateKeyInfo, der);
+MAKE_ENCODER(ml_dsa_65, ml_dsa, EVP_PKEY_ML_DSA_65, PrivateKeyInfo, pem);
+MAKE_ENCODER(ml_dsa_65, ml_dsa, EVP_PKEY_ML_DSA_65, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(ml_dsa_65, ml_dsa, EVP_PKEY_ML_DSA_65, SubjectPublicKeyInfo, pem);
+
+MAKE_ENCODER(ml_dsa_87, ml_dsa, EVP_PKEY_ML_DSA_87, EncryptedPrivateKeyInfo, der);
+MAKE_ENCODER(ml_dsa_87, ml_dsa, EVP_PKEY_ML_DSA_87, EncryptedPrivateKeyInfo, pem);
+MAKE_ENCODER(ml_dsa_87, ml_dsa, EVP_PKEY_ML_DSA_87, PrivateKeyInfo, der);
+MAKE_ENCODER(ml_dsa_87, ml_dsa, EVP_PKEY_ML_DSA_87, PrivateKeyInfo, pem);
+MAKE_ENCODER(ml_dsa_87, ml_dsa, EVP_PKEY_ML_DSA_87, SubjectPublicKeyInfo, der);
+MAKE_ENCODER(ml_dsa_87, ml_dsa, EVP_PKEY_ML_DSA_87, SubjectPublicKeyInfo, pem);
+#endif /* OPENSSL_NO_ML_DSA */
index ebad2e1876f71670886981d94bc67fe58a51f734..a67c63d6cc6382d2f15983eacdff28f098fa08e8 100644 (file)
@@ -24,6 +24,7 @@
 #include "crypto/ec.h"           /* ossl_ec_key_get_libctx */
 #include "crypto/ecx.h"          /* ECX_KEY, etc... */
 #include "crypto/rsa.h"          /* RSA_PSS_PARAMS_30, etc... */
+#include "crypto/ml_dsa.h"
 #include "prov/bio.h"
 #include "prov/implementations.h"
 #include "internal/encoder.h"
@@ -587,6 +588,49 @@ static int rsa_to_text(BIO *out, const void *key, int selection)
 
 /* ---------------------------------------------------------------------- */
 
+#ifndef OPENSSL_NO_ML_DSA
+static int ml_dsa_to_text(BIO *out, const void *key, int selection)
+{
+    const char *name;
+
+    if (out == NULL || key == NULL) {
+        ERR_raise(ERR_LIB_PROV, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    if (ossl_ml_dsa_key_get_pub(key) == NULL) {
+        /* Regardless of the |selection|, there must be a public key */
+        ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PUBLIC_KEY);
+        return 0;
+    }
+
+    name = ossl_ml_dsa_key_get_name(key);
+    if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) {
+        if (ossl_ml_dsa_key_get_priv(key) == NULL) {
+            ERR_raise(ERR_LIB_PROV, PROV_R_NOT_A_PRIVATE_KEY);
+            return 0;
+        }
+        if (BIO_printf(out, "%s Private-Key:\n", name) <= 0)
+            return 0;
+        if (!ossl_bio_print_labeled_buf(out, "priv:",
+                                        ossl_ml_dsa_key_get_priv(key),
+                                        ossl_ml_dsa_key_get_priv_len(key)))
+            return 0;
+    } else if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) {
+        if (BIO_printf(out, "%s Public-Key:\n", name) <= 0)
+            return 0;
+    }
+
+    if (!ossl_bio_print_labeled_buf(out, "pub:",
+                                    ossl_ml_dsa_key_get_pub(key),
+                                    ossl_ml_dsa_key_get_pub_len(key)))
+        return 0;
+
+    return 1;
+}
+#endif /* OPENSSL_NO_ML_DSA */
+
+/* ---------------------------------------------------------------------- */
+
 static void *key2text_newctx(void *provctx)
 {
     return provctx;
@@ -681,3 +725,9 @@ MAKE_TEXT_ENCODER(x448, ecx);
 #endif
 MAKE_TEXT_ENCODER(rsa, rsa);
 MAKE_TEXT_ENCODER(rsapss, rsa);
+
+#ifndef OPENSSL_NO_ML_DSA
+MAKE_TEXT_ENCODER(ml_dsa_44, ml_dsa);
+MAKE_TEXT_ENCODER(ml_dsa_65, ml_dsa);
+MAKE_TEXT_ENCODER(ml_dsa_87, ml_dsa);
+#endif
index f4b0be387c1234c86e8a6b2d720a54e8868e81c3..3863d96a4073baf10a3eb0d6c9100d5b7885b0db 100644 (file)
@@ -536,6 +536,33 @@ extern const OSSL_DISPATCH ossl_x448_to_SubjectPublicKeyInfo_pem_encoder_functio
 extern const OSSL_DISPATCH ossl_x448_to_OSSL_current_der_encoder_functions[];
 extern const OSSL_DISPATCH ossl_x448_to_text_encoder_functions[];
 
+extern const OSSL_DISPATCH ossl_ml_dsa_44_to_EncryptedPrivateKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_44_to_EncryptedPrivateKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_44_to_PrivateKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_44_to_PrivateKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_44_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_44_to_SubjectPublicKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_44_to_OSSL_current_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_44_to_text_encoder_functions[];
+
+extern const OSSL_DISPATCH ossl_ml_dsa_65_to_EncryptedPrivateKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_65_to_EncryptedPrivateKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_65_to_PrivateKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_65_to_PrivateKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_65_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_65_to_SubjectPublicKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_65_to_OSSL_current_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_65_to_text_encoder_functions[];
+
+extern const OSSL_DISPATCH ossl_ml_dsa_87_to_EncryptedPrivateKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_87_to_EncryptedPrivateKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_87_to_PrivateKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_87_to_PrivateKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_87_to_SubjectPublicKeyInfo_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_87_to_SubjectPublicKeyInfo_pem_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_87_to_OSSL_current_der_encoder_functions[];
+extern const OSSL_DISPATCH ossl_ml_dsa_87_to_text_encoder_functions[];
+
 /* Decoders */
 extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_dh_decoder_functions[];
 extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_dh_decoder_functions[];
@@ -593,3 +620,12 @@ 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_PrivateKeyInfo_der_to_ml_dsa_44_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ml_dsa_44_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_ml_dsa_65_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ml_dsa_65_decoder_functions[];
+
+extern const OSSL_DISPATCH ossl_PrivateKeyInfo_der_to_ml_dsa_87_decoder_functions[];
+extern const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_ml_dsa_87_decoder_functions[];
index 1bf99556f94dbde2532c4cc5a0bdfb38d44f7a37..29a94cd554bfc8f56b7fcdd7c00ab52d59020a86 100644 (file)
@@ -105,7 +105,8 @@ static EVP_PKEY *make_template(const char *type, OSSL_PARAM *genparams)
 }
 #endif
 
-#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_DSA) || !defined(OPENSSL_NO_EC)
+#if !defined(OPENSSL_NO_DH) || !defined(OPENSSL_NO_DSA) \
+    || !defined(OPENSSL_NO_EC) || !defined(OPENSSL_NO_ML_DSA)
 static EVP_PKEY *make_key(const char *type, EVP_PKEY *template,
                           OSSL_PARAM *genparams)
 {
@@ -1064,6 +1065,15 @@ IMPLEMENT_TEST_SUITE_UNPROTECTED_PVK(RSA, "RSA")
 IMPLEMENT_TEST_SUITE_PROTECTED_PVK(RSA, "RSA")
 #endif
 
+#ifndef OPENSSL_ML_DSA
+KEYS(ML_DSA_44);
+KEYS(ML_DSA_65);
+KEYS(ML_DSA_87);
+IMPLEMENT_TEST_SUITE(ML_DSA_44, "ML-DSA-44", 0)
+IMPLEMENT_TEST_SUITE(ML_DSA_65, "ML-DSA-65", 0)
+IMPLEMENT_TEST_SUITE(ML_DSA_87, "ML-DSA-87", 0)
+#endif /*  OPENSSL_ML_DSA */
+
 #ifndef OPENSSL_NO_EC
 /* Explicit parameters that match a named curve */
 static int do_create_ec_explicit_prime_params(OSSL_PARAM_BLD *bld,
@@ -1407,6 +1417,12 @@ int setup_tests(void)
     MAKE_KEYS(X25519, "X25519", NULL);
     MAKE_KEYS(X448, "X448", NULL);
 #endif
+#ifndef OPENSSL_ML_DSA
+    MAKE_KEYS(ML_DSA_44, "ML-DSA-44", NULL);
+    MAKE_KEYS(ML_DSA_65, "ML-DSA-65", NULL);
+    MAKE_KEYS(ML_DSA_87, "ML-DSA-87", NULL);
+#endif /* OPENSSL_ML_DSA */
+
     TEST_info("Loading RSA key...");
     ok = ok && TEST_ptr(key_RSA = load_pkey_pem(rsa_file, keyctx));
     TEST_info("Loading RSA_PSS key...");
@@ -1475,6 +1491,12 @@ int setup_tests(void)
 # ifndef OPENSSL_NO_RC4
         ADD_TEST_SUITE_PROTECTED_PVK(RSA);
 # endif
+
+#ifndef OPENSSL_ML_DSA
+        ADD_TEST_SUITE(ML_DSA_44);
+        ADD_TEST_SUITE(ML_DSA_65);
+        ADD_TEST_SUITE(ML_DSA_87);
+#endif /* OPENSSL_ML_DSA */
     }
 
     return 1;
@@ -1522,6 +1544,12 @@ void cleanup_tests(void)
     FREE_KEYS(RSA);
     FREE_KEYS(RSA_PSS);
 
+#ifndef OPENSSL_ML_DSA
+    FREE_KEYS(ML_DSA_44);
+    FREE_KEYS(ML_DSA_65);
+    FREE_KEYS(ML_DSA_87);
+#endif /* OPENSSL_ML_DSA */
+
     OSSL_PROVIDER_unload(nullprov);
     OSSL_PROVIDER_unload(deflprov);
     OSSL_PROVIDER_unload(keyprov);