Merge pull request #3337 from ronald-cron-arm/include_directories

CMake build system: Declare include directories at the target level.
diff --git a/ChangeLog.d/bugfix_PR3422.txt b/ChangeLog.d/bugfix_PR3422.txt
new file mode 100644
index 0000000..dfe152c
--- /dev/null
+++ b/ChangeLog.d/bugfix_PR3422.txt
@@ -0,0 +1,2 @@
+Bugfix
+   * Fix building library/net_sockets.c and the ssl_mail_client program on NetBSD. Contributed by Nia Alarie in #3422.
diff --git a/ChangeLog.d/pass-unsupported-policies-to-callback.txt b/ChangeLog.d/pass-unsupported-policies-to-callback.txt
new file mode 100644
index 0000000..d139b4c
--- /dev/null
+++ b/ChangeLog.d/pass-unsupported-policies-to-callback.txt
@@ -0,0 +1,4 @@
+Features
+   * Pass the "certificate policies" extension to the callback supplied to
+     mbedtls_x509_crt_parse_der_with_ext_cb() if it contains unsupported
+     policies (#3419).
diff --git a/ChangeLog.d/sysctl-arnd-support.txt b/ChangeLog.d/sysctl-arnd-support.txt
new file mode 100644
index 0000000..14ad674
--- /dev/null
+++ b/ChangeLog.d/sysctl-arnd-support.txt
@@ -0,0 +1,2 @@
+Features
+   * Added support to entropy_poll for the kern.arandom syscall supported on some BSD systems. Contributed by Nia Alarie in #3423.
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index 9a9b397..ab0d0cd 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -308,7 +308,11 @@
  *
  *                 Callbacks of this type are passed to and used by the
  *                 mbedtls_x509_crt_parse_der_with_ext_cb() routine when
- *                 it encounters an unsupported extension.
+ *                 it encounters either an unsupported extension or a
+ *                 "certificate policies" extension containing any
+ *                 unsupported certificate policies.
+ *                 Future versions of the library may invoke the callback
+ *                 in other cases, if and when the need arises.
  *
  * \param p_ctx    An opaque context passed to the callback.
  * \param crt      The certificate being parsed.
@@ -360,7 +364,9 @@
  *                   mbedtls_x509_crt_parse_der(), and/or
  *                   mbedtls_x509_crt_parse_der_nocopy()
  *                   but it calls the callback with every unsupported
- *                   certificate extension.
+ *                   certificate extension and additionally the
+ *                   "certificate policies" extension if it contains any
+ *                   unsupported certificate policies.
  *                   The callback must return a negative error code if it
  *                   does not know how to handle such an extension.
  *                   When the callback fails to parse a critical extension
@@ -368,6 +374,8 @@
  *                   When the callback fails to parse a non critical extension
  *                   mbedtls_x509_crt_parse_der_with_ext_cb() simply skips
  *                   the extension and continues parsing.
+ *                   Future versions of the library may invoke the callback
+ *                   in other cases, if and when the need arises.
  *
  * \return           \c 0 if successful.
  * \return           A negative error code on failure.
diff --git a/library/entropy_poll.c b/library/entropy_poll.c
index 8b4a5af..dc62183 100644
--- a/library/entropy_poll.c
+++ b/library/entropy_poll.c
@@ -115,6 +115,41 @@
 #endif /* SYS_getrandom */
 #endif /* __linux__ || __midipix__ */
 
+/*
+ * Some BSD systems provide KERN_ARND.
+ * This is equivalent to reading from /dev/urandom, only it doesn't require an
+ * open file descriptor, and provides up to 256 bytes per call (basically the
+ * same as getentropy(), but with a longer history).
+ *
+ * Documentation: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7
+ */
+#if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(HAVE_GETRANDOM)
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#if defined(KERN_ARND)
+#define HAVE_SYSCTL_ARND
+
+static int sysctl_arnd_wrapper( unsigned char *buf, size_t buflen )
+{
+    int name[2];
+    size_t len;
+
+    name[0] = CTL_KERN;
+    name[1] = KERN_ARND;
+
+    while( buflen > 0 )
+    {
+        len = buflen > 256 ? 256 : buflen;
+        if( sysctl(name, 2, buf, &len, NULL, 0) == -1 )
+            return( -1 );
+        buflen -= len;
+        buf += len;
+    }
+    return( 0 );
+}
+#endif /* KERN_ARND */
+#endif /* __FreeBSD__ || __NetBSD__ */
+
 #include <stdio.h>
 
 int mbedtls_platform_entropy_poll( void *data,
@@ -139,6 +174,15 @@
     ((void) ret);
 #endif /* HAVE_GETRANDOM */
 
+#if defined(HAVE_SYSCTL_ARND)
+    ((void) file);
+    ((void) read_len);
+    if( sysctl_arnd_wrapper( output, len ) == -1 )
+        return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED );
+    *olen = len;
+    return( 0 );
+#else
+
     *olen = 0;
 
     file = fopen( "/dev/urandom", "rb" );
@@ -156,6 +200,7 @@
     *olen = len;
 
     return( 0 );
+#endif /* HAVE_SYSCTL_ARND */
 }
 #endif /* _WIN32 && !EFIX64 && !EFI32 */
 #endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */
diff --git a/library/net_sockets.c b/library/net_sockets.c
index 8258aea..b26e858 100644
--- a/library/net_sockets.c
+++ b/library/net_sockets.c
@@ -23,6 +23,7 @@
  * be set before config.h, which pulls in glibc's features.h indirectly.
  * Harmless on other platforms. */
 #define _POSIX_C_SOURCE 200112L
+#define _XOPEN_SOURCE 600 /* sockaddr_storage */
 
 #if !defined(MBEDTLS_CONFIG_FILE)
 #include "mbedtls/config.h"
@@ -322,7 +323,8 @@
     struct sockaddr_storage client_addr;
 
 #if defined(__socklen_t_defined) || defined(_SOCKLEN_T) ||  \
-    defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t)
+    defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t) || \
+    defined(socklen_t)
     socklen_t n = (socklen_t) sizeof( client_addr );
     socklen_t type_len = (socklen_t) sizeof( type );
 #else
diff --git a/library/x509_crt.c b/library/x509_crt.c
index ee3b48d..04822e8 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -894,7 +894,7 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     size_t len;
-    unsigned char *end_ext_data, *end_ext_octet;
+    unsigned char *end_ext_data, *start_ext_octet, *end_ext_octet;
 
     if( *p == end )
         return( 0 );
@@ -940,6 +940,7 @@
                 MBEDTLS_ASN1_OCTET_STRING ) ) != 0 )
             return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
 
+        start_ext_octet = *p;
         end_ext_octet = *p + len;
 
         if( end_ext_octet != end_ext_data )
