Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "RootCertificateTelemetryUtils.h"
8 :
9 : #include "mozilla/Logging.h"
10 : #include "RootHashes.inc" // Note: Generated by genRootCAHashes.js
11 : #include "ScopedNSSTypes.h"
12 : #include "mozilla/ArrayUtils.h"
13 : #include "mozilla/SizePrintfMacros.h"
14 :
15 : namespace mozilla { namespace psm {
16 :
17 : mozilla::LazyLogModule gPublicKeyPinningTelemetryLog("PublicKeyPinningTelemetryService");
18 :
19 : // Used in the BinarySearch method, this does a memcmp between the pointer
20 : // provided to its construtor and whatever the binary search is looking for.
21 : //
22 : // This implementation assumes everything to be of HASH_LEN, so it should not
23 : // be used generically.
24 : class BinaryHashSearchArrayComparator
25 : {
26 : public:
27 0 : explicit BinaryHashSearchArrayComparator(const uint8_t* aTarget, size_t len)
28 0 : : mTarget(aTarget)
29 : {
30 0 : MOZ_ASSERT(len == HASH_LEN, "Hashes should be of the same length.");
31 0 : }
32 :
33 0 : int operator()(const CertAuthorityHash val) const {
34 0 : return memcmp(mTarget, val.hash, HASH_LEN);
35 : }
36 :
37 : private:
38 : const uint8_t* mTarget;
39 : };
40 :
41 : // Perform a hash of the provided cert, then search in the RootHashes.inc data
42 : // structure for a matching bin number.
43 : int32_t
44 0 : RootCABinNumber(const SECItem* cert)
45 : {
46 0 : Digest digest;
47 :
48 : // Compute SHA256 hash of the certificate
49 0 : nsresult rv = digest.DigestBuf(SEC_OID_SHA256, cert->data, cert->len);
50 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
51 0 : return ROOT_CERTIFICATE_HASH_FAILURE;
52 : }
53 :
54 : // Compare against list of stored hashes
55 : size_t idx;
56 :
57 0 : MOZ_LOG(gPublicKeyPinningTelemetryLog, LogLevel::Debug,
58 : ("pkpinTelem: First bytes %02x %02x %02x %02x\n",
59 : digest.get().data[0], digest.get().data[1], digest.get().data[2], digest.get().data[3]));
60 :
61 0 : if (mozilla::BinarySearchIf(ROOT_TABLE, 0, ArrayLength(ROOT_TABLE),
62 0 : BinaryHashSearchArrayComparator(static_cast<uint8_t*>(digest.get().data),
63 0 : digest.get().len),
64 : &idx)) {
65 :
66 0 : MOZ_LOG(gPublicKeyPinningTelemetryLog, LogLevel::Debug,
67 : ("pkpinTelem: Telemetry index was %" PRIuSIZE ", bin is %d\n",
68 : idx, ROOT_TABLE[idx].binNumber));
69 0 : return (int32_t) ROOT_TABLE[idx].binNumber;
70 : }
71 :
72 : // Didn't match.
73 0 : return ROOT_CERTIFICATE_UNKNOWN;
74 : }
75 :
76 :
77 : // Attempt to increment the appropriate bin in the provided Telemetry probe ID. If
78 : // there was a hash failure, we do nothing.
79 : void
80 0 : AccumulateTelemetryForRootCA(mozilla::Telemetry::HistogramID probe,
81 : const CERTCertificate* cert)
82 : {
83 0 : int32_t binId = RootCABinNumber(&cert->derCert);
84 :
85 0 : if (binId != ROOT_CERTIFICATE_HASH_FAILURE) {
86 0 : Accumulate(probe, binId);
87 : }
88 0 : }
89 :
90 : } // namespace psm
91 : } // namespace mozilla
|