Add x509_crt_check_key_usage()
diff --git a/include/polarssl/config.h b/include/polarssl/config.h
index c2c2708..2def1ee 100644
--- a/include/polarssl/config.h
+++ b/include/polarssl/config.h
@@ -958,6 +958,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
  *
  * If set, the SSL/TLS module uses ZLIB to support compression and
diff --git a/include/polarssl/x509_crt.h b/include/polarssl/x509_crt.h
index e3c8b18..e3443d0 100644
--- a/include/polarssl/x509_crt.h
+++ b/include/polarssl/x509_crt.h
@@ -244,6 +244,26 @@
                      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 d9f25ed..6ab30e6 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1360,6 +1360,17 @@
     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 ef9a331..b1cf1c7 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -826,3 +826,28 @@
 
 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 effa4cc..a4b2cf3 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -316,6 +316,21 @@
 }
 /* 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()
 {