Fix use of pem_read_buffer() in PK, DHM and X509
diff --git a/library/dhm.c b/library/dhm.c
index c5e41a3..92fd611 100644
--- a/library/dhm.c
+++ b/library/dhm.c
@@ -421,10 +421,14 @@
 
     mbedtls_pem_init( &pem );
 
-    ret = mbedtls_pem_read_buffer( &pem,
-                           "-----BEGIN DH PARAMETERS-----",
-                           "-----END DH PARAMETERS-----",
-                           dhmin, NULL, 0, &dhminlen );
+    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
+    if( dhmin[dhminlen - 1] != '\0' )
+        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+    else
+        ret = mbedtls_pem_read_buffer( &pem,
+                               "-----BEGIN DH PARAMETERS-----",
+                               "-----END DH PARAMETERS-----",
+                               dhmin, NULL, 0, &dhminlen );
 
     if( ret == 0 )
     {
@@ -503,6 +507,10 @@
 #if defined(MBEDTLS_FS_IO)
 /*
  * Load all data from a file into a given buffer.
+ *
+ * The file is expected to contain either PEM or DER encoded data.
+ * A terminating null byte is always appended. It is included in the announced
+ * length only if the data looks like it is PEM encoded.
  */
 static int load_file( const char *path, unsigned char **buf, size_t *n )
 {
@@ -540,6 +548,9 @@
 
     (*buf)[*n] = '\0';
 
+    if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
+        ++*n;
+
     return( 0 );
 }
 
@@ -557,7 +568,7 @@
 
     ret = mbedtls_dhm_parse_dhm( dhm, buf, n );
 
-    mbedtls_zeroize( buf, n + 1 );
+    mbedtls_zeroize( buf, n );
     mbedtls_free( buf );
 
     return( ret );
@@ -584,7 +595,7 @@
         mbedtls_printf( "  DHM parameter load: " );
 
     if( ( ret = mbedtls_dhm_parse_dhm( &dhm, (const unsigned char *) mbedtls_test_dhm_params,
-                               strlen( mbedtls_test_dhm_params ) ) ) != 0 )
+                               mbedtls_test_dhm_params_len ) ) != 0 )
     {
         if( verbose != 0 )
             mbedtls_printf( "failed\n" );
diff --git a/library/pkparse.c b/library/pkparse.c
index f5a9853..edf6e31 100644
--- a/library/pkparse.c
+++ b/library/pkparse.c
@@ -69,6 +69,10 @@
 
 /*
  * Load all data from a file into a given buffer.
+ *
+ * The file is expected to contain either PEM or DER encoded data.
+ * A terminating null byte is always appended. It is included in the announced
+ * length only if the data looks like it is PEM encoded.
  */
 int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n )
 {
@@ -106,6 +110,9 @@
 
     (*buf)[*n] = '\0';
 
+    if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL )
+        ++*n;
+
     return( 0 );
 }
 
@@ -128,7 +135,7 @@
         ret = mbedtls_pk_parse_key( ctx, buf, n,
                 (const unsigned char *) pwd, strlen( pwd ) );
 
-    mbedtls_zeroize( buf, n + 1 );
+    mbedtls_zeroize( buf, n );
     mbedtls_free( buf );
 
     return( ret );
@@ -148,7 +155,7 @@
 
     ret = mbedtls_pk_parse_public_key( ctx, buf, n );
 
-    mbedtls_zeroize( buf, n + 1 );
+    mbedtls_zeroize( buf, n );
     mbedtls_free( buf );
 
     return( ret );
@@ -1064,10 +1071,15 @@
     mbedtls_pem_init( &pem );
 
 #if defined(MBEDTLS_RSA_C)
