[openweave] Expand WeaveCertificateSet API for cert replacement

Add the ability to replace a cert. This is done by splitting out the
load functionality and allowing a caller to overwrite an existing
WeaveCertificateData element.

Bug: b/284072303
Test: Verified dev cert is replaced.
Change-Id: I79992631243ae8bb42dd5a1b412541fc13a1a5fd
(cherry picked from commit 1d23f3d03fa93c7933767aad705624308c5424dc)
diff --git a/src/lib/profiles/security/WeaveCert.cpp b/src/lib/profiles/security/WeaveCert.cpp
index 26f84be..39d85e5 100644
--- a/src/lib/profiles/security/WeaveCert.cpp
+++ b/src/lib/profiles/security/WeaveCert.cpp
@@ -163,22 +163,37 @@
 WEAVE_ERROR WeaveCertificateSet::LoadCert(TLVReader& reader, uint16_t decodeFlags, WeaveCertificateData *& cert)
 {
     WEAVE_ERROR err;
-    ASN1Writer writer;
-    uint8_t *decodeBuf = mDecodeBuf;
 
     cert = NULL;
 
-    // Must be positioned on the structure element representing the certificate.
-    VerifyOrExit(reader.GetType() == kTLVType_Structure, err = WEAVE_ERROR_INVALID_ARGUMENT);
-
     // Verify we have room for the new certificate.
     VerifyOrExit(CertCount < MaxCerts, err = WEAVE_ERROR_NO_MEMORY);
 
+    cert = &Certs[CertCount];
+
+    err = LoadCertToElement(reader, decodeFlags, cert);
+    SuccessOrExit(err);
+
+    CertCount++;
+
+exit:
+    return err;
+}
+
+WEAVE_ERROR WeaveCertificateSet::LoadCertToElement(TLVReader& reader, uint16_t decodeFlags, WeaveCertificateData * cert)
+{
+    WEAVE_ERROR err;
+    ASN1Writer writer;
+    uint8_t *decodeBuf = mDecodeBuf;
+
+    // Must be positioned on the structure element representing the certificate.
+    VerifyOrExit(reader.GetType() == kTLVType_Structure, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
     if (decodeBuf == NULL && mAllocFunct != NULL)
         decodeBuf = (uint8_t *)(mAllocFunct(mDecodeBufSize));
     VerifyOrExit(decodeBuf != NULL, err = WEAVE_ERROR_NO_MEMORY);
 
-    cert = &Certs[CertCount];
+    VerifyOrExit(cert != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
     memset(cert, 0, sizeof(*cert));
 
     // Record the starting point of the certificate's elements.
@@ -272,8 +287,6 @@
     // Record the overall size of the certificate.
     cert->EncodedCertLen = reader.GetReadPoint() - cert->EncodedCert;
 
-    CertCount++;
-
     // If requested by the caller, mark the certificate as trusted.
     if (decodeFlags & kDecodeFlag_IsTrusted)
     {
@@ -287,6 +300,28 @@
 exit:
     if (decodeBuf != NULL && decodeBuf != mDecodeBuf && mFreeFunct != NULL)
         mFreeFunct(decodeBuf);
+
+    return err;
+}
+
+WEAVE_ERROR WeaveCertificateSet::ReplaceCert(const uint8_t *weaveCert, uint32_t weaveCertLen,
+                                             uint16_t decodeFlags, WeaveCertificateData *& oldCert)
+{
+    WEAVE_ERROR err = WEAVE_ERROR_CERT_NOT_FOUND;
+    VerifyOrExit(oldCert != NULL, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+    TLVReader reader;
+
+    reader.Init(weaveCert, weaveCertLen);
+    reader.ImplicitProfileId = kWeaveProfile_Security;
+
+    err = reader.Next(kTLVType_Structure,
+                      ProfileTag(kWeaveProfile_Security, kTag_WeaveCertificate));
+    SuccessOrExit(err);
+
+    err = LoadCertToElement(reader, decodeFlags, oldCert);
+
+exit:
     return err;
 }
 
diff --git a/src/lib/profiles/security/WeaveCert.h b/src/lib/profiles/security/WeaveCert.h
index 862b2fe..13de382 100644
--- a/src/lib/profiles/security/WeaveCert.h
+++ b/src/lib/profiles/security/WeaveCert.h
@@ -248,6 +248,16 @@
     WeaveCertificateData *FindCert(const CertificateKeyId& subjectKeyId) const;
     WeaveCertificateData *LastCert(void) const { return (CertCount > 0) ? &Certs[CertCount-1] : NULL; }
 
+    // Load a weave-encoded cert from a TLVReader to a WeaveCertificateData pointer.
+    WEAVE_ERROR LoadCertToElement(TLVReader& reader, uint16_t decodeFlags, WeaveCertificateData * cert);
+
+    // Replace a certificate in the set.
+    // This takes a pointer to the old cert to be replaced, which can be
+    // obtained by FindCert. The new cert is loaded to the pointer reference.
+    // The args are parallel with the LoadCert API.
+    WEAVE_ERROR ReplaceCert(const uint8_t *weaveCert, uint32_t weaveCertLen, uint16_t decodeFlags,
+                            WeaveCertificateData *& oldCert);
+
     WEAVE_ERROR ValidateCert(WeaveCertificateData& cert, ValidationContext& context);
     WEAVE_ERROR FindValidCert(const WeaveDN& subjectDN, const CertificateKeyId& subjectKeyId,
             ValidationContext& context, WeaveCertificateData *& cert);