Implement new PKCS#8 parsers.

As with SPKI parsers, the intent is make EVP_PKEY capture the key's
constraints in full fidelity, so we'd have to add new types or store the
information in the underlying key object if people introduce variant key
types with weird constraints on them.

Note that because PKCS#8 has a space for arbitrary attributes, this
parser must admit a hole. I'm assuming for now that we don't need an API
that enforces no attributes and just ignore trailing data in the
structure for simplicity.

BUG=499653

Change-Id: I6fc641355e87136c7220f5d7693566d1144a68e8
Reviewed-on: https://boringssl-review.googlesource.com/6866
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/evp/evp_asn1.c b/crypto/evp/evp_asn1.c
index e90bed5..ed7ae8b 100644
--- a/crypto/evp/evp_asn1.c
+++ b/crypto/evp/evp_asn1.c
@@ -114,6 +114,54 @@
   return key->ameth->pub_encode(cbb, key);
 }
 
+EVP_PKEY *EVP_parse_private_key(CBS *cbs) {
+  /* Parse the PrivateKeyInfo. */
+  CBS pkcs8, algorithm, oid, key;
+  uint64_t version;
+  if (!CBS_get_asn1(cbs, &pkcs8, CBS_ASN1_SEQUENCE) ||
+      !CBS_get_asn1_uint64(&pkcs8, &version) ||
+      version != 0 ||
+      !CBS_get_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
+      !CBS_get_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) ||
+      !CBS_get_asn1(&pkcs8, &key, CBS_ASN1_OCTETSTRING)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+    return NULL;
+  }
+
+  /* A PrivateKeyInfo ends with a SET of Attributes which we ignore. */
+
+  /* Set up an |EVP_PKEY| of the appropriate type. */
+  EVP_PKEY *ret = EVP_PKEY_new();
+  if (ret == NULL ||
+      !EVP_PKEY_set_type(ret, OBJ_cbs2nid(&oid))) {
+    goto err;
+  }
+
+  /* Call into the type-specific PrivateKeyInfo decoding function. */
+  if (ret->ameth->priv_decode == NULL) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
+    goto err;
+  }
+  if (!ret->ameth->priv_decode(ret, &algorithm, &key)) {
+    goto err;
+  }
+
+  return ret;
+
+err:
+  EVP_PKEY_free(ret);
+  return NULL;
+}
+
+int EVP_marshal_private_key(CBB *cbb, const EVP_PKEY *key) {
+  if (key->ameth->priv_encode == NULL) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_UNSUPPORTED_ALGORITHM);
+    return 0;
+  }
+
+  return key->ameth->priv_encode(cbb, key);
+}
+
 EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out, const uint8_t **inp,
                          long len) {
   EVP_PKEY *ret;
diff --git a/crypto/evp/evp_test.cc b/crypto/evp/evp_test.cc
index 4e7b56e..a7dac2b 100644
--- a/crypto/evp/evp_test.cc
+++ b/crypto/evp/evp_test.cc
@@ -70,13 +70,11 @@
 #pragma warning(pop)
 #endif
 
-#include <openssl/bio.h>
 #include <openssl/bytestring.h>
 #include <openssl/crypto.h>
 #include <openssl/digest.h>
 #include <openssl/err.h>
 #include <openssl/evp.h>
-#include <openssl/pem.h>
 
 #include "../test/file_test.h"
 #include "../test/scoped_types.h"
@@ -121,29 +119,9 @@
 
 using KeyMap = std::map<std::string, ScopedEVP_PKEY>;
 
-// ImportPrivateKey evaluates a PrivateKey test in |t| and writes the resulting
-// private key to |key_map|.
-static bool ImportPrivateKey(FileTest *t, KeyMap *key_map) {
-  const std::string &key_name = t->GetParameter();
-  if (key_map->count(key_name) > 0) {
-    t->PrintLine("Duplicate key '%s'.", key_name.c_str());
-    return false;
-  }
-  const std::string &block = t->GetBlock();
-  ScopedBIO bio(BIO_new_mem_buf(const_cast<char*>(block.data()), block.size()));
-  if (!bio) {
-    return false;
-  }
-  ScopedEVP_PKEY pkey(PEM_read_bio_PrivateKey(bio.get(), nullptr, 0, nullptr));
-  if (!pkey) {
-    t->PrintLine("Error reading private key.");
-    return false;
-  }
-  (*key_map)[key_name] = std::move(pkey);
-  return true;
-}
-
-static bool ImportPublicKey(FileTest *t, KeyMap *key_map) {
+static bool ImportKey(FileTest *t, KeyMap *key_map,
+                      EVP_PKEY *(*parse_func)(CBS *cbs),
+                      int (*marshal_func)(CBB *cbb, const EVP_PKEY *key)) {
   std::vector<uint8_t> input;
   if (!t->GetBytes(&input, "Input")) {
     return false;
@@ -151,7 +129,7 @@
 
   CBS cbs;
   CBS_init(&cbs, input.data(), input.size());
-  ScopedEVP_PKEY pkey(EVP_parse_public_key(&cbs));
+  ScopedEVP_PKEY pkey(parse_func(&cbs));
   if (!pkey) {
     return false;
   }
@@ -165,18 +143,24 @@
     return false;
   }
 
-  // The encoding must round-trip.
+  // The key must re-encode correctly.
   ScopedCBB cbb;
-  uint8_t *spki;
-  size_t spki_len;
+  uint8_t *der;
+  size_t der_len;
   if (!CBB_init(cbb.get(), 0) ||
-      !EVP_marshal_public_key(cbb.get(), pkey.get()) ||
-      !CBB_finish(cbb.get(), &spki, &spki_len)) {
+      !marshal_func(cbb.get(), pkey.get()) ||
+      !CBB_finish(cbb.get(), &der, &der_len)) {
     return false;
   }
-  ScopedOpenSSLBytes free_spki(spki);
-  if (!t->ExpectBytesEqual(input.data(), input.size(), spki, spki_len)) {
-    t->PrintLine("Re-encoding the SPKI did not match.");
+  ScopedOpenSSLBytes free_der(der);
+
+  std::vector<uint8_t> output = input;
+  if (t->HasAttribute("Output") &&
+      !t->GetBytes(&output, "Output")) {
+    return false;
+  }
+  if (!t->ExpectBytesEqual(output.data(), output.size(), der, der_len)) {
+    t->PrintLine("Re-encoding the key did not match.");
     return false;
   }
 
@@ -193,11 +177,12 @@
 static bool TestEVP(FileTest *t, void *arg) {
   KeyMap *key_map = reinterpret_cast<KeyMap*>(arg);
   if (t->GetType() == "PrivateKey") {
-    return ImportPrivateKey(t, key_map);
+    return ImportKey(t, key_map, EVP_parse_private_key,
+                     EVP_marshal_private_key);
   }
 
   if (t->GetType() == "PublicKey") {
-    return ImportPublicKey(t, key_map);
+    return ImportKey(t, key_map, EVP_parse_public_key, EVP_marshal_public_key);
   }
 
   int (*key_op_init)(EVP_PKEY_CTX *ctx);
diff --git a/crypto/evp/evp_tests.txt b/crypto/evp/evp_tests.txt
index 2320125..f0601b2 100644
--- a/crypto/evp/evp_tests.txt
+++ b/crypto/evp/evp_tests.txt
@@ -4,34 +4,8 @@
 
 # RSA 2048 bit key.
 PrivateKey = RSA-2048
------BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDNAIHqeyrh6gbV
-n3xz2f+5SglhXC5Lp8Y2zvCN01M+wxhVJbAVx2m5mnfWclv5w1Mqm25fZifV+4UW
-B2jT3anL01l0URcX3D0wnS/EfuQfl+Mq23+d2GShxHZ6Zm7NcbwarPXnUX9LOFlP
-6psF5C1a2pkSAIAT5FMWpNm7jtCGuI0odYusr5ItRqhotIXSOcm66w4rZFknEPQr
-LR6gpLSALAvsqzKPimiwBzvbVG/uqYCdKEmRKzkMFTK8finHZY+BdfrkbzQzL/h7
-yrPkBkm5hXeGnaDqcYNT8HInVIhpE2SHYNEivmduD8SD3SD/wxvalqMZZsmqLnWt
-A95H4cRPAgMBAAECggEAYCl6x5kbFnoG1rJHWLjL4gi+ubLZ7Jc4vYD5Ci41AF3X
-ziktnim6iFvTFv7x8gkTvArJDWsICLJBTYIQREHYYkozzgIzyPeApIs3Wv8C12cS
-IopwJITbP56+zM+77hcJ26GCgA2Unp5CFuC/81WDiPi9kNo3Oh2CdD7D+90UJ/0W
-glplejFpEuhpU2URfKL4RckJQF/KxV+JX8FdIDhsJu54yemQdQKaF4psHkzwwgDo
-qc+yfp0Vb4bmwq3CKxqEoc1cpbJ5CHXXlAfISzUjlcuBzD/tW7BDtp7eDAcgRVAC
-XO6MX0QBcLYSC7SOD3R7zY9SIRCFDfBDxCjf0YcFMQKBgQD2+WG0fLwDXTrt68fe
-hQqVa2Xs25z2B2QGPxWqSFU8WNly/mZ1BW413f3De/O58vYi7icTNyVoScm+8hdv
-6PfD+LuRujdN1TuvPeyBTSvewQwf3IjN0Wh28mse36PwlBl+301C/x+ylxEDuJjK
-hZxCcocIaoQqtBC7ac8tNa9r4wKBgQDUfnJKf/QQSLJwwlJKQQGHi3MVm7c9PbwY
-eyIOY1s1NPluJDoYTZP4YLa/u2txwe2aHh9FhYMCPDAelqaSwaCLU9DsnKkQEA2A
-RR47fcagG6xK7O+N95iEa8I1oIy7os9MBoBMwRIZ6VYIxxTj8UMNSR+tu6MqV1Gg
-T5d0WDTJpQKBgCHyRSu5uV39AoyRS/eZ8cp36JqV1Q08FtOE+EVfi9evnrPfo9WR
-2YQt7yNfdjCo5IwIj/ZkLhAXlFNakz4el2+oUJ/HKLLaDEoaCNf883q6rh/zABrK
-HcG7sF2d/7qhoJ9/se7zgjfZ68zHIrkzhDbd5xGREnmMJoCcGo3sQyBhAoGAH3UQ
-qmLC2N5KPFMoJ4H0HgLQ6LQCrnhDLkScSBEBYaEUA/AtAYgKjcyTgVLXlyGkcRpg
-esRHHr+WSBD5W+R6ReYEmeKfTJdzyDdzQE9gZjdyjC0DUbsDwybIu3OnIef6VEDq
-IXK7oUZfzDDcsNn4mTDoFaoff5cpqFfgDgM43VkCgYBNHw11b+d+AQmaZS9QqIt7
-aF3FvwCYHV0jdv0Mb+Kc1bY4c0R5MFpzrTwVmdOerjuuA1+9b+0Hwo3nBZM4eaBu
-SOamA2hu2OJWCl9q8fLCT69KqWDjghhvFe7c6aJJGucwaA3Uz3eLcPqoaCarMiNH
-fMkTd7GabVourqIZdgvu1Q==
------END PRIVATE KEY-----
+Type = RSA
+Input = 308204bc020100300d06092a864886f70d0101010500048204a6308204a20201000282010100cd0081ea7b2ae1ea06d59f7c73d9ffb94a09615c2e4ba7c636cef08dd3533ec3185525b015c769b99a77d6725bf9c3532a9b6e5f6627d5fb85160768d3dda9cbd35974511717dc3d309d2fc47ee41f97e32adb7f9dd864a1c4767a666ecd71bc1aacf5e7517f4b38594fea9b05e42d5ada9912008013e45316a4d9bb8ed086b88d28758bacaf922d46a868b485d239c9baeb0e2b64592710f42b2d1ea0a4b4802c0becab328f8a68b0073bdb546feea9809d2849912b390c1532bc7e29c7658f8175fae46f34332ff87bcab3e40649b98577869da0ea718353f0722754886913648760d122be676e0fc483dd20ffc31bda96a31966c9aa2e75ad03de47e1c44f02030100010282010060297ac7991b167a06d6b24758b8cbe208beb9b2d9ec9738bd80f90a2e35005dd7ce292d9e29ba885bd316fef1f20913bc0ac90d6b0808b2414d82104441d8624a33ce0233c8f780a48b375aff02d76712228a702484db3f9ebecccfbbee1709dba182800d949e9e4216e0bff3558388f8bd90da373a1d82743ec3fbdd1427fd16825a657a316912e8695365117ca2f845c909405fcac55f895fc15d20386c26ee78c9e99075029a178a6c1e4cf0c200e8a9cfb27e9d156f86e6c2adc22b1a84a1cd5ca5b2790875d79407c84b352395cb81cc3fed5bb043b69ede0c07204550025cee8c5f440170b6120bb48e0f747bcd8f522110850df043c428dfd187053102818100f6f961b47cbc035d3aedebc7de850a956b65ecdb9cf60764063f15aa48553c58d972fe6675056e35ddfdc37bf3b9f2f622ee271337256849c9bef2176fe8f7c3f8bb91ba374dd53baf3dec814d2bdec10c1fdc88cdd16876f26b1edfa3f094197edf4d42ff1fb2971103b898ca859c427287086a842ab410bb69cf2d35af6be302818100d47e724a7ff41048b270c2524a4101878b73159bb73d3dbc187b220e635b3534f96e243a184d93f860b6bfbb6b71c1ed9a1e1f458583023c301e96a692c1a08b53d0ec9ca910100d80451e3b7dc6a01bac4aecef8df798846bc235a08cbba2cf4c06804cc11219e95608c714e3f1430d491fadbba32a5751a04f97745834c9a502818021f2452bb9b95dfd028c914bf799f1ca77e89a95d50d3c16d384f8455f8bd7af9eb3dfa3d591d9842def235f7630a8e48c088ff6642e101794535a933e1e976fa8509fc728b2da0c4a1a08d7fcf37abaae1ff3001aca1dc1bbb05d9dffbaa1a09f7fb1eef38237d9ebccc722b9338436dde7119112798c26809c1a8dec4320610281801f7510aa62c2d8de4a3c53282781f41e02d0e8b402ae78432e449c48110161a11403f02d01880a8dcc938152d79721a4711a607ac4471ebf964810f95be47a45e60499e29f4c9773c83773404f606637728c2d0351bb03c326c8bb73a721e7fa5440ea2172bba1465fcc30dcb0d9f89930e815aa1f7f9729a857e00e0338dd590281804d1f0d756fe77e01099a652f50a88b7b685dc5bf00981d5d2376fd0c6fe29cd5b638734479305a73ad3c1599d39eae3bae035fbd6fed07c28de705933879a06e48e6a603686ed8e2560a5f6af1f2c24faf4aa960e382186f15eedce9a2491ae730680dd4cf778b70faa86826ab3223477cc91377b19a6d5a2eaea219760beed5
 
 # The public half of the same key encoded as a SubjectPublicKeyInfo.
 PublicKey = RSA-2048-SPKI
@@ -50,11 +24,25 @@
 
 # EC P-256 key
 PrivateKey = P-256
------BEGIN PRIVATE KEY-----
-MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgiocvtiiTxNH/xbnw
-+RdYBp+DUuCPoFpJ+NuSbLVyhyWhRANCAAQsFQ9CnOcPIWwlLPXgYs4fY5zV0WXH
-+JQkBywnGX14szuSDpXNtmTpkNzwz+oNlOKo5q+dDlgFbmUxBJJbn+bJ
------END PRIVATE KEY-----
+Type = EC
+Input = 308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104208a872fb62893c4d1ffc5b9f0f91758069f8352e08fa05a49f8db926cb5728725a144034200042c150f429ce70f216c252cf5e062ce1f639cd5d165c7f89424072c27197d78b33b920e95cdb664e990dcf0cfea0d94e2a8e6af9d0e58056e653104925b9fe6c9
+
+# The same key as above with the optional public key omitted.
+PrivateKey = P-256-MissingPublic
+Type = EC
+Input = 3041020100301306072a8648ce3d020106082a8648ce3d0301070427302502010104208a872fb62893c4d1ffc5b9f0f91758069f8352e08fa05a49f8db926cb5728725
+
+# The same key as above with redundant parameters.
+PrivateKey = P-256-ExtraParameters
+Type = EC
+Input = 308193020100301306072a8648ce3d020106082a8648ce3d0301070479307702010104208a872fb62893c4d1ffc5b9f0f91758069f8352e08fa05a49f8db926cb5728725a00a06082a8648ce3d030107a144034200042c150f429ce70f216c252cf5e062ce1f639cd5d165c7f89424072c27197d78b33b920e95cdb664e990dcf0cfea0d94e2a8e6af9d0e58056e653104925b9fe6c9
+# The key re-encodes with the parameters removed.
+Output = 308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b02010104208a872fb62893c4d1ffc5b9f0f91758069f8352e08fa05a49f8db926cb5728725a144034200042c150f429ce70f216c252cf5e062ce1f639cd5d165c7f89424072c27197d78b33b920e95cdb664e990dcf0cfea0d94e2a8e6af9d0e58056e653104925b9fe6c9
+
+# The same key, but with the redundant parameters in the ECPrivateKey mismatched.
+PrivateKey = P-256-BadInnerParameters
+Input = 308190020100301306072a8648ce3d020106082a8648ce3d0301070476307402010104208a872fb62893c4d1ffc5b9f0f91758069f8352e08fa05a49f8db926cb5728725a00706052b81040022a144034200042c150f429ce70f216c252cf5e062ce1f639cd5d165c7f89424072c27197d78b33b920e95cdb664e990dcf0cfea0d94e2a8e6af9d0e58056e653104925b9fe6c9
+Error = GROUP_MISMATCH
 
 # The public half of the same key encoded as a PublicKey.
 PublicKey = P-256-SPKI
@@ -66,13 +54,18 @@
 Input = 3082014b3082010306072a8648ce3d02013081f7020101302c06072a8648ce3d0101022100ffffffff00000001000000000000000000000000ffffffffffffffffffffffff305b0420ffffffff00000001000000000000000000000000fffffffffffffffffffffffc04205ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b031500c49d360886e704936a6678e1139d26b7819f7e900441046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5022100ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551020101034200042c150f429ce70f216c252cf5e062ce1f639cd5d165c7f89424072c27197d78b33b920e95cdb664e990dcf0cfea0d94e2a8e6af9d0e58056e653104925b9fe6c9
 Error = DECODE_ERROR
 
-# A DSA key.
-PublicKey = DSA-1024
+# A DSA private key.
+PrivateKey = DSA-1024
+Type = DSA
+Input = 308202650201003082023906072a8648ce3804013082022c02820101009e12fab3de12213501dd82aa10ca2d101d2d4ebfef4d2a3f8daa0fe0cedad8d6af85616aa2f3252c0a2b5a6db09e6f14900e0ddb8311876dd8f9669525f99ed65949e184d5064793271169a228680b95ec12f59a8e20b21f2b58eb2a2012d35bde2ee351822fe8f32d0a330565dcce5c672b7259c14b2433d0b5b2ca2b2db0ab626e8f13f47fe0345d904e7294bb038e9ce21a9e580b83356278706cfe768436c69de149ccff98b4aab8cb4f6385c9f102ce59346eaeef27e0ad222d53d6e89cc8cde5776dd00057b03f2d88ab3cedbafd7b585f0b7f7835e17a3728bbf25ea62572f245dc111f3ce39cb6ffacc31b0a2790e7bde90224ea9b09315362af3d2b022100f381dcf53ebf724f8b2e5ca82c010fb4b5eda9358d0fd88ed278589488b54fc3028201000c402a725dcc3a62e02bf4cf43cd17f4a493591220223669cf4193edab423ad08dfb552e308a6a57a5ffbc7cd0fb2087f81f8df0cb08ab2133287d2b6968714a94f633c940845a48a3e16708dde761cc6a8eab2d84db21b6ea5b07681493cc9c31fbc368b243f6ddf8c932a8b4038f44e7b15ca876344a147859f2b43b39458668ad5e0a1a9a669546dd2812e3b3617a0aef99d58e3bb4cc87fd94225e01d2dcc469a77268146c51918f18e8b4d70aa1f0c7623bcc52cf3731d38641b2d2830b7eecb2f09552ff137d046e494e7f33c3590002b16d1b97d936fda28f90c3ed3ca35338168ac16f77c3c57adc2e8f7c6c2256e41a5f65450590dbb5bcf06d66610423022100b0c768702743bc51242993a971a52889795444f7c6452203d0ce84fe6117d46e
+
+# A DSA public key.
+PublicKey = DSA-1024-SPKI
 Type = DSA
 Input = 308201b73082012c06072a8648ce3804013082011f02818100b3429b8b128c9079f9b72e86857e98d265e5d91661ed8b5f4cc56e5eed1e571da30186983a9dd76297eab73ee13a1db841f8800d04a7cab478af6cde2ea4a2868531af169a24858c6268efa39ceb7ed0d4227eb5bbb01124a2a5a26038c7bcfb8cc827f68f5202345166e4718596799b65c9def82828ce44e62e38e41a0d24b1021500c5a56c81ddd87f47e676546c56d05706421624cf0281810094de40d27314fe929e47ff9b1ac65cfc73ef38c4d381c890be6217b15039ae18190e6b421af8c0bda35a5cfd050f58ae2644adce83e68c8e5ba11729df56bbb21e227a60b816cc033fa799a38fe1ba5b4aa1801b6f841ce3df99feb3b4fb96950c960af13fa2ce920aabc12dd24ad2044a35063ea0e25f67f560f4cfbdc5598303818400028180258c30ebbb7f34fdc873ce679f6cea373c7886d75d4421b90920db034daedd292c64d8edd8cdbdd7f3ad23d74cfa2135247d0cef6ecf2e14f99e19d22a8c1266bd8fb8719c0e5667c716c45c7adbdabe548085bdad2dfee636f8d52fd6adb2193df6c4f0520fbd171b91882e0e4f321f8250ffecf4dbea00e114427d3ef96c1a
 
 # The same key as above, but without the parameters.
-PublicKey = DSA-1024-No-Params
+PublicKey = DSA-1024-SPKI-No-Params
 Type = DSA
 Input = 308192300906072a8648ce38040103818400028180258c30ebbb7f34fdc873ce679f6cea373c7886d75d4421b90920db034daedd292c64d8edd8cdbdd7f3ad23d74cfa2135247d0cef6ecf2e14f99e19d22a8c1266bd8fb8719c0e5667c716c45c7adbdabe548085bdad2dfee636f8d52fd6adb2193df6c4f0520fbd171b91882e0e4f321f8250ffecf4dbea00e114427d3ef96c1a
 
diff --git a/crypto/evp/internal.h b/crypto/evp/internal.h
index ffe768c..7fe707e 100644
--- a/crypto/evp/internal.h
+++ b/crypto/evp/internal.h
@@ -106,8 +106,16 @@
   int (*pub_cmp)(const EVP_PKEY *a, const EVP_PKEY *b);
   int (*pub_print)(BIO *out, const EVP_PKEY *pkey, int indent, ASN1_PCTX *pctx);
 
-  int (*priv_decode)(EVP_PKEY *pk, PKCS8_PRIV_KEY_INFO *p8inf);
-  int (*priv_encode)(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pk);
+  /* priv_decode decodes |params| and |key| as a PrivateKeyInfo and writes the
+   * result into |out|. It returns one on success and zero on error. |params| is
+   * the AlgorithmIdentifier after the OBJECT IDENTIFIER type field, and |key|
+   * is the contents of the OCTET STRING privateKey field. */
+  int (*priv_decode)(EVP_PKEY *out, CBS *params, CBS *key);
+
+  /* priv_encode encodes |key| as a PrivateKeyInfo and appends the result to
+   * |out|. It returns one on success and zero on error. */
+  int (*priv_encode)(CBB *out, const EVP_PKEY *key);
+
   int (*priv_print)(BIO *out, const EVP_PKEY *pkey, int indent,
                     ASN1_PCTX *pctx);
 
diff --git a/crypto/evp/p_dsa_asn1.c b/crypto/evp/p_dsa_asn1.c
index bed23c3..09f6909 100644
--- a/crypto/evp/p_dsa_asn1.c
+++ b/crypto/evp/p_dsa_asn1.c
@@ -55,11 +55,11 @@
 
 #include <openssl/evp.h>
 
-#include <limits.h>
-
 #include <openssl/asn1.h>
 #include <openssl/asn1t.h>
 #include <openssl/digest.h>
+#include <openssl/bn.h>
+#include <openssl/bytestring.h>
 #include <openssl/dsa.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
@@ -128,128 +128,69 @@
   return 1;
 }
 
-static int dsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) {
-  const uint8_t *p, *pm;
-  int pklen, pmlen;
-  int ptype;
-  void *pval;
-  ASN1_STRING *pstr;
-  X509_ALGOR *palg;
-  ASN1_INTEGER *privkey = NULL;
+static int dsa_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) {
+  /* See PKCS#11, v2.40, section 2.5. */
+
+  /* Decode parameters. */
   BN_CTX *ctx = NULL;
-
-  /* In PKCS#8 DSA: you just get a private key integer and parameters in the
-   * AlgorithmIdentifier the pubkey must be recalculated. */
-
-  DSA *dsa = NULL;
-
-  if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) {
-    return 0;
-  }
-  privkey = d2i_ASN1_INTEGER(NULL, &p, pklen);
-  if (privkey == NULL || privkey->type == V_ASN1_NEG_INTEGER) {
-    goto decerr;
+  DSA *dsa = DSA_parse_parameters(params);
+  if (dsa == NULL || CBS_len(params) != 0) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+    goto err;
   }
 
-  X509_ALGOR_get0(NULL, &ptype, &pval, palg);
-  if (ptype != V_ASN1_SEQUENCE) {
-    goto decerr;
-  }
-  pstr = pval;
-  pm = pstr->data;
-  pmlen = pstr->length;
-  dsa = d2i_DSAparams(NULL, &pm, pmlen);
-  if (dsa == NULL) {
-    goto decerr;
-  }
-  /* We have parameters. Now set private key */
-  dsa->priv_key = ASN1_INTEGER_to_BN(privkey, NULL);
-  if (dsa->priv_key == NULL) {
-    OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN);
-    goto dsaerr;
-  }
-  /* Calculate public key. */
+  dsa->priv_key = BN_new();
   dsa->pub_key = BN_new();
-  if (dsa->pub_key == NULL) {
-    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
-    goto dsaerr;
+  if (dsa->priv_key == NULL || dsa->pub_key == NULL) {
+    goto err;
   }
+
+  /* Decode the key. */
+  if (!BN_parse_asn1_unsigned(key, dsa->priv_key) ||
+      CBS_len(key) != 0) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+    goto err;
+  }
+
+  /* Calculate the public key. */
   ctx = BN_CTX_new();
-  if (ctx == NULL) {
-    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
-    goto dsaerr;
+  if (ctx == NULL ||
+      !BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx)) {
+    goto err;
   }
 
-  if (!BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx)) {
-    OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN);
-    goto dsaerr;
-  }
-
-  EVP_PKEY_assign_DSA(pkey, dsa);
   BN_CTX_free(ctx);
