diff options
Diffstat (limited to 'security/manager/ssl/RootCertificateTelemetryUtils.cpp')
-rw-r--r-- | security/manager/ssl/RootCertificateTelemetryUtils.cpp | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/security/manager/ssl/RootCertificateTelemetryUtils.cpp b/security/manager/ssl/RootCertificateTelemetryUtils.cpp new file mode 100644 index 0000000000..3f9ea3eb62 --- /dev/null +++ b/security/manager/ssl/RootCertificateTelemetryUtils.cpp @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RootCertificateTelemetryUtils.h" + +#include "mozilla/Logging.h" +#include "RootHashes.inc" // Note: Generated by genRootCAHashes.js +#include "ScopedNSSTypes.h" +#include "mozilla/ArrayUtils.h" + +namespace mozilla { namespace psm { + +mozilla::LazyLogModule gPublicKeyPinningTelemetryLog("PublicKeyPinningTelemetryService"); + +// Used in the BinarySearch method, this does a memcmp between the pointer +// provided to its construtor and whatever the binary search is looking for. +// +// This implementation assumes everything to be of HASH_LEN, so it should not +// be used generically. +class BinaryHashSearchArrayComparator +{ +public: + explicit BinaryHashSearchArrayComparator(const uint8_t* aTarget, size_t len) + : mTarget(aTarget) + { + NS_ASSERTION(len == HASH_LEN, "Hashes should be of the same length."); + } + + int operator()(const CertAuthorityHash val) const { + return memcmp(mTarget, val.hash, HASH_LEN); + } + +private: + const uint8_t* mTarget; +}; + +// Perform a hash of the provided cert, then search in the RootHashes.inc data +// structure for a matching bin number. +int32_t +RootCABinNumber(const SECItem* cert) +{ + Digest digest; + + // Compute SHA256 hash of the certificate + nsresult rv = digest.DigestBuf(SEC_OID_SHA256, cert->data, cert->len); + if (NS_WARN_IF(NS_FAILED(rv))) { + return ROOT_CERTIFICATE_HASH_FAILURE; + } + + // Compare against list of stored hashes + size_t idx; + + MOZ_LOG(gPublicKeyPinningTelemetryLog, LogLevel::Debug, + ("pkpinTelem: First bytes %02hx %02hx %02hx %02hx\n", + digest.get().data[0], digest.get().data[1], digest.get().data[2], digest.get().data[3])); + + if (mozilla::BinarySearchIf(ROOT_TABLE, 0, ArrayLength(ROOT_TABLE), + BinaryHashSearchArrayComparator(static_cast<uint8_t*>(digest.get().data), + digest.get().len), + &idx)) { + + MOZ_LOG(gPublicKeyPinningTelemetryLog, LogLevel::Debug, + ("pkpinTelem: Telemetry index was %lu, bin is %d\n", + idx, ROOT_TABLE[idx].binNumber)); + return (int32_t) ROOT_TABLE[idx].binNumber; + } + + // Didn't match. + return ROOT_CERTIFICATE_UNKNOWN; +} + + +// Attempt to increment the appropriate bin in the provided Telemetry probe ID. If +// there was a hash failure, we do nothing. +void +AccumulateTelemetryForRootCA(mozilla::Telemetry::ID probe, + const CERTCertificate* cert) +{ + int32_t binId = RootCABinNumber(&cert->derCert); + + if (binId != ROOT_CERTIFICATE_HASH_FAILURE) { + Accumulate(probe, binId); + } +} + +} // namespace psm +} // namespace mozilla |