Skip to content

Commit

Permalink
Ignore root cert expiration in Server. (#26372)
Browse files Browse the repository at this point in the history
Since there is no real way to rotate the root cert for a fabric, even just to
update its validity period, enforcing the validity period for it just means
making the fabric not work and runs the risk of making devices completely
unreachable.

Switch to not validating expiration time for a root certificate, while keeping
existing behavior for the NotBefore and all other certificate types.
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Nov 23, 2023
1 parent 191df0a commit 4764579
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 24 deletions.
6 changes: 3 additions & 3 deletions src/app/server/Server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams)
mOperationalKeystore = initParams.operationalKeystore;
mOpCertStore = initParams.opCertStore;

mCertificateValidityPolicy = initParams.certificateValidityPolicy;
mCertificateValidityPolicy.Init(initParams.certificateValidityPolicy);

#if defined(CHIP_SUPPORT_ENABLE_STORAGE_API_AUDIT)
VerifyOrDie(chip::audit::ExecutePersistentStorageApiAudit(*mDeviceStorage));
Expand Down Expand Up @@ -286,7 +286,7 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams)
.sessionInitParams = {
.sessionManager = &mSessions,
.sessionResumptionStorage = mSessionResumptionStorage,
.certificateValidityPolicy = mCertificateValidityPolicy,
.certificateValidityPolicy = &mCertificateValidityPolicy,
.exchangeMgr = &mExchangeMgr,
.fabricTable = &mFabrics,
.groupDataProvider = mGroupsProvider,
Expand All @@ -300,7 +300,7 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams)
SuccessOrExit(err);

err = mCASEServer.ListenForSessionEstablishment(&mExchangeMgr, &mSessions, &mFabrics, mSessionResumptionStorage,
mCertificateValidityPolicy, mGroupsProvider);
&mCertificateValidityPolicy, mGroupsProvider);
SuccessOrExit(err);

err = chip::app::InteractionModelEngine::GetInstance()->Init(&mExchangeMgr, &GetFabricTable(), &mCASESessionManager,
Expand Down
50 changes: 49 additions & 1 deletion src/app/server/Server.h
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,53 @@ class Server
Server * mServer = nullptr;
};

/**
* Since root certificates for Matter nodes cannot be updated in a reasonable
* way, it doesn't make sense to enforce expiration time on root certificates.
* This policy allows through root certificates, even if they're expired, and
* otherwise delegates to the provided policy, or to the default policy if no
* policy is provided.
*/
class IgnoreRootExpirationValidityPolicy : public Credentials::CertificateValidityPolicy
{
public:
IgnoreRootExpirationValidityPolicy() {}

void Init(Credentials::CertificateValidityPolicy * providedPolicy) { mProvidedPolicy = providedPolicy; }

CHIP_ERROR ApplyCertificateValidityPolicy(const Credentials::ChipCertificateData * cert, uint8_t depth,
Credentials::CertificateValidityResult result) override
{
switch (result)
{
case Credentials::CertificateValidityResult::kExpired:
case Credentials::CertificateValidityResult::kExpiredAtLastKnownGoodTime:
case Credentials::CertificateValidityResult::kTimeUnknown: {
uint8_t certType;
ReturnErrorOnFailure(cert->mSubjectDN.GetCertType(certType));
if (certType == Credentials::kCertType_Root)
{
return CHIP_NO_ERROR;
}

break;
}
default:
break;
}

if (mProvidedPolicy)
{
return mProvidedPolicy->ApplyCertificateValidityPolicy(cert, depth, result);
}

return Credentials::CertificateValidityPolicy::ApplyDefaultPolicy(cert, depth, result);
}

private:
Credentials::CertificateValidityPolicy * mProvidedPolicy = nullptr;
};

#if CONFIG_NETWORK_LAYER_BLE
Ble::BleLayer * mBleLayer = nullptr;
#endif
Expand All @@ -560,10 +607,11 @@ class Server
#endif // CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY_CLIENT
CommissioningWindowManager mCommissioningWindowManager;

IgnoreRootExpirationValidityPolicy mCertificateValidityPolicy;

PersistentStorageDelegate * mDeviceStorage;
SessionResumptionStorage * mSessionResumptionStorage;
app::SubscriptionResumptionStorage * mSubscriptionResumptionStorage;
Credentials::CertificateValidityPolicy * mCertificateValidityPolicy;
Credentials::GroupDataProvider * mGroupsProvider;
Crypto::SessionKeystore * mSessionKeystore;
app::DefaultAttributePersistenceProvider mAttributePersister;
Expand Down
46 changes: 26 additions & 20 deletions src/credentials/CHIPCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -431,26 +431,7 @@ CHIP_ERROR ChipCertificateSet::ValidateCert(const ChipCertificateData * cert, Va
}
else
{
switch (validityResult)
{
case CertificateValidityResult::kValid:
case CertificateValidityResult::kNotExpiredAtLastKnownGoodTime:
// By default, we do not enforce certificate validity based upon a Last
// Known Good Time source. However, implementations may always inject a
// policy that does enforce based upon this.
case CertificateValidityResult::kExpiredAtLastKnownGoodTime:
case CertificateValidityResult::kTimeUnknown:
break;
case CertificateValidityResult::kNotYetValid:
ExitNow(err = CHIP_ERROR_CERT_NOT_VALID_YET);
break;
case CertificateValidityResult::kExpired:
ExitNow(err = CHIP_ERROR_CERT_EXPIRED);
break;
default:
ExitNow(err = CHIP_ERROR_INTERNAL);
break;
}
SuccessOrExit(err = CertificateValidityPolicy::ApplyDefaultPolicy(cert, depth, validityResult));
}

// If the certificate itself is trusted, then it is implicitly valid. Record this certificate as the trust
Expand Down Expand Up @@ -1505,5 +1486,30 @@ CHIP_ERROR ExtractSubjectDNFromX509Cert(const ByteSpan & x509Cert, ChipDN & dn)
return err;
}

CHIP_ERROR CertificateValidityPolicy::ApplyDefaultPolicy(const ChipCertificateData * cert, uint8_t depth,
CertificateValidityResult result)
{
switch (result)
{
case CertificateValidityResult::kValid:
case CertificateValidityResult::kNotExpiredAtLastKnownGoodTime:
// By default, we do not enforce certificate validity based upon a Last
// Known Good Time source. However, implementations may always inject a
// policy that does enforce based upon this.
case CertificateValidityResult::kExpiredAtLastKnownGoodTime:
case CertificateValidityResult::kTimeUnknown:
return CHIP_NO_ERROR;

case CertificateValidityResult::kNotYetValid:
return CHIP_ERROR_CERT_NOT_VALID_YET;

case CertificateValidityResult::kExpired:
return CHIP_ERROR_CERT_EXPIRED;

default:
return CHIP_ERROR_INTERNAL;
}
}

} // namespace Credentials
} // namespace chip
6 changes: 6 additions & 0 deletions src/credentials/CertificateValidityPolicy.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ class CertificateValidityPolicy
*/
virtual CHIP_ERROR ApplyCertificateValidityPolicy(const ChipCertificateData * cert, uint8_t depth,
CertificateValidityResult result) = 0;

/**
* Default policy that will be used if no other policy is defined. This is
* exposed to allow other policies to explicitly delegate to it as needed.
*/
static CHIP_ERROR ApplyDefaultPolicy(const ChipCertificateData * cert, uint8_t depth, CertificateValidityResult result);
};

} // namespace Credentials
Expand Down

0 comments on commit 4764579

Please sign in to comment.