-  ASN1_INTEGER_free(privkey);
-
+  EVP_PKEY_assign_DSA(out, dsa);
   return 1;
 
-decerr:
-  OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
-
-dsaerr:
+err:
   BN_CTX_free(ctx);
-  ASN1_INTEGER_free(privkey);
   DSA_free(dsa);
   return 0;
 }
 
-static int dsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) {
-  ASN1_STRING *params = NULL;
-  ASN1_INTEGER *prkey = NULL;
-  uint8_t *dp = NULL;
-  int dplen;
-
-  if (!pkey->pkey.dsa || !pkey->pkey.dsa->priv_key) {
+static int dsa_priv_encode(CBB *out, const EVP_PKEY *key) {
+  const DSA *dsa = key->pkey.dsa;
+  if (dsa == NULL || dsa->priv_key == NULL) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
-    goto err;
+    return 0;
   }
 
-  params = ASN1_STRING_new();
-  if (!params) {
-    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
-    goto err;
-  }
-
-  params->length = i2d_DSAparams(pkey->pkey.dsa, &params->data);
-  if (params->length <= 0) {
-    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
-    goto err;
-  }
-  params->type = V_ASN1_SEQUENCE;
-
-  /* Get private key into integer. */
-  prkey = BN_to_ASN1_INTEGER(pkey->pkey.dsa->priv_key, NULL);
-
-  if (!prkey) {
-    OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN);
-    goto err;
-  }
-
-  dplen = i2d_ASN1_INTEGER(prkey, &dp);
-
-  ASN1_INTEGER_free(prkey);
-  prkey = NULL;
-
-  if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_dsa), 0,
-                       V_ASN1_SEQUENCE, params, dp, dplen)) {
-    goto err;
+  /* See PKCS#11, v2.40, section 2.5. */
+  CBB pkcs8, algorithm, private_key;
+  if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
+      !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
+      !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
+      !OBJ_nid2cbb(&algorithm, NID_dsa) ||
+      !DSA_marshal_parameters(&algorithm, dsa) ||
+      !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
+      !BN_marshal_asn1(&private_key, dsa->priv_key) ||
+      !CBB_flush(out)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
+    return 0;
   }
 
   return 1;
