From 76fd75a3deb191906c071c1e2b2689d9e6d336da Mon Sep 17 00:00:00 2001
From: Paul Bakker
Date: Sun, 16 Jan 2011 21:12:10 +0000
Subject: [PATCH] - Improved certificate validation and validation against the
available CRLs
---
ChangeLog | 6 +-
library/x509parse.c | 172 +++++++++++++------------
tests/suites/test_suite_x509parse.data | 2 +-
3 files changed, 98 insertions(+), 82 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index bb15887b2..364f2a522 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -8,9 +8,11 @@ Note: Most of these features have been donated by Fox-IT
for integration with OpenVPN
* Added reading of DHM context from memory and file
* Added verification callback on certificate chain
- verification to allow external blacklisting.
+ verification to allow external blacklisting
* Improved X509 certificate parsing to include extended
- certificate fields, including Key Usage.
+ certificate fields, including Key Usage
+ * Improved certificate verification and verification
+ against the available CRLs
* Detection for DES weak keys and parity bits added
= Version 0.14.0 released on 2010-08-16
diff --git a/library/x509parse.c b/library/x509parse.c
index 2347bb574..6dae94304 100644
--- a/library/x509parse.c
+++ b/library/x509parse.c
@@ -2626,6 +2626,69 @@ static void x509_hash( const unsigned char *in, int len, int alg,
}
}
+/*
+ * Check that the given certificate is valid accoring to the CRL.
+ */
+static int x509parse_verifycrl(x509_cert *crt, x509_cert *ca,
+ x509_crl *crl_list)
+{
+ int flags = 0;
+ int hash_id;
+ unsigned char hash[64];
+
+ /*
+ * TODO: What happens if no CRL is present?
+ * Suggestion: Revocation state should be unknown if no CRL is present.
+ * For backwards compatibility this is not yet implemented.
+ */
+
+ while( ca != NULL && crl_list != NULL && crl_list->version != 0 )
+ {
+ if( crl_list->issuer_raw.len != ca->subject_raw.len ||
+ memcmp( crl_list->issuer_raw.p, ca->subject_raw.p,
+ crl_list->issuer_raw.len ) != 0 )
+ {
+ crl_list = crl_list->next;
+ continue;
+ }
+
+ /*
+ * Check if CRL is correctly signed by the trusted CA
+ */
+ hash_id = crl_list->sig_alg;
+
+ x509_hash( crl_list->tbs.p, crl_list->tbs.len, hash_id, hash );
+
+ if( !rsa_pkcs1_verify( &ca->rsa, RSA_PUBLIC, hash_id,
+ 0, hash, crl_list->sig.p ) == 0 )
+ {
+ /*
+ * CRL is not trusted
+ */
+ flags |= BADCRL_NOT_TRUSTED;
+ break;
+ }
+
+ /*
+ * Check for validity of CRL (Do not drop out)
+ */
+ if( x509parse_time_expired( &crl_list->next_update ) )
+ flags |= BADCRL_EXPIRED;
+
+ /*
+ * Check if certificate is revoked
+ */
+ if( x509parse_revoked(crt, crl_list) )
+ {
+ flags |= BADCERT_REVOKED;
+ break;
+ }
+
+ crl_list = crl_list->next;
+ }
+ return flags;
+}
+
/*
* Verify the certificate validity
*/
@@ -2639,7 +2702,7 @@ int x509parse_verify( x509_cert *crt,
int cn_len;
int hash_id;
int pathlen;
- x509_cert *cur;
+ x509_cert *parent;
x509_name *name;
unsigned char hash[64];
@@ -2667,26 +2730,22 @@ int x509parse_verify( x509_cert *crt,
*flags |= BADCERT_CN_MISMATCH;
}
- *flags |= BADCERT_NOT_TRUSTED;
-
/*
* Iterate upwards in the given cert chain,
* ignoring any upper cert with CA != TRUE.
*/
- cur = crt->next;
+ parent = crt->next;
pathlen = 1;
- while( cur != NULL && cur->version != 0 )
+ while( parent != NULL && parent->version != 0 )
{
- int verify_ok = 1;
-
- if( cur->ca_istrue == 0 ||
- crt->issuer_raw.len != cur->subject_raw.len ||
- memcmp( crt->issuer_raw.p, cur->subject_raw.p,
+ if( parent->ca_istrue == 0 ||
+ crt->issuer_raw.len != parent->subject_raw.len ||
+ memcmp( crt->issuer_raw.p, parent->subject_raw.p,
crt->issuer_raw.len ) != 0 )
{
- cur = cur->next;
+ parent = parent->next;
continue;
}
@@ -2694,28 +2753,35 @@ int x509parse_verify( x509_cert *crt,
x509_hash( crt->tbs.p, crt->tbs.len, hash_id, hash );
- if( rsa_pkcs1_verify( &cur->rsa, RSA_PUBLIC, hash_id,
- 0, hash, crt->sig.p ) != 0 )
- verify_ok = 0;
+ if( rsa_pkcs1_verify( &parent->rsa, RSA_PUBLIC, hash_id, 0, hash,
+ crt->sig.p ) != 0 )
+ *flags |= BADCERT_NOT_TRUSTED;
+
+ /* Check trusted CA's CRL for the given crt */
+ *flags |= x509parse_verifycrl(crt, parent, ca_crl);
/* crt is verified to be a child of the parent cur, call verify callback */
if( NULL != f_vrfy )
{
- if ( f_vrfy( p_vrfy, crt, pathlen-1, verify_ok ) != 0 )
+ if( f_vrfy( p_vrfy, crt, pathlen - 1, ( *flags == 0 ) ) != 0 )
return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED );
- } else if ( verify_ok == 0 ) {
- return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED );
+ else
+ *flags = 0;
}
+ else if( *flags != 0 )
+ return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED );
pathlen++;
- crt = cur;
- cur = crt->next;
+ crt = parent;
+ parent = crt->next;
}
/*
- * Atempt to validate topmost cert with our CA chain.
+ * Attempt to validate topmost cert with our CA chain.
*/
+ *flags |= BADCERT_NOT_TRUSTED;
+
while( trust_ca != NULL && trust_ca->version != 0 )
{
if( crt->issuer_raw.len != trust_ca->subject_raw.len ||
@@ -2747,71 +2813,19 @@ int x509parse_verify( x509_cert *crt,
trust_ca = trust_ca->next;
}
- /*
- * TODO: What happens if no CRL is present?
- * Suggestion: Revocation state should be unknown if no CRL is present.
- * For backwards compatibility this is not yet implemented.
- */
-
- /*
- * Check if the topmost certificate is revoked if the trusted CA is
- * determined.
- */
- while( trust_ca != NULL && ca_crl != NULL && ca_crl->version != 0 )
- {
- if( ca_crl->issuer_raw.len != trust_ca->subject_raw.len ||
- memcmp( ca_crl->issuer_raw.p, trust_ca->subject_raw.p,
- ca_crl->issuer_raw.len ) != 0 )
- {
- ca_crl = ca_crl->next;
- continue;
- }
-
- /*
- * Check if CRL is correctry signed by the trusted CA
- */
- hash_id = ca_crl->sig_alg;
-
- x509_hash( ca_crl->tbs.p, ca_crl->tbs.len, hash_id, hash );
-
- if( !rsa_pkcs1_verify( &trust_ca->rsa, RSA_PUBLIC, hash_id,
- 0, hash, ca_crl->sig.p ) == 0 )
- {
- /*
- * CRL is not trusted
- */
- *flags |= BADCRL_NOT_TRUSTED;
- break;
- }
-
- /*
- * Check for validity of CRL (Do not drop out)
- */
- if( x509parse_time_expired( &ca_crl->next_update ) )
- *flags |= BADCRL_EXPIRED;
-
- /*
- * Check if certificate is revoked
- */
- if( x509parse_revoked(crt, ca_crl) )
- {
- *flags |= BADCERT_REVOKED;
- break;
- }
-
- ca_crl = ca_crl->next;
- }
-
- if( *flags != 0 )
- return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED );
-
+ /* Check trusted CA's CRL for the given crt */
+ *flags |= x509parse_verifycrl( crt, trust_ca, ca_crl );
/* Verification succeeded, call callback on top cert */
if( NULL != f_vrfy )
{
- if ( f_vrfy(p_vrfy, crt, pathlen - 1, 1) != 0 )
+ if( f_vrfy(p_vrfy, crt, pathlen-1, ( *flags == 0 ) ) != 0 )
return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED );
+ else
+ *flags = 0;
}
+ else if( *flags != 0 )
+ return( POLARSSL_ERR_X509_CERT_VERIFY_FAILED );
return( 0 );
}
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index e130567e5..a156992cd 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -167,7 +167,7 @@ depends_on:POLARSSL_SHA4_C
x509_verify:"data_files/cert_sha512.crt":"data_files/test-ca.crt":"data_files/crl.pem":NULL:POLARSSL_ERR_X509_CERT_VERIFY_FAILED:0:&verify_none
X509 Certificate verification #20 (Not trusted Cert, allowing callback)
-x509_verify:"data_files/server2.crt":"data_files/server1.crt":"data_files/crl_expired.pem":NULL:POLARSSL_ERR_X509_CERT_VERIFY_FAILED:BADCERT_NOT_TRUSTED:&verify_all
+x509_verify:"data_files/server2.crt":"data_files/server1.crt":"data_files/crl_expired.pem":NULL:0:0:&verify_all
X509 Parse Selftest
depends_on:POLARSSL_MD5_C