summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2004-07-31 07:59:41 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2004-07-31 07:59:41 +0000
commitd2e2d0736c4a7c8f3052cffbe0fa1a8b81239a6a (patch)
tree47f03b8a964a563ef8594da97abaa9936d8022e9
parent137d8c711053184dab90b83c98418016ae17eb48 (diff)
downloadgnutls-d2e2d0736c4a7c8f3052cffbe0fa1a8b81239a6a.tar.gz
Added some default limits in the verification of certificate
chains, to avoid denial of service attacks. Also added gnutls_certificate_set_verify_limits() to override them.
-rw-r--r--NEWS3
-rw-r--r--lib/auth_cert.h2
-rw-r--r--lib/gnutls.h.in.in3
-rw-r--r--lib/gnutls_cert.c86
-rw-r--r--lib/gnutls_errors.c1
-rw-r--r--lib/gnutls_errors_int.h1
-rw-r--r--lib/gnutls_int.h5
-rw-r--r--lib/gnutls_ui.c19
-rw-r--r--lib/gnutls_ui.h1
-rw-r--r--lib/gnutls_x509.c36
10 files changed, 136 insertions, 21 deletions
diff --git a/NEWS b/NEWS
index 22a70f60a3..d99109d90c 100644
--- a/NEWS
+++ b/NEWS
@@ -3,6 +3,9 @@ Version 1.0.17
latest (yet unreleased) draft. Unfortunately this breaks
compatibility with previous versions.
- Changed the makefiles to be more portable.
+- Added some default limits in the verification of certificate
+ chains, to avoid denial of service attacks. Also added
+ gnutls_certificate_set_verify_limits() to override them.
Version 1.0.16 (10/07/2004)
- Do not free the SRP (prime and generator) parameters obtained from the
diff --git a/lib/auth_cert.h b/lib/auth_cert.h
index a27dbffc92..2d4b6cc1eb 100644
--- a/lib/auth_cert.h
+++ b/lib/auth_cert.h
@@ -81,6 +81,8 @@ typedef struct {
unsigned int verify_flags; /* flags to be used at
* certificate verification.
*/
+ unsigned int verify_depth;
+ unsigned int verify_bits;
/* holds a sequence of the
* RDNs of the CAs above.
diff --git a/lib/gnutls.h.in.in b/lib/gnutls.h.in.in
index 114f348bda..41cccb244d 100644
--- a/lib/gnutls.h.in.in
+++ b/lib/gnutls.h.in.in
@@ -363,7 +363,8 @@ void gnutls_certificate_free_crls(gnutls_certificate_credentials sc);
void gnutls_certificate_set_dh_params(gnutls_certificate_credentials res, gnutls_dh_params);
void gnutls_certificate_set_rsa_export_params(gnutls_certificate_credentials res, gnutls_rsa_params rsa_params);
void gnutls_certificate_set_verify_flags(gnutls_certificate_credentials res, unsigned int flags);
-
+void gnutls_certificate_set_verify_limits(gnutls_certificate_credentials res, unsigned int max_bits,
+ unsigned int max_depth);
int gnutls_certificate_set_x509_trust_file( gnutls_certificate_credentials res, const char* CAFILE,
gnutls_x509_crt_fmt);
diff --git a/lib/gnutls_cert.c b/lib/gnutls_cert.c
index 5c1ca58869..81875677ad 100644
--- a/lib/gnutls_cert.c
+++ b/lib/gnutls_cert.c
@@ -227,6 +227,9 @@ int gnutls_certificate_allocate_credentials(gnutls_certificate_credentials * res
if (*res == NULL)
return GNUTLS_E_MEMORY_ERROR;
+
+ (*res)->verify_bits = DEFAULT_VERIFY_BITS;
+ (*res)->verify_depth = DEFAULT_VERIFY_DEPTH;
return 0;
}
@@ -482,6 +485,11 @@ int _gnutls_openpgp_cert_verify_peers(gnutls_session session)
return GNUTLS_E_NO_CERTIFICATE_FOUND;
}
+ if (info->ncerts > cred->verify_depth) {
+ gnutls_assert();
+ return GNUTLS_E_CONSTRAINT_ERROR;
+ }
+
/* generate a list of gnutls_certs based on the auth info
* raw certs.
*/
@@ -509,6 +517,59 @@ int _gnutls_openpgp_cert_verify_peers(gnutls_session session)
}
/**
+ * gnutls_certificate_verify_peers2 - This function returns the peer's certificate verification status
+ * @session: is a gnutls session
+ * @status: is the output of the verification
+ *
+ * This function will try to verify the peer's certificate and return its status (trusted, invalid etc.).
+ * The value of @status should be one or more of the gnutls_certificate_status_t
+ * enumerated elements bitwise or'd.
+ * However you must also check the peer's name in order to check if the verified certificate belongs to the
+ * actual peer.
+ *
+ * Returns a negative error code on error and zero on success.
+ *
+ * This is the same as gnutls_x509_verify_certificate().
+ *
+ **/
+int gnutls_certificate_verify_peers2(gnutls_session session, unsigned int *status)
+{
+ CERTIFICATE_AUTH_INFO info;
+ int ret;
+
+ CHECK_AUTH(GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST);
+
+ info = _gnutls_get_auth_info(session);
+ if (info == NULL) {
+ return GNUTLS_E_NO_CERTIFICATE_FOUND;
+ }
+
+ if (info->raw_certificate_list == NULL || info->ncerts == 0)
+ return GNUTLS_E_NO_CERTIFICATE_FOUND;
+
+ switch (gnutls_certificate_type_get(session)) {
+ case GNUTLS_CRT_X509: {
+ ret = _gnutls_x509_cert_verify_peers(session);
+ *status = ret;
+
+ if (ret < 0)
+ return ret;
+ return 0;
+ }
+ case GNUTLS_CRT_OPENPGP: {
+ ret = _gnutls_openpgp_cert_verify_peers(session);
+ *status = ret;
+
+ if (ret < 0)
+ return ret;
+ return 0;
+ }
+ default:
+ return GNUTLS_E_INVALID_REQUEST;
+ }
+}
+
+/**
* gnutls_certificate_verify_peers - This function returns the peer's certificate verification status
* @session: is a gnutls session
*
@@ -517,33 +578,20 @@ int _gnutls_openpgp_cert_verify_peers(gnutls_session session)
* actual peer.
*
* The return value should be one or more of the gnutls_certificate_status
- * enumerated elements bitwise or'd.
+ * enumerated elements bitwise or'd, or a negative error code on error.
*
* This is the same as gnutls_x509_verify_certificate().
*
**/
int gnutls_certificate_verify_peers(gnutls_session session)
{
- CERTIFICATE_AUTH_INFO info;
-
- CHECK_AUTH(GNUTLS_CRD_CERTIFICATE, GNUTLS_E_INVALID_REQUEST);
+unsigned int status;
+int ret;
- info = _gnutls_get_auth_info(session);
- if (info == NULL) {
- return GNUTLS_E_NO_CERTIFICATE_FOUND;
- }
+ ret = gnutls_certificate_verify_peers2( session, &status);
+ if (ret < 0) return ret;
- if (info->raw_certificate_list == NULL || info->ncerts == 0)
- return GNUTLS_E_NO_CERTIFICATE_FOUND;
-
- switch( gnutls_certificate_type_get( session)) {
- case GNUTLS_CRT_X509:
- return _gnutls_x509_cert_verify_peers( session);
- case GNUTLS_CRT_OPENPGP:
- return _gnutls_openpgp_cert_verify_peers( session);
- default:
- return GNUTLS_E_INVALID_REQUEST;
- }
+ return status;
}
/**
diff --git a/lib/gnutls_errors.c b/lib/gnutls_errors.c
index c68239e28c..734947204d 100644
--- a/lib/gnutls_errors.c
+++ b/lib/gnutls_errors.c
@@ -148,6 +148,7 @@ static gnutls_error_entry error_algorithms[] = {
ERROR_ENTRY("The PKCS structure's bag type is unknown.", GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE, 1),
ERROR_ENTRY("The given password contains invalid characters.", GNUTLS_E_INVALID_PASSWORD, 1),
ERROR_ENTRY("The Message Authentication Code verification failed.", GNUTLS_E_MAC_VERIFY_FAILED, 1),
+ ERROR_ENTRY("Some constraint limits were reached.", GNUTLS_E_CONSTRAINT_ERROR, 1),
{NULL, NULL, 0, 0}
};
diff --git a/lib/gnutls_errors_int.h b/lib/gnutls_errors_int.h
index 3f64c626d7..10f7e27f75 100644
--- a/lib/gnutls_errors_int.h
+++ b/lib/gnutls_errors_int.h
@@ -115,6 +115,7 @@
#define GNUTLS_E_UNKNOWN_PKCS_BAG_TYPE -98
#define GNUTLS_E_INVALID_PASSWORD -99
#define GNUTLS_E_MAC_VERIFY_FAILED -100 /* for PKCS #12 MAC */
+#define GNUTLS_E_CONSTRAINT_ERROR -101
#define GNUTLS_E_BASE64_ENCODING_ERROR -201
#define GNUTLS_E_INCOMPATIBLE_GCRYPT_LIBRARY -202
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index f14d7e5ced..65e072d4af 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -92,6 +92,11 @@ typedef void * gnutls_transport_ptr;
#define HANDSHAKE_HEADER_SIZE 4
+/* defaults for verification functions
+ */
+#define DEFAULT_VERIFY_DEPTH 5
+#define DEFAULT_VERIFY_BITS 8200
+
#include <gnutls_mem.h>
#include <gnutls_ui.h>
diff --git a/lib/gnutls_ui.c b/lib/gnutls_ui.c
index b19a4b8499..8a5708a1de 100644
--- a/lib/gnutls_ui.c
+++ b/lib/gnutls_ui.c
@@ -373,7 +373,6 @@ void gnutls_anon_set_params_function(gnutls_anon_server_credentials res,
res->params_func = func;
}
-
/**
* gnutls_certificate_set_verify_flags - This function will set the flags to be used at certificate verification
* @res: is a gnutls_certificate_credentials structure
@@ -389,6 +388,24 @@ void gnutls_certificate_set_verify_flags(gnutls_certificate_credentials res, uns
}
/**
+ * gnutls_certificate_set_verify_limits - This function will set the upper limits to be used at certificate verification
+ * @res: is a gnutls_certificate_credentials structure
+ * @max_bits: is the number of bits of an acceptable certificate (default 8200)
+ * @max_depth: is maximum depth of the verification of a certificate chain (default 5)
+ *
+ * This function will set some upper limits for the default verification function
+ * (gnutls_certificate_verify_peers()) to avoid denial of service attacks.
+ *
+ **/
+void gnutls_certificate_set_verify_limits(gnutls_certificate_credentials res, unsigned int max_bits,
+ unsigned int max_depth)
+{
+ res->verify_depth = max_depth;
+ res->verify_bits = max_bits;
+}
+
+
+/**
* gnutls_certificate_set_rsa_export_params - This function will set the RSA parameters for a server to use
* @res: is a gnutls_certificate_credentials structure
* @rsa_params: is a structure that holds temporary RSA parameters.
diff --git a/lib/gnutls_ui.h b/lib/gnutls_ui.h
index f30f5afae0..0d6f04224b 100644
--- a/lib/gnutls_ui.h
+++ b/lib/gnutls_ui.h
@@ -105,6 +105,7 @@ time_t gnutls_certificate_expiration_time_peers(gnutls_session session);
int gnutls_certificate_client_get_request_status(gnutls_session);
int gnutls_certificate_verify_peers(gnutls_session);
+int gnutls_certificate_verify_peers2(gnutls_session, unsigned int* status);
int gnutls_pem_base64_encode(const char *header, const gnutls_datum * data,
char *result, size_t * result_size);
diff --git a/lib/gnutls_x509.c b/lib/gnutls_x509.c
index 5d7d5484a3..437c945928 100644
--- a/lib/gnutls_x509.c
+++ b/lib/gnutls_x509.c
@@ -53,6 +53,29 @@
* some x509 certificate parsing functions.
*/
+/* Check if the number of bits of the key in the certificate
+ * is unacceptable.
+ */
+inline
+static int check_bits( gnutls_x509_crt crt, unsigned int max_bits)
+{
+int ret;
+unsigned int bits;
+
+ ret = gnutls_x509_crt_get_pk_algorithm( crt, &bits);
+ if (ret < 0) {
+ gnutls_assert();
+ return ret;
+ }
+
+ if ( bits > max_bits) {
+ gnutls_assert();
+ return GNUTLS_E_CONSTRAINT_ERROR;
+ }
+
+ return 0;
+}
+
#define CLEAR_CERTS for(x=0;x<peer_certificate_list_size;x++) { \
if (peer_certificate_list[x]) \
gnutls_x509_crt_deinit(peer_certificate_list[x]); \
@@ -93,6 +116,12 @@ int _gnutls_x509_cert_verify_peers(gnutls_session session)
if (info->raw_certificate_list == NULL || info->ncerts == 0)
return GNUTLS_E_NO_CERTIFICATE_FOUND;
+
+ if (info->ncerts > cred->verify_depth) {
+ gnutls_assert();
+ return GNUTLS_E_CONSTRAINT_ERROR;
+ }
+
/* generate a list of gnutls_certs based on the auth info
* raw certs.
@@ -122,6 +151,13 @@ int _gnutls_x509_cert_verify_peers(gnutls_session session)
CLEAR_CERTS;
return ret;
}
+
+ ret = check_bits( peer_certificate_list[i], cred->verify_bits);
+ if (ret < 0) {
+ gnutls_assert();
+ CLEAR_CERTS;
+ return ret;
+ }
}
/* Verify certificate