#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)
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;
return 0;
}
-#endif
int _gnutls_x509_write_pubkey_params(const gnutls_pk_params_st *params,
gnutls_datum_t *der)
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;
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);
}
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)
*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)
{
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;
}
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);
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)
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.
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,