@@ -1025,6 +1026,13 @@
             if( ( ret = x509_get_certificate_policies( p, end_ext_octet,
                     &crt->certificate_policies ) ) != 0 )
             {
+                /* Give the callback (if any) a chance to handle the extension
+                 * if it contains unsupported policies */
+                if( ret == MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE && cb != NULL &&
+                    cb( p_ctx, crt, &extn_oid, is_critical,
+                        start_ext_octet, end_ext_octet ) == 0 )
+                    break;
+
 #if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION)
                 if( is_critical )
                     return( ret );
diff --git a/programs/ssl/ssl_mail_client.c b/programs/ssl/ssl_mail_client.c
index 08ff025..b7458cd 100644
--- a/programs/ssl/ssl_mail_client.c
+++ b/programs/ssl/ssl_mail_client.c
@@ -23,6 +23,7 @@
  * be set before config.h, which pulls in glibc's features.h indirectly.
  * Harmless on other platforms. */
 #define _POSIX_C_SOURCE 200112L
+#define _XOPEN_SOURCE 600
 
 #if !defined(MBEDTLS_CONFIG_FILE)
 #include "mbedtls/config.h"
diff --git a/tests/git-scripts/pre-push.sh b/tests/git-scripts/pre-push.sh
index d3b4629..b9cdc0e 100755
--- a/tests/git-scripts/pre-push.sh
+++ b/tests/git-scripts/pre-push.sh
@@ -45,18 +45,4 @@
 
 set -eu
 
-run_test()
-{
-    TEST=$1
-    echo "running '$TEST'"
-    if ! `$TEST > /dev/null 2>&1`; then
-        echo "test '$TEST' failed"
-        return 1
-    fi
-}
-
-run_test ./tests/scripts/check-doxy-blocks.pl
-run_test ./tests/scripts/check-names.sh
-run_test ./tests/scripts/check-generated-files.sh
-run_test ./tests/scripts/check-files.py
-run_test ./tests/scripts/doxygen.sh
+tests/scripts/all.sh -q -k 'check_*'
diff --git a/tests/scripts/all.sh b/tests/scripts/all.sh
index 865c73d..01f5910 100755
--- a/tests/scripts/all.sh
+++ b/tests/scripts/all.sh
@@ -133,8 +133,17 @@
     append_outcome=0
     MEMORY=0
     FORCE=0
+    QUIET=0
     KEEP_GOING=0
 
+    # Seed value used with the --release-test option.
+    #
+    # See also RELEASE_SEED in basic-build-test.sh. Debugging is easier if
+    # both values are kept in sync. If you change the value here because it
+    # breaks some tests, you'll definitely want to change it in
+    # basic-build-test.sh as well.
+    RELEASE_SEED=1
+
     : ${MBEDTLS_TEST_OUTCOME_FILE=}
     : ${MBEDTLS_TEST_PLATFORM="$(uname -s | tr -c \\n0-9A-Za-z _)-$(uname -m | tr -c \\n0-9A-Za-z _)"}
     export MBEDTLS_TEST_OUTCOME_FILE
@@ -213,6 +222,7 @@
   --list-components     List components supported on this platform and exit.
 
 General options:
+  -q|--quiet            Only output component names, and errors if any.
   -f|--force            Force the tests to overwrite any modified files.
   -k|--keep-going       Run all tests and report errors at the end.
   -m|--memory           Additional optional memory tests.
@@ -228,11 +238,12 @@
      --no-force         Refuse to overwrite modified files (default).
      --no-keep-going    Stop at the first error (default).
      --no-memory        No additional memory tests (default).
+     --no-quiet         Print full ouput from components.
      --out-of-source-dir=<path>  Directory used for CMake out-of-source build tests.
      --outcome-file=<path>  File where test outcomes are written (not done if
                             empty; default: \$MBEDTLS_TEST_OUTCOME_FILE).
      --random-seed      Use a random seed value for randomized tests (default).
-  -r|--release-test     Run this script in release mode. This fixes the seed value to 1.
+  -r|--release-test     Run this script in release mode. This fixes the seed value to ${RELEASE_SEED}.
   -s|--seed             Integer seed value to use for this test run.
 
 Tool path options:
@@ -301,6 +312,11 @@
     else
         current_section="$1"
     fi
+
+    if [ $QUIET -eq 1 ]; then
+        return
+    fi
+
     echo ""
     echo "******************************************************************"
     echo "* $current_section "
@@ -376,13 +392,15 @@
             --no-force) FORCE=0;;
             --no-keep-going) KEEP_GOING=0;;
             --no-memory) MEMORY=0;;
+            --no-quiet) QUIET=0;;
             --openssl) shift; OPENSSL="$1";;
             --openssl-legacy) shift; OPENSSL_LEGACY="$1";;
             --openssl-next) shift; OPENSSL_NEXT="$1";;
             --outcome-file) shift; MBEDTLS_TEST_OUTCOME_FILE="$1";;
             --out-of-source-dir) shift; OUT_OF_SOURCE_DIR="$1";;
+            --quiet|-q) QUIET=1;;
             --random-seed) unset SEED;;
-            --release-test|-r) SEED=1;;
+            --release-test|-r) SEED=$RELEASE_SEED;;
             --seed|-s) shift; SEED="$1";;
             -*)
                 echo >&2 "Unknown option: $1"
@@ -462,7 +480,7 @@
             failure_summary="$failure_summary
 $text"
             failure_count=$((failure_count + 1))
-            echo "${start_red}^^^^$text^^^^${end_color}"
+            echo "${start_red}^^^^$text^^^^${end_color}" >&2
         fi
     }
     make () {
@@ -508,6 +526,24 @@
     ! "$@"
 }
 
