[weave] Replace expired dev cert in service config.

Replace expired dev cert in service config.

Bug: b/284072303
Test:Verified dev cert is replaced.
Change-Id: I90bb362c171bf684a84988995ab244080f596f9e
diff --git a/src/connectivity/weave/adaptation/platform_auth_delegate.cpp b/src/connectivity/weave/adaptation/platform_auth_delegate.cpp
index 0f264f8..00a81f2 100644
--- a/src/connectivity/weave/adaptation/platform_auth_delegate.cpp
+++ b/src/connectivity/weave/adaptation/platform_auth_delegate.cpp
@@ -19,6 +19,10 @@
 namespace Security = ::nl::Weave::Profiles::Security;
 namespace ServiceProvisioning = ::nl::Weave::Profiles::ServiceProvisioning;
 
+using Profiles::Security::CertificateKeyId;
+using Profiles::Security::kDecodeFlag_IsTrusted;
+using Profiles::Security::PackedCertDateToTime;
+using Profiles::Security::WeaveDN;
 using Security::WeaveCertificateData;
 
 // TODO(fxbug.dev/51130): Allow build-time configuration of these values.
@@ -26,6 +30,28 @@
 constexpr size_t kMaxServiceConfigSize = 10000;
 constexpr size_t kCertDecodeBufferSize = 5000;
 
+WEAVE_ERROR GetEffectiveTime(uint32_t& effective_time) {
+  // Set the effective time for certificate validation. Use the current time if
+  // the system's real time clock is synchronized, but otherwise use the
+  // firmware build time and arrange to ignore the 'not before' date in the
+  // peer's certificate.
+  uint64_t now_ms;
+  WEAVE_ERROR err = System::Layer::GetClock_RealTimeMS(now_ms);
+  if (err == WEAVE_NO_ERROR) {
+    // TODO(fxbug.dev/51890): The default implementation of GetClock_RealTimeMS only returns
+    // not-synced if the value is before Jan 1, 2000. Use the UTC fidl instead
+    // to confirm whether the clock source is from some external source.
+    effective_time =
+        Security::SecondsSinceEpochToPackedCertTime(static_cast<uint32_t>(now_ms / 1000));
+  } else if (err == WEAVE_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED) {
+    // TODO(fxbug.dev/51890): Acquire the firmware build time, for now we set it to May 26, 2023
+    // as reasonable default time.
+    effective_time = Security::SecondsSinceEpochToPackedCertTime(1685059200U);
+    FX_LOGS(WARNING) << "Real time clock not synchronized, using default time for cert validation.";
+  }
+  return err;
+}
+
 }  // namespace
 
 static PlatformAuthDelegate gPlatformCASEAuthDelegate;
@@ -346,12 +372,55 @@
   return Security::ConvertECDSASignature_DERToWeave(output->data(), output->size(), writer, tag);
 }
 
+// If the service config contains a dev root cert that has expired, replace it.
+WEAVE_ERROR PlatformAuthDelegate::ReplaceExpiredCertInServiceConfig(WeaveCertificateSet& cert_set) {
+  WEAVE_ERROR err;
+  WeaveCertificateData* candidate = nullptr;
+  const CertificateKeyId skid = {
+      .Id = nl::NestCerts::Development::Root::SubjectKeyId,
+      .Len = static_cast<uint8_t>(nl::NestCerts::Development::Root::SubjectKeyIdLength)};
+
+  const WeaveDN dn = {.AttrValue = {.WeaveId = nl::NestCerts::Development::Root::CAId},
+                      .AttrOID = ASN1::kOID_AttributeType_WeaveCAId};
+  ValidationContext valid_ctx;
+  enum { kLastSecondOfDay = nl::kSecondsPerDay - 1 };
+
+  // Search for dev root cert, return if not found.
+  candidate = cert_set.FindCert(skid);
+  if (!candidate) {
+    return WEAVE_NO_ERROR;
+  }
+
+  if (!candidate->SubjectDN.IsEqual(dn)) {
+    return WEAVE_NO_ERROR;
+  }
+
+  FX_LOGS(INFO) << "Found Dev root CA";
+
+  uint32_t effective_time = 0;
+  err = GetEffectiveTime(effective_time);
+  valid_ctx.EffectiveTime = effective_time;
+
+  if (candidate->NotAfterDate != 0 &&
+      valid_ctx.EffectiveTime > PackedCertDateToTime(candidate->NotAfterDate) + kLastSecondOfDay) {
+    FX_LOGS(INFO) << "Dev root CA expired, so replace it.";
+    err = cert_set.ReplaceCert(nl::NestCerts::Development::Root::Cert,
+                               nl::NestCerts::Development::Root::CertLength, kDecodeFlag_IsTrusted,
+                               candidate);
+    if (err != WEAVE_NO_ERROR) {
+      FX_LOGS(ERROR) << "Failed to replace Dev root CA";
+      return err;
+    }
+  }
+
+  return WEAVE_NO_ERROR;
+}
+
 WEAVE_ERROR PlatformAuthDelegate::BeginCertValidation(ValidationContext& valid_ctx,
                                                       WeaveCertificateSet& cert_set,
                                                       bool is_initiator) {
   WEAVE_ERROR err = WEAVE_NO_ERROR;
   size_t service_config_len = 0;
-  uint64_t now_ms;
 
   service_config_.clear();
   service_config_.resize(kMaxServiceConfigSize);
@@ -376,6 +445,11 @@
     return err;
   }
 
