Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / cert / internal / verify_signed_data.cc
blob9b0ebd458171e111f6fd6be3fa2182c860422830
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.
5 #include "net/cert/internal/verify_signed_data.h"
7 #include "base/logging.h"
8 #include "net/der/parse_values.h"
10 // TODO(eroman): There is no intention to implement this for non-OpenSSL. Remove
11 // this branch once the migration is complete. This could have been done as a
12 // conditional file (_openssl.cc) in the build file instead, but that is likely
13 // not worth the effort at this point.
15 #if !defined(USE_OPENSSL)
17 namespace net {
19 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
20 const der::Input& signed_data,
21 const der::BitString& signature_value,
22 const der::Input& public_key,
23 const SignaturePolicy* policy) {
24 NOTIMPLEMENTED();
25 return false;
28 } // namespace net
30 #else
32 #include <openssl/digest.h>
33 #include <openssl/ec.h>
34 #include <openssl/ec_key.h>
35 #include <openssl/evp.h>
36 #include <openssl/rsa.h>
37 #include <openssl/x509.h>
39 #include "base/compiler_specific.h"
40 #include "crypto/openssl_util.h"
41 #include "crypto/scoped_openssl_types.h"
42 #include "net/cert/internal/signature_algorithm.h"
43 #include "net/cert/internal/signature_policy.h"
44 #include "net/der/input.h"
45 #include "net/der/parser.h"
47 namespace net {
49 namespace {
51 // Converts a DigestAlgorithm to an equivalent EVP_MD*.
52 WARN_UNUSED_RESULT bool GetDigest(DigestAlgorithm digest, const EVP_MD** out) {
53 *out = nullptr;
55 switch (digest) {
56 case DigestAlgorithm::Sha1:
57 *out = EVP_sha1();
58 break;
59 case DigestAlgorithm::Sha256:
60 *out = EVP_sha256();
61 break;
62 case DigestAlgorithm::Sha384:
63 *out = EVP_sha384();
64 break;
65 case DigestAlgorithm::Sha512:
66 *out = EVP_sha512();
67 break;
70 return *out != nullptr;
73 // Sets the RSASSA-PSS parameters on |pctx|. Returns true on success.
74 WARN_UNUSED_RESULT bool ApplyRsaPssOptions(const RsaPssParameters* params,
75 EVP_PKEY_CTX* pctx) {
76 // BoringSSL takes a signed int for the salt length, and interprets
77 // negative values in a special manner. Make sure not to silently underflow.
78 base::CheckedNumeric<int> salt_length_bytes_int(params->salt_length());
79 if (!salt_length_bytes_int.IsValid())
80 return false;
82 const EVP_MD* mgf1_hash;
83 if (!GetDigest(params->mgf1_hash(), &mgf1_hash))
84 return false;
86 return EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) &&
87 EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_hash) &&
88 EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx,
89 salt_length_bytes_int.ValueOrDie());
92 // TODO(eroman): This function is not strict enough. It accepts BER, other RSA
93 // OIDs, and does not check id-rsaEncryption parameters.
94 // See https://crbug.com/522228 and https://crbug.com/522232
95 WARN_UNUSED_RESULT bool ImportPkeyFromSpki(const der::Input& spki,
96 int expected_pkey_id,
97 crypto::ScopedEVP_PKEY* pkey) {
98 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
100 const uint8_t* ptr = spki.UnsafeData();
101 pkey->reset(d2i_PUBKEY(nullptr, &ptr, spki.Length()));
102 if (!pkey->get() || ptr != spki.UnsafeData() + spki.Length() ||
103 EVP_PKEY_id(pkey->get()) != expected_pkey_id) {
104 pkey->reset();
105 return false;
108 return true;
111 // Parses an RSA public key from SPKI to an EVP_PKEY.
113 // Returns true on success.
115 // There are two flavors of RSA public key that this function should recognize
116 // from RFC 5912 (however note that pk-rsaSSA-PSS is not supported in the
117 // current implementation).
118 // TODO(eroman): Support id-RSASSA-PSS and its associated parameters. See
119 // https://crbug.com/522232
121 // pk-rsa PUBLIC-KEY ::= {
122 // IDENTIFIER rsaEncryption
123 // KEY RSAPublicKey
124 // PARAMS TYPE NULL ARE absent
125 // -- Private key format not in this module --
126 // CERT-KEY-USAGE {digitalSignature, nonRepudiation,
127 // keyEncipherment, dataEncipherment, keyCertSign, cRLSign}
128 // }
130 // ...
132 // pk-rsaSSA-PSS PUBLIC-KEY ::= {
133 // IDENTIFIER id-RSASSA-PSS
134 // KEY RSAPublicKey
135 // PARAMS TYPE RSASSA-PSS-params ARE optional
136 // -- Private key format not in this module --
137 // CERT-KEY-USAGE { nonRepudiation, digitalSignature,
138 // keyCertSign, cRLSign }
139 // }
141 // Any RSA signature algorithm can accept a "pk-rsa" (rsaEncryption). However a
142 // "pk-rsaSSA-PSS" key is only accepted if the signature algorithm was for PSS
143 // mode:
145 // sa-rsaSSA-PSS SIGNATURE-ALGORITHM ::= {
146 // IDENTIFIER id-RSASSA-PSS
147 // PARAMS TYPE RSASSA-PSS-params ARE required
148 // HASHES { mda-sha1 | mda-sha224 | mda-sha256 | mda-sha384
149 // | mda-sha512 }
150 // PUBLIC-KEYS { pk-rsa | pk-rsaSSA-PSS }
151 // SMIME-CAPS { IDENTIFIED BY id-RSASSA-PSS }
152 // }
154 // Moreover, if a "pk-rsaSSA-PSS" key was used and it optionally provided
155 // parameters for the algorithm, they must match those of the signature
156 // algorithm.
158 // COMPATIBILITY NOTE: RFC 5912 and RFC 3279 are in disagreement on the value
159 // of parameters for rsaEncryption. Whereas RFC 5912 says they must be absent,
160 // RFC 3279 says they must be NULL:
162 // The rsaEncryption OID is intended to be used in the algorithm field
163 // of a value of type AlgorithmIdentifier. The parameters field MUST
164 // have ASN.1 type NULL for this algorithm identifier.
166 // Following RFC 3279 in this case.
167 WARN_UNUSED_RESULT bool ParseRsaKeyFromSpki(const der::Input& public_key_spki,
168 crypto::ScopedEVP_PKEY* pkey,
169 const SignaturePolicy* policy) {
170 if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_RSA, pkey))
171 return false;
173 // Extract the modulus length from the key.
174 crypto::ScopedRSA rsa(EVP_PKEY_get1_RSA(pkey->get()));
175 if (!rsa)
176 return false;
177 unsigned int modulus_length_bits = BN_num_bits(rsa->n);
179 return policy->IsAcceptableModulusLengthForRsa(modulus_length_bits);
182 // Does signature verification using either RSA or ECDSA.
183 WARN_UNUSED_RESULT bool DoVerify(const SignatureAlgorithm& algorithm,
184 const der::Input& signed_data,
185 const der::BitString& signature_value,
186 EVP_PKEY* public_key) {
187 DCHECK(algorithm.algorithm() == SignatureAlgorithmId::RsaPkcs1 ||
188 algorithm.algorithm() == SignatureAlgorithmId::RsaPss ||
189 algorithm.algorithm() == SignatureAlgorithmId::Ecdsa);
191 // For the supported algorithms the signature value must be a whole
192 // number of bytes.
193 if (signature_value.unused_bits() != 0)
194 return false;
195 const der::Input& signature_value_bytes = signature_value.bytes();
197 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
199 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create());
200 EVP_PKEY_CTX* pctx = nullptr; // Owned by |ctx|.
202 const EVP_MD* digest;
203 if (!GetDigest(algorithm.digest(), &digest))
204 return false;
206 if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, nullptr, public_key))
207 return false;
209 // Set the RSASSA-PSS specific options.
210 if (algorithm.algorithm() == SignatureAlgorithmId::RsaPss &&
211 !ApplyRsaPssOptions(algorithm.ParamsForRsaPss(), pctx)) {
212 return false;
215 if (!EVP_DigestVerifyUpdate(ctx.get(), signed_data.UnsafeData(),
216 signed_data.Length())) {
217 return false;
220 return 1 == EVP_DigestVerifyFinal(ctx.get(),
221 signature_value_bytes.UnsafeData(),
222 signature_value_bytes.Length());
225 // Parses an EC public key from SPKI to an EVP_PKEY.
227 // Returns true on success.
229 // RFC 5912 describes all the ECDSA signature algorithms as requiring a public
230 // key of type "pk-ec":
232 // pk-ec PUBLIC-KEY ::= {
233 // IDENTIFIER id-ecPublicKey
234 // KEY ECPoint
235 // PARAMS TYPE ECParameters ARE required
236 // -- Private key format not in this module --
237 // CERT-KEY-USAGE { digitalSignature, nonRepudiation, keyAgreement,
238 // keyCertSign, cRLSign }
239 // }
241 // Moreover RFC 5912 stipulates what curves are allowed. The ECParameters
242 // MUST NOT use an implicitCurve or specificCurve for PKIX:
244 // ECParameters ::= CHOICE {
245 // namedCurve CURVE.&id({NamedCurve})
246 // -- implicitCurve NULL
247 // -- implicitCurve MUST NOT be used in PKIX
248 // -- specifiedCurve SpecifiedCurve
249 // -- specifiedCurve MUST NOT be used in PKIX
250 // -- Details for specifiedCurve can be found in [X9.62]
251 // -- Any future additions to this CHOICE should be coordinated
252 // -- with ANSI X.9.
253 // }
254 // -- If you need to be able to decode ANSI X.9 parameter structures,
255 // -- uncomment the implicitCurve and specifiedCurve above, and also
256 // -- uncomment the following:
257 // --(WITH COMPONENTS {namedCurve PRESENT})
259 // The namedCurves are extensible. The ones described by RFC 5912 are:
261 // NamedCurve CURVE ::= {
262 // { ID secp192r1 } | { ID sect163k1 } | { ID sect163r2 } |
263 // { ID secp224r1 } | { ID sect233k1 } | { ID sect233r1 } |
264 // { ID secp256r1 } | { ID sect283k1 } | { ID sect283r1 } |
265 // { ID secp384r1 } | { ID sect409k1 } | { ID sect409r1 } |
266 // { ID secp521r1 } | { ID sect571k1 } | { ID sect571r1 },
267 // ... -- Extensible
268 // }
269 WARN_UNUSED_RESULT bool ParseEcKeyFromSpki(const der::Input& public_key_spki,
270 crypto::ScopedEVP_PKEY* pkey,
271 const SignaturePolicy* policy) {
272 if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_EC, pkey))
273 return false;
275 // Extract the curve name.
276 crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey->get()));
277 if (!ec.get())
278 return false; // Unexpected.
279 int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get()));
281 return policy->IsAcceptableCurveForEcdsa(curve_nid);
284 } // namespace
286 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm,
287 const der::Input& signed_data,
288 const der::BitString& signature_value,
289 const der::Input& public_key_spki,
290 const SignaturePolicy* policy) {
291 if (!policy->IsAcceptableSignatureAlgorithm(signature_algorithm))
292 return false;
294 crypto::ScopedEVP_PKEY public_key;
296 // Parse the SPKI to an EVP_PKEY appropriate for the signature algorithm.
297 switch (signature_algorithm.algorithm()) {
298 case SignatureAlgorithmId::RsaPkcs1:
299 case SignatureAlgorithmId::RsaPss:
300 if (!ParseRsaKeyFromSpki(public_key_spki, &public_key, policy))
301 return false;
302 break;
303 case SignatureAlgorithmId::Ecdsa:
304 if (!ParseEcKeyFromSpki(public_key_spki, &public_key, policy))
305 return false;
306 break;
309 return DoVerify(signature_algorithm, signed_data, signature_value,
310 public_key.get());
313 } // namespace net
315 #endif