Import mbedtls-3.6.0

Imports Mbed TLS 3.6.0 from https://github.com/Mbed-TLS/mbedtls.git
tags mbedtls-3.6.0, v3.6.0

Files that are not needed are removed:

cd lib/libmbedtls
rm -rf mbedtls
cp -R path/to/mbedtls-3.6.0/mbedtls .
cd mbedtls
rm CMakeLists.txt DartConfiguration.tcl Makefile
rm .gitignore .travis.yml .pylintrc .globalrc .mypy.ini BRANCHES.md
rm include/.gitignore include/CMakeLists.txt library/.gitignore
rm library/CMakeLists.txt library/Makefile
rm -r cmake
rm -rf .git .github doxygen configs programs scripts tests visualc
rm -rf 3rdparty ChangeLog.d docs pkgconfig .gitmodules .readthedocs.yaml
rm library/mps_*
cd ..
git add mbedtls

This time we leave library/psa_* present to enable TLS 1.3 features.

This is a complete overwrite of previous code so earlier changes in the
previous branch import/mbedtls-3.4.0 will be added on top of this commit.

Signed-off-by: Tom Van Eyck <tom.vaneyck@kuleuven.be>
Acked-by: Jens Wiklander <jens.wiklander@linaro.org>
diff --git a/lib/libmbedtls/mbedtls/library/pkparse.c b/lib/libmbedtls/mbedtls/library/pkparse.c
index ccca692..4f6ee13 100644
--- a/lib/libmbedtls/mbedtls/library/pkparse.c
+++ b/lib/libmbedtls/mbedtls/library/pkparse.c
@@ -2,19 +2,7 @@
  *  Public Key layer for parsing key files and structures
  *
  *  Copyright The Mbed TLS Contributors
- *  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.
+ *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
  */
 
 #include "common.h"
@@ -25,19 +13,25 @@
 #include "mbedtls/asn1.h"
 #include "mbedtls/oid.h"
 #include "mbedtls/platform_util.h"
+#include "mbedtls/platform.h"
 #include "mbedtls/error.h"
+#include "mbedtls/ecp.h"
+#include "pk_internal.h"
 
 #include <string.h>
 
+#if defined(MBEDTLS_USE_PSA_CRYPTO)
+#include "mbedtls/psa_util.h"
+#include "psa/crypto.h"
+#endif
+
+/* Key types */
 #if defined(MBEDTLS_RSA_C)
 #include "mbedtls/rsa.h"
+#include "rsa_internal.h"
 #endif
-#if defined(MBEDTLS_ECP_C)
-#include "mbedtls/ecp.h"
-#endif
-#if defined(MBEDTLS_ECDSA_C)
-#include "mbedtls/ecdsa.h"
-#endif
+
+/* Extended formats */
 #if defined(MBEDTLS_PEM_PARSE_C)
 #include "mbedtls/pem.h"
 #endif
@@ -48,163 +42,55 @@
 #include "mbedtls/pkcs12.h"
 #endif
 
-#include "mbedtls/platform.h"
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
 
-#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.
- */
-int mbedtls_pk_load_file(const char *path, unsigned char **buf, size_t *n)
+ *      Low-level ECC parsing: optional support for SpecifiedECDomain
+ *
+ * There are two functions here that are used by the rest of the code:
+ * - pk_ecc_tag_is_speficied_ec_domain()
+ * - pk_ecc_group_id_from_specified()
+ *
+ * All the other functions are internal to this section.
+ *
+ * The two "public" functions have a dummy variant provided
+ * in configs without MBEDTLS_PK_PARSE_EC_EXTENDED. This acts as an
+ * abstraction layer for this macro, which should not appear outside
+ * this section.
+ *
+ **********************************************************************/
+
+#if !defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
+/* See the "real" version for documentation */
+static int pk_ecc_tag_is_specified_ec_domain(int tag)
 {
-    FILE *f;
-    long size;
-
-    if ((f = fopen(path, "rb")) == NULL) {
-        return MBEDTLS_ERR_PK_FILE_IO_ERROR;
-    }
-
-    /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
-    mbedtls_setbuf(f, NULL);
-
-    fseek(f, 0, SEEK_END);
-    if ((size = ftell(f)) == -1) {
-        fclose(f);
-        return MBEDTLS_ERR_PK_FILE_IO_ERROR;
-    }
-    fseek(f, 0, SEEK_SET);
-
-    *n = (size_t) size;
-
-    if (*n + 1 == 0 ||
-        (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
-        fclose(f);
-        return MBEDTLS_ERR_PK_ALLOC_FAILED;
-    }
-
-    if (fread(*buf, 1, *n, f) != *n) {
-        fclose(f);
-
-        mbedtls_platform_zeroize(*buf, *n);
-        mbedtls_free(*buf);
-
-        return MBEDTLS_ERR_PK_FILE_IO_ERROR;
-    }
-
-    fclose(f);
-
-    (*buf)[*n] = '\0';
-
-    if (strstr((const char *) *buf, "-----BEGIN ") != NULL) {
-        ++*n;
-    }
-
+    (void) tag;
     return 0;
 }
 
+/* See the "real" version for documentation */
+static int pk_ecc_group_id_from_specified(const mbedtls_asn1_buf *params,
+                                          mbedtls_ecp_group_id *grp_id)
+{
+    (void) params;
+    (void) grp_id;
+    return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
+}
+#else /* MBEDTLS_PK_PARSE_EC_EXTENDED */
 /*
- * Load and parse a private key
+ * Tell if the passed tag might be the start of SpecifiedECDomain
+ * (that is, a sequence).
  */
-int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx,
-                             const char *path, const char *pwd,
-                             int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
+static int pk_ecc_tag_is_specified_ec_domain(int tag)
 {
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t n;
-    unsigned char *buf;
-
-    if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
-        return ret;
-    }
-
-    if (pwd == NULL) {
-        ret = mbedtls_pk_parse_key(ctx, buf, n, NULL, 0, f_rng, p_rng);
-    } else {
-        ret = mbedtls_pk_parse_key(ctx, buf, n,
-                                   (const unsigned char *) pwd, strlen(pwd), f_rng, p_rng);
-    }
-
-    mbedtls_platform_zeroize(buf, n);
-    mbedtls_free(buf);
-
-    return ret;
+    return tag == (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE);
 }
 
 /*
- * Load and parse a public key
- */
-int mbedtls_pk_parse_public_keyfile(mbedtls_pk_context *ctx, const char *path)
-{
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t n;
-    unsigned char *buf;
-
-    if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
-        return ret;
-    }
-
-    ret = mbedtls_pk_parse_public_key(ctx, buf, n);
-
-    mbedtls_platform_zeroize(buf, n);
-    mbedtls_free(buf);
-
-    return ret;
-}
-#endif /* MBEDTLS_FS_IO */
-
-#if defined(MBEDTLS_ECP_C)
-/* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf
- *
- * ECParameters ::= CHOICE {
- *   namedCurve         OBJECT IDENTIFIER
- *   specifiedCurve     SpecifiedECDomain -- = SEQUENCE { ... }
- *   -- implicitCurve   NULL
- * }
- */
-static int pk_get_ecparams(unsigned char **p, const unsigned char *end,
-                           mbedtls_asn1_buf *params)
-{
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-
-    if (end - *p < 1) {
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
-                                 MBEDTLS_ERR_ASN1_OUT_OF_DATA);
-    }
-
-    /* Tag may be either OID or SEQUENCE */
-    params->tag = **p;
-    if (params->tag != MBEDTLS_ASN1_OID
-#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
-        && params->tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)
-#endif
-        ) {
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
-                                 MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
-    }
-
-    if ((ret = mbedtls_asn1_get_tag(p, end, &params->len, params->tag)) != 0) {
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
-    }
-
-    params->p = *p;
-    *p += params->len;
-
-    if (*p != end) {
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
-                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
-    }
-
-    return 0;
-}
-
-#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
-/*
  * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it.
  * WARNING: the resulting group should only be used with
- * pk_group_id_from_specified(), since its base point may not be set correctly
+ * pk_ecc_group_id_from_specified(), since its base point may not be set correctly
  * if it was encoded compressed.
  *
  *  SpecifiedECDomain ::= SEQUENCE {
@@ -224,7 +110,7 @@
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     unsigned char *p = params->p;
-    const unsigned char * const end = params->p + params->len;
+    const unsigned char *const end = params->p + params->len;
     const unsigned char *end_field, *end_curve;
     size_t len;
     int ver;
@@ -396,7 +282,6 @@
             mbedtls_mpi_get_bit(&grp->G.Y, 0) == mbedtls_mpi_get_bit(&ref.G.Y, 0)) {
             break;
         }
-
     }
 
 cleanup:
@@ -414,8 +299,8 @@
 /*
  * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID
  */