-
-err:
-  OPENSSL_free(dp);
-  ASN1_STRING_free(params);
-  ASN1_INTEGER_free(prkey);
-  return 0;
 }
 
 static int int_dsa_size(const EVP_PKEY *pkey) {
diff --git a/crypto/evp/p_ec.c b/crypto/evp/p_ec.c
index f842c27..4952182 100644
--- a/crypto/evp/p_ec.c
+++ b/crypto/evp/p_ec.c
@@ -57,7 +57,6 @@
 
 #include <string.h>
 
-#include <openssl/asn1.h>
 #include <openssl/bn.h>
 #include <openssl/buf.h>
 #include <openssl/digest.h>
diff --git a/crypto/evp/p_ec_asn1.c b/crypto/evp/p_ec_asn1.c
index f072ffe..14f3839 100644
--- a/crypto/evp/p_ec_asn1.c
+++ b/crypto/evp/p_ec_asn1.c
@@ -59,6 +59,8 @@
 #include <openssl/bn.h>
 #include <openssl/bytestring.h>
 #include <openssl/ec.h>
+#include <openssl/ec_key.h>
+#include <openssl/ecdsa.h>
 #include <openssl/err.h>
 #include <openssl/mem.h>
 #include <openssl/obj.h>
@@ -67,26 +69,6 @@
 #include "internal.h"
 
 
-static int eckey_param2type(int *pptype, void **ppval, EC_KEY *ec_key) {
-  const EC_GROUP *group;
-  int nid;
-
-  if (ec_key == NULL || (group = EC_KEY_get0_group(ec_key)) == NULL) {
-    OPENSSL_PUT_ERROR(EVP, EVP_R_MISSING_PARAMETERS);
-    return 0;
-  }
-
-  nid = EC_GROUP_get_curve_name(group);
-  if (nid == NID_undef) {
-    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE);
-    return 0;
-  }
-
-  *ppval = (void*) OBJ_nid2obj(nid);
-  *pptype = V_ASN1_OBJECT;
-  return 1;
-}
-
 static int eckey_pub_encode(CBB *out, const EVP_PKEY *key) {
   const EC_KEY *ec_key = key->pkey.ec;
   const EC_GROUP *group = EC_KEY_get0_group(ec_key);
@@ -164,124 +146,52 @@
   }
 }
 
