Commit 370a7fda authored by Matt Mueller's avatar Matt Mueller Committed by Commit Bot

[net] Record debug data in TrustStoreMac::GetTrust.

Records a bitfield of the various types of trust settings that were                                                                                    seen.

Bug: 991247
Change-Id: I50d4070a309088a99c5317dc13a4a3c59acae47d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1754276
Commit-Queue: Matt Mueller <mattm@chromium.org>
Reviewed-by: default avatarEric Roman <eroman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#689277}
parent bd1d533a
......@@ -72,6 +72,7 @@
#elif defined(OS_MACOSX)
#include "base/mac/mac_util.h"
#include "net/cert/cert_verify_proc_mac.h"
#include "net/cert/internal/trust_store_mac.h"
#elif defined(OS_WIN)
#include "base/win/windows_version.h"
#include "net/cert/cert_verify_proc_win.h"
......@@ -1977,6 +1978,17 @@ TEST_P(CertVerifyProcInternalTest, TestKnownRoot) {
<< "that date, please disable and file a bug "
<< "against rsleevi.";
EXPECT_TRUE(verify_result.is_issued_by_known_root);
#if defined(OS_MACOSX) && !defined(OS_IOS)
if (verify_proc_type() == CERT_VERIFY_PROC_BUILTIN) {
auto* mac_trust_debug_info =
net::TrustStoreMac::ResultDebugData::Get(&verify_result);
ASSERT_TRUE(mac_trust_debug_info);
// Since this test queries the real trust store, can't know exactly
// what bits should be set in the trust debug info, but it should at
// least have something set.
EXPECT_NE(0, mac_trust_debug_info->combined_trust_debug_info());
}
#endif
}
// This tests that on successful certificate verification,
......
This diff is collapsed.
......@@ -24,6 +24,71 @@ namespace net {
// TrustStoreMac object outlives any threads accessing it.
class NET_EXPORT TrustStoreMac : public TrustStore {
public:
// Bits representing different conditions encountered while evaluating
// the trustSettings returned by SecTrustSettingsCopyTrustSettings.
enum TrustDebugInfo {
// The trustSettings array was empty.
TRUST_SETTINGS_ARRAY_EMPTY = 1 << 0,
// One of the trustSettings dictionaries was empty.
TRUST_SETTINGS_DICT_EMPTY = 1 << 1,
// One of the trustSettings dictionaries contained an unknown key.
TRUST_SETTINGS_DICT_UNKNOWN_KEY = 1 << 2,
// One of the trustSettings dictionaries contained a
// kSecTrustSettingsPolicy key.
TRUST_SETTINGS_DICT_CONTAINS_POLICY = 1 << 3,
// One of the trustSettings dictionaries contained a
// kSecTrustSettingsPolicy key with a value that was not a SecPolicyRef.
TRUST_SETTINGS_DICT_INVALID_POLICY_TYPE = 1 << 4,
// One of the trustSettings dictionaries contained a
// kSecTrustSettingsApplication key.
TRUST_SETTINGS_DICT_CONTAINS_APPLICATION = 1 << 5,
// One of the trustSettings dictionaries contained a
// kSecTrustSettingsPolicyString key.
TRUST_SETTINGS_DICT_CONTAINS_POLICY_STRING = 1 << 6,
// One of the trustSettings dictionaries contained a
// kSecTrustSettingsKeyUsage key.
TRUST_SETTINGS_DICT_CONTAINS_KEY_USAGE = 1 << 7,
// One of the trustSettings dictionaries contained a
// kSecTrustSettingsResult key.
TRUST_SETTINGS_DICT_CONTAINS_RESULT = 1 << 8,
// One of the trustSettings dictionaries contained a
// kSecTrustSettingsResult key with a value that was not a CFNumber or
// could not be represented by a signed int.
TRUST_SETTINGS_DICT_INVALID_RESULT_TYPE = 1 << 9,
// One of the trustSettings dictionaries contained a
// kSecTrustSettingsAllowedError key.
TRUST_SETTINGS_DICT_CONTAINS_ALLOWED_ERROR = 1 << 10,
};
class ResultDebugData : public base::SupportsUserData::Data {
public:
static const ResultDebugData* Get(const base::SupportsUserData* debug_data);
static ResultDebugData* GetOrCreate(base::SupportsUserData* debug_data);
void UpdateTrustDebugInfo(int trust_debug_info);
// base::SupportsUserData::Data implementation:
std::unique_ptr<Data> Clone() override;
// Returns a bitfield of TrustDebugInfo flags. If multiple GetTrust calls
// were done with the same SupportsUserData object, this will return the
// union of all the TrustDebugInfo flags.
int combined_trust_debug_info() const { return combined_trust_debug_info_; }
private:
int combined_trust_debug_info_ = 0;
};
// Creates a TrustStoreMac which will find anchors that are trusted for
// |policy_oid|. For list of possible policy values, see:
// https://developer.apple.com/reference/security/1667150-certificate_key_and_trust_servic/1670151-standard_policies_for_specific_c?language=objc
......
......@@ -92,6 +92,11 @@ std::vector<std::string> ParsedCertificateListAsDER(
return result;
}
class DebugData : public base::SupportsUserData {
public:
~DebugData() override = default;
};
} // namespace
// Test the trust store using known test certificates in a keychain. Tests
......@@ -197,8 +202,11 @@ TEST(TrustStoreMacTest, MultiRootNotTrusted) {
for (const auto& cert :
{a_by_b, b_by_c, b_by_f, c_by_d, c_by_e, f_by_e, d_by_d, e_by_e}) {
CertificateTrust trust = CertificateTrust::ForTrustAnchor();
trust_store.GetTrust(cert.get(), &trust, /*debug_data=*/nullptr);
DebugData debug_data;
trust_store.GetTrust(cert.get(), &trust, &debug_data);
EXPECT_EQ(CertificateTrustType::UNSPECIFIED, trust.type);
// Certs without trust settings should not add debug info to debug_data.
EXPECT_FALSE(TrustStoreMac::ResultDebugData::Get(&debug_data));
}
}
......@@ -265,7 +273,8 @@ TEST(TrustStoreMacTest, SystemCerts) {
}
// Check if this cert is considered a trust anchor by TrustStoreMac.
CertificateTrust cert_trust;
trust_store.GetTrust(cert, &cert_trust, /*debug_data=*/nullptr);
DebugData debug_data;
trust_store.GetTrust(cert, &cert_trust, &debug_data);
bool is_trust_anchor = cert_trust.IsTrustAnchor();
// Check if this cert is considered a trust anchor by the OS.
......@@ -294,6 +303,15 @@ TEST(TrustStoreMacTest, SystemCerts) {
(trust_result == kSecTrustResultUnspecified)) &&
(SecTrustGetCertificateCount(trust) == 1);
EXPECT_EQ(expected_trust_anchor, is_trust_anchor);
if (is_trust_anchor) {
auto* trust_debug_data =
TrustStoreMac::ResultDebugData::Get(&debug_data);
ASSERT_TRUE(trust_debug_data);
// Since this test queries the real trust store, can't know exactly
// what bits should be set in the trust debug info, but it should at
// least have something set.
EXPECT_NE(0, trust_debug_data->combined_trust_debug_info());
}
}
}
}
......
......@@ -8,8 +8,13 @@
#include "base/files/file_util.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "net/cert/pem_tokenizer.h"
#if defined(OS_MACOSX) && !defined(OS_IOS)
#include "net/cert/internal/trust_store_mac.h"
#endif
namespace {
// The PEM block header used for PEM-encoded DER certificates.
......@@ -98,3 +103,15 @@ void PrintCertError(const std::string& error, const CertInput& cert) {
std::cerr << " (" << cert.source_details << ")";
std::cerr << "\n";
}
void PrintDebugData(const base::SupportsUserData* debug_data) {
#if defined(OS_MACOSX) && !defined(OS_IOS)
auto* mac_trust_debug_info =
net::TrustStoreMac::ResultDebugData::Get(debug_data);
if (mac_trust_debug_info) {
std::cout << base::StringPrintf(
"TrustStoreMac::ResultDebugData::combined_trust_debug_info: 0x%x\n",
mac_trust_debug_info->combined_trust_debug_info());
}
#endif
}
......@@ -10,6 +10,10 @@
#include "base/files/file_path.h"
namespace base {
class SupportsUserData;
}
// Stores DER certificate bytes and details about where they were read from.
// This allows decoupling the input file reading from the certificate parsing
// while retaining useful error messages.
......@@ -49,4 +53,7 @@ bool WriteToFile(const base::FilePath& file_path, const std::string& data);
// was read from, as well as which block in the file if it was a PEM file.
void PrintCertError(const std::string& error, const CertInput& cert);
// Prints any known debug information from |debug_data|.
void PrintDebugData(const base::SupportsUserData* debug_data);
#endif // NET_TOOLS_CERT_VERIFY_TOOL_CERT_VERIFY_TOOL_UTIL_H_
......@@ -78,6 +78,7 @@ void PrintCertStatus(int cert_status) {
}
void PrintCertVerifyResult(const net::CertVerifyResult& result) {
PrintDebugData(&result);
PrintCertStatus(result.cert_status);
if (result.has_md2)
std::cout << "has_md2\n";
......
......@@ -189,6 +189,8 @@ bool VerifyUsingPathBuilder(
std::cout << "CertPathBuilder result: "
<< (result.HasValidPath() ? "SUCCESS" : "FAILURE") << "\n";
PrintDebugData(&result);
for (size_t i = 0; i < result.paths.size(); ++i) {
PrintResultPath(result.paths[i].get(), i, i == result.best_result_index);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment