Add x509_crt_verify_info()
diff --git a/ChangeLog b/ChangeLog
index ceb3985..8d7a810 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,7 @@
 Security
 
 Features
+   * Add x509_crt_verify_info() to display certificate verification results.
    * Add support for reading DH parameters with privateValueLength included
      (contributed by Daniel Kahn Gillmor).
    * Add support for bit strings in X.509 names (request by Fredrik Axelsson).
diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h
index 0dece06..cd01539 100644
--- a/include/polarssl/x509.h
+++ b/include/polarssl/x509.h
@@ -82,17 +82,21 @@
  * \name X509 Verify codes
  * \{
  */
+/* Reminder: update x509_crt_verify_strings[] in library/x509_crt.c */
 #define BADCERT_EXPIRED             0x01  /**< The certificate validity has expired. */
 #define BADCERT_REVOKED             0x02  /**< The certificate has been revoked (is on a CRL). */
 #define BADCERT_CN_MISMATCH         0x04  /**< The certificate Common Name (CN) does not match with the expected CN. */
 #define BADCERT_NOT_TRUSTED         0x08  /**< The certificate is not correctly signed by the trusted CA. */
-#define BADCRL_NOT_TRUSTED          0x10  /**< CRL is not correctly signed by the trusted CA. */
-#define BADCRL_EXPIRED              0x20  /**< CRL is expired. */
+#define BADCRL_NOT_TRUSTED          0x10  /**< The CRL is not correctly signed by the trusted CA. */
+#define BADCRL_EXPIRED              0x20  /**< The CRL is expired. */
 #define BADCERT_MISSING             0x40  /**< Certificate was missing. */
 #define BADCERT_SKIP_VERIFY         0x80  /**< Certificate verification was skipped. */
 #define BADCERT_OTHER             0x0100  /**< Other reason (can be used by verify callback) */
 #define BADCERT_FUTURE            0x0200  /**< The certificate validity starts in the future. */
 #define BADCRL_FUTURE             0x0400  /**< The CRL is from the future */
+#define BADCERT_KEY_USAGE         0x0800  /**< Usage does not match the keyUsage extension. */
+#define BADCERT_EXT_KEY_USAGE     0x1000  /**< Usage does not match the extendedKeyUsage extension. */
+#define BADCERT_NS_CERT_TYPE      0x2000  /**< Usage does not match the nsCertType extension. */
 /* \} name */
 /* \} addtogroup x509_module */
 
diff --git a/include/polarssl/x509_crt.h b/include/polarssl/x509_crt.h
index fe27007..24f7c7a 100644
--- a/include/polarssl/x509_crt.h
+++ b/include/polarssl/x509_crt.h
@@ -203,6 +203,21 @@
                    const x509_crt *crt );
 
 /**
+ * \brief          Returns an informational string about the
+ *                 verification status of a certificate.
+ *
+ * \param buf      Buffer to write to
+ * \param size     Maximum size of buffer
+ * \param prefix   A line prefix
+ * \param flags    Verification flags created by x509_crt_verify()
+ *
+ * \return         The amount of data written to the buffer, or -1 in
+ *                 case of an error.
+ */
+int x509_crt_verify_info( char *buf, size_t size, const char *prefix,
+                          int flags );
+
+/**
  * \brief          Verify the certificate signature
  *
  *                 The verify callback is a user-supplied callback that
@@ -219,6 +234,9 @@
  *                 are also returned to the application. The function should
  *                 return 0 for anything but a fatal error.
  *
+ * \note           In case verification failed, the results can be displayed
+ *                 using \c x509_crt_verify_info()
+ *
  * \param crt      a certificate to be verified
  * \param trust_ca the trusted CA chain
  * \param ca_crl   the CRL chain for trusted CA's
@@ -229,12 +247,8 @@
  * \param p_vrfy   verification parameter
  *
  * \return         0 if successful or POLARSSL_ERR_X509_SIG_VERIFY_FAILED,
- *                 in which case *flags will have one or more of
- *                 the following values set:
- *                      BADCERT_EXPIRED --
- *                      BADCERT_REVOKED --
- *                      BADCERT_CN_MISMATCH --
- *                      BADCERT_NOT_TRUSTED
+ *                 in which case *flags will have one or more BADCERT_XXX or
+ *                 BADCRL_XXX flags set,
  *                 or another error in case of a fatal error encountered
  *                 during the verification process.
  */
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 77008ed..4e4d806 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -1382,6 +1382,57 @@
     return( (int) ( size - n ) );
 }
 
+struct x509_crt_verify_string {
+    int code;
+    const char *string;
+};
+
+static const struct x509_crt_verify_string x509_crt_verify_strings[] = {
+    { BADCERT_EXPIRED,       "The certificate validity has expired" },
+    { BADCERT_REVOKED,       "The certificate has been revoked (is on a CRL)" },
+    { BADCERT_CN_MISMATCH,   "The certificate Common Name (CN) does not match with the expected CN" },
+    { BADCERT_NOT_TRUSTED,   "The certificate is not correctly signed by the trusted CA" },
+    { BADCRL_NOT_TRUSTED,    "The CRL is not correctly signed by the trusted CA" },
+    { BADCRL_EXPIRED,        "The CRL is expired" },
+    { BADCERT_MISSING,       "Certificate was missing" },
+    { BADCERT_SKIP_VERIFY,   "Certificate verification was skipped" },
+    { BADCERT_OTHER,         "Other reason (can be used by verify callback)" },
+    { BADCERT_FUTURE,        "The certificate validity starts in the future" },
+    { BADCRL_FUTURE,         "The CRL is from the future" },
+    { BADCERT_KEY_USAGE,     "Usage does not match the keyUsage extension" },
+    { BADCERT_EXT_KEY_USAGE, "Usage does not match the extendedKeyUsage extension" },
+    { BADCERT_NS_CERT_TYPE,  "Usage does not match the nsCertType extension" },
+    { 0, NULL }
+};
+
+int x509_crt_verify_info( char *buf, size_t size, const char *prefix,
+                          int flags )
+{
+    int ret;
+    const struct x509_crt_verify_string *cur;
+    char *p = buf;
+    size_t n = size;
+
+    for( cur = x509_crt_verify_strings; cur->string != NULL ; cur++ )
+    {
+        if( ( flags & cur->code ) == 0 )
+            continue;
+
+        ret = polarssl_snprintf( p, n, "%s%s\n", prefix, cur->string );
+        SAFE_SNPRINTF();
+        flags ^= cur->code;
+    }
+
+    if( flags != 0 )
+    {
+        ret = polarssl_snprintf( p, n, "%sUnknown reason "
+                                       "(this should not happen)\n", prefix );
+        SAFE_SNPRINTF();
+    }
+
+    return( (int) ( size - n ) );
+}
+
 #if defined(POLARSSL_X509_CHECK_KEY_USAGE)
 int x509_crt_check_key_usage( const x509_crt *crt, int usage )
 {
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 491f14e..47eef41 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -262,6 +262,27 @@
 depends_on:POLARSSL_PEM_PARSE_C:POLARSSL_X509_RSASSA_PSS_SUPPORT:POLARSSL_SHA512_C
 x509_csr_info:"data_files/server9.req.sha512":"CSR version   \: 1\nsubject name  \: C=NL, O=PolarSSL, CN=localhost\nsigned using  \: RSASSA-PSS (SHA512, MGF1-SHA512, 0x3E)\nRSA key size  \: 1024 bits\n"
 
+X509 Verify Information: empty
+x509_verify_info:0:"":""
+
+X509 Verify Information: one issue
+x509_verify_info:BADCERT_MISSING:"":"Certificate was missing\n"
+
+X509 Verify Information: two issues
+x509_verify_info:BADCERT_EXPIRED | BADCRL_EXPIRED:"":"The certificate validity has expired\nThe CRL is expired\n"
+
+X509 Verify Information: two issues, one unknown
+x509_verify_info:BADCERT_OTHER | 0x8000:"":"Other reason (can be used by verify callback)\nUnknown reason (this should not happen)\n"
+
+X509 Verify Information: empty, with prefix
+x509_verify_info:0:"  ! ":""
+
+X509 Verify Information: one issue, with prefix
+x509_verify_info:BADCERT_MISSING:"  ! ":"  ! Certificate was missing\n"
+
+X509 Verify Information: two issues, with prefix
+x509_verify_info:BADCERT_EXPIRED | BADCRL_EXPIRED:"  ! ":"  ! The certificate validity has expired\n  ! The CRL is expired\n"
+
 X509 Get Distinguished Name #1
 depends_on:POLARSSL_PEM_PARSE_C:POLARSSL_RSA_C
 x509_dn_gets:"data_files/server1.crt":"subject":"C=NL, O=PolarSSL, CN=PolarSSL Server 1"
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index 6959484..ab397e5 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -102,6 +102,22 @@
 }
 /* END_CASE */
 
+/* BEGIN_CASE depends_on:POLARSSL_X509_CRT_PARSE_C */
+void x509_verify_info( int flags, char *prefix, char *result_str )
+{
+    char buf[2000];
+    int res;
+
+    memset( buf, 0, sizeof( buf ) );
+
+    res = x509_crt_verify_info( buf, sizeof( buf ), prefix, flags );
+
+    TEST_ASSERT( res >= 0 );
+
+    TEST_ASSERT( strcmp( buf, result_str ) == 0 );
+}
+/* END_CASE */
+
 /* BEGIN_CASE depends_on:POLARSSL_FS_IO:POLARSSL_X509_CRT_PARSE_C:POLARSSL_X509_CRL_PARSE_C */
 void x509_verify( char *crt_file, char *ca_file, char *crl_file,
                   char *cn_name_str, int result, int flags_result,