diff options
author | David Benjamin <davidben@chromium.org> | 2016-01-01 09:17:30 +0300 |
---|---|---|
committer | Adam Langley <agl@google.com> | 2016-02-17 20:24:10 +0300 |
commit | e30a09e6049d8e6451da936e66f1591648a06d2e (patch) | |
tree | 9763d2b5da2217e13d0d1cd938c28d3cd66d4cf1 /crypto | |
parent | 440f1037716eca16f203edb8f03d4a59c92ae0cc (diff) |
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>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/evp/evp_asn1.c | 48 | ||||
-rw-r--r-- | crypto/evp/evp_test.cc | 57 | ||||
-rw-r--r-- | crypto/evp/evp_tests.txt | 65 | ||||
-rw-r--r-- | crypto/evp/internal.h | 12 | ||||
-rw-r--r-- | crypto/evp/p_dsa_asn1.c | 143 | ||||
-rw-r--r-- | crypto/evp/p_ec.c | 1 | ||||
-rw-r--r-- | crypto/evp/p_ec_asn1.c | 158 | ||||
-rw-r--r-- | crypto/evp/p_rsa_asn1.c | 44 | ||||
-rw-r--r-- | crypto/pkcs8/pkcs8.c | 86 | ||||
-rw-r--r-- | crypto/test/file_test.cc | 2 |
10 files changed, 242 insertions, 374 deletions
diff --git a/crypto/evp/evp_asn1.c b/crypto/evp/evp_asn1.c index e90bed5f..ed7ae8b7 100644 --- a/crypto/evp/evp_asn1.c +++ b/crypto/evp/evp_asn1.c @@ -114,6 +114,54 @@ int EVP_marshal_public_key(CBB *cbb, const EVP_PKEY *key) { 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 4e7b56e3..a7dac2bf 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 @@ static int GetKeyType(FileTest *t, const std::string &name) { 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 @@ static bool ImportPublicKey(FileTest *t, KeyMap *key_map) { 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 @@ static bool ImportPublicKey(FileTest *t, KeyMap *key_map) { 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_der(der); + + std::vector<uint8_t> output = input; + if (t->HasAttribute("Output") && + !t->GetBytes(&output, "Output")) { 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."); + 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 ImportPublicKey(FileTest *t, KeyMap *key_map) { 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 2320125e..f0601b21 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 @@ Error = DECODE_ERROR # 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 @@ PublicKey = P-256-SPKI 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 ffe768ce..7fe707e1 100644 --- a/crypto/evp/internal.h +++ b/crypto/evp/internal.h @@ -106,8 +106,16 @@ struct evp_pkey_asn1_method_st { 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 bed23c3e..09f69090 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 @@ static int dsa_pub_encode(CBB *out, const EVP_PKEY *key) { 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; - 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; +static int dsa_priv_decode(EVP_PKEY *out, CBS *params, CBS *key) { + /* See PKCS#11, v2.40, section 2.5. */ - 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; + /* Decode parameters. */ + BN_CTX *ctx = NULL; + 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; } - ctx = BN_CTX_new(); - if (ctx == NULL) { - OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); - goto dsaerr; + + /* 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; } - if (!BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx)) { - OPENSSL_PUT_ERROR(EVP, ERR_LIB_BN); - goto dsaerr; + /* Calculate the public key. */ + ctx = BN_CTX_new(); + if (ctx == NULL || + !BN_mod_exp(dsa->pub_key, dsa->g, dsa->priv_key, dsa->p, ctx)) { + goto err; } - 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; - } - - params = ASN1_STRING_new(); - if (!params) { - OPENSSL_PUT_ERROR(EVP, ERR_R_MALLOC_FAILURE); - goto err; - } - - params->length = i2d_DSAparams(pkey->pkey.dsa, ¶ms->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; + return 0; } - 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 f842c270..49521827 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 f072ffe0..14f38396 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 int eckey_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { } } -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 */ - - /* 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); + /* 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; - 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 dc6c0f99..6848cc47 100644 --- a/crypto/evp/p_rsa_asn1.c +++ b/crypto/evp/p_rsa_asn1.c @@ -121,39 +121,41 @@ static int rsa_pub_cmp(const EVP_PKEY *a, const EVP_PKEY *b) { 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 fdce544a..175a8855 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 @@ err: } 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 4752f04a..6b725b9f 100644 --- a/crypto/test/file_test.cc +++ b/crypto/test/file_test.cc @@ -224,6 +224,7 @@ bool FileTest::GetBytes(std::vector<uint8_t> *out, const std::string &key) { 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 @@ int FileTestMain(bool (*run_test)(FileTest *t, void *arg), void *arg, t.GetAttributeOrDie("Error").c_str(), ERR_reason_error_string(err)); failed = true; + ERR_clear_error(); continue; } ERR_clear_error(); |