+pre_setup_quiet_redirect () {
+    if [ $QUIET -ne 1 ]; then
+        redirect_out () {
+            "$@"
+        }
+        redirect_err () {
+            "$@"
+        }
+    else
+        redirect_out () {
+            "$@" >/dev/null
+        }
+        redirect_err () {
+            "$@" 2>/dev/null
+        }
+    fi
+}
+
 pre_prepare_outcome_file () {
     case "$MBEDTLS_TEST_OUTCOME_FILE" in
       [!/]*) MBEDTLS_TEST_OUTCOME_FILE="$PWD/$MBEDTLS_TEST_OUTCOME_FILE";;
@@ -518,6 +554,10 @@
 }
 
 pre_print_configuration () {
+    if [ $QUIET -eq 1 ]; then
+        return
+    fi
+
     msg "info: $0 configuration"
     echo "MEMORY: $MEMORY"
     echo "FORCE: $FORCE"
@@ -592,6 +632,11 @@
                         "$ARMC6_CC" "$ARMC6_AR" "$ARMC6_FROMELF";;
     esac
 
+    # past this point, no call to check_tool, only printing output
+    if [ $QUIET -eq 1 ]; then
+        return
+    fi
+
     msg "info: output_env.sh"
     case $RUN_COMPONENTS in
         *_armcc*)
@@ -657,7 +702,13 @@
 
 component_check_test_cases () {
     msg "Check: test case descriptions" # < 1s
-    record_status tests/scripts/check-test-cases.py
+    if [ $QUIET -eq 1 ]; then
+        opt='--quiet'
+    else
+        opt=''
+    fi
+    record_status tests/scripts/check-test-cases.py $opt
+    unset opt
 }
 
 component_check_doxygen_warnings () {
@@ -1911,7 +1962,10 @@
 
 component_check_generate_test_code () {
     msg "uint test: generate_test_code.py"
-    record_status ./tests/scripts/test_generate_test_code.py
+    # unittest writes out mundane stuff like number or tests run on stderr.
+    # Our convention is to reserve stderr for actual errors, and write
+    # harmless info on stdout so it can be suppress with --quiet.
+    record_status ./tests/scripts/test_generate_test_code.py 2>&1
 }
 
 ################################################################
@@ -1942,13 +1996,18 @@
     # Unconditionally create a seedfile that's sufficiently long.
     # Do this before each component, because a previous component may
     # have messed it up or shortened it.
-    dd if=/dev/urandom of=./tests/seedfile bs=64 count=1
+    redirect_err dd if=/dev/urandom of=./tests/seedfile bs=64 count=1
 
     # Run the component code.
-    "$@"
+    if [ $QUIET -eq 1 ]; then
+        # msg() is silenced, so just print the component name here
+        echo "${current_component#component_}"
+    fi
+    redirect_out "$@"
 
     # Restore the build tree to a clean state.
     cleanup
+    unset current_component
 }
 
 # Preliminary setup
@@ -1966,6 +2025,7 @@
         "$@"
     }
 fi
+pre_setup_quiet_redirect
 pre_prepare_outcome_file
 pre_print_configuration
 pre_check_tools
diff --git a/tests/scripts/basic-build-test.sh b/tests/scripts/basic-build-test.sh
index 4fb9247..83646f3 100755
--- a/tests/scripts/basic-build-test.sh
+++ b/tests/scripts/basic-build-test.sh
@@ -56,6 +56,14 @@
 : ${GNUTLS_LEGACY_CLI:="$GNUTLS_CLI"}
 : ${GNUTLS_LEGACY_SERV:="$GNUTLS_SERV"}
 