-static EC_KEY *eckey_type2param(int ptype, void *pval) {
-  EC_KEY *eckey = NULL;
-
-  if (ptype == V_ASN1_SEQUENCE) {
-    ASN1_STRING *pstr = pval;
-    const uint8_t *pm = pstr->data;
-    int pmlen = pstr->length;
-
-    eckey = d2i_ECParameters(NULL, &pm, pmlen);
-    if (eckey == NULL) {
-      OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
-      goto err;
-    }
-  } else if (ptype == V_ASN1_OBJECT) {
-    ASN1_OBJECT *poid = pval;
-
-    /* type == V_ASN1_OBJECT => the parameters are given
-     * by an asn1 OID */
-    eckey = EC_KEY_new_by_curve_name(OBJ_obj2nid(poid));
-    if (eckey == NULL) {
-      goto err;
-    }
-  } else {
+static int eckey_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) {
+  /* See RFC 5915. */
+  EC_GROUP *group = EC_KEY_parse_parameters(params);
+  if (group == NULL || CBS_len(params) != 0) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
-    goto err;
-  }
-
-  return eckey;
-
-err:
-  if (eckey) {
-    EC_KEY_free(eckey);
-  }
-  return NULL;
-}
-
-static int eckey_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) {
-  const uint8_t *p = NULL;
-  void *pval;
-  int ptype, pklen;
-  EC_KEY *eckey = NULL;
-  X509_ALGOR *palg;
-
-  if (!PKCS8_pkey_get0(NULL, &p, &pklen, &palg, p8)) {
+    EC_GROUP_free(group);
     return 0;
   }
-  X509_ALGOR_get0(NULL, &ptype, &pval, palg);
 
-  eckey = eckey_type2param(ptype, pval);
-
-  if (!eckey) {
-    goto ecliberr;
-  }
-
-  /* We have parameters now set private key */
-  if (!d2i_ECPrivateKey(&eckey, &p, pklen)) {
+  EC_KEY *ec_key = EC_KEY_parse_private_key(key, group);
+  EC_GROUP_free(group);
+  if (ec_key == NULL || CBS_len(key) != 0) {
     OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
-    goto ecerr;
+    EC_KEY_free(ec_key);
+    return 0;
   }
 
-  EVP_PKEY_assign_EC_KEY(pkey, eckey);
+  EVP_PKEY_assign_EC_KEY(out, ec_key);
   return 1;
-
-ecliberr:
-  OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
-ecerr:
-  if (eckey) {
-    EC_KEY_free(eckey);
-  }
-  return 0;
 }
 
-static int eckey_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) {
-  EC_KEY *ec_key;
-  uint8_t *ep, *p;
-  int eplen, ptype;
-  void *pval;
-  unsigned int tmp_flags, old_flags;
-
-  ec_key = pkey->pkey.ec;
-
-  if (!eckey_param2type(&ptype, &pval, ec_key)) {
-    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+static int eckey_priv_encode(CBB *out, const EVP_PKEY *key) {
+  const EC_KEY *ec_key = key->pkey.ec;
+  int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec_key));
+  if (curve_nid == NID_undef) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_NO_NID_FOR_CURVE);
     return 0;
   }
 
