Bug 1159155 - Add telemetry probe for SHA-1 usage (r=keeler)

This commit is contained in:
Mark Goodwin 2015-07-09 07:22:29 +01:00
parent b625ffc87b
commit fc2d7be9e8
12 changed files with 184 additions and 66 deletions

View File

@ -255,7 +255,7 @@ AppTrustDomain::IsChainValid(const DERArray& certChain, Time time)
}
Result
AppTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm)
AppTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm, EndEntityOrCA)
{
// TODO: We should restrict signatures to SHA-256 or better.
return Success;

View File

@ -40,7 +40,8 @@ public:
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain,
mozilla::pkix::Time time) override;
virtual Result CheckSignatureDigestAlgorithm(
mozilla::pkix::DigestAlgorithm digestAlg) override;
mozilla::pkix::DigestAlgorithm digestAlg,
mozilla::pkix::EndEntityOrCA endEntityOrCA) override;
virtual Result CheckRSAPublicKeyModulusSizeInBits(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
unsigned int modulusSizeInBits) override;

View File

@ -123,13 +123,15 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
/*optional out*/ ScopedCERTCertList* builtChain,
/*optional out*/ SECOidTag* evOidPolicy,
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
/*optional out*/ KeySizeStatus* keySizeStatus)
/*optional out*/ KeySizeStatus* keySizeStatus,
/*optional out*/ SignatureDigestStatus* sigDigestStatus)
{
MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("Top of VerifyCert\n"));
PR_ASSERT(cert);
PR_ASSERT(usage == certificateUsageSSLServer || !(flags & FLAG_MUST_BE_EV));
PR_ASSERT(usage == certificateUsageSSLServer || !keySizeStatus);
PR_ASSERT(usage == certificateUsageSSLServer || !sigDigestStatus);
if (builtChain) {
*builtChain = nullptr;
@ -153,6 +155,14 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
*keySizeStatus = KeySizeStatus::NeverChecked;
}
if (sigDigestStatus) {
if (usage != certificateUsageSSLServer) {
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
return SECFailure;
}
*sigDigestStatus = SignatureDigestStatus::NeverChecked;
}
if (!cert ||
(usage != certificateUsageSSLServer && (flags & FLAG_MUST_BE_EV))) {
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
@ -197,13 +207,13 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
case certificateUsageSSLClient: {
// XXX: We don't really have a trust bit for SSL client authentication so
// just use trustEmail as it is the closest alternative.
NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching, mOCSPCache,
pinArg, ocspGETConfig,
NSSCertDBTrustDomain trustDomain(trustEmail, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays,
pinningDisabled,
MIN_RSA_BITS_WEAK,
pinningDisabled, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
nullptr, builtChain);
AcceptAllAlgorithms, nullptr,
builtChain);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature,
@ -217,6 +227,28 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
// restrict the acceptable key usage based on the key exchange method
// chosen by the server.
SignatureDigestOption digestAlgorithmOptions[] = {
DisableSHA1Everywhere,
DisableSHA1ForCA,
DisableSHA1ForEE,
AcceptAllAlgorithms
};
SignatureDigestStatus digestAlgorithmStatuses[] = {
SignatureDigestStatus::GoodAlgorithmsOnly,
SignatureDigestStatus::WeakEECert,
SignatureDigestStatus::WeakCACert,
SignatureDigestStatus::WeakCAAndEE
};
size_t digestAlgorithmOptionsCount = MOZ_ARRAY_LENGTH(digestAlgorithmStatuses);
static_assert(MOZ_ARRAY_LENGTH(digestAlgorithmOptions) ==
MOZ_ARRAY_LENGTH(digestAlgorithmStatuses),
"digestAlgorithm array lengths differ");
rv = Result::ERROR_UNKNOWN_ERROR;
#ifndef MOZ_NO_EV_CERTS
// Try to validate for EV first.
NSSCertDBTrustDomain::OCSPFetching evOCSPFetching
@ -227,12 +259,15 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
CertPolicyId evPolicy;
SECOidTag evPolicyOidTag;
SECStatus srv = GetFirstEVPolicy(cert, evPolicy, evPolicyOidTag);
if (srv == SECSuccess) {
for (size_t i=0;
i < digestAlgorithmOptionsCount && rv != Success && srv == SECSuccess;
i++) {
NSSCertDBTrustDomain
trustDomain(trustSSL, evOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays, mPinningMode, MIN_RSA_BITS,
ValidityCheckingMode::CheckForEV, hostname, builtChain);
ValidityCheckingMode::CheckForEV,
digestAlgorithmOptions[i], hostname, builtChain);
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
KeyUsage::digitalSignature,// (EC)DHE
KeyUsage::keyEncipherment, // RSA
@ -241,12 +276,19 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
evPolicy, stapledOCSPResponse,
ocspStaplingStatus);
if (rv == Success) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("cert is EV with status %i\n", digestAlgorithmStatuses[i]));
if (evOidPolicy) {
*evOidPolicy = evPolicyOidTag;
}
break;
if (sigDigestStatus) {
*sigDigestStatus = digestAlgorithmStatuses[i];
}
}
}
if (rv == Success) {
break;
}
#endif
if (flags & FLAG_MUST_BE_EV) {
@ -255,48 +297,59 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
}
// Now try non-EV.
NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays, mPinningMode,
MIN_RSA_BITS,
ValidityCheckingMode::CheckingOff,
hostname, builtChain);
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
KeyUsage::digitalSignature, // (EC)DHE
KeyUsage::keyEncipherment, // RSA
KeyUsage::keyAgreement, // (EC)DH
KeyPurposeId::id_kp_serverAuth,
CertPolicyId::anyPolicy,
stapledOCSPResponse,
ocspStaplingStatus);
if (rv == Success) {
if (keySizeStatus) {
*keySizeStatus = KeySizeStatus::LargeMinimumSucceeded;
unsigned int keySizeOptions[] = {
MIN_RSA_BITS,
MIN_RSA_BITS_WEAK
};
KeySizeStatus keySizeStatuses[] = {
KeySizeStatus::LargeMinimumSucceeded,
KeySizeStatus::CompatibilityRisk
};
static_assert(MOZ_ARRAY_LENGTH(keySizeOptions) ==
MOZ_ARRAY_LENGTH(keySizeStatuses),
"keySize array lengths differ");
size_t keySizeOptionsCount = MOZ_ARRAY_LENGTH(keySizeStatuses);
for (size_t i=0; i<keySizeOptionsCount && rv != Success; i++) {
for (size_t j=0; j<digestAlgorithmOptionsCount && rv != Success; j++) {
NSSCertDBTrustDomain trustDomain(trustSSL, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays,
mPinningMode, keySizeOptions[i],
ValidityCheckingMode::CheckingOff,
digestAlgorithmOptions[j],
hostname, builtChain);
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
KeyUsage::digitalSignature,//(EC)DHE
KeyUsage::keyEncipherment,//RSA
KeyUsage::keyAgreement,//(EC)DH
KeyPurposeId::id_kp_serverAuth,
CertPolicyId::anyPolicy,
stapledOCSPResponse,
ocspStaplingStatus);
if (rv == Success) {
if (keySizeStatus) {
*keySizeStatus = keySizeStatuses[i];
}
if (sigDigestStatus) {
*sigDigestStatus = digestAlgorithmStatuses[j];
}
}
}
}
if (rv == Success) {
break;
}
// If that failed, try again with a smaller minimum key size.
NSSCertDBTrustDomain trustDomainWeak(trustSSL, defaultOCSPFetching,
mOCSPCache, pinArg, ocspGETConfig,
mCertShortLifetimeInDays,
mPinningMode, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
hostname, builtChain);
rv = BuildCertChainForOneKeyUsage(trustDomainWeak, certDER, time,
KeyUsage::digitalSignature, // (EC)DHE
KeyUsage::keyEncipherment, // RSA
KeyUsage::keyAgreement, // (EC)DH
KeyPurposeId::id_kp_serverAuth,
CertPolicyId::anyPolicy,
stapledOCSPResponse,
ocspStaplingStatus);
if (keySizeStatus) {
if (rv == Success) {
*keySizeStatus = KeySizeStatus::CompatibilityRisk;
} else {
*keySizeStatus = KeySizeStatus::AlreadyBad;
}
*keySizeStatus = KeySizeStatus::AlreadyBad;
}
if (sigDigestStatus) {
*sigDigestStatus = SignatureDigestStatus::AlreadyBad;
}
break;
@ -308,7 +361,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
nullptr, builtChain);
AcceptAllAlgorithms, nullptr,
builtChain);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeCA, KeyUsage::keyCertSign,
KeyPurposeId::id_kp_serverAuth,
@ -322,7 +376,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
nullptr, builtChain);
AcceptAllAlgorithms, nullptr,
builtChain);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature,
@ -347,7 +402,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
nullptr, builtChain);
AcceptAllAlgorithms, nullptr,
builtChain);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::keyEncipherment, // RSA
@ -369,7 +425,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
nullptr, builtChain);
AcceptAllAlgorithms, nullptr,
builtChain);
rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature,
@ -400,7 +457,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
pinArg, ocspGETConfig, mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
nullptr, builtChain);
AcceptAllAlgorithms, nullptr, builtChain);
rv = BuildCertChain(sslTrust, certDER, time, endEntityOrCA,
keyUsage, eku, CertPolicyId::anyPolicy,
stapledOCSPResponse);
@ -410,7 +467,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
mCertShortLifetimeInDays,
pinningDisabled, MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
nullptr, builtChain);
AcceptAllAlgorithms, nullptr,
builtChain);
rv = BuildCertChain(emailTrust, certDER, time, endEntityOrCA,
keyUsage, eku, CertPolicyId::anyPolicy,
stapledOCSPResponse);
@ -422,6 +480,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
pinningDisabled,
MIN_RSA_BITS_WEAK,
ValidityCheckingMode::CheckingOff,
AcceptAllAlgorithms,
nullptr, builtChain);
rv = BuildCertChain(objectSigningTrust, certDER, time,
endEntityOrCA, keyUsage, eku,
@ -455,7 +514,8 @@ CertVerifier::VerifySSLServerCert(CERTCertificate* peerCert,
/*optional out*/ ScopedCERTCertList* builtChain,
/*optional out*/ SECOidTag* evOidPolicy,
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus,
/*optional out*/ KeySizeStatus* keySizeStatus)
/*optional out*/ KeySizeStatus* keySizeStatus,
/*optional out*/ SignatureDigestStatus* sigDigestStatus)
{
PR_ASSERT(peerCert);
// XXX: PR_ASSERT(pinarg)
@ -480,7 +540,7 @@ CertVerifier::VerifySSLServerCert(CERTCertificate* peerCert,
SECStatus rv = VerifyCert(peerCert, certificateUsageSSLServer, time, pinarg,
hostname, flags, stapledOCSPResponse,
&builtChainTemp, evOidPolicy, ocspStaplingStatus,
keySizeStatus);
keySizeStatus, sigDigestStatus);
if (rv != SECSuccess) {
return rv;
}

View File

@ -21,6 +21,16 @@ enum class KeySizeStatus {
AlreadyBad = 3,
};
// These values correspond to the CERT_CHAIN_SIGNATURE_DIGEST telemetry.
enum class SignatureDigestStatus {
NeverChecked = 0,
GoodAlgorithmsOnly = 1,
WeakEECert = 2,
WeakCACert = 3,
WeakCAAndEE = 4,
AlreadyBad = 5,
};
class CertVerifier
{
public:
@ -51,7 +61,8 @@ public:
/*optional out*/ ScopedCERTCertList* builtChain = nullptr,
/*optional out*/ SECOidTag* evOidPolicy = nullptr,
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
/*optional out*/ KeySizeStatus* keySizeStatus = nullptr);
/*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
/*optional out*/ SignatureDigestStatus* sigDigestStatus = nullptr);
SECStatus VerifySSLServerCert(
CERTCertificate* peerCert,
@ -64,7 +75,8 @@ public:
/*optional out*/ ScopedCERTCertList* builtChain = nullptr,
/*optional out*/ SECOidTag* evOidPolicy = nullptr,
/*optional out*/ OCSPStaplingStatus* ocspStaplingStatus = nullptr,
/*optional out*/ KeySizeStatus* keySizeStatus = nullptr);
/*optional out*/ KeySizeStatus* keySizeStatus = nullptr,
/*optional out*/ SignatureDigestStatus* sigDigestStatus = nullptr);
enum PinningMode {
pinningDisabled = 0,

View File

@ -49,6 +49,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType,
CertVerifier::PinningMode pinningMode,
unsigned int minRSABits,
ValidityCheckingMode validityCheckingMode,
SignatureDigestOption signatureDigestOption,
/*optional*/ const char* hostname,
/*optional*/ ScopedCERTCertList* builtChain)
: mCertDBTrustType(certDBTrustType)
@ -60,6 +61,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType,
, mPinningMode(pinningMode)
, mMinRSABits(minRSABits)
, mValidityCheckingMode(validityCheckingMode)
, mSignatureDigestOption(signatureDigestOption)
, mHostname(hostname)
, mBuiltChain(builtChain)
, mCertBlocklist(do_GetService(NS_CERTBLOCKLIST_CONTRACTID))
@ -796,8 +798,28 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time)
}
Result
NSSCertDBTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm)
NSSCertDBTrustDomain::CheckSignatureDigestAlgorithm(DigestAlgorithm aAlg,
EndEntityOrCA endEntityOrCA)
{
MOZ_LOG(gCertVerifierLog, LogLevel::Debug,
("NSSCertDBTrustDomain: CheckSignatureDigestAlgorithm"));
if (aAlg == DigestAlgorithm::sha1) {
if (mSignatureDigestOption == DisableSHA1Everywhere) {
return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
}
if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("CA cert is SHA1"));
return mSignatureDigestOption == DisableSHA1ForCA
? Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
: Success;
} else {
MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("EE cert is SHA1"));
return mSignatureDigestOption == DisableSHA1ForEE
? Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED
: Success;
}
}
return Success;
}