-static int pk_group_id_from_specified(const mbedtls_asn1_buf *params,
-                                      mbedtls_ecp_group_id *grp_id)
+static int pk_ecc_group_id_from_specified(const mbedtls_asn1_buf *params,
+                                          mbedtls_ecp_group_id *grp_id)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     mbedtls_ecp_group grp;
@@ -430,7 +315,7 @@
 
 cleanup:
     /* The API respecting lifecycle for mbedtls_ecp_group struct is
-     * _init(), _load() and _free(). In pk_group_id_from_specified() the
+     * _init(), _load() and _free(). In pk_ecc_group_id_from_specified() the
      * temporary grp breaks that flow and it's members are populated
      * by pk_group_id_from_group(). As such mbedtls_ecp_group_free()
      * which is assuming a group populated by _setup() may not clean-up
@@ -446,6 +331,53 @@
 }
 #endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */
 
+/***********************************************************************
+ *
+ * Unsorted (yet!) from this point on until the next section header
+ *
+ **********************************************************************/
+
+/* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf
+ *
+ * ECParameters ::= CHOICE {
+ *   namedCurve         OBJECT IDENTIFIER
+ *   specifiedCurve     SpecifiedECDomain -- = SEQUENCE { ... }
+ *   -- implicitCurve   NULL
+ * }
+ */
+static int pk_get_ecparams(unsigned char **p, const unsigned char *end,
+                           mbedtls_asn1_buf *params)
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+
+    if (end - *p < 1) {
+        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
+                                 MBEDTLS_ERR_ASN1_OUT_OF_DATA);
+    }
+
+    /* Acceptable tags: OID for namedCurve, or specifiedECDomain */
+    params->tag = **p;
+    if (params->tag != MBEDTLS_ASN1_OID &&
+        !pk_ecc_tag_is_specified_ec_domain(params->tag)) {
+        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
+                                 MBEDTLS_ERR_ASN1_UNEXPECTED_TAG);
+    }
+
+    if ((ret = mbedtls_asn1_get_tag(p, end, &params->len, params->tag)) != 0) {
+        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
+    }
+
+    params->p = *p;
+    *p += params->len;
+
+    if (*p != end) {
+        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
+                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
+    }
+
+    return 0;
+}
+
 /*
  * Use EC parameters to initialise an EC group
  *
@@ -454,7 +386,7 @@
  *   specifiedCurve     SpecifiedECDomain -- = SEQUENCE { ... }
  *   -- implicitCurve   NULL
  */