+# Used to make ssl-opt.sh deterministic.
+#
+# See also RELEASE_SEED in all.sh. Debugging is easier if both values are kept
+# in sync. If you change the value here because it breaks some tests, you'll
+# definitely want to change it in all.sh as well.
+: ${SEED:=1}
+export SEED
+
 # To avoid setting OpenSSL and GnuTLS for each call to compat.sh and ssl-opt.sh
 # we just export the variables they require
 export OPENSSL_CMD="$OPENSSL"
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 0ba3b2c..d5f538b 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -2032,6 +2032,22 @@
 depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
 x509parse_crt_cb:"308203353082021da00302010202104d3ebbb8a870f9c78c55a8a7e12fd516300d06092a864886f70d01010b05003010310e300c06035504030c0564756d6d79301e170d3230303432383137343234335a170d3230303632373137343234335a3010310e300c06035504030c0564756d6d7930820122300d06092a864886f70d01010105000382010f003082010a0282010100a51b75b3f7da2d60ea1b0fc077f0dbb2bbb6fe1b474028368af8dc2664672896efff171033b0aede0b323a89d5c6db4d517404bc97b65264e41b9e9e86a6f40ace652498d4b3b859544d1bacfd7f86325503eed046f517406545c0ffb5560f83446dedce0fcafcc41ac8495488a6aa912ae45192ef7e3efa20d0f7403b0baa62c7e2e5404c620c5793623132aa20f624f08d88fbf0985af39433f5a24d0b908e5219d8ba6a404d3ee8418203b62a40c8eb18837354d50281a6a2bf5012e505c419482787b7a81e5935613ceea0c6d93e86f76282b6aa406fb3a1796c56b32e8a22afc3f7a3c9daa8f0e2846ff0d50abfc862a52f6cf0aaece6066c860376f3ed0203010001a3818a308187300c0603551d13040530030101ff30130603551d110101ff04093007820564756d6d79301206082b0601050507011e0101000403040100300e0603551d0f0101ff040403020184301d0603551d0e04160414e6e451ec8d19d9677b2d272a9d73b939fa2d915a301f0603551d23041830168014e6e451ec8d19d9677b2d272a9d73b939fa2d915a300d06092a864886f70d01010b0500038201010056d06047b7f48683e2347ca726997d9700b4f2cf1d8bc0ef17addac8445d38ffd7f8079055ead878b6a74c8384d0e30150c8990aa74f59cda6ebcb49465d8991ffa16a4c927a26e4639d1875a3ac396c7455c7eda40dbe66054a03d27f961c15e86bd5b06db6b26572977bcda93453b6b6a88ef96b31996a7bd17323525b33050d28deec9c33a3f9765a11fb99d0e222bd39a6db3a788474c9ca347377688f837d42f5841667bffcbe6b473e6f229f286a0829963e591a99aa7f67e9d20c36ccd2ac84cb85b7a8b3396a6cbe59a573ffff726f373197c230de5c92a52c5bc87e29c20bdf6e89609764a60c649022aabd768f3557661b083ae00e6afc8a5bf2ed":"cert. version     \: 3\nserial number     \: 4D\:3E\:BB\:B8\:A8\:70\:F9\:C7\:8C\:55\:A8\:A7\:E1\:2F\:D5\:16\nissuer name       \: CN=dummy\nsubject name      \: CN=dummy\nissued  on        \: 2020-04-28 17\:42\:43\nexpires on        \: 2020-06-27 17\:42\:43\nsigned using      \: RSA with SHA-256\nRSA key size      \: 2048 bits\nbasic constraints \: CA=true\nsubject alt name  \:\n    dNSName \: dummy\nkey usage         \: Digital Signature, Key Cert Sign\n":0
 
