summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/includes/gnutls/pkcs11.h8
-rw-r--r--lib/pkcs11.c14
-rw-r--r--lib/x509/common.c2
-rw-r--r--lib/x509/common.h6
-rw-r--r--lib/x509/crl.c2
-rw-r--r--lib/x509/verify.c54
-rw-r--r--lib/x509/x509.c12
-rw-r--r--lib/x509/x509_int.h1
8 files changed, 87 insertions, 12 deletions
diff --git a/lib/includes/gnutls/pkcs11.h b/lib/includes/gnutls/pkcs11.h
index da6cf8c4bd..8fd121dab6 100644
--- a/lib/includes/gnutls/pkcs11.h
+++ b/lib/includes/gnutls/pkcs11.h
@@ -101,9 +101,10 @@ void gnutls_pkcs11_obj_set_pin_function(gnutls_pkcs11_obj_t obj,
* @GNUTLS_PKCS11_OBJ_FLAG_MARK_NOT_PRIVATE: marked as not private.
* @GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_ANY: When retrieving an object, do not set any requirements.
* GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED: When retrieving an object, only retrieve the marked as trusted.
- * In gnutls_pkcs11_crt_is_known() it implies GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_COMPARE.
+ * In gnutls_pkcs11_crt_is_known() it implies %GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_COMPARE if %GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY is not given.
* @GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_DISTRUSTED: When retrieving an object, only retrieve the marked as distrusted.
- * @GNUTLS_PKCS11_OBJ_FLAG_COMPARE: When checking an object's presence, full compare it before returning any result.
+ * @GNUTLS_PKCS11_OBJ_FLAG_COMPARE: When checking an object's presence, fully compare it before returning any result.
+ * @GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY: When checking an object's presence, compare the key before returning any result.
* @GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE: The object must be present in a marked as trusted module.
* @GNUTLS_PKCS11_OBJ_FLAG_MARK_CA: Mark the object as a CA.
* @GNUTLS_PKCS11_OBJ_FLAG_MARK_KEY_WRAP: Mark the generated key pair as wrapping and unwrapping keys.
@@ -123,7 +124,8 @@ typedef enum gnutls_pkcs11_obj_flags {
GNUTLS_PKCS11_OBJ_FLAG_COMPARE = (1<<9),
GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE = (1<<10),
GNUTLS_PKCS11_OBJ_FLAG_MARK_CA = (1<<11),
- GNUTLS_PKCS11_OBJ_FLAG_MARK_KEY_WRAP = (1<<12)
+ GNUTLS_PKCS11_OBJ_FLAG_MARK_KEY_WRAP = (1<<12),
+ GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY = (1<<13)
} gnutls_pkcs11_obj_flags;
/**
diff --git a/lib/pkcs11.c b/lib/pkcs11.c
index 030d5f8d17..3be05b8979 100644
--- a/lib/pkcs11.c
+++ b/lib/pkcs11.c
@@ -3278,6 +3278,18 @@ find_cert_cb(struct pkcs11_session_info *sinfo,
}
}
+ if (priv->flags & GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY) {
+ if (priv->crt == NULL) {
+ gnutls_assert();
+ break;
+ }
+
+ if (_gnutls_check_if_same_key2(priv->crt, &data) == 0) {
+ /* doesn't match */
+ break;
+ }
+ }
+
found = 1;
break;
} else {
@@ -3479,7 +3491,7 @@ int gnutls_pkcs11_crt_is_known(const char *url, gnutls_x509_crt_t cert,
/* when looking for a trusted certificate, we always fully compare
* with the given */
- if (flags & GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED)
+ if (flags & GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED && !(flags & GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY))
flags |= GNUTLS_PKCS11_OBJ_FLAG_COMPARE;
priv.flags = flags;
diff --git a/lib/x509/common.c b/lib/x509/common.c
index ba8299fc37..83833d541a 100644
--- a/lib/x509/common.c
+++ b/lib/x509/common.c
@@ -1844,7 +1844,7 @@ int _gnutls_strdatum_to_buf(gnutls_datum_t * d, void *buf,
/* returns a constant string in @dn pointing to @raw */
int
-_gnutls_x509_get_raw_dn2(ASN1_TYPE c2, gnutls_datum_t * raw,
+_gnutls_x509_get_raw_field2(ASN1_TYPE c2, gnutls_datum_t * raw,
const char *whom, gnutls_datum_t * dn)
{
int result, len1;
diff --git a/lib/x509/common.h b/lib/x509/common.h
index 402d242bea..76ba54a123 100644
--- a/lib/x509/common.h
+++ b/lib/x509/common.h
@@ -172,10 +172,14 @@ void _asnstr_append_name(char *name, size_t name_size, const char *part1,
const char *part2);
int
-_gnutls_x509_get_raw_dn2(ASN1_TYPE c2, gnutls_datum_t * raw,
+_gnutls_x509_get_raw_field2(ASN1_TYPE c2, gnutls_datum_t * raw,
const char *whom, gnutls_datum_t * dn);
bool
+_gnutls_check_if_same_key2(gnutls_x509_crt_t cert1,
+ gnutls_datum_t * cert2bin);
+
+bool
_gnutls_check_if_same_cert(gnutls_x509_crt_t cert1,
gnutls_x509_crt_t cert2);
diff --git a/lib/x509/crl.c b/lib/x509/crl.c
index 28a5573459..63e20c2ff4 100644
--- a/lib/x509/crl.c
+++ b/lib/x509/crl.c
@@ -165,7 +165,7 @@ gnutls_x509_crl_import(gnutls_x509_crl_t crl,
goto cleanup;
}
- result = _gnutls_x509_get_raw_dn2(crl->crl, &crl->der,
+ result = _gnutls_x509_get_raw_field2(crl->crl, &crl->der,
"tbsCertList.issuer.rdnSequence",
&crl->raw_issuer_dn);
if (result < 0) {
diff --git a/lib/x509/verify.c b/lib/x509/verify.c
index 75381524fa..7f9831a6e9 100644
--- a/lib/x509/verify.c
+++ b/lib/x509/verify.c
@@ -39,7 +39,51 @@
#include <gnutls_pk.h>
#include <stdbool.h>
-/* Checks if two certs are identical. Return 1 on match. */
+/* Checks if two certs have the same name and the same key. Return 1 on match. */
+static bool
+_gnutls_check_if_same_key(gnutls_x509_crt_t cert1,
+ gnutls_x509_crt_t cert2)
+{
+ int ret;
+ bool result;
+
+ ret = _gnutls_is_same_dn(cert1, cert2);
+ if (ret == 0)
+ return 0;
+
+ if (cert1->raw_spki.size > 0 && (cert1->raw_spki.size == cert2->raw_spki.size) &&
+ (memcmp(cert1->raw_spki.data, cert2->raw_spki.data, cert1->raw_spki.size) == 0))
+ result = 1;
+ else
+ result = 0;
+
+ fail:
+ return result;
+}
+
+bool
+_gnutls_check_if_same_key2(gnutls_x509_crt_t cert1,
+ gnutls_datum_t * cert2bin)
+{
+ int ret;
+ gnutls_x509_crt_t cert2;
+
+ ret = gnutls_x509_crt_init(&cert2);
+ if (ret < 0)
+ return gnutls_assert_val(0);
+
+ ret = gnutls_x509_crt_import(cert2, cert2bin, GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ gnutls_x509_crt_deinit(cert2);
+ return gnutls_assert_val(0);
+ }
+
+ ret = _gnutls_check_if_same_key(cert1, cert2);
+
+ gnutls_x509_crt_deinit(cert2);
+ return ret;
+}
+
bool
_gnutls_check_if_same_cert(gnutls_x509_crt_t cert1,
gnutls_x509_crt_t cert2)
@@ -838,7 +882,11 @@ _gnutls_verify_crt_status(const gnutls_x509_crt_t * certificate_list,
int j;
for (j = 0; j < tcas_size; j++) {
- if (_gnutls_check_if_same_cert
+ /* we check for a certificate that may not be identical with the one
+ * sent by the client, but will have the same name and key. That is
+ * because it can happen that a CA certificate is upgraded from intermediate
+ * CA to self-signed CA at some point. */
+ if (_gnutls_check_if_same_key
(certificate_list[i], trusted_cas[j]) != 0) {
/* explicit time check for trusted CA that we remove from
* list. GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS
@@ -986,7 +1034,7 @@ _gnutls_pkcs11_verify_crt_status(const char* url,
for (; i < clist_size; i++) {
if (gnutls_pkcs11_crt_is_known (url, certificate_list[i],
GNUTLS_PKCS11_OBJ_FLAG_PRESENT_IN_TRUSTED_MODULE|
- GNUTLS_PKCS11_OBJ_FLAG_COMPARE|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED) != 0) {
+ GNUTLS_PKCS11_OBJ_FLAG_COMPARE_KEY|GNUTLS_PKCS11_OBJ_FLAG_RETRIEVE_TRUSTED) != 0) {
if (!(flags & GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS) &&
!(flags & GNUTLS_VERIFY_DISABLE_TIME_CHECKS)) {
diff --git a/lib/x509/x509.c b/lib/x509/x509.c
index 32052824f8..69bdf88e32 100644
--- a/lib/x509/x509.c
+++ b/lib/x509/x509.c
@@ -246,7 +246,7 @@ gnutls_x509_crt_import(gnutls_x509_crt_t cert,
goto cleanup;
}
- result = _gnutls_x509_get_raw_dn2(cert->cert, &cert->der,
+ result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der,
"tbsCertificate.issuer.rdnSequence",
&cert->raw_issuer_dn);
if (result < 0) {
@@ -254,7 +254,7 @@ gnutls_x509_crt_import(gnutls_x509_crt_t cert,
goto cleanup;
}
- result = _gnutls_x509_get_raw_dn2(cert->cert, &cert->der,
+ result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der,
"tbsCertificate.subject.rdnSequence",
&cert->raw_dn);
if (result < 0) {
@@ -262,6 +262,14 @@ gnutls_x509_crt_import(gnutls_x509_crt_t cert,
goto cleanup;
}
+ result = _gnutls_x509_get_raw_field2(cert->cert, &cert->der,
+ "tbsCertificate.subjectPublicKeyInfo",
+ &cert->raw_spki);
+ if (result < 0) {
+ gnutls_assert();
+ goto cleanup;
+ }
+
/* Since we do not want to disable any extension
*/
cert->use_extensions = 1;
diff --git a/lib/x509/x509_int.h b/lib/x509/x509_int.h
index 455701eaf6..9ae7064f34 100644
--- a/lib/x509/x509_int.h
+++ b/lib/x509/x509_int.h
@@ -70,6 +70,7 @@ typedef struct gnutls_x509_crt_int {
* get_raw_*_dn(). */
gnutls_datum_t raw_dn;
gnutls_datum_t raw_issuer_dn;
+ gnutls_datum_t raw_spki;
gnutls_datum_t der;
struct pin_info_st pin;