-static int pk_use_ecparams(const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp)
+static int pk_use_ecparams(const mbedtls_asn1_buf *params, mbedtls_pk_context *pk)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     mbedtls_ecp_group_id grp_id;
@@ -464,116 +396,71 @@
             return MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE;
         }
     } else {
-#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED)
-        if ((ret = pk_group_id_from_specified(params, &grp_id)) != 0) {
+        ret = pk_ecc_group_id_from_specified(params, &grp_id);
+        if (ret != 0) {
             return ret;
         }
-#else
+    }
+
+    return mbedtls_pk_ecc_set_group(pk, grp_id);
+}
+
+#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
+
+/*
+ * Load an RFC8410 EC key, which doesn't have any parameters
+ */
+static int pk_use_ecparams_rfc8410(const mbedtls_asn1_buf *params,
+                                   mbedtls_ecp_group_id grp_id,
+                                   mbedtls_pk_context *pk)
+{
+    if (params->tag != 0 || params->len != 0) {
         return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
-#endif
+    }
+
+    return mbedtls_pk_ecc_set_group(pk, grp_id);
+}
+
+/*
+ * Parse an RFC 8410 encoded private EC key
+ *
+ * CurvePrivateKey ::= OCTET STRING
+ */
+static int pk_parse_key_rfc8410_der(mbedtls_pk_context *pk,
+                                    unsigned char *key, size_t keylen, const unsigned char *end,
+                                    int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t len;
+
+    if ((ret = mbedtls_asn1_get_tag(&key, (key + keylen), &len, MBEDTLS_ASN1_OCTET_STRING)) != 0) {
+        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
+    }
+
+    if (key + len != end) {
+        return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
     }
 
     /*
-     * grp may already be initialized; if so, make sure IDs match
+     * Load the private key
      */
-    if (grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id) {
-        return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
+    ret = mbedtls_pk_ecc_set_key(pk, key, len);
+    if (ret != 0) {
+        return ret;
     }
 
-    if ((ret = mbedtls_ecp_group_load(grp, grp_id)) != 0) {
+    /* pk_parse_key_pkcs8_unencrypted_der() only supports version 1 PKCS8 keys,
+     * which never contain a public key. As such, derive the public key
+     * unconditionally. */
+    if ((ret = mbedtls_pk_ecc_set_pubkey_from_prv(pk, key, len, f_rng, p_rng)) != 0) {
         return ret;
     }
 
     return 0;
 }
+#endif /* MBEDTLS_PK_HAVE_RFC8410_CURVES */
 
-/*
- * EC public key is an EC point
- *
- * The caller is responsible for clearing the structure upon failure if
- * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE
- * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state.
- */
-static int pk_get_ecpubkey(unsigned char **p, const unsigned char *end,
-                           mbedtls_ecp_keypair *key)
-{
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-
-    if ((ret = mbedtls_ecp_point_read_binary(&key->grp, &key->Q,
-                                             (const unsigned char *) *p, end - *p)) == 0) {
-        ret = mbedtls_ecp_check_pubkey(&key->grp, &key->Q);
-    }
-
-    /*
-     * We know mbedtls_ecp_point_read_binary consumed all bytes or failed
-     */
-    *p = (unsigned char *) end;
-
-    return ret;
-}
-#endif /* MBEDTLS_ECP_C */
-
-#if defined(MBEDTLS_RSA_C)
-/*
- *  RSAPublicKey ::= SEQUENCE {
- *      modulus           INTEGER,  -- n
- *      publicExponent    INTEGER   -- e
- *  }
- */
-static int pk_get_rsapubkey(unsigned char **p,
-                            const unsigned char *end,
-                            mbedtls_rsa_context *rsa)
-{
-    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
-    size_t len;
-
-    if ((ret = mbedtls_asn1_get_tag(p, end, &len,
-                                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret);
-    }
-
-    if (*p + len != end) {
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY,
-                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
-    }
-
-    /* Import N */
-    if ((ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) {
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret);
-    }
-
-    if ((ret = mbedtls_rsa_import_raw(rsa, *p, len, NULL, 0, NULL, 0,
-                                      NULL, 0, NULL, 0)) != 0) {
-        return MBEDTLS_ERR_PK_INVALID_PUBKEY;
-    }
-
-    *p += len;
-
-    /* Import E */
-    if ((ret = mbedtls_asn1_get_tag(p, end, &len, MBEDTLS_ASN1_INTEGER)) != 0) {
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret);
-    }
-
-    if ((ret = mbedtls_rsa_import_raw(rsa, NULL, 0, NULL, 0, NULL, 0,
-                                      NULL, 0, *p, len)) != 0) {
-        return MBEDTLS_ERR_PK_INVALID_PUBKEY;
-    }
-
-    *p += len;
-
-    if (mbedtls_rsa_complete(rsa) != 0 ||
-        mbedtls_rsa_check_pubkey(rsa) != 0) {
-        return MBEDTLS_ERR_PK_INVALID_PUBKEY;
-    }
-
-    if (*p != end) {
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY,
-                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
-    }
-
-    return 0;
-}
-#endif /* MBEDTLS_RSA_C */
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
 
 /* Get a PK algorithm identifier
  *
@@ -583,7 +470,8 @@
  */
 static int pk_get_pk_alg(unsigned char **p,
                          const unsigned char *end,
-                         mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params)
+                         mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params,
+                         mbedtls_ecp_group_id *ec_grp_id)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     mbedtls_asn1_buf alg_oid;
@@ -594,7 +482,18 @@
         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_ALG, ret);
     }
 
