summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDaniel Kahn Gillmor <dkg@fifthhorseman.net>2021-05-07 20:12:15 -0400
committerDaniel Kahn Gillmor <dkg@fifthhorseman.net>2021-09-17 16:33:07 -0400
commit7d895c807989f640e5a5c3c58ab4f3c0cb0215f4 (patch)
treebfcadc83f9138f77f718656f1f553c69f983671e /lib
parentddb527ea6ac199b7735ab8943a06562b9d9d3135 (diff)
downloadgnutls-7d895c807989f640e5a5c3c58ab4f3c0cb0215f4.tar.gz
pubkey: handle X25519 and X448 in gnutls_pubkey_import_pkcs11
I am not confident in the strings I chose to match on in ASN1_ETYPE_PRINTABLE_STRING, in that I do not know what registry I should look this up in. The *parse_ecc_ecdh_params and *import_ecc_ecdh functions are tweaked analogs to the eddsa versions of those functions. Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
Diffstat (limited to 'lib')
-rw-r--r--lib/pubkey.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/lib/pubkey.c b/lib/pubkey.c
index a1735cf766..6d00e87876 100644
--- a/lib/pubkey.c
+++ b/lib/pubkey.c
@@ -497,6 +497,139 @@ gnutls_pubkey_import_ecc_eddsa(gnutls_pubkey_t key,
return ret;
}
+/* Same as above, but for Edwards key agreement */
+static int
+gnutls_pubkey_parse_ecc_ecdh_params(const gnutls_datum_t *parameters,
+ gnutls_ecc_curve_t *outcurve)
+{
+ gnutls_ecc_curve_t curve = GNUTLS_ECC_CURVE_INVALID;
+ ASN1_TYPE asn1 = ASN1_TYPE_EMPTY;
+ unsigned int etype = ASN1_ETYPE_INVALID;
+ char str[MAX_OID_SIZE];
+ int str_size;
+ int ret;
+
+ ret = asn1_create_element(_gnutls_get_gnutls_asn(),
+ "GNUTLS.pkcs-11-ec-Parameters", &asn1);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ return _gnutls_asn2err(ret);
+ }
+
+ ret = asn1_der_decoding(&asn1, parameters->data, parameters->size,
+ NULL);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+
+ /* Read the type of choice.
+ */
+ str_size = sizeof(str) - 1;
+ ret = asn1_read_value(asn1, "", str, &str_size);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ goto cleanup;
+ }
+ str[str_size] = 0;
+
+ /* Convert the choice to enum type */
+ if (strcmp(str, "oId") == 0) {
+ etype = ASN1_ETYPE_OBJECT_ID;
+ } else if (strcmp(str, "curveName") == 0) {
+ etype = ASN1_ETYPE_PRINTABLE_STRING;
+ }
+
+ str_size = sizeof(str) - 1;
+ switch (etype) {
+ case ASN1_ETYPE_OBJECT_ID:
+ ret = asn1_read_value(asn1, "oId", str, &str_size);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ break;
+ }
+
+ curve = gnutls_oid_to_ecc_curve(str);
+ if (curve != GNUTLS_ECC_CURVE_X25519 &&
+ curve != GNUTLS_ECC_CURVE_X448) {
+ _gnutls_debug_log("Curve %s is not supported for Edwards-based key agreement\n", str);
+ gnutls_assert();
+ curve = GNUTLS_ECC_CURVE_INVALID;
+ ret = GNUTLS_E_ECC_UNSUPPORTED_CURVE;
+ break;
+ }
+
+ ret = GNUTLS_E_SUCCESS;
+ break;
+
+ case ASN1_ETYPE_PRINTABLE_STRING:
+ ret = asn1_read_value(asn1, "curveName", str, &str_size);
+ if (ret != ASN1_SUCCESS) {
+ gnutls_assert();
+ ret = _gnutls_asn2err(ret);
+ break;
+ }
+
+ if (str_size == strlen("x25519") &&
+ strncmp(str, "x25519", str_size) == 0) {
+ curve = GNUTLS_ECC_CURVE_X25519;
+ ret = GNUTLS_E_SUCCESS;
+ break;
+ } else if (str_size == strlen("x448") &&
+ strncmp(str, "x448", str_size) == 0) {
+ curve = GNUTLS_ECC_CURVE_X448;
+ ret = GNUTLS_E_SUCCESS;
+ break;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ /* Neither of CHOICEs found. Fail */
+ gnutls_assert();
+ ret = GNUTLS_E_ECC_UNSUPPORTED_CURVE;
+ curve = GNUTLS_ECC_CURVE_INVALID;
+ break;
+ }
+
+
+ cleanup:
+ asn1_delete_structure(&asn1);
+ *outcurve = curve;
+ return ret;
+}
+
+static int
+gnutls_pubkey_import_ecc_ecdh(gnutls_pubkey_t key,
+ const gnutls_datum_t * parameters,
+ const gnutls_datum_t * ecpoint)
+{
+ int ret;
+
+ gnutls_ecc_curve_t curve = GNUTLS_ECC_CURVE_INVALID;
+ gnutls_datum_t raw_point = {NULL, 0};
+
+ ret = gnutls_pubkey_parse_ecc_ecdh_params(parameters, &curve);
+ if (ret < 0) {
+ return gnutls_assert_val(ret);
+ }
+
+ ret = _gnutls_x509_decode_string(ASN1_ETYPE_OCTET_STRING,
+ ecpoint->data, ecpoint->size,
+ &raw_point, 0);
+ if (ret < 0) {
+ gnutls_assert();
+ gnutls_free(raw_point.data);
+ return ret;
+ }
+ ret = gnutls_pubkey_import_ecc_raw(key, curve, &raw_point, NULL);
+
+ gnutls_free(raw_point.data);
+ return ret;
+}
+
/**
* gnutls_pubkey_import_pkcs11:
* @key: The public key
@@ -577,6 +710,10 @@ gnutls_pubkey_import_pkcs11(gnutls_pubkey_t key,
ret = gnutls_pubkey_import_ecc_eddsa(key, &obj->pubkey[0],
&obj->pubkey[1]);
break;
+ case GNUTLS_PK_ECDH_X25519:
+ ret = gnutls_pubkey_import_ecc_ecdh(key, &obj->pubkey[0],
+ &obj->pubkey[1]);
+ break;
default:
gnutls_assert();
return GNUTLS_E_UNIMPLEMENTED_FEATURE;