-  /* set the private key */
+  /* Omit the redundant copy of the curve name. This contradicts RFC 5915 but
+   * aligns with PKCS #11. SEC 1 only says they may be omitted if known by other
+   * means. Both OpenSSL and NSS omit the redundant parameters, so we omit them
+   * as well. */
+  unsigned enc_flags = EC_KEY_get_enc_flags(ec_key) | EC_PKEY_NO_PARAMETERS;
 
-  /* do not include the parameters in the SEC1 private key
-   * see PKCS#11 12.11 */
-  old_flags = EC_KEY_get_enc_flags(ec_key);
-  tmp_flags = old_flags | EC_PKEY_NO_PARAMETERS;
-  EC_KEY_set_enc_flags(ec_key, tmp_flags);
-  eplen = i2d_ECPrivateKey(ec_key, NULL);
-  if (!eplen) {
-    EC_KEY_set_enc_flags(ec_key, old_flags);
-    OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
-    return 0;
-  }
-  ep = OPENSSL_malloc(eplen);
-  if (!ep) {
-    EC_KEY_set_enc_flags(ec_key, old_flags);
-    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
-    return 0;
-  }
-  p = ep;
-  if (!i2d_ECPrivateKey(ec_key, &p)) {
-    EC_KEY_set_enc_flags(ec_key, old_flags);
-    OPENSSL_free(ep);
-    OPENSSL_PUT_ERROR(EVP, ERR_R_EC_LIB);
-    return 0;
-  }
-  /* restore old encoding flags */
-  EC_KEY_set_enc_flags(ec_key, old_flags);
-
-  if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_X9_62_id_ecPublicKey),
-                       0, ptype, pval, ep, eplen)) {
-    OPENSSL_free(ep);
+  /* See RFC 5915. */
+  CBB pkcs8, algorithm, private_key;
+  if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
+      !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
+      !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
+      !OBJ_nid2cbb(&algorithm, NID_X9_62_id_ecPublicKey) ||
+      !OBJ_nid2cbb(&algorithm, curve_nid) ||
+      !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
+      !EC_KEY_marshal_private_key(&private_key, ec_key, enc_flags) ||
+      !CBB_flush(out)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
     return 0;
   }
 