-    ret = mbedtls_pem_read_buffer( &pem,
-                           "-----BEGIN RSA PRIVATE KEY-----",
-                           "-----END RSA PRIVATE KEY-----",
-                           key, pwd, pwdlen, &len );
+    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
+    if( key[keylen - 1] != '\0' )
+        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+    else
+        ret = mbedtls_pem_read_buffer( &pem,
+                               "-----BEGIN RSA PRIVATE KEY-----",
+                               "-----END RSA PRIVATE KEY-----",
+                               key, pwd, pwdlen, &len );
+
     if( ret == 0 )
     {
         if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL )
@@ -1092,10 +1104,14 @@
 #endif /* MBEDTLS_RSA_C */
 
 #if defined(MBEDTLS_ECP_C)
-    ret = mbedtls_pem_read_buffer( &pem,
-                           "-----BEGIN EC PRIVATE KEY-----",
-                           "-----END EC PRIVATE KEY-----",
-                           key, pwd, pwdlen, &len );
+    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
+    if( key[keylen - 1] != '\0' )
+        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+    else
+        ret = mbedtls_pem_read_buffer( &pem,
+                               "-----BEGIN EC PRIVATE KEY-----",
+                               "-----END EC PRIVATE KEY-----",
+                               key, pwd, pwdlen, &len );
     if( ret == 0 )
     {
         if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == NULL )
@@ -1119,10 +1135,14 @@
         return( ret );
 #endif /* MBEDTLS_ECP_C */
 
