Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/cert/internal/verify_signed_data.h" | |
| 6 | |
| 7 #include "net/cert/internal/signature_algorithm.h" | |
| 8 | |
| 9 // TODO(eroman): There is no intention to implement this for non-OpenSSL. Remove | |
| 10 // this branch once the migration is complete. This could have been done as a | |
| 11 // conditional file (_openssl.cc) in the build file instead, but that is likely | |
| 12 // not worth the effort at this point. | |
| 13 | |
| 14 #if !defined(USE_OPENSSL) | |
| 15 | |
| 16 namespace net { | |
| 17 | |
| 18 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm, | |
| 19 const der::Input& signed_data, | |
| 20 const der::Input& signature_value, | |
| 21 const der::Input& public_key) { | |
| 22 // Not implemented | |
| 23 return false; | |
| 24 } | |
| 25 | |
| 26 } // namespace net | |
| 27 | |
| 28 #else | |
| 29 | |
| 30 #include <openssl/evp.h> | |
| 31 #include <openssl/pkcs12.h> | |
|
davidben
2015/07/07 18:03:56
What's this include for?
eroman
2015/07/07 18:34:43
I was apparently relying on it for its transitive
| |
| 32 #include <openssl/rand.h> | |
|
eroman
2015/07/07 18:34:43
This similarly was not needed, and removed.
| |
| 33 | |
| 34 #include "crypto/openssl_util.h" | |
| 35 #include "crypto/scoped_openssl_types.h" | |
| 36 #include "net/der/input.h" | |
| 37 #include "net/der/parser.h" | |
| 38 | |
| 39 namespace net { | |
| 40 | |
| 41 namespace { | |
| 42 | |
| 43 // Creates a EVP_PKEY given the der-encoded bytes of the SPKI. This function | |
| 44 // does not do any sort of validation of the resultant key. The consumer is | |
| 45 // responsible for verifying the key's type and validity of its parameters. | |
| 46 WARN_UNUSED_RESULT bool ImportUnverifiedPkeyFromSpki( | |
| 47 const der::Input& spki, | |
| 48 crypto::ScopedEVP_PKEY* pkey) { | |
| 49 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
| 50 | |
| 51 const uint8_t* ptr = spki.UnsafeData(); | |
| 52 pkey->reset(d2i_PUBKEY(nullptr, &ptr, spki.Length())); | |
|
davidben
2015/07/07 18:03:56
This needs x509.h. I'd rather we not use x509.h, b
eroman
2015/07/07 18:34:43
Thanks David!
So my take-away is:
(1) Switch t
davidben
2015/07/07 18:53:21
Oh, good point. I hadn't thought about WebCrypto.
| |
| 53 if (!pkey->get() || ptr != spki.UnsafeData() + spki.Length()) | |
| 54 return false; | |
| 55 | |
| 56 return true; | |
| 57 } | |
| 58 | |
| 59 // Converts a DigestAlgorithm to an equivalent EVP_MD*. | |
| 60 WARN_UNUSED_RESULT bool GetDigest(DigestAlgorithm digest, const EVP_MD** out) { | |
| 61 switch (digest) { | |
| 62 case DigestAlgorithm::Sha1: | |
| 63 *out = EVP_sha1(); | |
| 64 break; | |
| 65 case DigestAlgorithm::Sha256: | |
| 66 *out = EVP_sha256(); | |
| 67 break; | |
| 68 case DigestAlgorithm::Sha384: | |
| 69 *out = EVP_sha384(); | |
| 70 break; | |
| 71 case DigestAlgorithm::Sha512: | |
| 72 *out = EVP_sha512(); | |
| 73 break; | |
| 74 } | |
| 75 | |
| 76 return *out; | |
|
davidben
2015/07/07 18:03:57
I believe MSVC will grump about this and want !!*o
eroman
2015/07/07 18:34:43
Done.
| |
| 77 } | |
| 78 | |
| 79 // Sets the RSASSA-PSS parameters on |pctx|. Returns true on success. | |
| 80 bool ApplyRsaPssOptions(const RsaPssParameters* params, EVP_PKEY_CTX* pctx) { | |
| 81 // BoringSSL takes a signed int for the salt length, and interprets | |
| 82 // negative values in a special manner. Make sure not to silently underflow. | |
| 83 base::CheckedNumeric<int> salt_length_bytes_int(params->salt_length()); | |
| 84 if (!salt_length_bytes_int.IsValid()) | |
| 85 return false; | |
| 86 | |
| 87 const EVP_MD* mgf1_hash; | |
| 88 if (!GetDigest(params->mgf1_hash(), &mgf1_hash)) | |
| 89 return false; | |
| 90 | |
| 91 return (1 == EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) && | |
| 92 1 == EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_hash) && | |
| 93 1 == EVP_PKEY_CTX_set_rsa_pss_saltlen( | |
| 94 pctx, salt_length_bytes_int.ValueOrDie())); | |
| 95 } | |
| 96 | |
| 97 bool RsaVerify(const SignatureAlgorithm& algorithm, | |
| 98 const der::Input& signed_data, | |
| 99 const der::Input& signature_value, | |
| 100 EVP_PKEY* public_key) { | |
| 101 // TODO(eroman): Is it necessary to verify that the public key's parameters | |
| 102 // are congruent with the signature algorithm, or will BoringSSL already do | |
| 103 // the needed checks? | |
|
Ryan Sleevi
2015/07/07 14:07:31
David: Look here
davidben
2015/07/07 18:03:56
I don't believe BoringSSL is even passed the signa
eroman
2015/07/07 18:34:43
Thanks!
Indeed, seems the checks are in fact quit
| |
| 104 | |
| 105 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
| 106 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create()); | |
| 107 EVP_PKEY_CTX* pctx = NULL; // Owned by |ctx|. | |
| 108 | |
| 109 const EVP_MD* digest; | |
| 110 if (!GetDigest(algorithm.digest(), &digest)) | |
| 111 return false; | |
| 112 | |
| 113 if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, NULL, public_key)) | |
| 114 return false; | |
| 115 | |
| 116 // Set the RSASSA-PSS specific options. | |
| 117 if (algorithm.algorithm() == SignatureAlgorithmId::RsaPss && | |
| 118 !ApplyRsaPssOptions(algorithm.ParamsForRsaPss(), pctx)) { | |
| 119 return false; | |
| 120 } | |
| 121 | |
| 122 if (!EVP_DigestVerifyUpdate(ctx.get(), signed_data.UnsafeData(), | |
| 123 signed_data.Length())) { | |
| 124 return false; | |
| 125 } | |
| 126 | |
| 127 return 1 == EVP_DigestVerifyFinal(ctx.get(), signature_value.UnsafeData(), | |
| 128 signature_value.Length()); | |
| 129 } | |
| 130 | |
| 131 bool EcdsaVerify(const SignatureAlgorithm& algorithm, | |
| 132 const der::Input& signed_data, | |
| 133 const der::Input& signature_value, | |
| 134 EVP_PKEY* public_key) { | |
| 135 // TODO(eroman): Is it necessary to verify that the public key's parameters | |
| 136 // are congruent with the signature algorithm, or will BoringSSL already do | |
| 137 // the needed checks? | |
|
Ryan Sleevi
2015/07/07 14:07:31
David: And here
davidben
2015/07/07 18:03:56
Ditto.
| |
| 138 | |
| 139 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
| 140 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create()); | |
| 141 | |
| 142 const EVP_MD* digest; | |
| 143 if (!GetDigest(algorithm.digest(), &digest)) | |
| 144 return false; | |
| 145 | |
| 146 if (!EVP_DigestVerifyInit(ctx.get(), NULL, digest, NULL, public_key) || | |
| 147 !EVP_DigestVerifyUpdate(ctx.get(), signed_data.UnsafeData(), | |
| 148 signed_data.Length())) { | |
| 149 return false; | |
| 150 } | |
| 151 | |
| 152 return 1 == EVP_DigestVerifyFinal(ctx.get(), signature_value.UnsafeData(), | |
| 153 signature_value.Length()); | |
| 154 } | |
| 155 | |
| 156 } // namespace | |
| 157 | |
| 158 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm, | |
| 159 const der::Input& signed_data, | |
| 160 const der::Input& signature_value, | |
| 161 const der::Input& public_key_spki) { | |
| 162 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); | |
| 163 | |
| 164 // The validity checks on the public key are done in the algorithm-specific | |
| 165 // verification functions. | |
| 166 crypto::ScopedEVP_PKEY public_key; | |
| 167 if (!ImportUnverifiedPkeyFromSpki(public_key_spki, &public_key)) | |
| 168 return false; | |
| 169 | |
| 170 switch (signature_algorithm.algorithm()) { | |
| 171 case SignatureAlgorithmId::RsaPkcs1: | |
| 172 case SignatureAlgorithmId::RsaPss: | |
| 173 return RsaVerify(signature_algorithm, signed_data, signature_value, | |
| 174 public_key.get()); | |
| 175 case SignatureAlgorithmId::Ecdsa: | |
| 176 return EcdsaVerify(signature_algorithm, signed_data, signature_value, | |
| 177 public_key.get()); | |
| 178 } | |
| 179 | |
| 180 return false; // Unsupported algorithm. | |
| 181 } | |
| 182 | |
| 183 } // namespace net | |
| 184 | |
| 185 #endif | |
| OLD | NEW |