diff --git a/crypto/evp/p_rsa_asn1.c b/crypto/evp/p_rsa_asn1.c
index dc6c0f9..6848cc4 100644
--- a/crypto/evp/p_rsa_asn1.c
+++ b/crypto/evp/p_rsa_asn1.c
@@ -121,39 +121,41 @@
          BN_cmp(b->pkey.rsa->e, a->pkey.rsa->e) == 0;
 }
 
-static int rsa_priv_encode(PKCS8_PRIV_KEY_INFO *p8, const EVP_PKEY *pkey) {
-  uint8_t *encoded;
-  size_t encoded_len;
-  if (!RSA_private_key_to_bytes(&encoded, &encoded_len, pkey->pkey.rsa)) {
-    return 0;
-  }
-
-  /* TODO(fork): const correctness in next line. */
-  if (!PKCS8_pkey_set0(p8, (ASN1_OBJECT *)OBJ_nid2obj(NID_rsaEncryption), 0,
-                       V_ASN1_NULL, NULL, encoded, encoded_len)) {
-    OPENSSL_free(encoded);
-    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
+static int rsa_priv_encode(CBB *out, const EVP_PKEY *key) {
+  CBB pkcs8, algorithm, null, private_key;
+  if (!CBB_add_asn1(out, &pkcs8, CBS_ASN1_SEQUENCE) ||
+      !CBB_add_asn1_uint64(&pkcs8, 0 /* version */) ||
+      !CBB_add_asn1(&pkcs8, &algorithm, CBS_ASN1_SEQUENCE) ||
+      !OBJ_nid2cbb(&algorithm, NID_rsaEncryption) ||
+      !CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL) ||
+      !CBB_add_asn1(&pkcs8, &private_key, CBS_ASN1_OCTETSTRING) ||
+      !RSA_marshal_private_key(&private_key, key->pkey.rsa) ||
+      !CBB_flush(out)) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_ENCODE_ERROR);
     return 0;
   }
 
   return 1;
 }
 
