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 "base/logging.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_bit_string, |
| 21 const der::Input& public_key) { |
| 22 NOTIMPLEMENTED(); |
| 23 return false; |
| 24 } |
| 25 |
| 26 } // namespace net |
| 27 |
| 28 #else |
| 29 |
| 30 #include <openssl/digest.h> |
| 31 #include <openssl/ec.h> |
| 32 #include <openssl/ec_key.h> |
| 33 #include <openssl/evp.h> |
| 34 #include <openssl/rsa.h> |
| 35 #include <openssl/x509.h> |
| 36 |
| 37 #include "base/compiler_specific.h" |
| 38 #include "crypto/openssl_util.h" |
| 39 #include "crypto/scoped_openssl_types.h" |
| 40 #include "net/cert/internal/signature_algorithm.h" |
| 41 #include "net/der/input.h" |
| 42 #include "net/der/parser.h" |
| 43 |
| 44 namespace net { |
| 45 |
| 46 namespace { |
| 47 |
| 48 // Converts a DigestAlgorithm to an equivalent EVP_MD*. |
| 49 WARN_UNUSED_RESULT bool GetDigest(DigestAlgorithm digest, const EVP_MD** out) { |
| 50 *out = nullptr; |
| 51 |
| 52 switch (digest) { |
| 53 case DigestAlgorithm::Sha1: |
| 54 *out = EVP_sha1(); |
| 55 break; |
| 56 case DigestAlgorithm::Sha256: |
| 57 *out = EVP_sha256(); |
| 58 break; |
| 59 case DigestAlgorithm::Sha384: |
| 60 *out = EVP_sha384(); |
| 61 break; |
| 62 case DigestAlgorithm::Sha512: |
| 63 *out = EVP_sha512(); |
| 64 break; |
| 65 } |
| 66 |
| 67 return *out != nullptr; |
| 68 } |
| 69 |
| 70 // Sets the RSASSA-PSS parameters on |pctx|. Returns true on success. |
| 71 WARN_UNUSED_RESULT bool ApplyRsaPssOptions(const RsaPssParameters* params, |
| 72 EVP_PKEY_CTX* pctx) { |
| 73 // BoringSSL takes a signed int for the salt length, and interprets |
| 74 // negative values in a special manner. Make sure not to silently underflow. |
| 75 base::CheckedNumeric<int> salt_length_bytes_int(params->salt_length()); |
| 76 if (!salt_length_bytes_int.IsValid()) |
| 77 return false; |
| 78 |
| 79 const EVP_MD* mgf1_hash; |
| 80 if (!GetDigest(params->mgf1_hash(), &mgf1_hash)) |
| 81 return false; |
| 82 |
| 83 return EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) && |
| 84 EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, mgf1_hash) && |
| 85 EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, |
| 86 salt_length_bytes_int.ValueOrDie()); |
| 87 } |
| 88 |
| 89 // TODO(eroman): This function is not strict enough. It accepts BER, other RSA |
| 90 // OIDs, and does not check id-rsaEncryption parameters. |
| 91 WARN_UNUSED_RESULT bool ImportPkeyFromSpki(const der::Input& spki, |
| 92 int expected_pkey_id, |
| 93 crypto::ScopedEVP_PKEY* pkey) { |
| 94 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
| 95 |
| 96 const uint8_t* ptr = spki.UnsafeData(); |
| 97 pkey->reset(d2i_PUBKEY(nullptr, &ptr, spki.Length())); |
| 98 if (!pkey->get() || ptr != spki.UnsafeData() + spki.Length() || |
| 99 EVP_PKEY_id(pkey->get()) != expected_pkey_id) { |
| 100 pkey->reset(); |
| 101 return false; |
| 102 } |
| 103 |
| 104 return true; |
| 105 } |
| 106 |
| 107 // Parses an RSA public key from SPKI to an EVP_PKEY. |
| 108 // |
| 109 // Returns true on success. |
| 110 // |
| 111 // There are two flavors of RSA public key that this function should recognize |
| 112 // from RFC 5912 (however note that pk-rsaSSA-PSS is not supported in the |
| 113 // current implementation). |
| 114 // TODO(eroman): Support id-RSASSA-PSS and its associated parameters. |
| 115 // |
| 116 // pk-rsa PUBLIC-KEY ::= { |
| 117 // IDENTIFIER rsaEncryption |
| 118 // KEY RSAPublicKey |
| 119 // PARAMS TYPE NULL ARE absent |
| 120 // -- Private key format not in this module -- |
| 121 // CERT-KEY-USAGE {digitalSignature, nonRepudiation, |
| 122 // keyEncipherment, dataEncipherment, keyCertSign, cRLSign} |
| 123 // } |
| 124 // |
| 125 // ... |
| 126 // |
| 127 // pk-rsaSSA-PSS PUBLIC-KEY ::= { |
| 128 // IDENTIFIER id-RSASSA-PSS |
| 129 // KEY RSAPublicKey |
| 130 // PARAMS TYPE RSASSA-PSS-params ARE optional |
| 131 // -- Private key format not in this module -- |
| 132 // CERT-KEY-USAGE { nonRepudiation, digitalSignature, |
| 133 // keyCertSign, cRLSign } |
| 134 // } |
| 135 // |
| 136 // Any RSA signature algorithm can accept a "pk-rsa" (rsaEncryption). However a |
| 137 // "pk-rsaSSA-PSS" key is only accepted if the signature algorithm was for PSS |
| 138 // mode: |
| 139 // |
| 140 // sa-rsaSSA-PSS SIGNATURE-ALGORITHM ::= { |
| 141 // IDENTIFIER id-RSASSA-PSS |
| 142 // PARAMS TYPE RSASSA-PSS-params ARE required |
| 143 // HASHES { mda-sha1 | mda-sha224 | mda-sha256 | mda-sha384 |
| 144 // | mda-sha512 } |
| 145 // PUBLIC-KEYS { pk-rsa | pk-rsaSSA-PSS } |
| 146 // SMIME-CAPS { IDENTIFIED BY id-RSASSA-PSS } |
| 147 // } |
| 148 // |
| 149 // Moreover, if a "pk-rsaSSA-PSS" key was used and it optionally provided |
| 150 // parameters for the algorithm, they must match those of the signature |
| 151 // algorithm. |
| 152 // |
| 153 // COMPATIBILITY NOTE: RFC 5912 and RFC 3279 are in disagreement on the value |
| 154 // of parameters for rsaEncryption. Whereas RFC 5912 says they must be absent, |
| 155 // RFC 3279 says they must be NULL: |
| 156 // |
| 157 // The rsaEncryption OID is intended to be used in the algorithm field |
| 158 // of a value of type AlgorithmIdentifier. The parameters field MUST |
| 159 // have ASN.1 type NULL for this algorithm identifier. |
| 160 // |
| 161 // Following RFC 3279 in this case. |
| 162 WARN_UNUSED_RESULT bool ParseRsaKeyFromSpki(const der::Input& public_key_spki, |
| 163 crypto::ScopedEVP_PKEY* pkey) { |
| 164 return ImportPkeyFromSpki(public_key_spki, EVP_PKEY_RSA, pkey); |
| 165 } |
| 166 |
| 167 // Does signature verification using either RSA or ECDSA. |
| 168 // |
| 169 // Note that the |signature_value| input is expected to be a byte string (and |
| 170 // not a DER-encoded BIT STRING) |
| 171 WARN_UNUSED_RESULT bool DoVerify(const SignatureAlgorithm& algorithm, |
| 172 const der::Input& signed_data, |
| 173 const der::Input& signature_value, |
| 174 EVP_PKEY* public_key) { |
| 175 DCHECK(algorithm.algorithm() == SignatureAlgorithmId::RsaPkcs1 || |
| 176 algorithm.algorithm() == SignatureAlgorithmId::RsaPss || |
| 177 algorithm.algorithm() == SignatureAlgorithmId::Ecdsa); |
| 178 |
| 179 crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); |
| 180 |
| 181 crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create()); |
| 182 EVP_PKEY_CTX* pctx = nullptr; // Owned by |ctx|. |
| 183 |
| 184 const EVP_MD* digest; |
| 185 if (!GetDigest(algorithm.digest(), &digest)) |
| 186 return false; |
| 187 |
| 188 if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, nullptr, public_key)) |
| 189 return false; |
| 190 |
| 191 // Set the RSASSA-PSS specific options. |
| 192 if (algorithm.algorithm() == SignatureAlgorithmId::RsaPss && |
| 193 !ApplyRsaPssOptions(algorithm.ParamsForRsaPss(), pctx)) { |
| 194 return false; |
| 195 } |
| 196 |
| 197 if (!EVP_DigestVerifyUpdate(ctx.get(), signed_data.UnsafeData(), |
| 198 signed_data.Length())) { |
| 199 return false; |
| 200 } |
| 201 |
| 202 return 1 == EVP_DigestVerifyFinal(ctx.get(), signature_value.UnsafeData(), |
| 203 signature_value.Length()); |
| 204 } |
| 205 |
| 206 // Returns true if the given curve is allowed for ECDSA. The input is a |
| 207 // BoringSSL NID. |
| 208 // |
| 209 // TODO(eroman): Extract policy decisions such as allowed curves, hashes, RSA |
| 210 // modulus size, to somewhere more central. |
| 211 WARN_UNUSED_RESULT bool IsAllowedCurveName(int curve_nid) { |
| 212 switch (curve_nid) { |
| 213 case NID_X9_62_prime256v1: |
| 214 case NID_secp384r1: |
| 215 case NID_secp521r1: |
| 216 return true; |
| 217 } |
| 218 return false; |
| 219 } |
| 220 |
| 221 // Parses an EC public key from SPKI to an EVP_PKEY. |
| 222 // |
| 223 // Returns true on success. |
| 224 // |
| 225 // RFC 5912 describes all the ECDSA signature algorithms as requiring a public |
| 226 // key of type "pk-ec": |
| 227 // |
| 228 // pk-ec PUBLIC-KEY ::= { |
| 229 // IDENTIFIER id-ecPublicKey |
| 230 // KEY ECPoint |
| 231 // PARAMS TYPE ECParameters ARE required |
| 232 // -- Private key format not in this module -- |
| 233 // CERT-KEY-USAGE { digitalSignature, nonRepudiation, keyAgreement, |
| 234 // keyCertSign, cRLSign } |
| 235 // } |
| 236 // |
| 237 // Moreover RFC 5912 stipulates what curves are allowed. The ECParameters |
| 238 // MUST NOT use an implicitCurve or specificCurve for PKIX: |
| 239 // |
| 240 // ECParameters ::= CHOICE { |
| 241 // namedCurve CURVE.&id({NamedCurve}) |
| 242 // -- implicitCurve NULL |
| 243 // -- implicitCurve MUST NOT be used in PKIX |
| 244 // -- specifiedCurve SpecifiedCurve |
| 245 // -- specifiedCurve MUST NOT be used in PKIX |
| 246 // -- Details for specifiedCurve can be found in [X9.62] |
| 247 // -- Any future additions to this CHOICE should be coordinated |
| 248 // -- with ANSI X.9. |
| 249 // } |
| 250 // -- If you need to be able to decode ANSI X.9 parameter structures, |
| 251 // -- uncomment the implicitCurve and specifiedCurve above, and also |
| 252 // -- uncomment the following: |
| 253 // --(WITH COMPONENTS {namedCurve PRESENT}) |
| 254 // |
| 255 // The namedCurves are extensible. The ones described by RFC 5912 are: |
| 256 // |
| 257 // NamedCurve CURVE ::= { |
| 258 // { ID secp192r1 } | { ID sect163k1 } | { ID sect163r2 } | |
| 259 // { ID secp224r1 } | { ID sect233k1 } | { ID sect233r1 } | |
| 260 // { ID secp256r1 } | { ID sect283k1 } | { ID sect283r1 } | |
| 261 // { ID secp384r1 } | { ID sect409k1 } | { ID sect409r1 } | |
| 262 // { ID secp521r1 } | { ID sect571k1 } | { ID sect571r1 }, |
| 263 // ... -- Extensible |
| 264 // } |
| 265 WARN_UNUSED_RESULT bool ParseEcKeyFromSpki(const der::Input& public_key_spki, |
| 266 crypto::ScopedEVP_PKEY* pkey) { |
| 267 if (!ImportPkeyFromSpki(public_key_spki, EVP_PKEY_EC, pkey)) |
| 268 return false; |
| 269 |
| 270 // Enforce policy on allowed curves in case ImportPkeyFromSpki() were to |
| 271 // recognize and allow use of a weak curve. |
| 272 crypto::ScopedEC_KEY ec(EVP_PKEY_get1_EC_KEY(pkey->get())); |
| 273 if (!ec.get()) |
| 274 return false; // Unexpected. |
| 275 |
| 276 int curve_nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec.get())); |
| 277 return IsAllowedCurveName(curve_nid); |
| 278 } |
| 279 |
| 280 } // namespace |
| 281 |
| 282 bool VerifySignedData(const SignatureAlgorithm& signature_algorithm, |
| 283 const der::Input& signed_data, |
| 284 const der::Input& signature_value_bit_string, |
| 285 const der::Input& public_key_spki) { |
| 286 crypto::ScopedEVP_PKEY public_key; |
| 287 |
| 288 // Parse the SPKI to an EVP_PKEY appropriate for the signature algorithm. |
| 289 switch (signature_algorithm.algorithm()) { |
| 290 case SignatureAlgorithmId::RsaPkcs1: |
| 291 case SignatureAlgorithmId::RsaPss: |
| 292 if (!ParseRsaKeyFromSpki(public_key_spki, &public_key)) |
| 293 return false; |
| 294 break; |
| 295 case SignatureAlgorithmId::Ecdsa: |
| 296 if (!ParseEcKeyFromSpki(public_key_spki, &public_key)) |
| 297 return false; |
| 298 break; |
| 299 } |
| 300 |
| 301 // Extract the bytes of the signature_value. Assume that the BIT STRING has |
| 302 // no unused bits (in other words, is a multiple of 8 bits), since that is the |
| 303 // case for all of the currently supported algorithms. |
| 304 der::Input signature_value; |
| 305 der::Parser parser(signature_value_bit_string); |
| 306 if (!parser.ReadBitStringNoUnusedBits(&signature_value)) |
| 307 return false; |
| 308 // By definition signature_value_bit_string must be a single BIT STRING. |
| 309 if (parser.HasMore()) |
| 310 return false; |
| 311 |
| 312 return DoVerify(signature_algorithm, signed_data, signature_value, |
| 313 public_key.get()); |
| 314 } |
| 315 |
| 316 } // namespace net |
| 317 |
| 318 #endif |
OLD | NEW |