-    if (mbedtls_oid_get_pk_alg(&alg_oid, pk_alg) != 0) {
+    ret = mbedtls_oid_get_pk_alg(&alg_oid, pk_alg);
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
+    if (ret == MBEDTLS_ERR_OID_NOT_FOUND) {
+        ret = mbedtls_oid_get_ec_grp_algid(&alg_oid, ec_grp_id);
+        if (ret == 0) {
+            *pk_alg = MBEDTLS_PK_ECKEY;
+        }
+    }
+#else
+    (void) ec_grp_id;
+#endif
+    if (ret != 0) {
         return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
     }
 
@@ -622,6 +521,7 @@
     size_t len;
     mbedtls_asn1_buf alg_params;
     mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
+    mbedtls_ecp_group_id ec_grp_id = MBEDTLS_ECP_DP_NONE;
     const mbedtls_pk_info_t *pk_info;
 
     if ((ret = mbedtls_asn1_get_tag(p, end, &len,
@@ -631,7 +531,7 @@
 
     end = *p + len;
 
-    if ((ret = pk_get_pk_alg(p, end, &pk_alg, &alg_params)) != 0) {
+    if ((ret = pk_get_pk_alg(p, end, &pk_alg, &alg_params, &ec_grp_id)) != 0) {
         return ret;
     }
 
@@ -654,17 +554,35 @@
 
 #if defined(MBEDTLS_RSA_C)
     if (pk_alg == MBEDTLS_PK_RSA) {
-        ret = pk_get_rsapubkey(p, end, mbedtls_pk_rsa(*pk));
-    } else
-#endif /* MBEDTLS_RSA_C */
-#if defined(MBEDTLS_ECP_C)
-    if (pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY) {
-        ret = pk_use_ecparams(&alg_params, &mbedtls_pk_ec(*pk)->grp);
+        ret = mbedtls_rsa_parse_pubkey(mbedtls_pk_rsa(*pk), *p, (size_t) (end - *p));
         if (ret == 0) {
-            ret = pk_get_ecpubkey(p, end, mbedtls_pk_ec(*pk));
+            /* On success all the input has been consumed by the parsing function. */
+            *p += end - *p;
+        } else if ((ret <= MBEDTLS_ERR_ASN1_OUT_OF_DATA) &&
+                   (ret >= MBEDTLS_ERR_ASN1_BUF_TOO_SMALL)) {
+            /* In case of ASN1 error codes add MBEDTLS_ERR_PK_INVALID_PUBKEY. */
+            ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY, ret);
+        } else {
+            ret = MBEDTLS_ERR_PK_INVALID_PUBKEY;
         }
     } else
-#endif /* MBEDTLS_ECP_C */
+#endif /* MBEDTLS_RSA_C */
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
+    if (pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY) {
+#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
+        if (MBEDTLS_PK_IS_RFC8410_GROUP_ID(ec_grp_id)) {
+            ret = pk_use_ecparams_rfc8410(&alg_params, ec_grp_id, pk);
+        } else
+#endif
+        {
+            ret = pk_use_ecparams(&alg_params, pk);
+        }
+        if (ret == 0) {
+            ret = mbedtls_pk_ecc_set_pubkey(pk, *p, (size_t) (end - *p));
+            *p += end - *p;
+        }
+    } else
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
     ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
 
     if (ret == 0 && *p != end) {
@@ -679,208 +597,20 @@
     return ret;
 }
 
-#if defined(MBEDTLS_RSA_C)
-/*
- * Wrapper around mbedtls_asn1_get_mpi() that rejects zero.
- *
- * The value zero is:
- * - never a valid value for an RSA parameter
- * - interpreted as "omitted, please reconstruct" by mbedtls_rsa_complete().
- *
- * Since values can't be omitted in PKCS#1, passing a zero value to
- * rsa_complete() would be incorrect, so reject zero values early.
- */
-static int asn1_get_nonzero_mpi(unsigned char **p,
-                                const unsigned char *end,
-                                mbedtls_mpi *X)
-{
-    int ret;
-
-    ret = mbedtls_asn1_get_mpi(p, end, X);
-    if (ret != 0) {
-        return ret;
-    }
-
-    if (mbedtls_mpi_cmp_int(X, 0) == 0) {
-        return MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
-    }
-
-    return 0;
-}
-
-/*
- * Parse a PKCS#1 encoded private RSA key
- */
-static int pk_parse_key_pkcs1_der(mbedtls_rsa_context *rsa,
-                                  const unsigned char *key,
-                                  size_t keylen)
-{
-    int ret, version;
-    size_t len;
-    unsigned char *p, *end;
-
-    mbedtls_mpi T;
-    mbedtls_mpi_init(&T);
-
-    p = (unsigned char *) key;
-    end = p + keylen;
-
-    /*
-     * This function parses the RSAPrivateKey (PKCS#1)
-     *
-     *  RSAPrivateKey ::= SEQUENCE {
-     *      version           Version,
-     *      modulus           INTEGER,  -- n
-     *      publicExponent    INTEGER,  -- e
-     *      privateExponent   INTEGER,  -- d
-     *      prime1            INTEGER,  -- p
-     *      prime2            INTEGER,  -- q
-     *      exponent1         INTEGER,  -- d mod (p-1)
-     *      exponent2         INTEGER,  -- d mod (q-1)
-     *      coefficient       INTEGER,  -- (inverse of q) mod p
-     *      otherPrimeInfos   OtherPrimeInfos OPTIONAL
-     *  }
-     */
-    if ((ret = mbedtls_asn1_get_tag(&p, end, &len,
-                                    MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) != 0) {
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
-    }
-
-    end = p + len;
-
-    if ((ret = mbedtls_asn1_get_int(&p, end, &version)) != 0) {
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
-    }
-
-    if (version != 0) {
-        return MBEDTLS_ERR_PK_KEY_INVALID_VERSION;
-    }
-
-    /* Import N */
-    if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
-        (ret = mbedtls_rsa_import(rsa, &T, NULL, NULL,
-                                  NULL, NULL)) != 0) {
-        goto cleanup;
-    }
-
-    /* Import E */
-    if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
-        (ret = mbedtls_rsa_import(rsa, NULL, NULL, NULL,
-                                  NULL, &T)) != 0) {
-        goto cleanup;
-    }
-
-    /* Import D */
-    if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
-        (ret = mbedtls_rsa_import(rsa, NULL, NULL, NULL,
-                                  &T, NULL)) != 0) {
-        goto cleanup;
-    }
-
-    /* Import P */
-    if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
-        (ret = mbedtls_rsa_import(rsa, NULL, &T, NULL,
-                                  NULL, NULL)) != 0) {
-        goto cleanup;
-    }
-
-    /* Import Q */
-    if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
-        (ret = mbedtls_rsa_import(rsa, NULL, NULL, &T,
-                                  NULL, NULL)) != 0) {
-        goto cleanup;
-    }
-
-#if !defined(MBEDTLS_RSA_NO_CRT) && !defined(MBEDTLS_RSA_ALT)
-    /*
-     * The RSA CRT parameters DP, DQ and QP are nominally redundant, in
-     * that they can be easily recomputed from D, P and Q. However by
-     * parsing them from the PKCS1 structure it is possible to avoid
-     * recalculating them which both reduces the overhead of loading
-     * RSA private keys into memory and also avoids side channels which
-     * can arise when computing those values, since all of D, P, and Q
-     * are secret. See https://eprint.iacr.org/2020/055 for a
-     * description of one such attack.
-     */
-
-    /* Import DP */
-    if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
-        (ret = mbedtls_mpi_copy(&rsa->DP, &T)) != 0) {
-        goto cleanup;
-    }
-
-    /* Import DQ */
-    if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
-        (ret = mbedtls_mpi_copy(&rsa->DQ, &T)) != 0) {
-        goto cleanup;
-    }
-
-    /* Import QP */
-    if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
-        (ret = mbedtls_mpi_copy(&rsa->QP, &T)) != 0) {
-        goto cleanup;
-    }
-
-#else
-    /* Verify existence of the CRT params */
-    if ((ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
-        (ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0 ||
-        (ret = asn1_get_nonzero_mpi(&p, end, &T)) != 0) {
-        goto cleanup;
-    }
-#endif
-
-    /* rsa_complete() doesn't complete anything with the default
-     * implementation but is still called:
-     * - for the benefit of alternative implementation that may want to
-     *   pre-compute stuff beyond what's provided (eg Montgomery factors)
-     * - as is also sanity-checks the key
-     *
-     * Furthermore, we also check the public part for consistency with
-     * mbedtls_pk_parse_pubkey(), as it includes size minima for example.
-     */
-    if ((ret = mbedtls_rsa_complete(rsa)) != 0 ||
-        (ret = mbedtls_rsa_check_pubkey(rsa)) != 0) {
-        goto cleanup;
-    }
-
-    if (p != end) {
-        ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
-                                MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
-    }
-
-cleanup:
-
-    mbedtls_mpi_free(&T);
-
-    if (ret != 0) {
-        /* Wrap error code if it's coming from a lower level */
-        if ((ret & 0xff80) == 0) {
-            ret = MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
-        } else {
-            ret = MBEDTLS_ERR_PK_KEY_INVALID_FORMAT;
-        }
-
-        mbedtls_rsa_free(rsa);
-    }
-
-    return ret;
-}
-#endif /* MBEDTLS_RSA_C */
-
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
 /*
  * Parse a SEC1 encoded private EC key
  */
-static int pk_parse_key_sec1_der(mbedtls_ecp_keypair *eck,
+static int pk_parse_key_sec1_der(mbedtls_pk_context *pk,
                                  const unsigned char *key, size_t keylen,
                                  int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
 {
     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
     int version, pubkey_done;
-    size_t len;
+    size_t len, d_len;
     mbedtls_asn1_buf params = { 0, 0, NULL };
     unsigned char *p = (unsigned char *) key;
+    unsigned char *d;
     unsigned char *end = p + keylen;
     unsigned char *end2;
 
@@ -913,10 +643,10 @@
         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
     }
 
-    if ((ret = mbedtls_mpi_read_binary(&eck->d, p, len)) != 0) {
-        mbedtls_ecp_keypair_free(eck);
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
-    }
+    /* Keep a reference to the position fo the private key. It will be used
+     * later in this function. */
+    d = p;
+    d_len = len;
 
     p += len;
 
@@ -929,16 +659,22 @@
                                         MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED |
                                         0)) == 0) {
             if ((ret = pk_get_ecparams(&p, p + len, &params)) != 0 ||
-                (ret = pk_use_ecparams(&params, &eck->grp)) != 0) {
-                mbedtls_ecp_keypair_free(eck);
+                (ret = pk_use_ecparams(&params, pk)) != 0) {
                 return ret;
             }
         } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