-static int rsa_priv_decode(EVP_PKEY *pkey, PKCS8_PRIV_KEY_INFO *p8) {
-  const uint8_t *p;
-  int pklen;
-  if (!PKCS8_pkey_get0(NULL, &p, &pklen, NULL, p8)) {
-    OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE);
+static int rsa_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) {
+  /* Per RFC 3447, A.1, the parameters have type NULL. */
+  CBS null;
+  if (!CBS_get_asn1(params, &null, CBS_ASN1_NULL) ||
+      CBS_len(&null) != 0 ||
+      CBS_len(params) != 0) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
     return 0;
   }
 
-  RSA *rsa = RSA_private_key_from_bytes(p, pklen);
-  if (rsa == NULL) {
-    OPENSSL_PUT_ERROR(EVP, ERR_R_RSA_LIB);
+  RSA *rsa = RSA_parse_private_key(key);
+  if (rsa == NULL || CBS_len(key) != 0) {
+    OPENSSL_PUT_ERROR(EVP, EVP_R_DECODE_ERROR);
+    RSA_free(rsa);
     return 0;
   }
 
-  EVP_PKEY_assign_RSA(pkey, rsa);
+  EVP_PKEY_assign_RSA(out, rsa);
   return 1;
 }
 
diff --git a/crypto/pkcs8/pkcs8.c b/crypto/pkcs8/pkcs8.c
index fdce544..175a885 100644
--- a/crypto/pkcs8/pkcs8.c
+++ b/crypto/pkcs8/pkcs8.c
@@ -62,6 +62,7 @@
 #include <openssl/asn1.h>
 #include <openssl/bn.h>
 #include <openssl/buf.h>
+#include <openssl/bytestring.h>
 #include <openssl/cipher.h>
 #include <openssl/digest.h>
 #include <openssl/err.h>
@@ -71,7 +72,6 @@
 
 #include "internal.h"
 #include "../bytestring/internal.h"
-#include "../evp/internal.h"
 
 
 #define PKCS12_KEY_ID 1
@@ -591,72 +591,52 @@
 }
 
 EVP_PKEY *EVP_PKCS82PKEY(PKCS8_PRIV_KEY_INFO *p8) {
-  EVP_PKEY *pkey = NULL;
-  ASN1_OBJECT *algoid;
-  char obj_tmp[80];
-
-  if (!PKCS8_pkey_get0(&algoid, NULL, NULL, NULL, p8)) {
+  uint8_t *der = NULL;
+  int der_len = i2d_PKCS8_PRIV_KEY_INFO(p8, &der);
+  if (der_len < 0) {
     return NULL;
   }
 
-  pkey = EVP_PKEY_new();
-  if (pkey == NULL) {
-    OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
+  CBS cbs;
+  CBS_init(&cbs, der, (size_t)der_len);
+  EVP_PKEY *ret = EVP_parse_private_key(&cbs);
+  if (ret == NULL || CBS_len(&cbs) != 0) {
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+    EVP_PKEY_free(ret);
+    OPENSSL_free(der);
     return NULL;
   }
 
-  if (!EVP_PKEY_set_type(pkey, OBJ_obj2nid(algoid))) {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
-    i2t_ASN1_OBJECT(obj_tmp, 80, algoid);
-    ERR_add_error_data(2, "TYPE=", obj_tmp);
-    goto error;
-  }
-
-  if (pkey->ameth->priv_decode) {
-    if (!pkey->ameth->priv_decode(pkey, p8)) {
-      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PRIVATE_KEY_DECODE_ERROR);
-      goto error;
-    }
-  } else {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_METHOD_NOT_SUPPORTED);
-    goto error;
-  }
-
-  return pkey;
-
-error:
-  EVP_PKEY_free(pkey);
-  return NULL;
+  OPENSSL_free(der);
+  return ret;
 }
 
 PKCS8_PRIV_KEY_INFO *EVP_PKEY2PKCS8(EVP_PKEY *pkey) {
-  PKCS8_PRIV_KEY_INFO *p8;
-
-  p8 = PKCS8_PRIV_KEY_INFO_new();
-  if (p8 == NULL) {
-    OPENSSL_PUT_ERROR(PKCS8, ERR_R_MALLOC_FAILURE);
-    return NULL;
+  CBB cbb;
+  uint8_t *der = NULL;
+  size_t der_len;
+  if (!CBB_init(&cbb, 0) ||
+      !EVP_marshal_private_key(&cbb, pkey) ||
+      !CBB_finish(&cbb, &der, &der_len) ||
+      der_len > LONG_MAX) {
+    CBB_cleanup(&cbb);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_ENCODE_ERROR);
+    goto err;
   }
-  p8->broken = PKCS8_OK;
 
-  if (pkey->ameth) {
-    if (pkey->ameth->priv_encode) {
-      if (!pkey->ameth->priv_encode(p8, pkey)) {
-        OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_PRIVATE_KEY_ENCODE_ERROR);
-        goto error;
-      }
-    } else {
-      OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_METHOD_NOT_SUPPORTED);
-      goto error;
-    }
-  } else {
-    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM);
-    goto error;
+  const uint8_t *p = der;
+  PKCS8_PRIV_KEY_INFO *p8 = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, (long)der_len);
+  if (p8 == NULL || p != der + der_len) {
+    PKCS8_PRIV_KEY_INFO_free(p8);
+    OPENSSL_PUT_ERROR(PKCS8, PKCS8_R_DECODE_ERROR);
+    goto err;
   }