-    ret = mbedtls_pem_read_buffer( &pem,
-                           "-----BEGIN PRIVATE KEY-----",
-                           "-----END PRIVATE KEY-----",
-                           key, NULL, 0, &len );
+    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
+    if( key[keylen - 1] != '\0' )
+        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+    else
+        ret = mbedtls_pem_read_buffer( &pem,
+                               "-----BEGIN PRIVATE KEY-----",
+                               "-----END PRIVATE KEY-----",
+                               key, NULL, 0, &len );
     if( ret == 0 )
     {
         if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk,
@@ -1138,10 +1158,14 @@
         return( ret );
 
 #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
-    ret = mbedtls_pem_read_buffer( &pem,
-                           "-----BEGIN ENCRYPTED PRIVATE KEY-----",
-                           "-----END ENCRYPTED PRIVATE KEY-----",
-                           key, NULL, 0, &len );
+    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
+    if( key[keylen - 1] != '\0' )
+        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+    else
+        ret = mbedtls_pem_read_buffer( &pem,
+                               "-----BEGIN ENCRYPTED PRIVATE KEY-----",
+                               "-----END ENCRYPTED PRIVATE KEY-----",
+                               key, NULL, 0, &len );
     if( ret == 0 )
     {
         if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk,
@@ -1231,10 +1255,15 @@
     mbedtls_pem_context pem;
 
     mbedtls_pem_init( &pem );
-    ret = mbedtls_pem_read_buffer( &pem,
-            "-----BEGIN PUBLIC KEY-----",
-            "-----END PUBLIC KEY-----",
-            key, NULL, 0, &len );
+
+    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
+    if( key[keylen - 1] != '\0' )
+        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+    else
+        ret = mbedtls_pem_read_buffer( &pem,
+                "-----BEGIN PUBLIC KEY-----",
+                "-----END PUBLIC KEY-----",
+                key, NULL, 0, &len );
 
     if( ret == 0 )
     {
diff --git a/library/x509.c b/library/x509.c
index 55daf74..08a1ec3 100644
--- a/library/x509.c
+++ b/library/x509.c
@@ -1008,7 +1008,7 @@
     mbedtls_x509_crt_init( &clicert );
 
     ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) mbedtls_test_cli_crt,
-                          strlen( mbedtls_test_cli_crt ) );
+                           mbedtls_test_cli_crt_len );
     if( ret != 0 )
     {
         if( verbose != 0 )
@@ -1020,7 +1020,7 @@
     mbedtls_x509_crt_init( &cacert );
 
     ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_ca_crt,
-                          strlen( mbedtls_test_ca_crt ) );
+                          mbedtls_test_ca_crt_len );
     if( ret != 0 )
     {
         if( verbose != 0 )
diff --git a/library/x509_crl.c b/library/x509_crl.c
index a915aba..fc4b2df 100644
--- a/library/x509_crl.c
+++ b/library/x509_crl.c
@@ -503,6 +503,11 @@
     do
     {
         mbedtls_pem_init( &pem );
+
+    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
+    if( buf[buflen - 1] != '\0' )
+        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+    else
         ret = mbedtls_pem_read_buffer( &pem,
                                "-----BEGIN X509 CRL-----",
                                "-----END X509 CRL-----",
@@ -532,7 +537,9 @@
             return( ret );
         }
     }
-    while( is_pem && buflen > 0 );
+    /* In the PEM case, buflen is 1 at the end, for the terminated NULL byte.
+     * And a valid CRL cannot be less than 1 byte anyway. */
+    while( is_pem && buflen > 1 );
 
     if( is_pem )
         return( 0 );
@@ -556,7 +563,7 @@
 
     ret = mbedtls_x509_crl_parse( chain, buf, n );
 
-    mbedtls_zeroize( buf, n + 1 );
+    mbedtls_zeroize( buf, n );
     mbedtls_free( buf );
 
     return( ret );
diff --git a/library/x509_crt.c b/library/x509_crt.c
index 4ebae77..059b60f 100644
--- a/library/x509_crt.c
+++ b/library/x509_crt.c
@@ -852,8 +852,11 @@
      * one or more PEM certificates.
      */
 #if defined(MBEDTLS_PEM_PARSE_C)
-    if( strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL )
+    if( buf[buflen - 1] == '\0' &&
+        strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL )
+    {
         buf_format = MBEDTLS_X509_FORMAT_PEM;
+    }
 #endif
 
     if( buf_format == MBEDTLS_X509_FORMAT_DER )
@@ -865,11 +868,13 @@
         int ret;
         mbedtls_pem_context pem;
 
-        while( buflen > 0 )
+        /* 1 rather than 0 since the terminating NULL byte is counted in */
+        while( buflen > 1 )
         {
             size_t use_len;
             mbedtls_pem_init( &pem );
 
+            /* If we get there, we know the string is null-terminated */
             ret = mbedtls_pem_read_buffer( &pem,
                            "-----BEGIN CERTIFICATE-----",
                            "-----END CERTIFICATE-----",
@@ -953,7 +958,7 @@
 
     ret = mbedtls_x509_crt_parse( chain, buf, n );
 
-    mbedtls_zeroize( buf, n + 1 );
+    mbedtls_zeroize( buf, n );
     mbedtls_free( buf );
 
     return( ret );
diff --git a/library/x509_csr.c b/library/x509_csr.c
index f6afa1e..5ec1b86 100644
--- a/library/x509_csr.c
+++ b/library/x509_csr.c
@@ -274,10 +274,15 @@
 
 #if defined(MBEDTLS_PEM_PARSE_C)
     mbedtls_pem_init( &pem );
-    ret = mbedtls_pem_read_buffer( &pem,
-                           "-----BEGIN CERTIFICATE REQUEST-----",
-                           "-----END CERTIFICATE REQUEST-----",
-                           buf, NULL, 0, &use_len );
+
+    /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */
+    if( buf[buflen - 1] != '\0' )
+        ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
+    else
+        ret = mbedtls_pem_read_buffer( &pem,
+                               "-----BEGIN CERTIFICATE REQUEST-----",
+                               "-----END CERTIFICATE REQUEST-----",
+                               buf, NULL, 0, &use_len );
 
     if( ret == 0 )
     {
@@ -315,7 +320,7 @@
 
     ret = mbedtls_x509_csr_parse( csr, buf, n );
 
-    mbedtls_zeroize( buf, n + 1 );
+    mbedtls_zeroize( buf, n );
     mbedtls_free( buf );
 
     return( ret );