Merge pull request #3557 from Ouss4/assert

Ensure that only one definition of ASSERT is present
diff --git a/ChangeLog.d/netbsd-rand-arc4random_buf.txt b/ChangeLog.d/netbsd-rand-arc4random_buf.txt
new file mode 100644
index 0000000..8539d1f
--- /dev/null
+++ b/ChangeLog.d/netbsd-rand-arc4random_buf.txt
@@ -0,0 +1,3 @@
+Bugfix
+   * Use arc4random_buf on NetBSD instead of rand implementation with cyclical
+     lower bits. Fix contributed in #3540.
diff --git a/ChangeLog.d/x509-verify-non-dns-san.txt b/ChangeLog.d/x509-verify-non-dns-san.txt
new file mode 100644
index 0000000..0cd81b3
--- /dev/null
+++ b/ChangeLog.d/x509-verify-non-dns-san.txt
@@ -0,0 +1,11 @@
+Security
+   * Fix a vulnerability in the verification of X.509 certificates when
+     matching the expected common name (the cn argument of
+     mbedtls_x509_crt_verify()) with the actual certificate name: when the
+     subjecAltName extension is present, the expected name was compared to any
+     name in that extension regardless of its type. This means that an
+     attacker could for example impersonate a 4-bytes or 16-byte domain by
+     getting a certificate for the corresponding IPv4 or IPv6 (this would
+     require the attacker to control that IP address, though). Similar attacks
+     using other subjectAltName name types might be possible. Found and
+     reported by kFYatek in #3498.
diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h
index ab0d0cd..d24204d 100644
--- a/include/mbedtls/x509_crt.h
+++ b/include/mbedtls/x509_crt.h
@@ -585,8 +585,11 @@
  * \param crt      The certificate chain to be verified.
  * \param trust_ca The list of trusted CAs.
  * \param ca_crl   The list of CRLs for trusted CAs.
- * \param cn       The expected Common Name. This may be \c NULL if the
- *                 CN need not be verified.
+ * \param cn       The expected Common Name. This will be checked to be
+ *                 present in the certificate's subjectAltNames extension or,
+ *                 if this extension is absent, as a CN component in its
+ *                 Subject name. Currently only DNS names are supported. This
+ *                 may be \c NULL if the CN need not be verified.
  * \param flags    The address at which to store the result of the verification.
  *                 If the verification couldn't be completed, the flag value is
  *                 set to (uint32_t) -1.
diff --git a/library/rsa.c b/library/rsa.c
index 83ed3c9..c6c5956 100644
--- a/library/rsa.c
+++ b/library/rsa.c
@@ -53,7 +53,7 @@
 #include "mbedtls/md.h"
 #endif
 
-#if defined(MBEDTLS_PKCS1_V15) && !defined(__OpenBSD__)
+#if defined(MBEDTLS_PKCS1_V15) && !defined(__OpenBSD__) && !defined(__NetBSD__)
 #include <stdlib.h>
 #endif
 
