Coverage Report

Created: 2026-10-19 07:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/boringssl/pki/verify_signed_data.cc
Line
Count
Source
1
// Copyright 2015 The Chromium Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     https://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#include "verify_signed_data.h"
16
17
#include <iterator>
18
19
#include <openssl/bytestring.h>
20
#include <openssl/digest.h>
21
#include <openssl/err.h>
22
#include <openssl/evp.h>
23
#include <openssl/pki/signature_verify_cache.h>
24
#include <openssl/rsa.h>
25
#include <openssl/sha2.h>
26
27
#include "input.h"
28
#include "parse_values.h"
29
#include "parser.h"
30
#include "signature_algorithm.h"
31
32
BSSL_NAMESPACE_BEGIN
33
34
namespace {
35
36
bool SHA256UpdateWithLengthPrefixedData(SHA256_CTX *s_ctx, const uint8_t *data,
37
0
                                        uint64_t length) {
38
0
  return (SHA256_Update(s_ctx, reinterpret_cast<uint8_t *>(&length),
39
0
                        sizeof(length)) &&
40
0
          SHA256_Update(s_ctx, data, length));
41
0
}
42
43
// Increase to make incompatible changes in the computation of the
44
// cache key.
45
constexpr uint32_t VerifyCacheKeyVersion = 1;
46
47
std::string SignatureVerifyCacheKey(std::string_view algorithm_name,
48
                                    der::Input signed_data,
49
                                    der::Input signature_value_bytes,
50
0
                                    const EVP_PKEY *public_key) {
51
0
  SHA256_CTX s_ctx;
52
0
  bssl::ScopedCBB public_key_cbb;
53
0
  uint8_t digest[SHA256_DIGEST_LENGTH];
54
0
  uint32_t version = VerifyCacheKeyVersion;
55
0
  if (CBB_init(public_key_cbb.get(), 128) &&
56
0
      EVP_marshal_public_key(public_key_cbb.get(), public_key) &&
57
0
      SHA256_Init(&s_ctx) &&
58
0
      SHA256_Update(&s_ctx, reinterpret_cast<uint8_t *>(&version),
59
0
                    sizeof(version)) &&
60
0
      SHA256UpdateWithLengthPrefixedData(
61
0
          &s_ctx, reinterpret_cast<const uint8_t *>(algorithm_name.data()),
62
0
          algorithm_name.length()) &&
63
0
      SHA256UpdateWithLengthPrefixedData(&s_ctx, CBB_data(public_key_cbb.get()),
64
0
                                         CBB_len(public_key_cbb.get())) &&
65
0
      SHA256UpdateWithLengthPrefixedData(&s_ctx, signature_value_bytes.data(),
66
0
                                         signature_value_bytes.size()) &&
67
0
      SHA256UpdateWithLengthPrefixedData(&s_ctx, signed_data.data(),
68
0
                                         signed_data.size()) &&
69
0
      SHA256_Final(digest, &s_ctx)) {
70
0
    return std::string(reinterpret_cast<char *>(digest), sizeof(digest));
71
0
  }
72
0
  return std::string();
73
0
}
74
75
// Place an instance of this class on the call stack to automatically clear
76
// the OpenSSL error stack on function exit.
77
// TODO(crbug.com/boringssl/38): Remove this when the library is more robust to
78
// leaving things in the error queue.
79
class OpenSSLErrStackTracer {
80
 public:
81
0
  ~OpenSSLErrStackTracer() { ERR_clear_error(); }
82
};
83
84
}  // namespace
85
86
// Parses an RSA, EC, or ML-DSA public key from SPKI to an EVP_PKEY. Returns
87
// true on success.
88
//
89
// This function only recognizes the "pk-rsa" (rsaEncryption) flavor of RSA
90
// public key from RFC 5912.
91
//
92
//     pk-rsa PUBLIC-KEY ::= {
93
//      IDENTIFIER rsaEncryption
94
//      KEY RSAPublicKey
95
//      PARAMS TYPE NULL ARE absent
96
//      -- Private key format not in this module --
97
//      CERT-KEY-USAGE {digitalSignature, nonRepudiation,
98
//      keyEncipherment, dataEncipherment, keyCertSign, cRLSign}
99
//     }
100
//
101
// COMPATIBILITY NOTE: RFC 5912 and RFC 3279 are in disagreement on the value
102
// of parameters for rsaEncryption. Whereas RFC 5912 says they must be absent,
103
// RFC 3279 says they must be NULL:
104
//
105
//     The rsaEncryption OID is intended to be used in the algorithm field
106
//     of a value of type AlgorithmIdentifier.  The parameters field MUST
107
//     have ASN.1 type NULL for this algorithm identifier.
108
//
109
// Following RFC 3279 in this case.
110
//
111
// In the case of parsing EC keys, RFC 5912 describes all the ECDSA
112
// signature algorithms as requiring a public key of type "pk-ec":
113
//
114
//     pk-ec PUBLIC-KEY ::= {
115
//      IDENTIFIER id-ecPublicKey
116
//      KEY ECPoint
117
//      PARAMS TYPE ECParameters ARE required
118
//      -- Private key format not in this module --
119
//      CERT-KEY-USAGE { digitalSignature, nonRepudiation, keyAgreement,
120
//                           keyCertSign, cRLSign }
121
//     }
122
//
123
// Moreover RFC 5912 stipulates what curves are allowed. The ECParameters
124
// MUST NOT use an implicitCurve or specificCurve for PKIX:
125
//
126
//     ECParameters ::= CHOICE {
127
//      namedCurve      CURVE.&id({NamedCurve})
128
//      -- implicitCurve   NULL
129
//        -- implicitCurve MUST NOT be used in PKIX
130
//      -- specifiedCurve  SpecifiedCurve
131
//        -- specifiedCurve MUST NOT be used in PKIX
132
//        -- Details for specifiedCurve can be found in [X9.62]
133
//        -- Any future additions to this CHOICE should be coordinated
134
//        -- with ANSI X.9.
135
//     }
136
//     -- If you need to be able to decode ANSI X.9 parameter structures,
137
//     -- uncomment the implicitCurve and specifiedCurve above, and also
138
//     -- uncomment the following:
139
//     --(WITH COMPONENTS {namedCurve PRESENT})
140
//
141
// The namedCurves are extensible. The ones described by RFC 5912 are:
142
//
143
//     NamedCurve CURVE ::= {
144
//     { ID secp192r1 } | { ID sect163k1 } | { ID sect163r2 } |
145
//     { ID secp224r1 } | { ID sect233k1 } | { ID sect233r1 } |
146
//     { ID secp256r1 } | { ID sect283k1 } | { ID sect283r1 } |
147
//     { ID secp384r1 } | { ID sect409k1 } | { ID sect409r1 } |
148
//     { ID secp521r1 } | { ID sect571k1 } | { ID sect571r1 },
149
//     ... -- Extensible
150
//     }
151
bool ParsePublicKey(der::Input public_key_spki,
152
0
                    bssl::UniquePtr<EVP_PKEY> *public_key) {
153
  // Parse the SPKI to an EVP_PKEY.
154
0
  OpenSSLErrStackTracer err_tracer;
155
0
  const EVP_PKEY_ALG *const algs[] = {
156
0
      EVP_pkey_rsa(),
157
0
      EVP_pkey_ec_p256(),
158
0
      EVP_pkey_ec_p384(),
159
      // TODO(davidben): Remove P-521 from here, or let callers configure this.
160
      // We don't advertise it in TLS.
161
0
      EVP_pkey_ec_p521(),
162
0
      EVP_pkey_ml_dsa_44(),
163
0
      EVP_pkey_ml_dsa_65(),
164
0
      EVP_pkey_ml_dsa_87(),
165
0
  };
166
0
  public_key->reset(EVP_PKEY_from_subject_public_key_info(
167
0
      public_key_spki.data(), public_key_spki.size(), algs, std::size(algs)));
168
0
  return *public_key != nullptr;
169
0
}
170
171
bool VerifySignedData(SignatureAlgorithm algorithm, der::Input signed_data,
172
                      const der::BitString &signature_value,
173
0
                      const EVP_PKEY *public_key, SignatureVerifyCache *cache) {
174
0
  int expected_pkey_id = 1;
175
0
  const EVP_MD *digest = nullptr;
176
0
  bool is_rsa_pss = false;
177
0
  std::string_view cache_algorithm_name;
178
0
  switch (algorithm) {
179
0
    case SignatureAlgorithm::kRsaPkcs1Sha1:
180
0
      expected_pkey_id = EVP_PKEY_RSA;
181
0
      digest = EVP_sha1();
182
0
      cache_algorithm_name = "RsaPkcs1Sha1";
183
0
      break;
184
0
    case SignatureAlgorithm::kRsaPkcs1Sha256:
185
0
      expected_pkey_id = EVP_PKEY_RSA;
186
0
      digest = EVP_sha256();
187
0
      cache_algorithm_name = "RsaPkcs1Sha256";
188
0
      break;
189
0
    case SignatureAlgorithm::kRsaPkcs1Sha384:
190
0
      expected_pkey_id = EVP_PKEY_RSA;
191
0
      digest = EVP_sha384();
192
0
      cache_algorithm_name = "RsaPkcs1Sha384";
193
0
      break;
194
0
    case SignatureAlgorithm::kRsaPkcs1Sha512:
195
0
      expected_pkey_id = EVP_PKEY_RSA;
196
0
      digest = EVP_sha512();
197
0
      cache_algorithm_name = "RsaPkcs1Sha512";
198
0
      break;
199
200
0
    case SignatureAlgorithm::kEcdsaSha1:
201
0
      expected_pkey_id = EVP_PKEY_EC;
202
0
      digest = EVP_sha1();
203
0
      cache_algorithm_name = "EcdsaSha1";
204
0
      break;
205
0
    case SignatureAlgorithm::kEcdsaSha256:
206
0
      expected_pkey_id = EVP_PKEY_EC;
207
0
      digest = EVP_sha256();
208
0
      cache_algorithm_name = "EcdsaSha256";
209
0
      break;
210
0
    case SignatureAlgorithm::kEcdsaSha384:
211
0
      expected_pkey_id = EVP_PKEY_EC;
212
0
      digest = EVP_sha384();
213
0
      cache_algorithm_name = "EcdsaSha384";
214
0
      break;
215
0
    case SignatureAlgorithm::kEcdsaSha512:
216
0
      expected_pkey_id = EVP_PKEY_EC;
217
0
      digest = EVP_sha512();
218
0
      cache_algorithm_name = "EcdsaSha512";
219
0
      break;
220
221
0
    case SignatureAlgorithm::kRsaPssSha256:
222
0
      expected_pkey_id = EVP_PKEY_RSA;
223
0
      digest = EVP_sha256();
224
0
      cache_algorithm_name = "RsaPssSha256";
225
0
      is_rsa_pss = true;
226
0
      break;
227
0
    case SignatureAlgorithm::kRsaPssSha384:
228
0
      expected_pkey_id = EVP_PKEY_RSA;
229
0
      digest = EVP_sha384();
230
0
      cache_algorithm_name = "RsaPssSha384";
231
0
      is_rsa_pss = true;
232
0
      break;
233
0
    case SignatureAlgorithm::kRsaPssSha512:
234
0
      expected_pkey_id = EVP_PKEY_RSA;
235
0
      digest = EVP_sha512();
236
0
      cache_algorithm_name = "RsaPssSha512";
237
0
      is_rsa_pss = true;
238
0
      break;
239
240
0
    case SignatureAlgorithm::kMtcProofDraftPlants04:
241
0
    case SignatureAlgorithm::kMtcProof:
242
      // This function can't verify MTC proofs.
243
0
      return false;
244
245
0
    case SignatureAlgorithm::kMldsa44:
246
0
      expected_pkey_id = EVP_PKEY_ML_DSA_44;
247
0
      cache_algorithm_name = "Mldsa44";
248
0
      break;
249
0
    case SignatureAlgorithm::kMldsa65:
250
0
      expected_pkey_id = EVP_PKEY_ML_DSA_65;
251
0
      cache_algorithm_name = "Mldsa65";
252
0
      break;
253
0
    case SignatureAlgorithm::kMldsa87:
254
0
      expected_pkey_id = EVP_PKEY_ML_DSA_87;
255
0
      cache_algorithm_name = "Mldsa87";
256
0
      break;
257
0
  }
258
259
0
  if (expected_pkey_id != EVP_PKEY_id(public_key)) {
260
0
    return false;
261
0
  }
262
263
  // For the supported algorithms the signature value must be a whole
264
  // number of bytes.
265
0
  if (signature_value.unused_bits() != 0) {
266
0
    return false;
267
0
  }
268
0
  der::Input signature_value_bytes = signature_value.bytes();
269
270
0
  std::string cache_key;
271
0
  if (cache) {
272
0
    cache_key = SignatureVerifyCacheKey(cache_algorithm_name, signed_data,
273
0
                                        signature_value_bytes, public_key);
274
0
    if (!cache_key.empty()) {
275
0
      switch (cache->Check(cache_key)) {
276
0
        case SignatureVerifyCache::Value::kValid:
277
0
          return true;
278
0
        case SignatureVerifyCache::Value::kInvalid:
279
0
          return false;
280
0
        case SignatureVerifyCache::Value::kUnknown:
281
0
          break;
282
0
      }
283
0
    }
284
0
  }
285
286
0
  OpenSSLErrStackTracer err_tracer;
287
288
0
  bssl::ScopedEVP_MD_CTX ctx;
289
0
  EVP_PKEY_CTX *pctx = nullptr;  // Owned by `ctx`.
290
291
0
  if (!EVP_DigestVerifyInit(ctx.get(), &pctx, digest, nullptr, public_key)) {
292
0
    return false;
293
0
  }
294
295
0
  if (is_rsa_pss) {
296
    // All supported RSASSA-PSS algorithms match signing and MGF-1 digest. They
297
    // also use the digest length as the salt length, which is specified with -1
298
    // in OpenSSL's API.
299
0
    if (!EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) ||
300
0
        !EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, RSA_PSS_SALTLEN_DIGEST)) {
301
0
      return false;
302
0
    }
303
0
  }
304
305
0
  bool ret = 1 == EVP_DigestVerify(ctx.get(), signature_value_bytes.data(),
306
0
                                   signature_value_bytes.size(),
307
0
                                   signed_data.data(), signed_data.size());
308
0
  if (!cache_key.empty()) {
309
0
    cache->Store(cache_key, ret ? SignatureVerifyCache::Value::kValid
310
0
                                : SignatureVerifyCache::Value::kInvalid);
311
0
  }
312
313
0
  return ret;
314
0
}
315
316
bool VerifySignedData(SignatureAlgorithm algorithm, der::Input signed_data,
317
                      const der::BitString &signature_value,
318
0
                      der::Input public_key_spki, SignatureVerifyCache *cache) {
319
0
  bssl::UniquePtr<EVP_PKEY> public_key;
320
0
  if (!ParsePublicKey(public_key_spki, &public_key)) {
321
0
    return false;
322
0
  }
323
0
  return VerifySignedData(algorithm, signed_data, signature_value,
324
0
                          public_key.get(), cache);
325
0
}
326
327
BSSL_NAMESPACE_END