blob: 02dc3cc34a48c9531036b17b9939ac7d454824f2 [file]
/*
*
* Copyright (c) 2026 Project CHIP Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <app-common/zap-generated/cluster-objects.h>
#include <credentials/CHIPCert.h>
#include <credentials/CertificationDeclaration.h>
#include <lib/core/CHIPError.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/ScopedMemoryBuffer.h>
#include <lib/support/Span.h>
namespace chip {
namespace Controller {
class CertificateChainRequestTracker
{
public:
static constexpr uint16_t kDefaultSegmentSize = 600;
static constexpr uint16_t kMaxCertificateDocumentSize = Credentials::kMaxDERCertLengthMlDsa65;
using CryptoProfile = app::Clusters::OperationalCredentials::AttestationCryptoProfileEnum;
// Bound both the subject key and issuer signature. Unknown algorithms retain the
// largest supported bound so mixed-algorithm chains are not rejected prematurely.
static constexpr uint16_t MaxCertificateDocumentSize(CryptoProfile subject, CryptoProfile issuer)
{
const auto subjectSize = MaxCertificateSizeForProfile(subject);
const auto issuerSize = MaxCertificateSizeForProfile(issuer);
return subjectSize > issuerSize ? subjectSize : issuerSize;
}
void Reset(CryptoProfile subject = CryptoProfile::kUnknownEnumValue, CryptoProfile issuer = CryptoProfile::kUnknownEnumValue);
CHIP_ERROR HandleResponse(ByteSpan certificate, const Optional<uint16_t> & totalDocumentSize,
const Optional<uint16_t> & nextSegmentId);
bool IsComplete() const { return mHasResponse && !mNextSegmentId.HasValue(); }
bool IsSegmentedTransfer() const { return mTotalDocumentSize.HasValue(); }
bool HasPendingSegment() const { return mNextSegmentId.HasValue(); }
Optional<uint16_t> NextSegmentId() const { return mNextSegmentId; }
ByteSpan GetCertificate() const { return ByteSpan(mStorage.Get(), mCertificateSize); }
private:
static constexpr uint16_t MaxCertificateSizeForProfile(CryptoProfile profile)
{
switch (profile)
{
case CryptoProfile::kEcdsaMatterLegacy:
return Credentials::kMaxDERCertLength;
case CryptoProfile::kMlDsa44:
return Credentials::kMaxDERCertLengthMlDsa44;
default:
return kMaxCertificateDocumentSize;
}
}
CHIP_ERROR HandleSingleResponse(ByteSpan certificate);
CHIP_ERROR HandleSegmentedResponse(ByteSpan certificate, uint16_t totalDocumentSize, const Optional<uint16_t> & nextSegmentId);
Platform::ScopedMemoryBufferWithSize<uint8_t> mStorage;
size_t mCertificateSize = 0;
size_t mWriteOffset = 0;
Optional<uint16_t> mTotalDocumentSize;
Optional<uint16_t> mNextSegmentId;
uint16_t mMaxCertificateDocumentSize = kMaxCertificateDocumentSize;
bool mHasResponse = false;
};
} // namespace Controller
} // namespace chip