+
+  OPENSSL_free(der);
   return p8;
 
-error:
-  PKCS8_PRIV_KEY_INFO_free(p8);
+err:
+  OPENSSL_free(der);
   return NULL;
 }
 
diff --git a/crypto/test/file_test.cc b/crypto/test/file_test.cc
index 4752f04..6b725b9 100644
--- a/crypto/test/file_test.cc
+++ b/crypto/test/file_test.cc
@@ -224,6 +224,7 @@
     PrintLine("Error decoding value: %s", value.c_str());
     return false;
   }
+  out->clear();
   out->reserve(value.size() / 2);
   for (size_t i = 0; i < value.size(); i += 2) {
     uint8_t hi, lo;
@@ -304,6 +305,7 @@
                      t.GetAttributeOrDie("Error").c_str(),
                      ERR_reason_error_string(err));
         failed = true;
+        ERR_clear_error();
         continue;
       }
       ERR_clear_error();
diff --git a/include/openssl/evp.h b/include/openssl/evp.h
index 3f8b59c..3db135b 100644
--- a/include/openssl/evp.h
+++ b/include/openssl/evp.h
@@ -202,20 +202,23 @@
  * success and zero on error. */
 OPENSSL_EXPORT int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key);
 
-/* d2i_PrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes at
- * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in
- * |*out|. If |*out| is already non-NULL on entry then the result is written
- * directly into |*out|, otherwise a fresh |EVP_PKEY| is allocated. However,
- * one should not depend on writing into |*out| because this behaviour is
- * likely to change in the future. On successful exit, |*inp| is advanced past
- * the DER structure. It returns the result or NULL on error. */
-OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out,
-                                        const uint8_t **inp, long len);
+/* EVP_parse_private_key decodes a DER-encoded PrivateKeyInfo structure (RFC
+ * 5208) from |cbs| and advances |cbs|. It returns a newly-allocated |EVP_PKEY|
+ * or NULL on error.
+ *
+ * The caller must check the type of the parsed private key to ensure it is
+ * suitable and validate other desired key properties such as RSA modulus size
+ * or EC curve.
+ *
+ * A PrivateKeyInfo ends with an optional set of attributes. These are not
+ * processed and so this function will silently ignore any trailing data in the
+ * structure. */
+OPENSSL_EXPORT EVP_PKEY *EVP_parse_private_key(CBS *cbs);
 
-/* d2i_AutoPrivateKey acts the same as |d2i_PrivateKey|, but detects the type
- * of the private key. */
-OPENSSL_EXPORT EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp,
-                                            long len);
+/* EVP_marshal_private_key marshals |key| as a DER-encoded PrivateKeyInfo
+ * structure (RFC 5208) and appends the result to |cbb|. It returns one on
+ * success and zero on error. */
+OPENSSL_EXPORT int EVP_marshal_private_key(CBB *cbb, const EVP_PKEY *key);
 
 
 /* Signing */
@@ -714,6 +717,29 @@
  * Use |RSA_marshal_public_key| or |EC_POINT_point2cbb| instead. */
 OPENSSL_EXPORT int i2d_PublicKey(EVP_PKEY *key, uint8_t **outp);
 
+/* d2i_PrivateKey parses an ASN.1, DER-encoded, private key from |len| bytes at
+ * |*inp|. If |out| is not NULL then, on exit, a pointer to the result is in
+ * |*out|. If |*out| is already non-NULL on entry then the result is written
+ * directly into |*out|, otherwise a fresh |EVP_PKEY| is allocated. However,
+ * one should not depend on writing into |*out| because this behaviour is
+ * likely to change in the future. On successful exit, |*inp| is advanced past
+ * the DER structure. It returns the result or NULL on error.
+ *
+ * This function tries to detect one of several formats. Instead, use
+ * |EVP_parse_private_key| for a PrivateKeyInfo, |RSA_parse_private_key| for an
+ * RSAPrivateKey, and |EC_parse_private_key| for an ECPrivateKey. */
+OPENSSL_EXPORT EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **out,
+                                        const uint8_t **inp, long len);
+
+/* d2i_AutoPrivateKey acts the same as |d2i_PrivateKey|, but detects the type
+ * of the private key.
+ *
+ * This function tries to detect one of several formats. Instead, use
+ * |EVP_parse_private_key| for a PrivateKeyInfo, |RSA_parse_private_key| for an
+ * RSAPrivateKey, and |EC_parse_private_key| for an ECPrivateKey. */
+OPENSSL_EXPORT EVP_PKEY *d2i_AutoPrivateKey(EVP_PKEY **out, const uint8_t **inp,
+                                            long len);
+
 
 /* Private functions */