24void formatTimestamp(
char* out, uint16_t year, uint8_t month, uint8_t day, uint8_t hour,
25 uint8_t minute, uint8_t second) {
27 out[0] =
'0' + (year / 1000) % 10;
28 out[1] =
'0' + (year / 100) % 10;
29 out[2] =
'0' + (year / 10) % 10;
30 out[3] =
'0' + year % 10;
31 out[4] =
'0' + month / 10;
32 out[5] =
'0' + month % 10;
33 out[6] =
'0' + day / 10;
34 out[7] =
'0' + day % 10;
36 out[9] =
'0' + hour / 10;
37 out[10] =
'0' + hour % 10;
38 out[11] =
'0' + minute / 10;
39 out[12] =
'0' + minute % 10;
40 out[13] =
'0' + second / 10;
41 out[14] =
'0' + second % 10;
47bool isValidTimestamp(std::string_view ts) {
48 if (ts.size() != VALIDITY_TIMESTAMP_SIZE) {
59 if (ts[i] <
'0' || ts[i] >
'9') {
70int compareTimestamp(
const char* a,
const char* b) {
71 return std::memcmp(a, b, VALIDITY_TIMESTAMP_SIZE);
77 std::string_view notAfter) {
87 return {.value = vp, .error = Error::Success};
101 return {.value =
ValidityPeriod{}, .error = Error::InvalidPacket};
104 const size_t vpEnd = decoder.
position() + header.value.length;
109 return {.value =
ValidityPeriod{}, .error = Error::InvalidPacket};
112 return {.value =
ValidityPeriod{}, .error = Error::InvalidPacket};
114 Error err = decoder.
readBytes(
reinterpret_cast<uint8_t*
>(vp.notBefore_.data()),
116 if (err != Error::Success) {
122 if (!naHeader.ok() || naHeader.value.type !=
tlv::NotAfter) {
123 return {.value =
ValidityPeriod{}, .error = Error::InvalidPacket};
126 return {.value =
ValidityPeriod{}, .error = Error::InvalidPacket};
130 if (err != Error::Success) {
138 if (bytesRead !=
nullptr) {
142 return {.value = vp, .error = Error::Success};
147 uint8_t valueBuf[64];
148 TlvEncoder valueEncoder(valueBuf,
sizeof(valueBuf));
154 if (err != Error::Success) {
161 if (err != Error::Success) {
168 if (err != Error::Success) {
172 encodedLen = encoder.
size();
173 return Error::Success;
177 uint8_t minute, uint8_t second) {
178 formatTimestamp(notBefore_.data(), year, month, day, hour, minute, second);
179 return Error::Success;
183 if (!isValidTimestamp(timestamp)) {
184 return Error::InvalidParam;
187 return Error::Success;
191 uint8_t minute, uint8_t second) {
192 formatTimestamp(notAfter_.data(), year, month, day, hour, minute, second);
193 return Error::Success;
197 if (!isValidTimestamp(timestamp)) {
198 return Error::InvalidParam;
201 return Error::Success;
209 return compareTimestamp(notBefore_.data(), currentTimestamp.data()) <= 0 &&
210 compareTimestamp(currentTimestamp.data(), notAfter_.data()) <= 0;
227 return {.value =
Certificate{}, .error = Error::InvalidPacket};
233 return {.value =
Certificate{}, .error = Error::InvalidPacket};
238 bool foundKey =
false;
241 if (comp.size == 3 && std::memcmp(comp.value,
"KEY", 3) == 0) {
248 if (!foundKey || keyIndex == 0 || name.
componentCount() < keyIndex + 3) {
255 for (
size_t i = 0; i < keyIndex; ++i) {
262 auto keyIdComp = name.
component(keyIndex + 1);
263 if (keyIdComp.size <= cert.keyId_.size()) {
264 std::memcpy(cert.keyId_.data(), keyIdComp.value, keyIdComp.size);
265 cert.keyIdSize_ = keyIdComp.size;
269 auto issuerIdComp = name.
component(keyIndex + 2);
270 if (issuerIdComp.size <= cert.issuerId_.size()) {
271 std::memcpy(cert.issuerId_.data(), issuerIdComp.value, issuerIdComp.size);
272 cert.issuerIdSize_ = issuerIdComp.size;
277 auto versionComp = name.
component(keyIndex + 3);
280 for (
size_t i = 0; i < versionComp.size && i < 8; ++i) {
290 return {.value =
Certificate{}, .error = Error::BufferTooSmall};
292 std::memcpy(cert.publicKey_.data(), data.
content(), keySize);
293 cert.publicKeySize_ = keySize;
301 std::memcpy(cert.signatureValue_.data(), data.
signatureValue(), sigSize);
302 cert.signatureSize_ = sigSize;
306 return {.value = cert, .error = Error::Success};
312 if (!dataResult.ok()) {
313 return {.value =
Certificate{}, .error = dataResult.error};
323 if (err != Error::Success) {
331 if (publicKeySize_ > 0) {
332 err = data.
setContent(publicKey_.data(), publicKeySize_);
333 if (err != Error::Success) {
344 return Error::Success;
351 size_t signedLen = 0;
352 Error err = encodeSignedPortion(valueBuf,
sizeof(valueBuf), signedLen);
353 if (err != Error::Success) {
357 TlvEncoder valueEncoder(valueBuf + signedLen,
sizeof(valueBuf) - signedLen);
361 if (err != Error::Success) {
366 const size_t valueLen = signedLen + valueEncoder.
size();
368 const size_t totalSize = headerSize + valueLen;
370 if (bufSize < totalSize) {
371 return Error::BufferTooSmall;
376 if (err != Error::Success) {
381 if (err != Error::Success) {
386 if (err != Error::Success) {
390 encodedLen = encoder.
size();
391 return Error::Success;
395 identityName_ = name;
404 identityName_ = result.value;
405 return Error::Success;
409 if (len > keyId_.size()) {
410 return Error::BufferTooSmall;
412 std::memcpy(keyId_.data(),
id, len);
414 return Error::Success;
418 if (len > issuerId_.size()) {
419 return Error::BufferTooSmall;
421 std::memcpy(issuerId_.data(),
id, len);
423 return Error::Success;
427 return setIssuerId(
reinterpret_cast<const uint8_t*
>(
id.data()),
id.size());
437 return Error::BufferTooSmall;
439 std::memcpy(publicKey_.data(), key, len);
440 publicKeySize_ = len;
441 return Error::Success;
450 signatureType_ = type;
461 if (err != Error::Success) {
468 if (err != Error::Success) {
473 if (keyIdSize_ > 0) {
475 if (err != Error::Success) {
481 if (issuerIdSize_ > 0) {
483 if (err != Error::Success) {
490 uint8_t versionBytes[8];
491 size_t versionLen = 0;
492 uint64_t v = version_;
497 }
else if (v <= 0xFFFF) {
499 }
else if (v <= 0xFFFFFF) {
501 }
else if (v <= 0xFFFFFFFF) {
508 for (
size_t i = 0; i < versionLen; ++i) {
509 versionBytes[versionLen - 1 - i] =
static_cast<uint8_t
>(v & 0xFF);
514 if (err != Error::Success) {
519 return Error::Success;
522Error Certificate::encodeSignedPortion(uint8_t* buf,
size_t bufSize,
size_t& encodedLen)
const {
526 if (err != Error::Success) {
530 TlvEncoder encoder(buf, bufSize);
534 err = certName.
encode(encoder.current(), encoder.remaining(), nameLen);
535 if (err != Error::Success) {
538 encoder.setPosition(encoder.position() + nameLen);
543 TlvEncoder metaEncoder(metaBuf,
sizeof(metaBuf));
545 static_cast<uint8_t
>(ContentType::Key));
547 encoder.writeTlv(
tlv::MetaInfo, metaBuf, metaEncoder.size());
551 if (publicKeySize_ > 0) {
552 encoder.writeTlv(
tlv::Content, publicKey_.data(), publicKeySize_);
557 uint8_t sigInfoBuf[96];
558 TlvEncoder sigInfoEncoder(sigInfoBuf,
sizeof(sigInfoBuf));
560 static_cast<uint8_t
>(signatureType_));
564 validity_.
encode(vpBuf,
sizeof(vpBuf), vpLen);
565 sigInfoEncoder.writeBytes(vpBuf, vpLen);
570 encodedLen = encoder.size();
571 return Error::Success;
575 signatureType_ = SignatureType::DigestSha256;
578 size_t signedLen = 0;
579 Error err = encodeSignedPortion(signedBuf,
sizeof(signedBuf), signedLen);
580 if (err != Error::Success) {
584 err = crypto::sha256(signedBuf, signedLen, signatureValue_.data());
585 if (err != Error::Success) {
590 return Error::Success;
594 if (key ==
nullptr || keyLen == 0) {
595 return Error::InvalidParam;
598 signatureType_ = SignatureType::SignatureHmacWithSha256;
601 size_t signedLen = 0;
602 Error err = encodeSignedPortion(signedBuf,
sizeof(signedBuf), signedLen);
603 if (err != Error::Success) {
607 err = crypto::hmacSha256(key, keyLen, signedBuf, signedLen, signatureValue_.data());
608 if (err != Error::Success) {
613 return Error::Success;
617 if (signatureType_ != SignatureType::DigestSha256) {
625 size_t signedLen = 0;
626 if (encodeSignedPortion(signedBuf,
sizeof(signedBuf), signedLen) != Error::Success) {
631 if (crypto::sha256(signedBuf, signedLen, computed) != Error::Success) {
635 return crypto::constantTimeCompare(computed, signatureValue_.data(),
SHA256_DIGEST_SIZE);
639 if (key ==
nullptr || keyLen == 0) {
642 if (signatureType_ != SignatureType::SignatureHmacWithSha256) {
650 size_t signedLen = 0;
651 if (encodeSignedPortion(signedBuf,
sizeof(signedBuf), signedLen) != Error::Success) {
656 if (crypto::hmacSha256(key, keyLen, signedBuf, signedLen, computed) != Error::Success) {
660 return crypto::constantTimeCompare(computed, signatureValue_.data(),
HMAC_SHA256_SIZE);
constexpr size_t CERTIFICATE_MAX_KEY_SIZE
Maximum public key size (DER-encoded SubjectPublicKeyInfo)
constexpr size_t VALIDITY_TIMESTAMP_SIZE
Length of ValidityPeriod ISO 8601 format string (YYYYMMDDThhmmss)
Certificate & setVersion(uint64_t version)
Set the version.
bool isValidAt(std::string_view timestamp) const
Check if the certificate is valid at a given time.
Error setIssuerId(const uint8_t *id, size_t len)
Set the Issuer ID (bytes)
Error signWithDigestSha256()
Sign with DigestSha256.
Error toData(Data &data) const
Convert the Certificate to a Data packet.
static Result< Certificate > fromWire(const uint8_t *buf, size_t len)
Decode a Certificate from TLV wire format.
Certificate & setSignatureType(SignatureType type)
Set the signature type.
Error signWithHmac(const uint8_t *key, size_t keyLen)
Sign with HMAC-SHA256.
Certificate & setValidity(const ValidityPeriod &validity)
Set the validity period.
bool verifyHmac(const uint8_t *key, size_t keyLen) const
Verify an HMAC-SHA256 signature.
Error setKeyId(const uint8_t *id, size_t len)
Set the Key ID.
Certificate & setIdentityName(const Name &name)
Set the identity name.
Error encode(uint8_t *buf, size_t bufSize, size_t &encodedLen) const
Encode the Certificate to TLV wire format.
const Name & identityName() const
Get the identity name.
Error buildName(Name &name) const
Build the full certificate name and store it in a Name.
bool verifyDigestSha256() const
Verify a DigestSha256 signature.
Error setPublicKey(const uint8_t *key, size_t len)
Set the public key.
static Result< Certificate > fromData(const Data &data)
Create a Certificate from a Data packet.
const ValidityPeriod & validity() const
Get the validity period (const)
uint64_t version() const
Get the version.
Data & setFreshnessPeriod(uint32_t periodMs)
Set the FreshnessPeriod.
const Name & name() const
Get the Name (const reference)
bool hasContent() const
Check if content is set.
size_t contentSize() const
Get the content size.
Data & setContentType(ContentType type)
Set the content type.
const uint8_t * content() const
Get a pointer to the content data.
const uint8_t * signatureValue() const
Get a pointer to the signature value.
Error setContent(const uint8_t *data, size_t size)
Set binary data as content.
Data & setSignatureType(SignatureType type)
Set the signature type.
size_t signatureValueSize() const
Get the size of the signature value.
SignatureType signatureType() const
Get the signature type.
ContentType contentType() const
Get the content type.
bool hasSignature() const
Check if a signature is set.
static Result< Data > fromWire(const uint8_t *buf, size_t len)
Decode a Data packet from TLV wire format.
Data & setName(const Name &name)
Set the Name (supports method chaining)
Error encode(uint8_t *buf, size_t bufSize, size_t &encodedLen) const
Encode the Name to TLV wire format.
Error appendComponent(std::string_view comp)
Append a string component.
size_t componentCount() const
Get the number of components.
NameComponent component(size_t index) const
Get the component at a given index.
static Result< Name > fromUri(std::string_view uri)
Create a Name from a URI string.
size_t position() const
Get current position.
Error readBytes(uint8_t *out, size_t len)
Read a specified number of bytes.
Result< TlvHeader > readTlvHeader()
Read a TLV header (Type and Length) at once.
Error writeLength(size_t length)
Write a TLV Length.
Error writeTlv(uint32_t type, const uint8_t *value, size_t valueLen)
Write a complete TLV structure.
Error writeBytes(const uint8_t *data, size_t len)
Write a byte sequence.
size_t size() const
Current write position (= number of bytes written)
Error writeType(uint32_t type)
Write a TLV Type.
static Result< ValidityPeriod > fromWire(const uint8_t *buf, size_t len, size_t *bytesRead=nullptr)
Decode a ValidityPeriod from TLV wire format.
const char * notAfter() const
Get the NotAfter time as an ISO 8601 string.
Error setNotAfter(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second)
Set the NotAfter time from date/time components.
bool equals(const ValidityPeriod &other) const
Check equality of two validity periods.
static Result< ValidityPeriod > fromStrings(std::string_view notBefore, std::string_view notAfter)
Create a ValidityPeriod from ISO 8601 format strings.
Error setNotBefore(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second)
Set the NotBefore time from date/time components.
bool isValidAt(std::string_view currentTimestamp) const
Check if the current time is within the validity period.
Error encode(uint8_t *buf, size_t bufSize, size_t &encodedLen) const
Encode the ValidityPeriod to TLV wire format.
const char * notBefore() const
Get the NotBefore time as an ISO 8601 string.
constexpr size_t PACKET_MAX_SIZE
Maximum packet size (ESP-NOW v2.0 compatible)
NDN cryptographic utilities.
constexpr uint32_t MetaInfo
Meta information.
constexpr uint32_t SignatureInfo
Signature info.
constexpr uint32_t ValidityPeriod
Validity period (253)
constexpr uint32_t NotBefore
Not before (254)
constexpr uint32_t FreshnessPeriod
Freshness period.
constexpr uint32_t Content
Content.
constexpr uint32_t SignatureValue
Signature value.
constexpr uint32_t ContentType
Content type.
constexpr uint32_t Data
Data packet.
constexpr uint32_t SignatureType
Signature type.
constexpr uint32_t NotAfter
Not after (255)
constexpr size_t SIGNATURE_MAX_SIZE
Maximum signature size (for ECDSA P-256, embedded)
constexpr size_t HMAC_SHA256_SIZE
HMAC-SHA256 size (bytes)
SignatureType
Signature type.
constexpr size_t SHA256_DIGEST_SIZE
SHA-256 digest size (bytes)
const uint8_t * value
Pointer to the component value.
NDN TLV (Type-Length-Value) encoding.
constexpr size_t varNumberSize(uint64_t value)
Calculate the encoded size of a VAR-NUMBER.