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)
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
) {
31 #include <openssl/digest.h>
32 #include <openssl/ec.h>
33 #include <openssl/ec_key.h>
34 #include <openssl/evp.h>
35 #include <openssl/rsa.h>
36 #include <openssl/x509.h>
38 #include "base/compiler_specific.h"
39 #include "crypto/openssl_util.h"
40 #include "crypto/scoped_openssl_types.h"
41 #include "net/cert/internal/signature_algorithm.h"
42 #include "net/der/input.h"
43 #include "net/der/parser.h"
49 // Converts a DigestAlgorithm to an equivalent EVP_MD*.
50 WARN_UNUSED_RESULT
bool GetDigest(DigestAlgorithm digest
, const EVP_MD
** out
) {
54 case DigestAlgorithm::Sha1
:
57 case DigestAlgorithm::Sha256
:
60 case DigestAlgorithm::Sha384
:
63 case DigestAlgorithm::Sha512
:
68 return *out
!= nullptr;
71 // Sets the RSASSA-PSS parameters on |pctx|. Returns true on success.
72 WARN_UNUSED_RESULT
bool ApplyRsaPssOptions(const RsaPssParameters
* params
,
74 // BoringSSL takes a signed int for the salt length, and interprets
75 // negative values in a special manner. Make sure not to silently underflow.
76 base::CheckedNumeric
<int> salt_length_bytes_int(params
->salt_length());
77 if (!salt_length_bytes_int
.IsValid())
80 const EVP_MD
* mgf1_hash
;
81 if (!GetDigest(params
->mgf1_hash(), &mgf1_hash
))
84 return EVP_PKEY_CTX_set_rsa_padding(pctx
, RSA_PKCS1_PSS_PADDING
) &&
85 EVP_PKEY_CTX_set_rsa_mgf1_md(pctx
, mgf1_hash
) &&
86 EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx
,
87 salt_length_bytes_int
.ValueOrDie());
90 // TODO(eroman): This function is not strict enough. It accepts BER, other RSA
91 // OIDs, and does not check id-rsaEncryption parameters.
92 WARN_UNUSED_RESULT
bool ImportPkeyFromSpki(const der::Input
& spki
,
94 crypto::ScopedEVP_PKEY
* pkey
) {
95 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
97 const uint8_t* ptr
= spki
.UnsafeData();
98 pkey
->reset(d2i_PUBKEY(nullptr, &ptr
, spki
.Length()));
99 if (!pkey
->get() || ptr
!= spki
.UnsafeData() + spki
.Length() ||
100 EVP_PKEY_id(pkey
->get()) != expected_pkey_id
) {
108 // Parses an RSA public key from SPKI to an EVP_PKEY.
110 // Returns true on success.
112 // There are two flavors of RSA public key that this function should recognize
113 // from RFC 5912 (however note that pk-rsaSSA-PSS is not supported in the
114 // current implementation).
115 // TODO(eroman): Support id-RSASSA-PSS and its associated parameters.
117 // pk-rsa PUBLIC-KEY ::= {
118 // IDENTIFIER rsaEncryption
120 // PARAMS TYPE NULL ARE absent
121 // -- Private key format not in this module --
122 // CERT-KEY-USAGE {digitalSignature, nonRepudiation,
123 // keyEncipherment, dataEncipherment, keyCertSign, cRLSign}
128 // pk-rsaSSA-PSS PUBLIC-KEY ::= {
129 // IDENTIFIER id-RSASSA-PSS
131 // PARAMS TYPE RSASSA-PSS-params ARE optional
132 // -- Private key format not in this module --
133 // CERT-KEY-USAGE { nonRepudiation, digitalSignature,
134 // keyCertSign, cRLSign }
137 // Any RSA signature algorithm can accept a "pk-rsa" (rsaEncryption). However a
138 // "pk-rsaSSA-PSS" key is only accepted if the signature algorithm was for PSS
141 // sa-rsaSSA-PSS SIGNATURE-ALGORITHM ::= {
142 // IDENTIFIER id-RSASSA-PSS
143 // PARAMS TYPE RSASSA-PSS-params ARE required
144 // HASHES { mda-sha1 | mda-sha224 | mda-sha256 | mda-sha384
146 // PUBLIC-KEYS { pk-rsa | pk-rsaSSA-PSS }
147 // SMIME-CAPS { IDENTIFIED BY id-RSASSA-PSS }
150 // Moreover, if a "pk-rsaSSA-PSS" key was used and it optionally provided
151 // parameters for the algorithm, they must match those of the signature
154 // COMPATIBILITY NOTE: RFC 5912 and RFC 3279 are in disagreement on the value
155 // of parameters for rsaEncryption. Whereas RFC 5912 says they must be absent,
156 // RFC 3279 says they must be NULL:
158 // The rsaEncryption OID is intended to be used in the algorithm field
159 // of a value of type AlgorithmIdentifier. The parameters field MUST
160 // have ASN.1 type NULL for this algorithm identifier.
162 // Following RFC 3279 in this case.
163 WARN_UNUSED_RESULT
bool ParseRsaKeyFromSpki(const der::Input
& public_key_spki
,
164 crypto::ScopedEVP_PKEY
* pkey
) {
165 return ImportPkeyFromSpki(public_key_spki
, EVP_PKEY_RSA
, pkey
);
168 // Does signature verification using either RSA or ECDSA.
169 WARN_UNUSED_RESULT
bool DoVerify(const SignatureAlgorithm
& algorithm
,
170 const der::Input
& signed_data
,
171 const der::BitString
& signature_value
,
172 EVP_PKEY
* public_key
) {
173 DCHECK(algorithm
.algorithm() == SignatureAlgorithmId::RsaPkcs1
||
174 algorithm
.algorithm() == SignatureAlgorithmId::RsaPss
||
175 algorithm
.algorithm() == SignatureAlgorithmId::Ecdsa
);
177 // For the supported algorithms the signature value must be a whole
179 if (signature_value
.unused_bits() != 0)
181 const der::Input
& signature_value_bytes
= signature_value
.bytes();
183 crypto::OpenSSLErrStackTracer
err_tracer(FROM_HERE
);
185 crypto::ScopedEVP_MD_CTX
ctx(EVP_MD_CTX_create());
186 EVP_PKEY_CTX
* pctx
= nullptr; // Owned by |ctx|.
188 const EVP_MD
* digest
;
189 if (!GetDigest(algorithm
.digest(), &digest
))
192 if (!EVP_DigestVerifyInit(ctx
.get(), &pctx
, digest
, nullptr, public_key
))
195 // Set the RSASSA-PSS specific options.
196 if (algorithm
.algorithm() == SignatureAlgorithmId::RsaPss
&&
197 !ApplyRsaPssOptions(algorithm
.ParamsForRsaPss(), pctx
)) {
201 if (!EVP_DigestVerifyUpdate(ctx
.get(), signed_data
.UnsafeData(),
202 signed_data
.Length())) {
206 return 1 == EVP_DigestVerifyFinal(ctx
.get(),
207 signature_value_bytes
.UnsafeData(),
208 signature_value_bytes
.Length());
211 // Returns true if the given curve is allowed for ECDSA. The input is a
214 // TODO(eroman): Extract policy decisions such as allowed curves, hashes, RSA
215 // modulus size, to somewhere more central.
216 WARN_UNUSED_RESULT
bool IsAllowedCurveName(int curve_nid
) {
218 case NID_X9_62_prime256v1
:
226 // Parses an EC public key from SPKI to an EVP_PKEY.
228 // Returns true on success.
230 // RFC 5912 describes all the ECDSA signature algorithms as requiring a public
231 // key of type "pk-ec":
233 // pk-ec PUBLIC-KEY ::= {
234 // IDENTIFIER id-ecPublicKey
236 // PARAMS TYPE ECParameters ARE required
237 // -- Private key format not in this module --
238 // CERT-KEY-USAGE { digitalSignature, nonRepudiation, keyAgreement,
239 // keyCertSign, cRLSign }
242 // Moreover RFC 5912 stipulates what curves are allowed. The ECParameters
243 // MUST NOT use an implicitCurve or specificCurve for PKIX:
245 // ECParameters ::= CHOICE {
246 // namedCurve CURVE.&id({NamedCurve})
247 // -- implicitCurve NULL
248 // -- implicitCurve MUST NOT be used in PKIX
249 // -- specifiedCurve SpecifiedCurve
250 // -- specifiedCurve MUST NOT be used in PKIX
251 // -- Details for specifiedCurve can be found in [X9.62]
252 // -- Any future additions to this CHOICE should be coordinated
255 // -- If you need to be able to decode ANSI X.9 parameter structures,
256 // -- uncomment the implicitCurve and specifiedCurve above, and also
257 // -- uncomment the following:
258 // --(WITH COMPONENTS {namedCurve PRESENT})
260 // The namedCurves are extensible. The ones described by RFC 5912 are:
262 // NamedCurve CURVE ::= {
263 // { ID secp192r1 } | { ID sect163k1 } | { ID sect163r2 } |
264 // { ID secp224r1 } | { ID sect233k1 } | { ID sect233r1 } |
265 // { ID secp256r1 } | { ID sect283k1 } | { ID sect283r1 } |
266 // { ID secp384r1 } | { ID sect409k1 } | { ID sect409r1 } |
267 // { ID secp521r1 } | { ID sect571k1 } | { ID sect571r1 },
270 WARN_UNUSED_RESULT
bool ParseEcKeyFromSpki(const der::Input
& public_key_spki
,
271 crypto::ScopedEVP_PKEY
* pkey
) {
272 if (!ImportPkeyFromSpki(public_key_spki
, EVP_PKEY_EC
, pkey
))
275 // Enforce policy on allowed curves in case ImportPkeyFromSpki() were to
276 // recognize and allow use of a weak curve.
277 crypto::ScopedEC_KEY
ec(EVP_PKEY_get1_EC_KEY(pkey
->get()));
279 return false; // Unexpected.
281 int curve_nid
= EC_GROUP_get_curve_name(EC_KEY_get0_group(ec
.get()));
282 return IsAllowedCurveName(curve_nid
);
287 bool VerifySignedData(const SignatureAlgorithm
& signature_algorithm
,
288 const der::Input
& signed_data
,
289 const der::BitString
& signature_value
,
290 const der::Input
& public_key_spki
) {
291 crypto::ScopedEVP_PKEY public_key
;
293 // Parse the SPKI to an EVP_PKEY appropriate for the signature algorithm.
294 switch (signature_algorithm
.algorithm()) {
295 case SignatureAlgorithmId::RsaPkcs1
:
296 case SignatureAlgorithmId::RsaPss
:
297 if (!ParseRsaKeyFromSpki(public_key_spki
, &public_key
))
300 case SignatureAlgorithmId::Ecdsa
:
301 if (!ParseEcKeyFromSpki(public_key_spki
, &public_key
))
306 return DoVerify(signature_algorithm
, signed_data
, signature_value
,