summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/abstract_int.h16
-rw-r--r--lib/gnutls_pubkey.c310
-rw-r--r--lib/gnutls_sig.c155
-rw-r--r--lib/gnutls_sig.h5
-rw-r--r--lib/includes/gnutls/abstract.h6
-rw-r--r--lib/includes/gnutls/compat.h10
-rw-r--r--lib/libgnutls.map2
-rw-r--r--lib/x509/common.c37
-rw-r--r--lib/x509/common.h11
-rw-r--r--lib/x509/crq.c15
-rw-r--r--lib/x509/privkey.c39
-rw-r--r--lib/x509/verify.c368
-rw-r--r--lib/x509/x509.c32
-rw-r--r--lib/x509/x509_int.h15
14 files changed, 568 insertions, 453 deletions
diff --git a/lib/abstract_int.h b/lib/abstract_int.h
index 1060679797..06318d3791 100644
--- a/lib/abstract_int.h
+++ b/lib/abstract_int.h
@@ -14,4 +14,20 @@ int
_gnutls_pubkey_get_mpis (gnutls_pubkey_t key,
gnutls_pk_params_st * params);
+int pubkey_verify_hashed_data (gnutls_pk_algorithm_t pk,
+ const gnutls_datum_t * hash,
+ const gnutls_datum_t * signature,
+ gnutls_pk_params_st * issuer_params);
+
+int pubkey_verify_data (gnutls_pk_algorithm_t pk,
+ gnutls_digest_algorithm_t algo,
+ const gnutls_datum_t * data,
+ const gnutls_datum_t * signature,
+ gnutls_pk_params_st * issuer_params);
+
+
+
+gnutls_digest_algorithm_t _gnutls_dsa_q_to_hash (gnutls_pk_algorithm_t algo,
+ const gnutls_pk_params_st* params, int* hash_len);
+
#endif
diff --git a/lib/gnutls_pubkey.c b/lib/gnutls_pubkey.c
index 5dddae2b1c..6352bbbeed 100644
--- a/lib/gnutls_pubkey.c
+++ b/lib/gnutls_pubkey.c
@@ -30,6 +30,7 @@
#include <gnutls_datum.h>
#include <pkcs11_int.h>
#include <gnutls/abstract.h>
+#include <gnutls_sig.h>
#include <gnutls_pk.h>
#include <x509_int.h>
#include <openpgp/openpgp_int.h>
@@ -1119,7 +1120,49 @@ gnutls_pubkey_verify_data (gnutls_pubkey_t pubkey, unsigned int flags,
return GNUTLS_E_INVALID_REQUEST;
}
- ret = pubkey_verify_sig( data, NULL, signature, pubkey->pk_algorithm,
+ ret = pubkey_verify_data( pubkey->pk_algorithm, GNUTLS_DIG_UNKNOWN, data, signature,
+ &pubkey->params);
+ if (ret < 0)
+ {
+ gnutls_assert();
+ }
+
+ return ret;
+}
+
+/**
+ * gnutls_pubkey_verify_data2:
+ * @pubkey: Holds the public key
+ * @algo: The signature algorithm used
+ * @flags: should be 0 for now
+ * @data: holds the signed data
+ * @signature: contains the signature
+ *
+ * This function will verify the given signed data, using the
+ * parameters from the certificate.
+ *
+ * Returns: In case of a verification failure
+ * %GNUTLS_E_PK_SIG_VERIFY_FAILED is returned, and a positive code
+ * on success.
+ *
+ * Since: 2.12.0
+ **/
+int
+gnutls_pubkey_verify_data2 (gnutls_pubkey_t pubkey,
+ gnutls_sign_algorithm_t algo,
+ unsigned int flags,
+ const gnutls_datum_t * data,
+ const gnutls_datum_t * signature)
+{
+ int ret;
+
+ if (pubkey == NULL)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ ret = pubkey_verify_data( pubkey->pk_algorithm, _gnutls_sign_get_hash_algorithm(algo), data, signature,
&pubkey->params);
if (ret < 0)
{
@@ -1158,7 +1201,7 @@ gnutls_pubkey_verify_hash (gnutls_pubkey_t key, unsigned int flags,
return _gnutls_rsa_verify (hash, signature, &key->params, 1);
else
{
- return pubkey_verify_sig (NULL, hash, signature, key->pk_algorithm,
+ return pubkey_verify_hashed_data (key->pk_algorithm, hash, signature,
&key->params);
}
}
@@ -1250,3 +1293,266 @@ _gnutls_pubkey_get_mpis (gnutls_pubkey_t key,
{
return _gnutls_pk_params_copy(params, &key->params);
}
+
+/* if hash==MD5 then we do RSA-MD5
+ * if hash==SHA then we do RSA-SHA
+ * params[0] is modulus
+ * params[1] is public key
+ */
+static int
+_pkcs1_rsa_verify_sig (const gnutls_datum_t * text,
+ const gnutls_datum_t * prehash,
+ const gnutls_datum_t * signature,
+ gnutls_pk_params_st * params)
+{
+ gnutls_mac_algorithm_t hash = GNUTLS_MAC_UNKNOWN;
+ int ret;
+ opaque digest[MAX_HASH_SIZE], md[MAX_HASH_SIZE], *cmp;
+ int digest_size;
+ digest_hd_st hd;
+ gnutls_datum_t decrypted;
+
+ ret =
+ _gnutls_pkcs1_rsa_decrypt (&decrypted, signature, params, 1);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ /* decrypted is a BER encoded data of type DigestInfo
+ */
+
+ digest_size = sizeof (digest);
+ if ((ret =
+ decode_ber_digest_info (&decrypted, &hash, digest, &digest_size)) != 0)
+ {
+ gnutls_assert ();
+ _gnutls_free_datum (&decrypted);
+ return ret;
+ }
+
+ _gnutls_free_datum (&decrypted);
+
+ if (digest_size != _gnutls_hash_get_algo_len (hash))
+ {
+ gnutls_assert ();
+ return GNUTLS_E_ASN1_GENERIC_ERROR;
+ }
+
+ if (prehash && prehash->data && prehash->size == digest_size)
+ {
+ cmp = prehash->data;
+ }
+ else
+ {
+ if (!text)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+
+ ret = _gnutls_hash_init (&hd, hash);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ _gnutls_hash (&hd, text->data, text->size);
+ _gnutls_hash_deinit (&hd, md);
+
+ cmp = md;
+ }
+
+ if (memcmp (cmp, digest, digest_size) != 0)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+ }
+
+ return 0;
+}
+
+/* Hashes input data and verifies a signature.
+ */
+static int
+dsa_verify_hashed_data (const gnutls_datum_t * hash,
+ const gnutls_datum_t * signature,
+ gnutls_pk_algorithm_t pk,
+ gnutls_pk_params_st* params)
+{
+ gnutls_datum_t digest;
+ gnutls_digest_algorithm_t algo;
+ int hash_len;
+
+ algo = _gnutls_dsa_q_to_hash (pk, params, &hash_len);
+
+ /* SHA1 or better allowed */
+ if (!hash->data || hash->size < hash_len)
+ {
+ gnutls_assert();
+ _gnutls_debug_log("Hash size (%d) does not correspond to hash %s(%d) or better.\n", (int)hash->size, gnutls_mac_get_name(algo), hash_len);
+
+ if (hash->size != 20) /* SHA1 is allowed */
+ return gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
+ }
+
+ digest.data = hash->data;
+ digest.size = hash->size;
+
+ return _gnutls_pk_verify (pk, &digest, signature, params);
+}
+
+static int
+dsa_verify_data (gnutls_pk_algorithm_t pk,
+ gnutls_digest_algorithm_t algo,
+ const gnutls_datum_t * data,
+ const gnutls_datum_t * signature,
+ gnutls_pk_params_st* params)
+{
+ int ret;
+ opaque _digest[MAX_HASH_SIZE];
+ gnutls_datum_t digest;
+ digest_hd_st hd;
+
+ if (algo == GNUTLS_DIG_UNKNOWN)
+ algo = _gnutls_dsa_q_to_hash (pk, params, NULL);
+
+ ret = _gnutls_hash_init (&hd, algo);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ _gnutls_hash (&hd, data->data, data->size);
+ _gnutls_hash_deinit (&hd, _digest);
+
+ digest.data = _digest;
+ digest.size = _gnutls_hash_get_algo_len(algo);
+
+ return _gnutls_pk_verify (pk, &digest, signature, params);
+}
+
+/* Verifies the signature data, and returns GNUTLS_E_PK_SIG_VERIFY_FAILED if
+ * not verified, or 1 otherwise.
+ */
+int
+pubkey_verify_hashed_data (gnutls_pk_algorithm_t pk,
+ const gnutls_datum_t * hash,
+ const gnutls_datum_t * signature,
+ gnutls_pk_params_st * issuer_params)
+{
+
+ switch (pk)
+ {
+ case GNUTLS_PK_RSA:
+
+ if (_pkcs1_rsa_verify_sig
+ (NULL, hash, signature, issuer_params) != 0)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+ }
+
+ return 1;
+ break;
+
+ case GNUTLS_PK_ECC:
+ case GNUTLS_PK_DSA:
+ if (dsa_verify_hashed_data(hash, signature, pk, issuer_params) != 0)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+ }
+
+ return 1;
+ break;
+ default:
+ gnutls_assert ();
+ return GNUTLS_E_INTERNAL_ERROR;
+
+ }
+}
+
+/* Verifies the signature data, and returns GNUTLS_E_PK_SIG_VERIFY_FAILED if
+ * not verified, or 1 otherwise.
+ */
+int
+pubkey_verify_data (gnutls_pk_algorithm_t pk,
+ gnutls_digest_algorithm_t algo,
+ const gnutls_datum_t * data,
+ const gnutls_datum_t * signature,
+ gnutls_pk_params_st * issuer_params)
+{
+
+ switch (pk)
+ {
+ case GNUTLS_PK_RSA:
+
+ if (_pkcs1_rsa_verify_sig
+ (data, NULL, signature, issuer_params) != 0)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+ }
+
+ return 1;
+ break;
+
+ case GNUTLS_PK_ECC:
+ case GNUTLS_PK_DSA:
+ if (dsa_verify_data(pk, algo, data, signature, issuer_params) != 0)
+ {
+ gnutls_assert ();
+ return GNUTLS_E_PK_SIG_VERIFY_FAILED;
+ }
+
+ return 1;
+ break;
+ default:
+ gnutls_assert ();
+ return GNUTLS_E_INTERNAL_ERROR;
+
+ }
+}
+
+gnutls_digest_algorithm_t
+_gnutls_dsa_q_to_hash (gnutls_pk_algorithm_t algo, const gnutls_pk_params_st* params, int* hash_len)
+{
+ int bits = 0;
+
+ if (algo == GNUTLS_PK_DSA)
+ bits = _gnutls_mpi_get_nbits (params->params[1]);
+ else if (algo == GNUTLS_PK_ECC)
+ bits = gnutls_ecc_curve_get_size(params->flags)*8;
+
+ if (bits <= 160)
+ {
+ if (hash_len) *hash_len = 20;
+ return GNUTLS_DIG_SHA1;
+ }
+ else if (bits <= 192)
+ {
+ if (hash_len) *hash_len = 24;
+ return GNUTLS_DIG_SHA256;
+ }
+ else if (bits <= 224)
+ {
+ if (hash_len) *hash_len = 28;
+ return GNUTLS_DIG_SHA256;
+ }
+ else if (bits <= 256)
+ {
+ if (hash_len) *hash_len = 32;
+ return GNUTLS_DIG_SHA256;
+ }
+ else if (bits <= 384)
+ {
+ if (hash_len) *hash_len = 48;
+ return GNUTLS_DIG_SHA384;
+ }
+ else
+ {
+ if (hash_len) *hash_len = 64;
+ return GNUTLS_DIG_SHA512;
+ }
+}
diff --git a/lib/gnutls_sig.c b/lib/gnutls_sig.c
index b93aa40a8a..db8a071d22 100644
--- a/lib/gnutls_sig.c
+++ b/lib/gnutls_sig.c
@@ -48,6 +48,11 @@ sign_tls_hash (gnutls_session_t session, gnutls_digest_algorithm_t hash_algo,
const gnutls_datum_t * hash_concat,
gnutls_datum_t * signature);
+static int
+encode_ber_digest_info (gnutls_digest_algorithm_t hash,
+ const gnutls_datum_t * digest,
+ gnutls_datum_t * output);
+
/* While this is currently equal to the length of RSA/SHA512
* signature, it should also be sufficient for DSS signature and any
* other RSA signatures including one with the old MD5/SHA1-combined
@@ -732,6 +737,120 @@ cleanup:
return ret;
}
+
+/*
+ * This function will do RSA PKCS #1 1.5 encoding
+ * on the given digest. The given digest must be allocated
+ * and will be freed if replacement is required.
+ */
+int
+pk_prepare_hash (gnutls_pk_algorithm_t pk,
+ gnutls_digest_algorithm_t hash, gnutls_datum_t * digest)
+{
+ int ret;
+ gnutls_datum_t old_digest = { digest->data, digest->size };
+
+ switch (pk)
+ {
+ case GNUTLS_PK_RSA:
+ /* Encode the digest as a DigestInfo
+ */
+ if ((ret = encode_ber_digest_info (hash, &old_digest, digest)) != 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ _gnutls_free_datum (&old_digest);
+ break;
+ case GNUTLS_PK_DSA:
+ case GNUTLS_PK_ECC:
+ break;
+ default:
+ gnutls_assert ();
+ return GNUTLS_E_UNIMPLEMENTED_FEATURE;
+ }
+
+ return 0;
+}
+
+/* Reads the digest information.
+ * we use DER here, although we should use BER. It works fine
+ * anyway.
+ */
+int
+decode_ber_digest_info (const gnutls_datum_t * info,
+ gnutls_mac_algorithm_t * hash,
+ opaque * digest, int *digest_size)
+{
+ ASN1_TYPE dinfo = ASN1_TYPE_EMPTY;
+ int result;
+ char str[1024];
+ int len;
+
+ if ((result = asn1_create_element (_gnutls_get_gnutls_asn (),
+ "GNUTLS.DigestInfo",
+ &dinfo)) != ASN1_SUCCESS)
+ {
+ gnutls_assert ();
+ return _gnutls_asn2err (result);
+ }
+
+ result = asn1_der_decoding (&dinfo, info->data, info->size, NULL);
+ if (result != ASN1_SUCCESS)
+ {
+ gnutls_assert ();
+ asn1_delete_structure (&dinfo);
+ return _gnutls_asn2err (result);
+ }
+
+ len = sizeof (str) - 1;
+ result = asn1_read_value (dinfo, "digestAlgorithm.algorithm", str, &len);
+ if (result != ASN1_SUCCESS)
+ {
+ gnutls_assert ();
+ asn1_delete_structure (&dinfo);
+ return _gnutls_asn2err (result);
+ }
+
+ *hash = _gnutls_x509_oid2mac_algorithm (str);
+
+ if (*hash == GNUTLS_MAC_UNKNOWN)
+ {
+
+ _gnutls_debug_log ("verify.c: HASH OID: %s\n", str);
+
+ gnutls_assert ();
+ asn1_delete_structure (&dinfo);
+ return GNUTLS_E_UNKNOWN_ALGORITHM;
+ }
+
+ len = sizeof (str) - 1;
+ result = asn1_read_value (dinfo, "digestAlgorithm.parameters", str, &len);
+ /* To avoid permitting garbage in the parameters field, either the
+ parameters field is not present, or it contains 0x05 0x00. */
+ if (!(result == ASN1_ELEMENT_NOT_FOUND ||
+ (result == ASN1_SUCCESS && len == ASN1_NULL_SIZE &&
+ memcmp (str, ASN1_NULL, ASN1_NULL_SIZE) == 0)))
+ {
+ gnutls_assert ();
+ asn1_delete_structure (&dinfo);
+ return GNUTLS_E_ASN1_GENERIC_ERROR;
+ }
+
+ result = asn1_read_value (dinfo, "digest", digest, digest_size);
+ if (result != ASN1_SUCCESS)
+ {
+ gnutls_assert ();
+ asn1_delete_structure (&dinfo);
+ return _gnutls_asn2err (result);
+ }
+
+ asn1_delete_structure (&dinfo);
+
+ return 0;
+}
+
/* Writes the digest information and the digest in a DER encoded
* structure. The digest info is allocated and stored into the info structure.
*/
@@ -818,39 +937,3 @@ encode_ber_digest_info (gnutls_digest_algorithm_t hash,
return 0;
}
-
-/*
- * This function will do RSA PKCS #1 1.5 encoding
- * on the given digest. The given digest must be allocated
- * and will be freed if replacement is required.
- */
-int
-pk_prepare_hash (gnutls_pk_algorithm_t pk,
- gnutls_digest_algorithm_t hash, gnutls_datum_t * digest)
-{
- int ret;
- gnutls_datum_t old_digest = { digest->data, digest->size };
-
- switch (pk)
- {
- case GNUTLS_PK_RSA:
- /* Encode the digest as a DigestInfo
- */
- if ((ret = encode_ber_digest_info (hash, &old_digest, digest)) != 0)
- {
- gnutls_assert ();
- return ret;
- }
-
- _gnutls_free_datum (&old_digest);
- break;
- case GNUTLS_PK_DSA:
- case GNUTLS_PK_ECC:
- break;
- default:
- gnutls_assert ();
- return GNUTLS_E_UNIMPLEMENTED_FEATURE;
- }
-
- return 0;
-}
diff --git a/lib/gnutls_sig.h b/lib/gnutls_sig.h
index 3b6957ac58..e3865b9a2a 100644
--- a/lib/gnutls_sig.h
+++ b/lib/gnutls_sig.h
@@ -67,4 +67,9 @@ _gnutls_privkey_sign_hash (gnutls_privkey_t key,
const gnutls_datum_t * hash,
gnutls_datum_t * signature);
+int
+decode_ber_digest_info (const gnutls_datum_t * info,
+ gnutls_mac_algorithm_t * hash,
+ opaque * digest, int *digest_size);
+
#endif
diff --git a/lib/includes/gnutls/abstract.h b/lib/includes/gnutls/abstract.h
index eec013cffc..078ab60897 100644
--- a/lib/includes/gnutls/abstract.h
+++ b/lib/includes/gnutls/abstract.h
@@ -95,6 +95,12 @@ int gnutls_pubkey_verify_data (gnutls_pubkey_t pubkey,
unsigned int flags,
const gnutls_datum_t * data,
const gnutls_datum_t * signature);
+int
+gnutls_pubkey_verify_data2 (gnutls_pubkey_t pubkey,
+ gnutls_sign_algorithm_t algo,
+ unsigned int flags,
+ const gnutls_datum_t * data,
+ const gnutls_datum_t * signature);
/* Private key operations */
diff --git a/lib/includes/gnutls/compat.h b/lib/includes/gnutls/compat.h
index e6b92776a7..fb88179c52 100644
--- a/lib/includes/gnutls/compat.h
+++ b/lib/includes/gnutls/compat.h
@@ -202,16 +202,6 @@ gnutls_sign_callback_get (gnutls_session_t session, void **userdata)
gnutls_datum_t * signature)
_GNUTLS_GCC_ATTR_DEPRECATED;
-
-/* Deprecated because verify_* functions are moved to public
- * keys. Check abstract.h for similar functionality.
- */
- int gnutls_x509_privkey_verify_data (gnutls_x509_privkey_t key,
- unsigned int flags,
- const gnutls_datum_t * data,
- const gnutls_datum_t * signature)
- _GNUTLS_GCC_ATTR_DEPRECATED;
-
/* we support the gnutls_privkey_sign_data() instead.
*/
int gnutls_x509_privkey_sign_data (gnutls_x509_privkey_t key,
diff --git a/lib/libgnutls.map b/lib/libgnutls.map
index 042b2f95cb..5c47ea3b57 100644
--- a/lib/libgnutls.map
+++ b/lib/libgnutls.map
@@ -508,7 +508,6 @@ GNUTLS_1_4
gnutls_x509_privkey_init;
gnutls_x509_privkey_sign_data;
gnutls_x509_privkey_sign_hash;
- gnutls_x509_privkey_verify_data;
gnutls_x509_rdn_get;
gnutls_x509_rdn_get_by_oid;
gnutls_x509_rdn_get_oid;
@@ -710,6 +709,7 @@ GNUTLS_3_0_0 {
gnutls_pubkey_get_pk_ecc_raw;
gnutls_x509_privkey_export_ecc_raw;
gnutls_x509_privkey_import_ecc_raw;
+ gnutls_pubkey_verify_data2;
} GNUTLS_2_12;
GNUTLS_PRIVATE {
diff --git a/lib/x509/common.c b/lib/x509/common.c
index 788b335030..16cd3e42f5 100644
--- a/lib/x509/common.c
+++ b/lib/x509/common.c
@@ -1344,6 +1344,43 @@ cleanup:
return result;
}
+/**
+ * gnutls_x509_crt_get_signature_algorithm:
+ * @cert: should contain a #gnutls_x509_crt_t structure
+ *
+ * This function will return a value of the #gnutls_sign_algorithm_t
+ * enumeration that is the signature algorithm that has been used to
+ * sign this certificate.
+ *
+ * Returns: a #gnutls_sign_algorithm_t value, or a negative value on
+ * error.
+ **/
+int
+_gnutls_x509_get_signature_algorithm (ASN1_TYPE src, const char *src_name)
+{
+ int result;
+ gnutls_datum_t sa;
+
+ /* Read the signature algorithm. Note that parameters are not
+ * read. They will be read from the issuer's certificate if needed.
+ */
+ result =
+ _gnutls_x509_read_value (src, src_name, &sa, 0);
+
+ if (result < 0)
+ {
+ gnutls_assert ();
+ return result;
+ }
+
+ result = _gnutls_x509_oid2sign_algorithm (sa.data);
+
+ _gnutls_free_datum (&sa);
+
+ return result;
+}
+
+
/* Reads the DER signature from the certificate and allocates space and
* returns them into signed_data.
*/
diff --git a/lib/x509/common.h b/lib/x509/common.h
index 0e96337e72..aebe338641 100644
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -128,6 +128,9 @@ int _gnutls_x509_decode_and_read_attribute (ASN1_TYPE asn1_struct,
int _gnutls_x509_get_pk_algorithm (ASN1_TYPE src, const char *src_name,
unsigned int *bits);
+int
+_gnutls_x509_get_signature_algorithm (ASN1_TYPE src, const char *src_name);
+
int _gnutls_x509_encode_and_copy_PKI_params (ASN1_TYPE dst,
const char *dst_name,
gnutls_pk_algorithm_t
@@ -140,8 +143,6 @@ int _gnutls_x509_get_signed_data (ASN1_TYPE src, const char *src_name,
int _gnutls_x509_get_signature (ASN1_TYPE src, const char *src_name,
gnutls_datum_t * signature);
-gnutls_digest_algorithm_t _gnutls_dsa_q_to_hash (gnutls_pk_algorithm_t algo,
- const gnutls_pk_params_st* params, int* hash_len);
int _gnutls_get_asn_mpis (ASN1_TYPE asn, const char *root,
gnutls_pk_params_st * params);
@@ -153,12 +154,6 @@ int _gnutls_get_key_id (gnutls_pk_algorithm_t pk, gnutls_pk_params_st*,
void _asnstr_append_name (char *name, size_t name_size, const char *part1,
const char *part2);
-int pubkey_verify_sig (const gnutls_datum_t * tbs,
- const gnutls_datum_t * hash,
- const gnutls_datum_t * signature,
- gnutls_pk_algorithm_t pk,
- gnutls_pk_params_st * issuer_params);
-
int
check_if_same_cert (gnutls_x509_crt_t cert1, gnutls_x509_crt_t cert2);
diff --git a/lib/x509/crq.c b/lib/x509/crq.c
index c61b3c4043..27dee3ed8e 100644
--- a/lib/x509/crq.c
+++ b/lib/x509/crq.c
@@ -2523,6 +2523,7 @@ gnutls_x509_crq_verify (gnutls_x509_crq_t crq,
gnutls_datum data = { NULL, 0 };
gnutls_datum signature = { NULL, 0 };
gnutls_pk_params_st params;
+gnutls_digest_algorithm_t algo;
int ret;
gnutls_pk_params_init(&params);
@@ -2534,6 +2535,15 @@ int ret;
gnutls_assert ();
return ret;
}
+
+ ret = _gnutls_x509_get_signature_algorithm(crq->crq, "signatureAlgorithm.algorithm");
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ goto cleanup;
+ }
+
+ algo = _gnutls_sign_get_hash_algorithm(ret);
ret = _gnutls_x509_get_signature (crq->crq, "signature", &signature);
if (ret < 0)
@@ -2550,9 +2560,8 @@ int ret;
goto cleanup;
}
- ret = pubkey_verify_sig(&data, NULL, &signature,
- gnutls_x509_crq_get_pk_algorithm (crq, NULL),
- &params);
+ ret = pubkey_verify_data(gnutls_x509_crq_get_pk_algorithm (crq, NULL), algo,
+ &data, &signature, &params);
if (ret < 0)
{
gnutls_assert ();
diff --git a/lib/x509/privkey.c b/lib/x509/privkey.c
index 08d89b5621..99f626f1d6 100644
--- a/lib/x509/privkey.c
+++ b/lib/x509/privkey.c
@@ -1641,45 +1641,6 @@ gnutls_x509_privkey_sign_data (gnutls_x509_privkey_t key,
/**
- * gnutls_x509_privkey_verify_data:
- * @key: Holds the key
- * @flags: should be 0 for now
- * @data: holds the data to be signed
- * @signature: contains the signature
- *
- * This function will verify the given signed data, using the
- * parameters in the private key.
- *
- * Returns: In case of a verification failure %GNUTLS_E_PK_SIG_VERIFY_FAILED
- * is returned, and a positive code on success.
- *
- * Deprecated: Use gnutls_pubkey_verify_data().
- */
-int
-gnutls_x509_privkey_verify_data (gnutls_x509_privkey_t key,
- unsigned int flags,
- const gnutls_datum_t * data,
- const gnutls_datum_t * signature)
-{
- int result;
-
- if (key == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_INVALID_REQUEST;
- }
-
- result = _gnutls_x509_privkey_verify_signature (data, signature, key);
- if (result < 0)
- {
- gnutls_assert ();
- return result;
- }
-
- return result;
-}
-
-/**
* gnutls_x509_privkey_fix:
* @key: Holds the key
*
diff --git a/lib/x509/verify.c b/lib/x509/verify.c
index 4ae9706776..2adb3dd5f6 100644
--- a/lib/x509/verify.c
+++ b/lib/x509/verify.c
@@ -369,7 +369,7 @@ _gnutls_verify_certificate2 (gnutls_x509_crt_t cert,
gnutls_datum_t cert_signed_data = { NULL, 0 };
gnutls_datum_t cert_signature = { NULL, 0 };
gnutls_x509_crt_t issuer = NULL;
- int issuer_version, result;
+ int issuer_version, result, hash_algo;
unsigned int out = 0;
if (output)
@@ -442,8 +442,17 @@ _gnutls_verify_certificate2 (gnutls_x509_crt_t cert,
goto cleanup;
}
+ result = _gnutls_x509_get_signature_algorithm(cert->cert, "signatureAlgorithm.algorithm");
+ if (result < 0)
+ {
+ gnutls_assert ();
+ goto cleanup;
+ }
+
+ hash_algo = _gnutls_sign_get_hash_algorithm(result);
+
result =
- _gnutls_x509_verify_signature (&cert_signed_data, NULL, &cert_signature,
+ _gnutls_x509_verify_data (hash_algo, &cert_signed_data, &cert_signature,
issuer);
if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED)
{
@@ -666,301 +675,6 @@ _gnutls_x509_verify_certificate (const gnutls_x509_crt_t * certificate_list,
return 0;
}
-
-/* Reads the digest information.
- * we use DER here, although we should use BER. It works fine
- * anyway.
- */
-static int
-decode_ber_digest_info (const gnutls_datum_t * info,
- gnutls_mac_algorithm_t * hash,
- opaque * digest, int *digest_size)
-{
- ASN1_TYPE dinfo = ASN1_TYPE_EMPTY;
- int result;
- char str[1024];
- int len;
-
- if ((result = asn1_create_element (_gnutls_get_gnutls_asn (),
- "GNUTLS.DigestInfo",
- &dinfo)) != ASN1_SUCCESS)
- {
- gnutls_assert ();
- return _gnutls_asn2err (result);
- }
-
- result = asn1_der_decoding (&dinfo, info->data, info->size, NULL);
- if (result != ASN1_SUCCESS)
- {
- gnutls_assert ();
- asn1_delete_structure (&dinfo);
- return _gnutls_asn2err (result);
- }
-
- len = sizeof (str) - 1;
- result = asn1_read_value (dinfo, "digestAlgorithm.algorithm", str, &len);
- if (result != ASN1_SUCCESS)
- {
- gnutls_assert ();
- asn1_delete_structure (&dinfo);
- return _gnutls_asn2err (result);
- }
-
- *hash = _gnutls_x509_oid2mac_algorithm (str);
-
- if (*hash == GNUTLS_MAC_UNKNOWN)
- {
-
- _gnutls_debug_log ("verify.c: HASH OID: %s\n", str);
-
- gnutls_assert ();
- asn1_delete_structure (&dinfo);
- return GNUTLS_E_UNKNOWN_ALGORITHM;
- }
-
- len = sizeof (str) - 1;
- result = asn1_read_value (dinfo, "digestAlgorithm.parameters", str, &len);
- /* To avoid permitting garbage in the parameters field, either the
- parameters field is not present, or it contains 0x05 0x00. */
- if (!(result == ASN1_ELEMENT_NOT_FOUND ||
- (result == ASN1_SUCCESS && len == ASN1_NULL_SIZE &&
- memcmp (str, ASN1_NULL, ASN1_NULL_SIZE) == 0)))
- {
- gnutls_assert ();
- asn1_delete_structure (&dinfo);
- return GNUTLS_E_ASN1_GENERIC_ERROR;
- }
-
- result = asn1_read_value (dinfo, "digest", digest, digest_size);
- if (result != ASN1_SUCCESS)
- {
- gnutls_assert ();
- asn1_delete_structure (&dinfo);
- return _gnutls_asn2err (result);
- }
-
- asn1_delete_structure (&dinfo);
-
- return 0;
-}
-
-/* if hash==MD5 then we do RSA-MD5
- * if hash==SHA then we do RSA-SHA
- * params[0] is modulus
- * params[1] is public key
- */
-static int
-_pkcs1_rsa_verify_sig (const gnutls_datum_t * text,
- const gnutls_datum_t * prehash,
- const gnutls_datum_t * signature,
- gnutls_pk_params_st * params)
-{
- gnutls_mac_algorithm_t hash = GNUTLS_MAC_UNKNOWN;
- int ret;
- opaque digest[MAX_HASH_SIZE], md[MAX_HASH_SIZE], *cmp;
- int digest_size;
- digest_hd_st hd;
- gnutls_datum_t decrypted;
-
- ret =
- _gnutls_pkcs1_rsa_decrypt (&decrypted, signature, params, 1);
- if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
-
- /* decrypted is a BER encoded data of type DigestInfo
- */
-
- digest_size = sizeof (digest);
- if ((ret =
- decode_ber_digest_info (&decrypted, &hash, digest, &digest_size)) != 0)
- {
- gnutls_assert ();
- _gnutls_free_datum (&decrypted);
- return ret;
- }
-
- _gnutls_free_datum (&decrypted);
-
- if (digest_size != _gnutls_hash_get_algo_len (hash))
- {
- gnutls_assert ();
- return GNUTLS_E_ASN1_GENERIC_ERROR;
- }
-
- if (prehash && prehash->data && prehash->size == digest_size)
- {
- cmp = prehash->data;
- }
- else
- {
- if (!text)
- {
- gnutls_assert ();
- return GNUTLS_E_INVALID_REQUEST;
- }
-
- ret = _gnutls_hash_init (&hd, hash);
- if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
-
- _gnutls_hash (&hd, text->data, text->size);
- _gnutls_hash_deinit (&hd, md);
-
- cmp = md;
- }
-
- if (memcmp (cmp, digest, digest_size) != 0)
- {
- gnutls_assert ();
- return GNUTLS_E_PK_SIG_VERIFY_FAILED;
- }
-
- return 0;
-}
-
-/* Hashes input data and verifies a signature.
- */
-static int
-dsa_verify_sig (const gnutls_datum_t * text,
- const gnutls_datum_t * hash,
- const gnutls_datum_t * signature,
- gnutls_pk_algorithm_t pk,
- gnutls_pk_params_st* params)
-{
- int ret;
- opaque _digest[MAX_HASH_SIZE];
- gnutls_datum_t digest;
- digest_hd_st hd;
- gnutls_digest_algorithm_t algo;
- int hash_len;
-
- algo = _gnutls_dsa_q_to_hash (pk, params, &hash_len);
- if (hash)
- {
- /* SHA1 or better allowed */
- if (!hash->data || hash->size < hash_len)
- {
- gnutls_assert();
- _gnutls_debug_log("Hash size (%d) does not correspond to hash %s(%d) or better.\n", (int)hash->size, gnutls_mac_get_name(algo), hash_len);
-
- if (hash->size != 20) /* SHA1 is allowed */
- return gnutls_assert_val(GNUTLS_E_PK_SIG_VERIFY_FAILED);
- }
-
- digest.data = hash->data;
- digest.size = hash->size;
- }
- else
- {
- ret = _gnutls_hash_init (&hd, algo);
- if (ret < 0)
- {
- gnutls_assert ();
- return ret;
- }
-
- _gnutls_hash (&hd, text->data, text->size);
- _gnutls_hash_deinit (&hd, _digest);
-
- digest.data = _digest;
- digest.size = _gnutls_hash_get_algo_len(algo);
- }
-
- ret = _gnutls_pk_verify (pk, &digest, signature, params);
-
- return ret;
-}
-
-/* Verifies the signature data, and returns GNUTLS_E_PK_SIG_VERIFY_FAILED if
- * not verified, or 1 otherwise.
- */
-int
-pubkey_verify_sig (const gnutls_datum_t * tbs,
- const gnutls_datum_t * hash,
- const gnutls_datum_t * signature,
- gnutls_pk_algorithm_t pk,
- gnutls_pk_params_st * issuer_params)
-{
-
- switch (pk)
- {
- case GNUTLS_PK_RSA:
-
- if (_pkcs1_rsa_verify_sig
- (tbs, hash, signature, issuer_params) != 0)
- {
- gnutls_assert ();
- return GNUTLS_E_PK_SIG_VERIFY_FAILED;
- }
-
- return 1;
- break;
-
- case GNUTLS_PK_ECC:
- case GNUTLS_PK_DSA:
- if (dsa_verify_sig(tbs, hash, signature, pk, issuer_params) != 0)
- {
- gnutls_assert ();
- return GNUTLS_E_PK_SIG_VERIFY_FAILED;
- }
-
- return 1;
- break;
- default:
- gnutls_assert ();
- return GNUTLS_E_INTERNAL_ERROR;
-
- }
-}
-
-gnutls_digest_algorithm_t
-_gnutls_dsa_q_to_hash (gnutls_pk_algorithm_t algo, const gnutls_pk_params_st* params, int* hash_len)
-{
- int bits = 0;
-
- if (algo == GNUTLS_PK_DSA)
- bits = _gnutls_mpi_get_nbits (params->params[1]);
- else if (algo == GNUTLS_PK_ECC)
- bits = gnutls_ecc_curve_get_size(params->flags)*8;
-
- if (bits <= 160)
- {
- if (hash_len) *hash_len = 20;
- return GNUTLS_DIG_SHA1;
- }
- else if (bits <= 192)
- {
- if (hash_len) *hash_len = 24;
- return GNUTLS_DIG_SHA256;
- }
- else if (bits <= 224)
- {
- if (hash_len) *hash_len = 28;
- return GNUTLS_DIG_SHA256;
- }
- else if (bits <= 256)
- {
- if (hash_len) *hash_len = 32;
- return GNUTLS_DIG_SHA256;
- }
- else if (bits <= 384)
- {
- if (hash_len) *hash_len = 48;
- return GNUTLS_DIG_SHA384;
- }
- else
- {
- if (hash_len) *hash_len = 64;
- return GNUTLS_DIG_SHA512;
- }
-}
-
/* This will return the appropriate hash to verify the given signature.
* If signature is NULL it will return an (or the) appropriate hash for
* the given parameters.
@@ -1040,14 +754,14 @@ cleanup:
/* verifies if the certificate is properly signed.
* returns GNUTLS_E_PK_VERIFY_SIG_FAILED on failure and 1 on success.
*
- * 'tbs' is the signed data
+ * 'data' is the signed data
* 'signature' is the signature!
*/
int
-_gnutls_x509_verify_signature (const gnutls_datum_t * tbs,
- const gnutls_datum_t * hash,
- const gnutls_datum_t * signature,
- gnutls_x509_crt_t issuer)
+_gnutls_x509_verify_data (gnutls_digest_algorithm_t algo,
+ const gnutls_datum_t * data,
+ const gnutls_datum_t * signature,
+ gnutls_x509_crt_t issuer)
{
gnutls_pk_params_st issuer_params;
int ret;
@@ -1063,9 +777,8 @@ _gnutls_x509_verify_signature (const gnutls_datum_t * tbs,
}
ret =
- pubkey_verify_sig (tbs, hash, signature,
- gnutls_x509_crt_get_pk_algorithm (issuer, NULL),
- &issuer_params);
+ pubkey_verify_data (gnutls_x509_crt_get_pk_algorithm (issuer, NULL), algo,
+ data, signature, &issuer_params);
if (ret < 0)
{
gnutls_assert ();
@@ -1078,26 +791,36 @@ _gnutls_x509_verify_signature (const gnutls_datum_t * tbs,
return ret;
}
-/* verifies if the certificate is properly signed.
- * returns GNUTLS_E_PK_VERIFY_SIG_FAILED on failure and 1 on success.
- *
- * 'tbs' is the signed data
- * 'signature' is the signature!
- */
int
-_gnutls_x509_privkey_verify_signature (const gnutls_datum_t * tbs,
- const gnutls_datum_t * signature,
- gnutls_x509_privkey_t issuer)
+_gnutls_x509_verify_hashed_data (const gnutls_datum_t * hash,
+ const gnutls_datum_t * signature,
+ gnutls_x509_crt_t issuer)
{
+ gnutls_pk_params_st issuer_params;
int ret;
- ret = pubkey_verify_sig (tbs, NULL, signature, issuer->pk_algorithm,
- &issuer->params);
+ /* Read the MPI parameters from the issuer's certificate.
+ */
+ ret =
+ _gnutls_x509_crt_get_mpis (issuer, &issuer_params);
+ if (ret < 0)
+ {
+ gnutls_assert ();
+ return ret;
+ }
+
+ ret =
+ pubkey_verify_hashed_data (gnutls_x509_crt_get_pk_algorithm (issuer, NULL),
+ hash, signature, &issuer_params);
if (ret < 0)
{
gnutls_assert ();
}
+ /* release all allocated MPIs
+ */
+ gnutls_pk_params_release(&issuer_params);
+
return ret;
}
@@ -1329,7 +1052,7 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl,
gnutls_datum_t crl_signed_data = { NULL, 0 };
gnutls_datum_t crl_signature = { NULL, 0 };
gnutls_x509_crt_t issuer;
- int result;
+ int result, hash_algo;
if (output)
*output = 0;
@@ -1381,8 +1104,17 @@ _gnutls_verify_crl2 (gnutls_x509_crl_t crl,
goto cleanup;
}
+ result = _gnutls_x509_get_signature_algorithm(crl->crl, "signatureAlgorithm.algorithm");
+ if (result < 0)
+ {
+ gnutls_assert ();
+ goto cleanup;
+ }
+
+ hash_algo = _gnutls_sign_get_hash_algorithm(result);
+
result =
- _gnutls_x509_verify_signature (&crl_signed_data, NULL, &crl_signature,
+ _gnutls_x509_verify_data (hash_algo, &crl_signed_data, &crl_signature,
issuer);
if (result == GNUTLS_E_PK_SIG_VERIFY_FAILED)
{
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
index 810057a049..582968f8e6 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -475,33 +475,7 @@ gnutls_x509_crt_get_dn_oid (gnutls_x509_crt_t cert,
int
gnutls_x509_crt_get_signature_algorithm (gnutls_x509_crt_t cert)
{
- int result;
- gnutls_datum_t sa;
-
- if (cert == NULL)
- {
- gnutls_assert ();
- return GNUTLS_E_INVALID_REQUEST;
- }
-
- /* Read the signature algorithm. Note that parameters are not
- * read. They will be read from the issuer's certificate if needed.
- */
- result =
- _gnutls_x509_read_value (cert->cert, "signatureAlgorithm.algorithm",
- &sa, 0);
-
- if (result < 0)
- {
- gnutls_assert ();
- return result;
- }
-
- result = _gnutls_x509_oid2sign_algorithm (sa.data);
-
- _gnutls_free_datum (&sa);
-
- return result;
+ return _gnutls_x509_get_signature_algorithm(cert->cert, "signatureAlgorithm.algorithm");
}
/**
@@ -2613,7 +2587,7 @@ gnutls_x509_crt_verify_data (gnutls_x509_crt_t crt, unsigned int flags,
return GNUTLS_E_INVALID_REQUEST;
}
- result = _gnutls_x509_verify_signature (data, NULL, signature, crt);
+ result = _gnutls_x509_verify_data (GNUTLS_DIG_UNKNOWN, data, signature, crt);
if (result < 0)
{
gnutls_assert ();
@@ -2651,7 +2625,7 @@ gnutls_x509_crt_verify_hash (gnutls_x509_crt_t crt, unsigned int flags,
return GNUTLS_E_INVALID_REQUEST;
}
- result = _gnutls_x509_verify_signature (NULL, hash, signature, crt);
+ result = _gnutls_x509_verify_hashed_data (hash, signature, crt);
if (result < 0)
{
gnutls_assert ();
diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
index 4df028befe..41ed58277b 100644
--- a/lib/x509/x509_int.h
+++ b/lib/x509/x509_int.h
@@ -182,13 +182,14 @@ _gnutls_x509_verify_algorithm (gnutls_mac_algorithm_t * hash,
gnutls_pk_algorithm_t pk,
gnutls_pk_params_st * issuer_params);
-int _gnutls_x509_verify_signature (const gnutls_datum_t * tbs,
- const gnutls_datum_t * hash,
- const gnutls_datum_t * signature,
- gnutls_x509_crt_t issuer);
-int _gnutls_x509_privkey_verify_signature (const gnutls_datum_t * tbs,
- const gnutls_datum_t * signature,
- gnutls_x509_privkey_t issuer);
+int _gnutls_x509_verify_data (gnutls_digest_algorithm_t algo,
+ const gnutls_datum_t * data,
+ const gnutls_datum_t * signature,
+ gnutls_x509_crt_t issuer);
+
+int _gnutls_x509_verify_hashed_data (const gnutls_datum_t * hash,
+ const gnutls_datum_t * signature,
+ gnutls_x509_crt_t issuer);
/* privkey.h */
ASN1_TYPE _gnutls_privkey_decode_pkcs1_rsa_key (const gnutls_datum_t *