@@ -2569,7 +2569,7 @@
 #if defined(MBEDTLS_PKCS1_V15)
 static int myrand( void *rng_state, unsigned char *output, size_t len )
 {
-#if !defined(__OpenBSD__)
+#if !defined(__OpenBSD__) && !defined(__NetBSD__)
     size_t i;
 
     if( rng_state != NULL )
@@ -2582,7 +2582,7 @@
         rng_state = NULL;
 
     arc4random_buf( output, len );
-#endif /* !OpenBSD */
+#endif /* !OpenBSD && !NetBSD */
 
     return( 0 );
 }
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 8fd8b86..2627224 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -3008,6 +3008,25 @@
 }
 
 /*
+ * Check for SAN match, see RFC 5280 Section 4.2.1.6
+ */
+static int x509_crt_check_san( const mbedtls_x509_buf *name,
+                               const char *cn, size_t cn_len )
+{
+    const unsigned char san_type = (unsigned char) name->tag &
+                                   MBEDTLS_ASN1_TAG_VALUE_MASK;
+
+    /* dNSName */
+    if( san_type == MBEDTLS_X509_SAN_DNS_NAME )
+        return( x509_crt_check_cn( name, cn, cn_len ) );
+
+    /* (We may handle other types here later.) */
+
+    /* Unrecognized type */
+    return( -1 );
+}
+
+/*
  * Verify the requested CN - only call this if cn is not NULL!
  */
 static void x509_crt_verify_name( const mbedtls_x509_crt *crt,
@@ -3022,7 +3041,7 @@
     {
         for( cur = &crt->subject_alt_names; cur != NULL; cur = cur->next )
         {
-            if( x509_crt_check_cn( &cur->buf, cn, cn_len ) == 0 )
+            if( x509_crt_check_san( &cur->buf, cn, cn_len ) == 0 )
                 break;
         }
 
diff --git a/tests/data_files/Makefile b/tests/data_files/Makefile
index 99d64eb..40c22f5 100644
--- a/tests/data_files/Makefile
+++ b/tests/data_files/Makefile
@@ -270,6 +270,10 @@
 server5-fan.crt: server5.key
 	$(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS FAN" -set_serial 77 -config $(test_ca_config_file) -extensions fan_cert -days 3650 -sha256 -key server5.key -out $@
 
+server5-tricky-ip-san.crt: server5.key
+	$(OPENSSL) req -x509 -new -subj "/C=UK/O=Mbed TLS/CN=Mbed TLS Tricky IP SAN" -set_serial 77 -config $(test_ca_config_file) -extensions tricky_ip_san -days 3650 -sha256 -key server5.key -out $@
+all_final += server5-tricky-ip-san.crt
+
 server10-badsign.crt: server10.crt
 	{ head -n-2 $<; tail -n-2 $< | sed -e '1s/0\(=*\)$$/_\1/' -e '1s/[^_=]\(=*\)$$/0\1/' -e '1s/_/1/'; } > $@
 all_final += server10-badsign.crt
diff --git a/tests/data_files/server5-tricky-ip-san.crt b/tests/data_files/server5-tricky-ip-san.crt
new file mode 100644
index 0000000..135830f
--- /dev/null
+++ b/tests/data_files/server5-tricky-ip-san.crt
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBljCCATygAwIBAgIBTTAKBggqhkjOPQQDAjBBMQswCQYDVQQGEwJVSzERMA8G
+A1UECgwITWJlZCBUTFMxHzAdBgNVBAMMFk1iZWQgVExTIFRyaWNreSBJUCBTQU4w
+HhcNMjAwNzIzMTAyNzQ2WhcNMzAwNzIxMTAyNzQ2WjBBMQswCQYDVQQGEwJVSzER
+MA8GA1UECgwITWJlZCBUTFMxHzAdBgNVBAMMFk1iZWQgVExTIFRyaWNreSBJUCBT
+QU4wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQ3zFbZdgkeWnI+x1kt/yBu7nz5
+BpF00K0UtfdoIllikk7lANgjEf/qL9I0XV0WvYqIwmt3DVXNiioO+gHItO3/oyUw
+IzAhBgNVHREEGjAYhwRhYmNkhxBhYmNkLmV4YW1wbGUuY29tMAoGCCqGSM49BAMC
+A0gAMEUCIFDc8ZALA/9Zv7dZTWrZOOp/dgPAEJRT+h68nD6KF+XyAiEAs1QqugOo
+Dwru0DSEmpYkmj1Keunpd0VopM0joC1cc5A=
+-----END CERTIFICATE-----
diff --git a/tests/data_files/test-ca.opensslconf b/tests/data_files/test-ca.opensslconf
index 9d34ed6..64347de 100644
--- a/tests/data_files/test-ca.opensslconf
+++ b/tests/data_files/test-ca.opensslconf
@@ -71,3 +71,7 @@
 
 [idpdata]
 fullname=URI:http://pki.example.com/
+
+# these IPs are the ascii values for 'abcd' and 'abcd.example.com'
+[tricky_ip_san]
+subjectAltName=IP:97.98.99.100,IP:6162:6364:2e65:7861:6d70:6c65:2e63:6f6d
diff --git a/tests/git-scripts/pre-commit.sh b/tests/git-scripts/pre-commit.sh
new file mode 100755
index 0000000..4365686
--- /dev/null
+++ b/tests/git-scripts/pre-commit.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+
+# pre-commit.sh
+#
+# Copyright (c) 2017, ARM Limited, All Rights Reserved
+# SPDX-License-Identifier: Apache-2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This file is part of Mbed TLS (https://tls.mbed.org)
+
+# Purpose
+#
+# This script does quick sanity checks before commiting:
+#   - check that generated files are up-to-date.
+#
+# It is meant to be called as a git pre-commit hook, see README.md.
+#
+# From the git sample pre-commit hook:
+#   Called by "git commit" with no arguments.  The hook should
+#   exit with non-zero status after issuing an appropriate message if
+#   it wants to stop the commit.
+
+set -eu
+
+tests/scripts/check-generated-files.sh
diff --git a/tests/scripts/check-generated-files.sh b/tests/scripts/check-generated-files.sh
index e39b661..cc5db97 100755
--- a/tests/scripts/check-generated-files.sh
+++ b/tests/scripts/check-generated-files.sh
@@ -23,11 +23,29 @@
 
 set -eu
 
+if [ $# -ne 0 ] && [ "$1" = "--help" ]; then
+    cat <<EOF
+$0 [-u]
+This script checks that all generated file are up-to-date. If some aren't, by
+default the scripts reports it and exits in error; with the -u option, it just
+updates them instead.
+
+  -u    Update the files rather than return an error for out-of-date files.
+EOF
+    exit
+fi
+
 if [ -d library -a -d include -a -d tests ]; then :; else
     echo "Must be run from mbed TLS root" >&2
     exit 1
 fi
 
+UPDATE=
+if [ $# -ne 0 ] && [ "$1" = "-u" ]; then
+    shift
+    UPDATE='y'
+fi
+
 check()
 {
     SCRIPT=$1
@@ -53,9 +71,15 @@
     for FILE in $FILES; do
         if ! diff $FILE $FILE.bak >/dev/null 2>&1; then
             echo "'$FILE' was either modified or deleted by '$SCRIPT'"
-            exit 1
+            if [ -z "$UPDATE" ]; then
+                exit 1
+            fi
         fi
-        mv $FILE.bak $FILE
+        if [ -z "$UPDATE" ]; then
+            mv $FILE.bak $FILE
+        else
+            rm $FILE.bak
+        fi
 
         if [ -d $TO_CHECK ]; then
             # Create a grep regular expression that we can check against the
@@ -72,7 +96,9 @@
         # Check if there are any new files
         if ls -1 $TO_CHECK | grep -v "$PATTERN" >/dev/null 2>&1; then
             echo "Files were created by '$SCRIPT'"
-            exit 1
+            if [ -z "$UPDATE" ]; then
+                exit 1
+            fi
         fi
     fi
 }
diff --git a/tests/src/random.c b/tests/src/random.c
index 3345f78..45748a9 100644
--- a/tests/src/random.c
+++ b/tests/src/random.c
@@ -32,7 +32,7 @@
                                unsigned char *output,
                                size_t len )
 {
-#if !defined(__OpenBSD__)
+#if !defined(__OpenBSD__) && !defined(__NetBSD__)
     size_t i;
 
     if( rng_state != NULL )
@@ -45,7 +45,7 @@
         rng_state = NULL;
 
     arc4random_buf( output, len );
-#endif /* !OpenBSD */
+#endif /* !OpenBSD && !NetBSD */
 
     return( 0 );
 }
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index d5f538b..f8e3891 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -911,6 +911,14 @@
 depends_on:MBEDTLS_SHA256_C:MBEDTLS_PEM_PARSE_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_ECDSA_C:MBEDTLS_SHA1_C
 x509_verify:"data_files/cert_sha256.crt":"data_files/test-ca.crt":"data_files/crl-ec-sha256.pem":"NULL":0:0:"next":"NULL"
 
+X509 CRT verification: domain identical to IPv4 in SubjectAltName
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C
+x509_verify:"data_files/server5-tricky-ip-san.crt":"data_files/server5-tricky-ip-san.crt":"data_files/crl_sha256.pem":"abcd":MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:MBEDTLS_X509_BADCERT_CN_MISMATCH:"":"NULL"
+
+X509 CRT verification: domain identical to IPv6 in SubjectAltName
+depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_ECDSA_C:MBEDTLS_SHA256_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_RSA_C
+x509_verify:"data_files/server5-tricky-ip-san.crt":"data_files/server5-tricky-ip-san.crt":"data_files/crl_sha256.pem":"abcd.example.com":MBEDTLS_ERR_X509_CERT_VERIFY_FAILED:MBEDTLS_X509_BADCERT_CN_MISMATCH:"":"NULL"
+
 X509 CRT verification with ca callback: failure
 depends_on:MBEDTLS_PEM_PARSE_C:MBEDTLS_SHA1_C:MBEDTLS_RSA_C:MBEDTLS_PKCS1_V15:MBEDTLS_X509_TRUSTED_CERTIFICATE_CALLBACK
 x509_verify_ca_cb_failure:"data_files/server1.crt":"data_files/test-ca.crt":"NULL":MBEDTLS_ERR_X509_FATAL_ERROR