]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
x509: stop using version field of MLDSAPrivateKey
authorDaiki Ueno <ueno@gnu.org>
Tue, 7 Jan 2025 03:36:19 +0000 (12:36 +0900)
committerDaiki Ueno <ueno@gnu.org>
Thu, 9 Jan 2025 10:40:27 +0000 (19:40 +0900)
Previously we indicated the used ML-DSA algorithm in the version field
of MLDSAPrivateKey, though this information is also available in
privateKeyAlgorithm field as OID. With this change, the version field
is always set to 1 to be compatible with OneAsymmetricKey with a
non-empty publicKey field. When decoding, if the version is 1, the
public key is read from publicKey field; otherwise it will be
extracted from the privateKey field to interoperate with the other
implementations such as OpenSSL/oqsprovider.

Signed-off-by: Daiki Ueno <ueno@gnu.org>
lib/algorithms.h
lib/x509/key_encode.c
lib/x509/privkey.c
lib/x509/x509_int.h

index dac466b830703cdd7e294b4fbe6e472dcb84035e..629da84f48955227acdd38ca1a69fd711dbac357 100644 (file)
 #define ML_DSA_65_PUBKEY_SIZE 1952
 #define ML_DSA_87_PUBKEY_SIZE 2592
 
+#define ML_DSA_44_PRIVKEY_SIZE 2560
+#define ML_DSA_65_PRIVKEY_SIZE 4032
+#define ML_DSA_87_PRIVKEY_SIZE 4896
+
 #define IS_GROUP_HYBRID(group) ((group)->ids[0] != GNUTLS_GROUP_INVALID)
 
 #define SIG_SEM_PRE_TLS12 (1 << 1)
index df445dea2842b81ffc9ea6c28d522cd75e9898f8..7af80def41a359375585191b355418b18371cd95 100644 (file)
@@ -257,9 +257,8 @@ cleanup:
        return ret;
 }
 