-            mbedtls_ecp_keypair_free(eck);
             return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
         }
     }
 
+    /*
+     * Load the private key
+     */
+    ret = mbedtls_pk_ecc_set_key(pk, d, d_len);
+    if (ret != 0) {
+        return ret;
+    }
+
     if (p != end) {
         /*
          * Is 'publickey' present? If not, or if we can't read it (eg because it
@@ -958,11 +694,11 @@
                                          MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
             }
 
-            if ((ret = pk_get_ecpubkey(&p, end2, eck)) == 0) {
+            if ((ret = mbedtls_pk_ecc_set_pubkey(pk, p, (size_t) (end2 - p))) == 0) {
                 pubkey_done = 1;
             } else {
                 /*
-                 * The only acceptable failure mode of pk_get_ecpubkey() above
+                 * The only acceptable failure mode of mbedtls_pk_ecc_set_pubkey() above
                  * is if the point format is not recognized.
                  */
                 if (ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) {
@@ -970,26 +706,25 @@
                 }
             }
         } else if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
-            mbedtls_ecp_keypair_free(eck);
             return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
         }
     }
 
-    if (!pubkey_done &&
-        (ret = mbedtls_ecp_mul(&eck->grp, &eck->Q, &eck->d, &eck->grp.G,
-                               f_rng, p_rng)) != 0) {
-        mbedtls_ecp_keypair_free(eck);
-        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT, ret);
-    }
-
-    if ((ret = mbedtls_ecp_check_privkey(&eck->grp, &eck->d)) != 0) {
-        mbedtls_ecp_keypair_free(eck);
-        return ret;
+    if (!pubkey_done) {
+        if ((ret = mbedtls_pk_ecc_set_pubkey_from_prv(pk, d, d_len, f_rng, p_rng)) != 0) {
+            return ret;
+        }
     }
 
     return 0;
 }