+  err = ReplaceExpiredCertInServiceConfig(cert_set);
+  if (err != WEAVE_NO_ERROR) {
+    return err;
+  }
+
   // Scan the list of trusted certs loaded from the service config. If the list
   // contains a general certificate with a CommonName subject, presume this is
   // the access token certificate.
@@ -390,24 +464,12 @@
 
   memset(&valid_ctx, 0, sizeof(valid_ctx));
 
-  // Set the effective time for certificate validation. Use the current time if
-  // the system's real time clock is synchronized, but otherwise use the
-  // firmware build time and arrange to ignore the 'not before' date in the
-  // peer's certificate.
-  err = System::Layer::GetClock_RealTimeMS(now_ms);
-  if (err == WEAVE_NO_ERROR) {
-    // TODO(fxbug.dev/51890): The default implementation of GetClock_RealTimeMS only returns
-    // not-synced if the value is before Jan 1, 2000. Use the UTC fidl instead
-    // to confirm whether the clock source is from some external source.
-    valid_ctx.EffectiveTime =
-        Security::SecondsSinceEpochToPackedCertTime(static_cast<uint32_t>(now_ms / 1000));
-  } else if (err == WEAVE_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED) {
-    // TODO(fxbug.dev/51890): Acquire the firmware build time, for now we set it to Jan 1, 2020
-    // as reasonable default time.
-    valid_ctx.EffectiveTime = Security::SecondsSinceEpochToPackedCertTime(1577836800U);
+  uint32_t effective_time = 0;
+  err = GetEffectiveTime(effective_time);
+  if (err == WEAVE_SYSTEM_ERROR_REAL_TIME_NOT_SYNCED) {
     valid_ctx.ValidateFlags |= Security::kValidateFlag_IgnoreNotBefore;
-    FX_LOGS(WARNING) << "Real time clock not synchronized, using default time for cert validation.";
   }
+  valid_ctx.EffectiveTime = effective_time;
 
   valid_ctx.RequiredKeyUsages = Security::kKeyUsageFlag_DigitalSignature;
   valid_ctx.RequiredKeyPurposes =
diff --git a/src/connectivity/weave/adaptation/platform_auth_delegate.h b/src/connectivity/weave/adaptation/platform_auth_delegate.h
index 070c1d0..b4d4d2b 100644
--- a/src/connectivity/weave/adaptation/platform_auth_delegate.h
+++ b/src/connectivity/weave/adaptation/platform_auth_delegate.h
@@ -56,6 +56,7 @@
                                  WeaveCertificateSet& cert_set) override;
   WEAVE_ERROR GenerateNodeSignature(WeaveKeyExport* key_export, const uint8_t* msg_hash,
                                     uint8_t msg_hash_len, TLVWriter& writer) override;
+  WEAVE_ERROR ReplaceExpiredCertInServiceConfig(WeaveCertificateSet& cert_set);
   WEAVE_ERROR BeginCertValidation(WeaveKeyExport* key_export, ValidationContext& valid_ctx,
                                   WeaveCertificateSet& cert_set) override;
   WEAVE_ERROR HandleCertValidationResult(WeaveKeyExport* key_export, ValidationContext& valid_ctx,