-#ifdef HAVE_LIBOQS
-static int _gnutls_x509_write_pqc_alg_pubkey(const gnutls_pk_params_st *params,
-                                            gnutls_datum_t *raw)
+static int _gnutls_x509_write_ml_dsa_pubkey(const gnutls_pk_params_st *params,
+                                           gnutls_datum_t *raw)
 {
        int ret;
 
@@ -276,7 +275,6 @@ static int _gnutls_x509_write_pqc_alg_pubkey(const gnutls_pk_params_st *params,
 
        return 0;
 }
-#endif
 
 int _gnutls_x509_write_pubkey_params(const gnutls_pk_params_st *params,
                                     gnutls_datum_t *der)
@@ -302,11 +300,9 @@ int _gnutls_x509_write_pubkey_params(const gnutls_pk_params_st *params,
        case GNUTLS_PK_EDDSA_ED448:
        case GNUTLS_PK_ECDH_X25519:
        case GNUTLS_PK_ECDH_X448:
-#ifdef HAVE_LIBOQS
        case GNUTLS_PK_ML_DSA_44:
        case GNUTLS_PK_ML_DSA_65:
        case GNUTLS_PK_ML_DSA_87:
-#endif
                der->data = NULL;
                der->size = 0;
 
@@ -342,12 +338,10 @@ int _gnutls_x509_write_pubkey(const gnutls_pk_params_st *params,
        case GNUTLS_PK_GOST_12_256:
        case GNUTLS_PK_GOST_12_512:
                return _gnutls_x509_write_gost_pubkey(params, der);
-#ifdef HAVE_LIBOQS
        case GNUTLS_PK_ML_DSA_44:
        case GNUTLS_PK_ML_DSA_65:
        case GNUTLS_PK_ML_DSA_87:
-               return _gnutls_x509_write_pqc_alg_pubkey(params, der);
-#endif
+               return _gnutls_x509_write_ml_dsa_pubkey(params, der);
        default:
                return gnutls_assert_val(GNUTLS_E_UNIMPLEMENTED_FEATURE);
        }
@@ -1178,70 +1172,17 @@ cleanup:
        return ret;
 }
 
-#ifdef HAVE_LIBOQS
-static int _gnutls_asn1_encode_pqc_alg(asn1_node *c2,
-                                      gnutls_pk_params_st *params,
-                                      const char *oid, uint8_t version)
-{
-       int ret;
-
-       if ((ret = asn1_write_value(*c2, "version", &version, 1)) !=
-           ASN1_SUCCESS) {
-               gnutls_assert();
-               return _gnutls_asn2err(ret);
-       }
-
-       if ((ret = asn1_write_value(*c2, "privateKeyAlgorithm.algorithm", oid,
-                                   1)) != ASN1_SUCCESS) {
-               gnutls_assert();
-               return _gnutls_asn2err(ret);
-       }
-
-       if ((ret = asn1_write_value(*c2, "privateKeyAlgorithm.parameters", NULL,
-                                   0)) != ASN1_SUCCESS) {
-               gnutls_assert();
-               return _gnutls_asn2err(ret);
-       }
-
-       if (params->raw_pub.size == 0 || params->raw_priv.size == 0)
-               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
-
-       ret = asn1_write_value(*c2, "privateKey", params->raw_priv.data,
-                              params->raw_priv.size);
-       if (ret != ASN1_SUCCESS) {
-               gnutls_assert();
-               return _gnutls_asn2err(ret);
-       }
-
-       ret = asn1_write_value(*c2, "publicKey", params->raw_pub.data,
-                              params->raw_pub.size);
-       if (ret != ASN1_SUCCESS) {
-               gnutls_assert();
-               return _gnutls_asn2err(ret);
-       }
-
-       return GNUTLS_E_SUCCESS;
-}
-
-static uint8_t _gnutls_get_pqc_alg_version(gnutls_pk_params_st *params)
-{
-       switch (params->algo) {
-       case GNUTLS_PK_ML_DSA_44:
-               return '\x04';
-       case GNUTLS_PK_ML_DSA_65:
-               return '\x06';
-       case GNUTLS_PK_ML_DSA_87:
-               return '\x08';
-       default:
-               return '\x00';
-       }
-}
-
+/* Encodes the ML-DSA parameters into an ASN.1 MLDSAPrivateKey structure.
+ */
 static int _gnutls_asn1_encode_ml_dsa(asn1_node *c2,
                                      gnutls_pk_params_st *params)
 {
-       int ret;
+       int result, ret;
        const char *oid;
+       const uint8_t one = 1;
+
+       if (unlikely(params->raw_pub.size == 0 || params->raw_priv.size == 0))
+               return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
 
        oid = gnutls_pk_get_oid(params->algo);
        if (oid == NULL)
@@ -1253,27 +1194,59 @@ static int _gnutls_asn1_encode_ml_dsa(asn1_node *c2,
                *c2 = NULL;
        }
 
-       if ((ret = asn1_create_element(_gnutls_get_gnutls_asn(),
-                                      "GNUTLS.MLDSAPrivateKey", c2)) !=
+       if ((result = asn1_create_element(_gnutls_get_gnutls_asn(),
+                                         "GNUTLS.MLDSAPrivateKey", c2)) !=
            ASN1_SUCCESS) {
                gnutls_assert();
-               ret = _gnutls_asn2err(ret);
+               ret = _gnutls_asn2err(result);
                goto cleanup;
        }
 
-       ret = _gnutls_asn1_encode_pqc_alg(c2, params, oid,
-                                         _gnutls_get_pqc_alg_version(params));
-       if (ret < 0)
+       /* signify publicKey is embedded in a separate field */
+       if ((result = asn1_write_value(*c2, "version", &one, 1)) !=
+           ASN1_SUCCESS) {
+               gnutls_assert();
+               ret = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+
+       if ((result = asn1_write_value(*c2, "privateKeyAlgorithm.algorithm",
+                                      oid, 1)) != ASN1_SUCCESS) {
+               gnutls_assert();
+               ret = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+
+       if ((result = asn1_write_value(*c2, "privateKeyAlgorithm.parameters",
+                                      NULL, 0)) != ASN1_SUCCESS) {
+               gnutls_assert();
+               ret = _gnutls_asn2err(result);
                goto cleanup;
+       }
+
+       result = asn1_write_value(*c2, "privateKey", params->raw_priv.data,
+                                 params->raw_priv.size);
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               ret = _gnutls_asn2err(result);
+               goto cleanup;
+       }
+
+       result = asn1_write_value(*c2, "publicKey", params->raw_pub.data,
+                                 params->raw_pub.size);
+       if (result != ASN1_SUCCESS) {
+               gnutls_assert();
+               ret = _gnutls_asn2err(result);
+               goto cleanup;
+       }
 
-       return GNUTLS_E_SUCCESS;
+       ret = GNUTLS_E_SUCCESS;
 
 cleanup:
        asn1_delete_structure2(c2, ASN1_DELETE_FLAG_ZEROIZE);
 
        return ret;
 }
-#endif
 
 int _gnutls_asn1_encode_privkey(asn1_node *c2, gnutls_pk_params_st *params)
 {
@@ -1297,12 +1270,10 @@ int _gnutls_asn1_encode_privkey(asn1_node *c2, gnutls_pk_params_st *params)
        case GNUTLS_PK_DH:
                /* DH keys are only exportable in PKCS#8 format */
                return GNUTLS_E_INVALID_REQUEST;
-#ifdef HAVE_LIBOQS
        case GNUTLS_PK_ML_DSA_44:
        case GNUTLS_PK_ML_DSA_65:
        case GNUTLS_PK_ML_DSA_87:
                return _gnutls_asn1_encode_ml_dsa(c2, params);
-#endif
        default:
                return GNUTLS_E_UNIMPLEMENTED_FEATURE;
        }
index f0c920da29abd7303e20bdeb2c0b96934d174946..6feca0478db0f725dcc3fd4d9e14e5bb40f2b926 100644 (file)
@@ -327,86 +327,106 @@ error:
        return ret;
 }
 
-#ifdef HAVE_LIBOQS
-struct pqc_algorithm_version_st {
-       uint8_t version;
-       gnutls_pk_algorithm_t algorithm;
-       int secret_key_length;
-       int public_key_length;
-};
-
-int _gnutls_decode_pqc_keys(asn1_node *pkey_asn, const gnutls_datum_t *raw_key,
-                           gnutls_x509_privkey_t pkey, uint8_t *version)
+static int decode_ml_dsa_key(asn1_node *pkey_asn, const gnutls_datum_t *raw_key,
+                            gnutls_x509_privkey_t pkey)
 {
-       int result;
-       unsigned int _version;
+       int result, ret;
+       unsigned int version;
+       char oid[MAX_OID_SIZE];
+       int oid_size;
+       size_t raw_pub_size, raw_priv_size;
 
        result = _asn1_strict_der_decode(pkey_asn, raw_key->data, raw_key->size,
                                         NULL);
        if (result != ASN1_SUCCESS) {
                gnutls_assert();
-               return result;
-       }
-
-       result = _gnutls_x509_read_uint(*pkey_asn, "version", &_version);
-       *version = _version;
-       if (result < 0) {
-               gnutls_assert();
-               return result;
+               return _gnutls_asn2err(result);
        }
 
-       result = _gnutls_x509_read_value(*pkey_asn, "privateKey",
-                                        &pkey->params.raw_priv);
-       if (result < 0) {
+       ret = _gnutls_x509_read_uint(*pkey_asn, "version", &version);
+       if (ret < 0) {
                gnutls_assert();
-               return result;
+               return ret;
        }
 
-       result = _gnutls_x509_read_value(*pkey_asn, "publicKey",
-                                        &pkey->params.raw_pub);
-       if (result < 0) {
+       oid_size = sizeof(oid);
+       result = asn1_read_value(*pkey_asn, "privateKeyAlgorithm.algorithm",
+                                oid, &oid_size);
+       if (result != ASN1_SUCCESS) {
                gnutls_assert();
-               return result;
+               return _gnutls_asn2err(result);
        }
 
-       return GNUTLS_E_SUCCESS;
-}
-
-static const struct pqc_algorithm_version_st ml_dsa_versions[] = {
-       { '\x04', GNUTLS_PK_ML_DSA_44, OQS_SIG_ml_dsa_44_length_secret_key,
-         OQS_SIG_ml_dsa_44_length_public_key },
-       { '\x06', GNUTLS_PK_ML_DSA_65, OQS_SIG_ml_dsa_65_length_secret_key,
-         OQS_SIG_ml_dsa_65_length_public_key },
-       { '\x08', GNUTLS_PK_ML_DSA_87, OQS_SIG_ml_dsa_87_length_secret_key,
-         OQS_SIG_ml_dsa_87_length_public_key },
+       pkey->params.algo = gnutls_oid_to_pk(oid);
 
-       { '\x00', GNUTLS_PK_UNKNOWN, 0, 0 }
-};
+       switch (pkey->params.algo) {
+       case GNUTLS_PK_ML_DSA_44:
+               raw_priv_size = ML_DSA_44_PRIVKEY_SIZE;
+               raw_pub_size = ML_DSA_44_PUBKEY_SIZE;
+               break;
+       case GNUTLS_PK_ML_DSA_65:
+               raw_priv_size = ML_DSA_65_PRIVKEY_SIZE;
+               raw_pub_size = ML_DSA_65_PUBKEY_SIZE;
+               break;
+       case GNUTLS_PK_ML_DSA_87:
+               raw_priv_size = ML_DSA_87_PRIVKEY_SIZE;
+               raw_pub_size = ML_DSA_87_PUBKEY_SIZE;
+               break;
+       default:
+               return gnutls_assert_val(
+                       GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM);
+       }
 
-static int _gnutls_set_ml_dsa_params(const uint8_t *version,
-                                    gnutls_x509_privkey_t pkey)
-{
-       const struct pqc_algorithm_version_st *v = ml_dsa_versions;
-       while (v->algorithm != GNUTLS_PK_UNKNOWN && v->version != *version)
-               v++;
+       ret = _gnutls_x509_read_value(*pkey_asn, "privateKey",
+                                     &pkey->params.raw_priv);
+       if (ret < 0) {
+               gnutls_assert();
+               return ret;
+       }
 
-       pkey->params.raw_priv.size = v->secret_key_length;
-       pkey->params.raw_pub.size = v->public_key_length;
-       pkey->params.params_nr = ML_DSA_PRIVATE_PARAMS;
-       pkey->params.algo = v->algorithm;
+       switch (version) {
+       case 0:
+               /* if version is 0, public key is embedded in
+                * privateKey field, concatenated after a private
+                * key */
+               if (pkey->params.raw_priv.size != raw_priv_size + raw_pub_size)
+                       return gnutls_assert_val(GNUTLS_E_ASN1_DER_ERROR);
+               ret = _gnutls_set_datum(
+                       &pkey->params.raw_pub,
+                       &pkey->params.raw_priv.data[raw_priv_size],
+                       raw_pub_size);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+               pkey->params.raw_priv.size = raw_priv_size;
+               break;
+       case 1:
+               /* if version is 1, public key is embedded in a
+                * separate field */
+               ret = _gnutls_x509_read_value(*pkey_asn, "publicKey",
+                                             &pkey->params.raw_pub);
+               if (ret < 0) {
+                       gnutls_assert();
+                       return ret;
+               }
+               break;
+       default:
+               return gnutls_assert_val(GNUTLS_E_ASN1_DER_ERROR);
+       }
 
-       if (v->algorithm == GNUTLS_PK_UNKNOWN)
-               return GNUTLS_E_UNKNOWN_ALGORITHM;
+       if (pkey->params.raw_pub.size != raw_pub_size ||
+           pkey->params.raw_priv.size != raw_priv_size)
+               return gnutls_assert_val(GNUTLS_E_ASN1_DER_ERROR);
 
-       return 0;
+       return GNUTLS_E_SUCCESS;
 }
 
-int _gnutls_privkey_decode_ml_dsa_key(asn1_node *pkey_asn,
-                                     const gnutls_datum_t *raw_key,
-                                     gnutls_x509_privkey_t pkey)
+static int _gnutls_privkey_decode_ml_dsa_key(asn1_node *pkey_asn,
+                                            const gnutls_datum_t *raw_key,
+                                            gnutls_x509_privkey_t pkey)
 {
        int result;
-       uint8_t version;
 
        gnutls_pk_params_init(&pkey->params);
 
@@ -417,23 +437,15 @@ int _gnutls_privkey_decode_ml_dsa_key(asn1_node *pkey_asn,
                return _gnutls_asn2err(result);
        }
 
-       result = _gnutls_decode_pqc_keys(pkey_asn, raw_key, pkey, &version);
-       if (result < 0)
-               goto error;
-
-       result = _gnutls_set_ml_dsa_params(&version, pkey);
-       if (result < 0)
-               goto error;
-
-       return 0;
-
-error:
+       result = decode_ml_dsa_key(pkey_asn, raw_key, pkey);
        asn1_delete_structure2(pkey_asn, ASN1_DELETE_FLAG_ZEROIZE);
-       gnutls_pk_params_clear(&pkey->params);
-       gnutls_pk_params_release(&pkey->params);
+       if (result < 0) {
+               gnutls_pk_params_clear(&pkey->params);
+               gnutls_pk_params_release(&pkey->params);
+       }
+
        return result;
 }
-#endif
 
 static asn1_node decode_dsa_key(const gnutls_datum_t *raw_key,
                                gnutls_x509_privkey_t pkey)
@@ -693,16 +705,13 @@ int gnutls_x509_privkey_import(gnutls_x509_privkey_t key,
                        gnutls_assert();
                        key->key = NULL;
                }
-#ifdef HAVE_LIBOQS
-       } else if (key->params.algo == GNUTLS_PK_ML_DSA_44) {
+       } else if (IS_ML_DSA(key->params.algo)) {
                result = _gnutls_privkey_decode_ml_dsa_key(&key->key, &_data,
                                                           key);
-
                if (result < 0) {
                        gnutls_assert();
                        key->key = NULL;
                }
-#endif
        } else {
                /* Try decoding each of the keys, and accept the one that
                 * succeeds.
index 723ebd4b9cc54acb9c4eb793335bf59c9c33df8d..693a4dd9249f15b441c4d0235f741e4e8c22d7a8 100644 (file)
@@ -241,10 +241,6 @@ int _gnutls_privkey_decode_ecc_key(asn1_node *pkey_asn,
                                   gnutls_x509_privkey_t pkey,
                                   gnutls_ecc_curve_t curve);
 
-int _gnutls_privkey_decode_ml_dsa_key(asn1_node *pkey_asn,
-                                     const gnutls_datum_t *raw_key,
-                                     gnutls_x509_privkey_t pkey);
-
 int _gnutls_privkey_decode_eddsa_key(asn1_node *pkey_asn,
                                     const gnutls_datum_t *raw_key,
                                     gnutls_x509_privkey_t pkey,