+X509 CRT ASN1 (Unsupported critical policy recognized by callback)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
+x509parse_crt_cb:"3081b130819ba0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092a864886f70d010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa100a200a315301330110603551d20010101040730053003060101300d06092a864886f70d01010b0500030200ff":"cert. version     \: 3\nserial number     \: DE\:AD\:BE\:EF\nissuer name       \: ??=Test\nsubject name      \: ??=Test\nissued  on        \: 2009-01-01 00\:00\:00\nexpires on        \: 2009-12-31 23\:59\:59\nsigned using      \: RSA with SHA-256\nRSA key size      \: 128 bits\ncertificate policies \: ???\n":0
+
+X509 CRT ASN1 (Unsupported critical policy not recognized by callback)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
+x509parse_crt_cb:"3081b130819ba0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092a864886f70d010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa100a200a315301330110603551d20010101040730053003060100300d06092a864886f70d01010b0500030200ff":"":MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE
+
+X509 CRT ASN1 (Unsupported non critical policy recognized by callback)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
+x509parse_crt_cb:"3081b130819ba0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092a864886f70d010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa100a200a315301330110603551d20010100040730053003060101300d06092a864886f70d01010b0500030200ff":"cert. version     \: 3\nserial number     \: DE\:AD\:BE\:EF\nissuer name       \: ??=Test\nsubject name      \: ??=Test\nissued  on        \: 2009-01-01 00\:00\:00\nexpires on        \: 2009-12-31 23\:59\:59\nsigned using      \: RSA with SHA-256\nRSA key size      \: 128 bits\ncertificate policies \: ???\n":0
+
+X509 CRT ASN1 (Unsupported non critical policy not recognized by callback)
+depends_on:MBEDTLS_RSA_C:MBEDTLS_SHA256_C
+x509parse_crt_cb:"3081b130819ba0030201028204deadbeef300d06092a864886f70d01010b0500300c310a30080600130454657374301c170c303930313031303030303030170c303931323331323335393539300c310a30080600130454657374302a300d06092a864886f70d010101050003190030160210ffffffffffffffffffffffffffffffff0202ffffa100a200a315301330110603551d20010100040730053003060100300d06092a864886f70d01010b0500030200ff":"cert. version     \: 3\nserial number     \: DE\:AD\:BE\:EF\nissuer name       \: ??=Test\nsubject name      \: ??=Test\nissued  on        \: 2009-01-01 00\:00\:00\nexpires on        \: 2009-12-31 23\:59\:59\nsigned using      \: RSA with SHA-256\nRSA key size      \: 128 bits\ncertificate policies \: ???\n":0
+
 X509 CRL ASN1 (Incorrect first tag)
 x509parse_crl:"":"":MBEDTLS_ERR_X509_INVALID_FORMAT
 
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index 54e5156..9cac2ec 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -303,17 +303,92 @@
 }
 
 int parse_crt_ext_cb( void *p_ctx, mbedtls_x509_crt const *crt, mbedtls_x509_buf const *oid,
-                      int critical, const unsigned char *p, const unsigned char *end )
+                      int critical, const unsigned char *cp, const unsigned char *end )
 {
     ( void ) crt;
-    ( void ) p;
-    ( void ) end;
     ( void ) critical;
     mbedtls_x509_buf *new_oid = (mbedtls_x509_buf *)p_ctx;
-    if( new_oid == NULL || new_oid->tag != oid->tag || new_oid->len != oid->len ||
-        memcmp(new_oid->p, oid->p, oid->len) != 0 )
+    if( oid->tag == MBEDTLS_ASN1_OID &&
+        MBEDTLS_OID_CMP( MBEDTLS_OID_CERTIFICATE_POLICIES, oid ) == 0 )
+    {
+        /* Handle unknown certificate policy */
+        int ret, parse_ret = 0;
+        size_t len;
+        unsigned char **p = (unsigned char **)&cp;
+
+        /* Get main sequence tag */
+        ret = mbedtls_asn1_get_tag( p, end, &len,
+                                 MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE );
+        if( ret != 0 )
+            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+        if( *p + len != end )
+            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                    MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+        /*
+         * Cannot be an empty sequence.
+         */
+        if( len == 0 )
+            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                    MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+        while( *p < end )
+        {
+            const unsigned char *policy_end;
+
+            /*
+             * Get the policy sequence
+             */
+            if( ( ret = mbedtls_asn1_get_tag( p, end, &len,
+                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+                return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+            policy_end = *p + len;
+
+            if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len,
+                                              MBEDTLS_ASN1_OID ) ) != 0 )
+                return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+
+            /*
+             * Recognize exclusively the policy with OID 1
+             */
+            if( len != 1 || *p[0] != 1 )
+                parse_ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
+
+            *p += len;
+
+           /*
+            * If there is an optional qualifier, then *p < policy_end
+            * Check the Qualifier len to verify it doesn't exceed policy_end.
+            */
+            if( *p < policy_end )
+            {
+                if( ( ret = mbedtls_asn1_get_tag( p, policy_end, &len,
+                         MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 )
+                    return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret );
+                /*
+                 * Skip the optional policy qualifiers.
+                 */
+                *p += len;
+            }
+
+            if( *p != policy_end )
+                return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                        MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+        }
+
+        if( *p != end )
+            return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS +
+                    MBEDTLS_ERR_ASN1_LENGTH_MISMATCH );
+
+        return( parse_ret );
+    }
+    else if( new_oid != NULL && new_oid->tag == oid->tag && new_oid->len == oid->len &&
+             memcmp( new_oid->p, oid->p, oid->len ) == 0 )
+        return( 0 );
+    else
         return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG );
-    return( 0 );
 }
 #endif /* MBEDTLS_X509_CRT_PARSE_C */
 /* END_HEADER */