View File

@ -41,6 +41,13 @@ char* DefaultServerNicknameForCert(CERTCertificate* cert);
void SaveIntermediateCerts(const ScopedCERTCertList& certList);
enum SignatureDigestOption {
AcceptAllAlgorithms,
DisableSHA1ForEE,
DisableSHA1ForCA,
DisableSHA1Everywhere,
};
class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain
{
@ -62,6 +69,7 @@ public:
CertVerifier::PinningMode pinningMode,
unsigned int minRSABits,
ValidityCheckingMode validityCheckingMode,
SignatureDigestOption,
/*optional*/ const char* hostname = nullptr,
/*optional out*/ ScopedCERTCertList* builtChain = nullptr);
@ -76,7 +84,8 @@ public:
override;
virtual Result CheckSignatureDigestAlgorithm(
mozilla::pkix::DigestAlgorithm digestAlg) override;
mozilla::pkix::DigestAlgorithm digestAlg,
mozilla::pkix::EndEntityOrCA endEntityOrCA) override;
virtual Result CheckRSAPublicKeyModulusSizeInBits(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
@ -144,6 +153,7 @@ private:
CertVerifier::PinningMode mPinningMode;
const unsigned int mMinRSABits;
ValidityCheckingMode mValidityCheckingMode;
SignatureDigestOption mSignatureDigestOption;
const char* mHostname; // non-owning - only used for pinning checks
ScopedCERTCertList* mBuiltChain; // non-owning
nsCOMPtr<nsICertBlocklist> mCertBlocklist;

View File

@ -1177,13 +1177,14 @@ AuthCertificate(CertVerifier& certVerifier,
CertVerifier::OCSPStaplingStatus ocspStaplingStatus =
CertVerifier::OCSP_STAPLING_NEVER_CHECKED;
KeySizeStatus keySizeStatus = KeySizeStatus::NeverChecked;
SignatureDigestStatus sigDigestStatus = SignatureDigestStatus::NeverChecked;
rv = certVerifier.VerifySSLServerCert(cert, stapledOCSPResponse,
time, infoObject,
infoObject->GetHostNameRaw(),
saveIntermediates, 0, &certList,
&evOidPolicy, &ocspStaplingStatus,
&keySizeStatus);
&keySizeStatus, &sigDigestStatus);
PRErrorCode savedErrorCode;
if (rv != SECSuccess) {
savedErrorCode = PR_GetError();
@ -1196,6 +1197,10 @@ AuthCertificate(CertVerifier& certVerifier,
Telemetry::Accumulate(Telemetry::CERT_CHAIN_KEY_SIZE_STATUS,
static_cast<uint32_t>(keySizeStatus));
}
if (sigDigestStatus != SignatureDigestStatus::NeverChecked) {
Telemetry::Accumulate(Telemetry::CERT_CHAIN_SIGNATURE_DIGEST_STATUS,
static_cast<uint32_t>(sigDigestStatus));
}
// We want to remember the CA certs in the temp db, so that the application can find the
// complete chain at any time it might need it.

View File

@ -277,7 +277,8 @@ public:
// Return Success if the algorithm is acceptable,
// Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED if the algorithm is not
// acceptable, or another error code if another error occurred.
virtual Result CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg) = 0;
virtual Result CheckSignatureDigestAlgorithm(DigestAlgorithm digestAlg,
EndEntityOrCA endEntityOrCA) = 0;
// Check that the RSA public key size is acceptable.
//

View File

@ -91,7 +91,7 @@ CheckSignatureAlgorithm(TrustDomain& trustDomain,
// more generally it short-circuits any path building with them (which, of
// course, is even slower).
rv = trustDomain.CheckSignatureDigestAlgorithm(digestAlg);
rv = trustDomain.CheckSignatureDigestAlgorithm(digestAlg, endEntityOrCA);
if (rv != Success) {
return rv;
}

View File

@ -203,7 +203,7 @@ public:
{
}
Result CheckSignatureDigestAlgorithm(DigestAlgorithm) override
Result CheckSignatureDigestAlgorithm(DigestAlgorithm, EndEntityOrCA) override
{
checkedDigestAlgorithm = true;
return Success;

View File

@ -125,7 +125,8 @@ public:
Result::FATAL_ERROR_LIBRARY_FAILURE);
}
Result CheckSignatureDigestAlgorithm(DigestAlgorithm) override
Result CheckSignatureDigestAlgorithm(DigestAlgorithm,
EndEntityOrCA) override
{
ADD_FAILURE();
return NotReached("CheckSignatureDigestAlgorithm should not be called",
@ -178,7 +179,7 @@ class DefaultCryptoTrustDomain : public EverythingFailsByDefaultTrustDomain
return TestDigestBuf(item, digestAlg, digestBuf, digestBufLen);
}
Result CheckSignatureDigestAlgorithm(DigestAlgorithm) override
Result CheckSignatureDigestAlgorithm(DigestAlgorithm, EndEntityOrCA) override
{
return Success;
}

View File

@ -7502,6 +7502,12 @@
"n_values": 4,
"description": "Does enforcing a larger minimum RSA key size cause verification failures? 1 = no, 2 = yes, 3 = another error prevented finding a verified chain"
},
"CERT_CHAIN_SIGNATURE_DIGEST_STATUS": {
"expires_in_version": "default",
"kind": "enumerated",
"n_values": 6,
"description": "Information on weak signature digest algorithms in the chain: 1 = Only good algorithms, 2 = a weak algorithm was present in an end entity, 3 = a weak algorithm was present in a CA cert, 4 = a weak algorithm was present in both EE and CA certs, 5 = another error prevented signature algorithm from being determined"
},
"WEAVE_CONFIGURED": {
"expires_in_version": "default",
"kind": "boolean",