-#endif /* MBEDTLS_ECP_C */
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
+
+/***********************************************************************
+ *
+ *      PKCS#8 parsing functions
+ *
+ **********************************************************************/
 
 /*
  * Parse an unencrypted PKCS#8 encoded private key
@@ -1015,9 +750,10 @@
     unsigned char *p = (unsigned char *) key;
     unsigned char *end = p + keylen;
     mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE;
+    mbedtls_ecp_group_id ec_grp_id = MBEDTLS_ECP_DP_NONE;
     const mbedtls_pk_info_t *pk_info;
 
-#if !defined(MBEDTLS_ECP_C)
+#if !defined(MBEDTLS_PK_HAVE_ECC_KEYS)
     (void) f_rng;
     (void) p_rng;
 #endif
@@ -1053,7 +789,7 @@
         return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_VERSION, ret);
     }
 
-    if ((ret = pk_get_pk_alg(&p, end, &pk_alg, &params)) != 0) {
+    if ((ret = pk_get_pk_alg(&p, end, &pk_alg, &params, &ec_grp_id)) != 0) {
         return ret;
     }
 
@@ -1076,23 +812,43 @@
 
 #if defined(MBEDTLS_RSA_C)
     if (pk_alg == MBEDTLS_PK_RSA) {
-        if ((ret = pk_parse_key_pkcs1_der(mbedtls_pk_rsa(*pk), p, len)) != 0) {
+        if ((ret = mbedtls_rsa_parse_key(mbedtls_pk_rsa(*pk), p, len)) != 0) {
             mbedtls_pk_free(pk);
             return ret;
         }
     } else
 #endif /* MBEDTLS_RSA_C */
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
     if (pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH) {
-        if ((ret = pk_use_ecparams(&params, &mbedtls_pk_ec(*pk)->grp)) != 0 ||
-            (ret = pk_parse_key_sec1_der(mbedtls_pk_ec(*pk), p, len, f_rng, p_rng)) != 0) {
-            mbedtls_pk_free(pk);
-            return ret;
+#if defined(MBEDTLS_PK_HAVE_RFC8410_CURVES)
+        if (MBEDTLS_PK_IS_RFC8410_GROUP_ID(ec_grp_id)) {
+            if ((ret =
+                     pk_use_ecparams_rfc8410(&params, ec_grp_id, pk)) != 0 ||
+                (ret =
+                     pk_parse_key_rfc8410_der(pk, p, len, end, f_rng,
+                                              p_rng)) != 0) {
+                mbedtls_pk_free(pk);
+                return ret;
+            }
+        } else
+#endif
+        {
+            if ((ret = pk_use_ecparams(&params, pk)) != 0 ||
+                (ret = pk_parse_key_sec1_der(pk, p, len, f_rng, p_rng)) != 0) {
+                mbedtls_pk_free(pk);
+                return ret;
+            }
         }
     } else
-#endif /* MBEDTLS_ECP_C */
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
     return MBEDTLS_ERR_PK_UNKNOWN_PK_ALG;
 
+    end = p + len;
+    if (end != (key + keylen)) {
+        return MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT,
+                                 MBEDTLS_ERR_ASN1_LENGTH_MISMATCH);
+    }
+
     return 0;
 }
 
@@ -1106,7 +862,7 @@
  *
  */
 #if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C)
-static int pk_parse_key_pkcs8_encrypted_der(
+MBEDTLS_STATIC_TESTABLE int mbedtls_pk_parse_key_pkcs8_encrypted_der(
     mbedtls_pk_context *pk,
     unsigned char *key, size_t keylen,
     const unsigned char *pwd, size_t pwdlen,
@@ -1117,10 +873,11 @@
     unsigned char *buf;
     unsigned char *p, *end;
     mbedtls_asn1_buf pbe_alg_oid, pbe_params;
-#if defined(MBEDTLS_PKCS12_C)
+#if defined(MBEDTLS_PKCS12_C) && defined(MBEDTLS_CIPHER_PADDING_PKCS7) && defined(MBEDTLS_CIPHER_C)
     mbedtls_cipher_type_t cipher_alg;
     mbedtls_md_type_t md_alg;
 #endif
+    size_t outlen = 0;
 
     p = key;
     end = p + keylen;
@@ -1164,11 +921,11 @@
     /*
      * Decrypt EncryptedData with appropriate PBE
      */
-#if defined(MBEDTLS_PKCS12_C)
+#if defined(MBEDTLS_PKCS12_C) && defined(MBEDTLS_CIPHER_PADDING_PKCS7) && defined(MBEDTLS_CIPHER_C)
     if (mbedtls_oid_get_pkcs12_pbe_alg(&pbe_alg_oid, &md_alg, &cipher_alg) == 0) {
-        if ((ret = mbedtls_pkcs12_pbe(&pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT,
-                                      cipher_alg, md_alg,
-                                      pwd, pwdlen, p, len, buf)) != 0) {
+        if ((ret = mbedtls_pkcs12_pbe_ext(&pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT,
+                                          cipher_alg, md_alg,
+                                          pwd, pwdlen, p, len, buf, len, &outlen)) != 0) {
             if (ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH) {
                 return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
             }
@@ -1178,11 +935,11 @@
 
         decrypted = 1;
     } else
-#endif /* MBEDTLS_PKCS12_C */
-#if defined(MBEDTLS_PKCS5_C)
+#endif /* MBEDTLS_PKCS12_C && MBEDTLS_CIPHER_PADDING_PKCS7 && MBEDTLS_CIPHER_C */
+#if defined(MBEDTLS_PKCS5_C) && defined(MBEDTLS_CIPHER_PADDING_PKCS7) && defined(MBEDTLS_CIPHER_C)
     if (MBEDTLS_OID_CMP(MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid) == 0) {
-        if ((ret = mbedtls_pkcs5_pbes2(&pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen,
-                                       p, len, buf)) != 0) {
+        if ((ret = mbedtls_pkcs5_pbes2_ext(&pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen,
+                                           p, len, buf, len, &outlen)) != 0) {
             if (ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH) {
                 return MBEDTLS_ERR_PK_PASSWORD_MISMATCH;
             }
@@ -1192,7 +949,7 @@
 
         decrypted = 1;
     } else
-#endif /* MBEDTLS_PKCS5_C */
+#endif /* MBEDTLS_PKCS5_C && MBEDTLS_CIPHER_PADDING_PKCS7 && MBEDTLS_CIPHER_C */
     {
         ((void) pwd);
     }
@@ -1200,11 +957,16 @@
     if (decrypted == 0) {
         return MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE;
     }
-
-    return pk_parse_key_pkcs8_unencrypted_der(pk, buf, len, f_rng, p_rng);
+    return pk_parse_key_pkcs8_unencrypted_der(pk, buf, outlen, f_rng, p_rng);
 }
 #endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */
 
+/***********************************************************************
+ *
+ *      Top-level functions, with format auto-discovery
+ *
+ **********************************************************************/
+
 /*
  * Parse a private key
  */
@@ -1233,16 +995,15 @@
         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
     } else {
         ret = mbedtls_pem_read_buffer(&pem,
-                                      "-----BEGIN RSA PRIVATE KEY-----",
-                                      "-----END RSA PRIVATE KEY-----",
+                                      PEM_BEGIN_PRIVATE_KEY_RSA, PEM_END_PRIVATE_KEY_RSA,
                                       key, pwd, pwdlen, &len);
     }
 
     if (ret == 0) {
         pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
         if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0 ||
-            (ret = pk_parse_key_pkcs1_der(mbedtls_pk_rsa(*pk),
-                                          pem.buf, pem.buflen)) != 0) {
+            (ret = mbedtls_rsa_parse_key(mbedtls_pk_rsa(*pk),
+                                         pem.buf, pem.buflen)) != 0) {
             mbedtls_pk_free(pk);
         }
 
@@ -1257,21 +1018,21 @@
     }
 #endif /* MBEDTLS_RSA_C */
 
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
     /* 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-----",
+                                      PEM_BEGIN_PRIVATE_KEY_EC,
+                                      PEM_END_PRIVATE_KEY_EC,
                                       key, pwd, pwdlen, &len);
     }
     if (ret == 0) {
         pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
 
         if ((ret = mbedtls_pk_setup(pk, pk_info)) != 0 ||
-            (ret = pk_parse_key_sec1_der(mbedtls_pk_ec(*pk),
+            (ret = pk_parse_key_sec1_der(pk,
                                          pem.buf, pem.buflen,
                                          f_rng, p_rng)) != 0) {
             mbedtls_pk_free(pk);
@@ -1286,15 +1047,14 @@
     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
         return ret;
     }
-#endif /* MBEDTLS_ECP_C */
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
 
     /* 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-----",
+                                      PEM_BEGIN_PRIVATE_KEY_PKCS8, PEM_END_PRIVATE_KEY_PKCS8,
                                       key, NULL, 0, &len);
     }
     if (ret == 0) {
@@ -1315,13 +1075,13 @@
         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
     } else {
         ret = mbedtls_pem_read_buffer(&pem,
-                                      "-----BEGIN ENCRYPTED PRIVATE KEY-----",
-                                      "-----END ENCRYPTED PRIVATE KEY-----",
+                                      PEM_BEGIN_ENCRYPTED_PRIVATE_KEY_PKCS8,
+                                      PEM_END_ENCRYPTED_PRIVATE_KEY_PKCS8,
                                       key, NULL, 0, &len);
     }
     if (ret == 0) {
-        if ((ret = pk_parse_key_pkcs8_encrypted_der(pk, pem.buf, pem.buflen,
-                                                    pwd, pwdlen, f_rng, p_rng)) != 0) {
+        if ((ret = mbedtls_pk_parse_key_pkcs8_encrypted_der(pk, pem.buf, pem.buflen,
+                                                            pwd, pwdlen, f_rng, p_rng)) != 0) {
             mbedtls_pk_free(pk);
         }
 
@@ -1353,11 +1113,10 @@
 
         memcpy(key_copy, key, keylen);
 
-        ret = pk_parse_key_pkcs8_encrypted_der(pk, key_copy, keylen,
-                                               pwd, pwdlen, f_rng, p_rng);
+        ret = mbedtls_pk_parse_key_pkcs8_encrypted_der(pk, key_copy, keylen,
+                                                       pwd, pwdlen, f_rng, p_rng);
 
-        mbedtls_platform_zeroize(key_copy, keylen);
-        mbedtls_free(key_copy);
+        mbedtls_zeroize_and_free(key_copy, keylen);
     }
 
     if (ret == 0) {
@@ -1384,7 +1143,7 @@
 
     pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_RSA);
     if (mbedtls_pk_setup(pk, pk_info) == 0 &&
-        pk_parse_key_pkcs1_der(mbedtls_pk_rsa(*pk), key, keylen) == 0) {
+        mbedtls_rsa_parse_key(mbedtls_pk_rsa(*pk), key, keylen) == 0) {
         return 0;
     }
 
@@ -1392,21 +1151,21 @@
     mbedtls_pk_init(pk);
 #endif /* MBEDTLS_RSA_C */
 
-#if defined(MBEDTLS_ECP_C)
+#if defined(MBEDTLS_PK_HAVE_ECC_KEYS)
     pk_info = mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY);
     if (mbedtls_pk_setup(pk, pk_info) == 0 &&
-        pk_parse_key_sec1_der(mbedtls_pk_ec(*pk),
+        pk_parse_key_sec1_der(pk,
                               key, keylen, f_rng, p_rng) == 0) {
         return 0;
     }
     mbedtls_pk_free(pk);
-#endif /* MBEDTLS_ECP_C */
+#endif /* MBEDTLS_PK_HAVE_ECC_KEYS */
 
-    /* If MBEDTLS_RSA_C is defined but MBEDTLS_ECP_C isn't,
+    /* If MBEDTLS_RSA_C is defined but MBEDTLS_PK_HAVE_ECC_KEYS isn't,
      * it is ok to leave the PK context initialized but not
      * freed: It is the caller's responsibility to call pk_init()
      * before calling this function, and to call pk_free()
-     * when it fails. If MBEDTLS_ECP_C is defined but MBEDTLS_RSA_C
+     * when it fails. If MBEDTLS_PK_HAVE_ECC_KEYS is defined but MBEDTLS_RSA_C
      * isn't, this leads to mbedtls_pk_free() being called
      * twice, once here and once by the caller, but this is
      * also ok and in line with the mbedtls_pk_free() calls
@@ -1443,8 +1202,7 @@
         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
     } else {
         ret = mbedtls_pem_read_buffer(&pem,
-                                      "-----BEGIN RSA PUBLIC KEY-----",
-                                      "-----END RSA PUBLIC KEY-----",
+                                      PEM_BEGIN_PUBLIC_KEY_RSA, PEM_END_PUBLIC_KEY_RSA,
                                       key, NULL, 0, &len);
     }
 
@@ -1460,7 +1218,7 @@
             return ret;
         }
 
-        if ((ret = pk_get_rsapubkey(&p, p + pem.buflen, mbedtls_pk_rsa(*ctx))) != 0) {
+        if ((ret = mbedtls_rsa_parse_pubkey(mbedtls_pk_rsa(*ctx), p, pem.buflen)) != 0) {
             mbedtls_pk_free(ctx);
         }
 
@@ -1477,8 +1235,7 @@
         ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT;
     } else {
         ret = mbedtls_pem_read_buffer(&pem,
-                                      "-----BEGIN PUBLIC KEY-----",
-                                      "-----END PUBLIC KEY-----",
+                                      PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY,
                                       key, NULL, 0, &len);
     }
 
@@ -1488,7 +1245,7 @@
          */
         p = pem.buf;
 
-        ret = mbedtls_pk_parse_subpubkey(&p,  p + pem.buflen, ctx);
+        ret = mbedtls_pk_parse_subpubkey(&p, p + pem.buflen, ctx);
         mbedtls_pem_free(&pem);
         return ret;
     } else if (ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) {
@@ -1508,13 +1265,12 @@
     }
 
     p = (unsigned char *) key;
-    ret = pk_get_rsapubkey(&p, p + keylen, mbedtls_pk_rsa(*ctx));
+    ret = mbedtls_rsa_parse_pubkey(mbedtls_pk_rsa(*ctx), p, keylen);
     if (ret == 0) {
         return ret;
     }
     mbedtls_pk_free(ctx);
-    if (ret != (MBEDTLS_ERROR_ADD(MBEDTLS_ERR_PK_INVALID_PUBKEY,
-                                  MBEDTLS_ERR_ASN1_UNEXPECTED_TAG))) {
+    if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) {
         return ret;
     }
 #endif /* MBEDTLS_RSA_C */
@@ -1525,4 +1281,112 @@
     return ret;
 }
 
+/***********************************************************************
+ *
+ *      Top-level functions, with filesystem support
+ *
+ **********************************************************************/
+
+#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.
+ */
+int mbedtls_pk_load_file(const char *path, unsigned char **buf, size_t *n)
+{
+    FILE *f;
+    long size;
+
+    if ((f = fopen(path, "rb")) == NULL) {
+        return MBEDTLS_ERR_PK_FILE_IO_ERROR;
+    }
+
+    /* Ensure no stdio buffering of secrets, as such buffers cannot be wiped. */
+    mbedtls_setbuf(f, NULL);
+
+    fseek(f, 0, SEEK_END);
+    if ((size = ftell(f)) == -1) {
+        fclose(f);
+        return MBEDTLS_ERR_PK_FILE_IO_ERROR;
+    }
+    fseek(f, 0, SEEK_SET);
+
+    *n = (size_t) size;
+
+    if (*n + 1 == 0 ||
+        (*buf = mbedtls_calloc(1, *n + 1)) == NULL) {
+        fclose(f);
+        return MBEDTLS_ERR_PK_ALLOC_FAILED;
+    }
+
+    if (fread(*buf, 1, *n, f) != *n) {
+        fclose(f);
+
+        mbedtls_zeroize_and_free(*buf, *n);
+
+        return MBEDTLS_ERR_PK_FILE_IO_ERROR;
+    }
+
+    fclose(f);
+
+    (*buf)[*n] = '\0';
+
+    if (strstr((const char *) *buf, "-----BEGIN ") != NULL) {
+        ++*n;
+    }
+
+    return 0;
+}
+
+/*
+ * Load and parse a private key
+ */
+int mbedtls_pk_parse_keyfile(mbedtls_pk_context *ctx,
+                             const char *path, const char *pwd,
+                             int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t n;
+    unsigned char *buf;
+
+    if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
+        return ret;
+    }
+
+    if (pwd == NULL) {
+        ret = mbedtls_pk_parse_key(ctx, buf, n, NULL, 0, f_rng, p_rng);
+    } else {
+        ret = mbedtls_pk_parse_key(ctx, buf, n,
+                                   (const unsigned char *) pwd, strlen(pwd), f_rng, p_rng);
+    }
+
+    mbedtls_zeroize_and_free(buf, n);
+
+    return ret;
+}
+
+/*
+ * Load and parse a public key
+ */
+int mbedtls_pk_parse_public_keyfile(mbedtls_pk_context *ctx, const char *path)
+{
+    int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
+    size_t n;
+    unsigned char *buf;
+
+    if ((ret = mbedtls_pk_load_file(path, &buf, &n)) != 0) {
+        return ret;
+    }
+
+    ret = mbedtls_pk_parse_public_key(ctx, buf, n);
+
+    mbedtls_zeroize_and_free(buf, n);
+
+    return ret;
+}
+#endif /* MBEDTLS_FS_IO */
+
 #endif /* MBEDTLS_PK_PARSE_C */