]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Fix Edwards EC_POINT encoding
authorZoltan Fridrich <zfridric@redhat.com>
Wed, 8 Jan 2025 14:15:12 +0000 (15:15 +0100)
committerZoltan Fridrich <zfridric@redhat.com>
Tue, 14 Jan 2025 12:07:16 +0000 (13:07 +0100)
Signed-off-by: Zoltan Fridrich <zfridric@redhat.com>
lib/pkcs11_write.c
lib/pubkey.c

index bde413713699510cb8c59bacd9c941a1699f735f..f5e9058e05346a9dcaa19f1f3283b88aed107324 100644 (file)
@@ -367,20 +367,19 @@ static int add_pubkey(gnutls_pubkey_t pubkey, struct ck_attribute *a,
                        return ret;
                }
 
-               a[*a_val].type = CKA_EC_PARAMS;
-               a[*a_val].value = params.data;
-               a[*a_val].value_len = params.size;
-               (*a_val)++;
-
-               ret = _gnutls_x509_encode_string(ASN1_ETYPE_OCTET_STRING,
-                                                pubkey->params.raw_pub.data,
-                                                pubkey->params.raw_pub.size,
-                                                &ecpoint);
+               ret = _gnutls_set_datum(&ecpoint, pubkey->params.raw_pub.data,
+                                       pubkey->params.raw_pub.size);
                if (ret < 0) {
                        gnutls_assert();
+                       _gnutls_free_datum(&params);
                        return ret;
                }
 
+               a[*a_val].type = CKA_EC_PARAMS;
+               a[*a_val].value = params.data;
+               a[*a_val].value_len = params.size;
+               (*a_val)++;
+
                a[*a_val].type = CKA_EC_POINT;
                a[*a_val].value = ecpoint.data;
                a[*a_val].value_len = ecpoint.size;
index 76baa849735124c371d2b7269bce7d8165c9b205..9e07777e74d59aabc6448b550eec9b57629f3606 100644 (file)
@@ -517,7 +517,10 @@ static int gnutls_pubkey_import_ecc_eddsa(gnutls_pubkey_t key,
                                          const gnutls_datum_t *parameters,
                                          const gnutls_datum_t *ecpoint)
 {
-       int ret;
+       int ret, tag_len;
+       unsigned long tag = 0;
+       unsigned char class;
+       unsigned int etype;
 
        gnutls_ecc_curve_t curve = GNUTLS_ECC_CURVE_INVALID;
        gnutls_datum_t raw_point = { NULL, 0 };
@@ -527,16 +530,43 @@ static int gnutls_pubkey_import_ecc_eddsa(gnutls_pubkey_t key,
                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;
+       /* Even though the PKCS#11 3.1 spec defines EC_POINT as
+        * "Public key bytes in little endian order", previous version
+         * of the spec caused confusion and lot of implementations instead
+         * store EC_POINT DER encoded either as a BIT STRING or OCTET STRING.
+         * We need to check all three options.
+        */
+       if (ecpoint->size == (unsigned int)gnutls_ecc_curve_get_size(curve)) {
+               raw_point.data = ecpoint->data;
+               raw_point.size = ecpoint->size;
+       } else {
+               ret = asn1_get_tag_der(ecpoint->data, ecpoint->size, &class,
+                                      &tag_len, &tag);
+               if (ret != ASN1_SUCCESS)
+                       return gnutls_assert_val(_gnutls_asn2err(ret));
+
+               switch (tag) {
+               case 0x03:
+                       etype = ASN1_ETYPE_BIT_STRING;
+                       break;
+               case 0x04:
+                       etype = ASN1_ETYPE_OCTET_STRING;
+                       break;
+               default:
+                       return gnutls_assert_val(GNUTLS_E_ASN1_TAG_ERROR);
+               }
+
+               ret = _gnutls_x509_decode_string(etype, ecpoint->data,
+                                                ecpoint->size, &raw_point, 0);
+               if (ret < 0)
+                       return gnutls_assert_val(ret);
        }
+
        ret = gnutls_pubkey_import_ecc_raw(key, curve, &raw_point, NULL);
 
-       gnutls_free(raw_point.data);
+       if (raw_point.data != ecpoint->data)
+               gnutls_free(raw_point.data);
+
        return ret;
 }