diff --git a/include/polarssl/config.h b/include/polarssl/config.h index c2c270881..2def1ee96 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -957,6 +957,20 @@ */ //#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION +/** + * \def POLARSSL_X509_CHECK_KEY_USAGE + * + * Enable verification of the keyUsage extension (CA and leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused + * (intermediate) CA and leaf certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip keyUsage checking for both CA and leaf certificates. + */ +#define POLARSSL_X509_CHECK_KEY_USAGE + /** * \def POLARSSL_ZLIB_SUPPORT * diff --git a/include/polarssl/x509_crt.h b/include/polarssl/x509_crt.h index e3c8b1877..e3443d016 100644 --- a/include/polarssl/x509_crt.h +++ b/include/polarssl/x509_crt.h @@ -244,6 +244,26 @@ int x509_crt_verify( x509_crt *crt, int (*f_vrfy)(void *, x509_crt *, int, int *), void *p_vrfy ); +#if defined(POLARSSL_X509_CHECK_KEY_USAGE) +/** + * \brief Check usage of certificate against keyUsage extension. + * + * \param crt Leaf certificate used. + * \param usage Intended usage(s) (eg KU_KEY_ENCIPHERMENT before using the + * certificate to perform an RSA key exchange). + * + * \return 0 is these uses of the certificate are allowed, + * POLARSSL_ERR_X509_BAD_INPUT_DATA if the keyUsage extenson + * is present but does not contain all the bits set in the + * usage argument. + * + * \note You should only call this function on leaf certificates, on + * (intermediate) CAs the keyUsage extension is automatically + * checked by \c x509_crt_verify(). + */ +int x509_crt_check_key_usage( const x509_crt *crt, int usage ); +#endif /* POLARSSL_X509_CHECK_KEY_USAGE) */ + #if defined(POLARSSL_X509_CRL_PARSE_C) /** * \brief Verify the certificate revocation status diff --git a/library/x509_crt.c b/library/x509_crt.c index d9f25edf1..6ab30e673 100644 --- a/library/x509_crt.c +++ b/library/x509_crt.c @@ -1360,6 +1360,17 @@ int x509_crt_info( char *buf, size_t size, const char *prefix, return( (int) ( size - n ) ); } +#if defined(POLARSSL_X509_CHECK_KEY_USAGE) +int x509_crt_check_key_usage( const x509_crt *crt, int usage ) +{ + if( ( crt->ext_types & EXT_KEY_USAGE ) != 0 && + ( crt->key_usage & usage ) != usage ) + return( POLARSSL_ERR_X509_BAD_INPUT_DATA ); + + return( 0 ); +} +#endif + #if defined(POLARSSL_X509_CRL_PARSE_C) /* * Return 1 if the certificate is revoked, or 0 otherwise. diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data index ef9a331f5..b1cf1c712 100644 --- a/tests/suites/test_suite_x509parse.data +++ b/tests/suites/test_suite_x509parse.data @@ -826,3 +826,28 @@ x509_oid_numstr:"2A864886F70D":"1.2.840.113549":15:14 X509 OID numstring #5 (arithmetic overflow) x509_oid_numstr:"2A8648F9F8F7F6F5F4F3F2F1F001":"":100:POLARSSL_ERR_OID_BUF_TOO_SMALL + +X509 crt keyUsage #1 (no extension, expected KU) +x509_check_key_usage:"data_files/server1.crt":KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT:0 + +X509 crt keyUsage #2 (no extension, suprising KU) +x509_check_key_usage:"data_files/server1.crt":KU_KEY_CERT_SIGN:0 + +X509 crt keyUsage #3 (extension present, no KU) +x509_check_key_usage:"data_files/server1.key_usage.crt":0:0 + +X509 crt keyUsage #4 (extension present, single KU present) +x509_check_key_usage:"data_files/server1.key_usage.crt":KU_DIGITAL_SIGNATURE:0 + +X509 crt keyUsage #5 (extension present, single KU absent) +x509_check_key_usage:"data_files/server1.key_usage.crt":KU_KEY_CERT_SIGN:POLARSSL_ERR_X509_BAD_INPUT_DATA + +X509 crt keyUsage #6 (extension present, combined KU present) +x509_check_key_usage:"data_files/server1.key_usage.crt":KU_DIGITAL_SIGNATURE|KU_KEY_ENCIPHERMENT:0 + +X509 crt keyUsage #7 (extension present, combined KU both absent) +x509_check_key_usage:"data_files/server1.key_usage.crt":KU_KEY_CERT_SIGN|KU_CRL_SIGN:POLARSSL_ERR_X509_BAD_INPUT_DATA + +X509 crt keyUsage #8 (extension present, combined KU one absent) +x509_check_key_usage:"data_files/server1.key_usage.crt":KU_KEY_ENCIPHERMENT|KU_KEY_AGREEMENT:POLARSSL_ERR_X509_BAD_INPUT_DATA + diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function index effa4cc30..a4b2cf3a4 100644 --- a/tests/suites/test_suite_x509parse.function +++ b/tests/suites/test_suite_x509parse.function @@ -316,6 +316,21 @@ void x509_oid_numstr( char *oid_str, char *numstr, int blen, int ret ) } /* END_CASE */ +/* BEGIN_CASE depends_on:POLARSSL_X509_CRT_PARSE_C */ +void x509_check_key_usage( char *crt_file, int usage, int ret ) +{ + x509_crt crt; + + x509_crt_init( &crt ); + + TEST_ASSERT( x509_crt_parse_file( &crt, crt_file ) == 0 ); + + TEST_ASSERT( x509_crt_check_key_usage( &crt, usage ) == ret ); + + x509_crt_free( &crt ); +} +/* END_CASE */ + /* BEGIN_CASE depends_on:POLARSSL_X509_CRT_PARSE_C:POLARSSL_SELF_TEST */ void x509_selftest() {