Skip to content

Commit

Permalink
[chip-cert] Add support for 'chip-hex' encoding to certificate tool. (#…
Browse files Browse the repository at this point in the history
…20147)

* [chip-cert] Add handling for hex encoding to chip-cert tool.

* [chip-tool] Expand chip-hex support to convert-key and generate-cert.

* [spell] [restyle] [pretty]
  • Loading branch information
turon authored and pull[bot] committed Oct 5, 2023
1 parent 786d82a commit 81e18a9
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 36 deletions.
12 changes: 12 additions & 0 deletions src/lib/support/BytesToHex.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,5 +178,17 @@ size_t UppercaseHexToUint32(const char * src_hex, const size_t src_size, uint32_
/** Same as UppercaseHexToUint64() but for uint16_t. */
size_t UppercaseHexToUint16(const char * src_hex, const size_t src_size, uint16_t & dest);

/**
* Computes the hex encoded length for a given input length.
* Left shift to generate optimized equivalent of LEN*2.
*/
#define HEX_ENCODED_LENGTH(LEN) ((LEN) << 1)

/**
* Computes the maximum possible decoded length for a given hex string input length.
* Right shift to generate optimized equivalent of LEN/2.
*/
#define HEX_MAX_DECODED_LENGTH(LEN) ((LEN) >> 1)

} // namespace Encoding
} // namespace chip
76 changes: 59 additions & 17 deletions src/tools/chip-cert/CertUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ using namespace chip;
using namespace chip::Credentials;
using namespace chip::ASN1;
using namespace chip::TLV;
using namespace chip::Encoding;

bool ToolChipDN::SetCertName(X509_NAME * name) const
{
Expand Down Expand Up @@ -173,6 +174,8 @@ CertFormat DetectCertFormat(uint8_t * cert, uint32_t certLen)
static const uint8_t chipRawPrefix[] = { 0x15, 0x30, 0x01 };
static const char * chipB64Prefix = "FTAB";
static const size_t chipB64PrefixLen = strlen(chipB64Prefix);
static const char * chipHexPrefix = "153001";
static const size_t chipHexPrefixLen = strlen(chipHexPrefix);
static const char * pemMarker = "-----BEGIN CERTIFICATE-----";

if (certLen > sizeof(chipRawPrefix) && memcmp(cert, chipRawPrefix, sizeof(chipRawPrefix)) == 0)
Expand All @@ -185,6 +188,11 @@ CertFormat DetectCertFormat(uint8_t * cert, uint32_t certLen)
return kCertFormat_Chip_Base64;
}

if (certLen > chipHexPrefixLen && memcmp(cert, chipHexPrefix, chipHexPrefixLen) == 0)
{
return kCertFormat_Chip_Hex;
}

if (ContainsPEMMarker(pemMarker, cert, certLen))
{
return kCertFormat_X509_PEM;
Expand Down Expand Up @@ -547,14 +555,22 @@ bool ReadCert(const char * fileName, X509 * cert, CertFormat & certFmt)
ReportOpenSSLErrorAndExit("d2i_X509", res = false);
}
}
// Otherwise, it is either CHIP TLV or CHIP TLV Base64 encoded.
// Otherwise, it is either CHIP TLV in raw, Base64, or hex encoded format.
else
{
if (certFmt == kCertFormat_Chip_Base64)
{
res = Base64Decode(certBuf.get(), certLen, certBuf.get(), certLen, certLen);
VerifyTrueOrExit(res);
}
else if (certFmt == kCertFormat_Chip_Hex)
{
const char * certChars = reinterpret_cast<const char *>(certBuf.get());

certLen = static_cast<uint32_t>(Encoding::HexToBytes(certChars, certLen, certBuf.get(), certLen));
res = (certLen > 0);
VerifyTrueOrExit(res);
}

std::unique_ptr<uint8_t[]> x509CertBuf(new uint8_t[kMaxDERCertLength]);
MutableByteSpan x509Cert(x509CertBuf.get(), kMaxDERCertLength);
Expand Down Expand Up @@ -684,26 +700,38 @@ bool WriteCert(const char * fileName, X509 * cert, CertFormat certFmt)
ReportOpenSSLErrorAndExit("i2d_X509_fp", res = false);
}
}
else if (certFmt == kCertFormat_Chip_Raw || certFmt == kCertFormat_Chip_Base64)
else if (certFmt == kCertFormat_Chip_Raw || certFmt == kCertFormat_Chip_Base64 || certFmt == kCertFormat_Chip_Hex)
{
uint8_t * certToWrite = nullptr;
size_t certToWriteLen = 0;
uint32_t chipCertBase64Len = BASE64_ENCODED_LEN(kMaxCHIPCertLength);
std::unique_ptr<uint8_t[]> chipCertBase64(new uint8_t[chipCertBase64Len]);
uint8_t * certToWrite = nullptr;
size_t certToWriteLen = 0;
uint32_t certLen;
uint32_t chipCertDecodedLen = HEX_ENCODED_LENGTH(kMaxCHIPCertLength);
std::unique_ptr<uint8_t[]> chipCertDecoded(new uint8_t[chipCertDecodedLen]);
uint8_t chipCertBuf[kMaxCHIPCertLength];
MutableByteSpan chipCert(chipCertBuf);

res = X509ToChipCert(cert, chipCert);
VerifyTrueOrExit(res);
certLen = static_cast<uint32_t>(chipCert.size());

if (certFmt == kCertFormat_Chip_Base64)
{
res = Base64Encode(chipCert.data(), static_cast<uint32_t>(chipCert.size()), chipCertBase64.get(), chipCertBase64Len,
chipCertBase64Len);
chipCertDecodedLen = BASE64_ENCODED_LEN(certLen);
res = Base64Encode(chipCert.data(), certLen, chipCertDecoded.get(), chipCertDecodedLen, chipCertDecodedLen);
VerifyTrueOrExit(res);

certToWrite = chipCertBase64.get();
certToWriteLen = chipCertBase64Len;
certToWrite = chipCertDecoded.get();
certToWriteLen = chipCertDecodedLen;
}
else if (certFmt == kCertFormat_Chip_Hex)
{
char * certHex = reinterpret_cast<char *>(chipCertDecoded.get());

chipCertDecodedLen = HEX_ENCODED_LENGTH(certLen);
SuccessOrExit(Encoding::BytesToLowercaseHexBuffer(chipCert.data(), certLen, certHex, chipCertDecodedLen));

certToWrite = chipCertDecoded.get();
certToWriteLen = chipCertDecodedLen;
}
else
{
Expand All @@ -718,6 +746,8 @@ bool WriteCert(const char * fileName, X509 * cert, CertFormat certFmt)
}
}

printf("\r\n");

exit:
CloseFile(file);
return res;
Expand All @@ -728,20 +758,32 @@ bool WriteChipCert(const char * fileName, const ByteSpan & chipCert, CertFormat
bool res = true;
FILE * file = nullptr;
const uint8_t * certToWrite = nullptr;
uint32_t certLen = static_cast<uint32_t>(chipCert.size());
size_t certToWriteLen = 0;
uint32_t chipCertBase64Len = BASE64_ENCODED_LEN(static_cast<uint32_t>(chipCert.size()));
std::unique_ptr<uint8_t[]> chipCertBase64(new uint8_t[chipCertBase64Len]);
uint32_t chipCertDecodedLen = HEX_ENCODED_LENGTH(kMaxCHIPCertLength); // Maximum possible encoding size
std::unique_ptr<uint8_t[]> chipCertDecoded(new uint8_t[chipCertDecodedLen]);

VerifyOrReturnError(certFmt == kCertFormat_Chip_Raw || certFmt == kCertFormat_Chip_Base64, false);
VerifyOrReturnError(certFmt == kCertFormat_Chip_Raw || certFmt == kCertFormat_Chip_Base64 || certFmt == kCertFormat_Chip_Hex,
false);

if (certFmt == kCertFormat_Chip_Base64)
{
res = Base64Encode(chipCert.data(), static_cast<uint32_t>(chipCert.size()), chipCertBase64.get(), chipCertBase64Len,
chipCertBase64Len);
chipCertDecodedLen = BASE64_ENCODED_LEN(certLen);
res = Base64Encode(chipCert.data(), certLen, chipCertDecoded.get(), chipCertDecodedLen, chipCertDecodedLen);
VerifyTrueOrExit(res);

certToWrite = chipCertBase64.get();
certToWriteLen = chipCertBase64Len;
certToWrite = chipCertDecoded.get();
certToWriteLen = chipCertDecodedLen;
}
else if (certFmt == kCertFormat_Chip_Hex)
{
char * certHex = reinterpret_cast<char *>(chipCertDecoded.get());
chipCertDecodedLen = HEX_ENCODED_LENGTH(certLen);

SuccessOrExit(Encoding::BytesToLowercaseHexBuffer(chipCert.data(), certLen, certHex, chipCertDecodedLen));

certToWrite = chipCertDecoded.get();
certToWriteLen = chipCertDecodedLen;
}
else
{
Expand Down
14 changes: 11 additions & 3 deletions src/tools/chip-cert/Cmd_ConvertCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ bool HandleNonOptionArgs(const char * progName, int argc, char * const argv[]);
OptionDef gCmdOptionDefs[] =
{
{ "x509-pem", kNoArgument, 'p' },
{ "x509-der", kNoArgument, 'x' },
{ "x509-der", kNoArgument, 'd' },
{ "chip", kNoArgument, 'c' },
{ "chip-hex", kNoArgument, 'x' },
{ "chip-b64", kNoArgument, 'b' },
{ }
};
Expand All @@ -52,14 +53,18 @@ const char * const gCmdOptionHelp =
"\n"
" Output certificate in X.509 PEM format.\n"
"\n"
" -x, --x509-der\n"
" -d, --x509-der\n"
"\n"
" Output certificate in X.509 DER format.\n"
"\n"
" -c, --chip\n"
"\n"
" Output certificate in raw CHIP TLV format.\n"
"\n"
" -x, --chip-hex\n"
"\n"
" Output certificate in CHIP TLV hexadecimal format.\n"
"\n"
" -b --chip-b64\n"
"\n"
" Output certificate in CHIP TLV base-64 encoded format.\n"
Expand Down Expand Up @@ -114,9 +119,12 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char
case 'p':
gOutCertFormat = kCertFormat_X509_PEM;
break;
case 'x':
case 'd':
gOutCertFormat = kCertFormat_X509_DER;
break;
case 'x':
gOutCertFormat = kCertFormat_Chip_Hex;
break;
case 'b':
gOutCertFormat = kCertFormat_Chip_Base64;
break;
Expand Down
13 changes: 10 additions & 3 deletions src/tools/chip-cert/Cmd_ConvertKey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,9 @@ bool HandleNonOptionArgs(const char * progName, int argc, char * const argv[]);
OptionDef gCmdOptionDefs[] =
{
{ "x509-pem", kNoArgument, 'p' },
{ "x509-der", kNoArgument, 'x' },
{ "x509-der", kNoArgument, 'd' },
{ "chip", kNoArgument, 'c' },
{ "chip-hex", kNoArgument, 'x' },
{ "chip-b64", kNoArgument, 'b' },
{ }
};
Expand All @@ -52,13 +53,16 @@ const char * const gCmdOptionHelp =
"\n"
" Output the private key in SEC1/RFC-5915 PEM format.\n"
"\n"
" -x, --x509-der\n"
" -d, --x509-der\n"
"\n"
" Output the private key in SEC1/RFC-5915 DER format. \n"
"\n"
" -c, --chip\n"
"\n"
" Output the private key in raw CHIP serialized format.\n"
" -x, --chip-hex\n"
"\n"
" Output the private key in hex encoded CHIP serialized format.\n"
"\n"
" -b, --chip-b64\n"
"\n"
Expand Down Expand Up @@ -115,12 +119,15 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char
case 'p':
gOutFormat = kKeyFormat_X509_PEM;
break;
case 'x':
case 'd':
gOutFormat = kKeyFormat_X509_DER;
break;
case 'b':
gOutFormat = kKeyFormat_Chip_Base64;
break;
case 'x':
gOutFormat = kKeyFormat_Chip_Hex;
break;
case 'c':
gOutFormat = kKeyFormat_Chip_Raw;
break;
Expand Down
6 changes: 6 additions & 0 deletions src/tools/chip-cert/Cmd_GenCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ const char * const gCmdOptionHelp =
" x509-pem - X.509 PEM format\n"
" x509-der - X.509 DER format\n"
" chip - raw CHIP TLV format\n"
" chip-hex - hex encoded CHIP TLV format\n"
" chip-b64 - base-64 encoded CHIP TLV format (default)\n"
"\n"
" -V, --valid-from <YYYY>-<MM>-<DD> [ <HH>:<MM>:<SS> ]\n"
Expand Down Expand Up @@ -459,6 +460,11 @@ bool HandleOption(const char * progName, OptionSet * optSet, int id, const char
gOutCertFormat = kCertFormat_Chip_Base64;
gOutKeyFormat = kKeyFormat_Chip_Base64;
}
else if (strcmp(arg, "chip-hex") == 0)
{
gOutCertFormat = kCertFormat_Chip_Hex;
gOutKeyFormat = kKeyFormat_Chip_Hex;
}
else
{
PrintArgError("%s: Invalid value specified for the output format: %s\n", progName, arg);
Expand Down
49 changes: 40 additions & 9 deletions src/tools/chip-cert/KeyUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@

#include "chip-cert.h"
#include <lib/support/BufferWriter.h>
#include <lib/support/BytesToHex.h>
#include <protocols/Protocols.h>

using namespace chip;
using namespace chip::Protocols;
using namespace chip::ASN1;
using namespace chip::TLV;
using namespace chip::Crypto;
using namespace chip::Encoding;

namespace {

Expand All @@ -42,6 +44,9 @@ KeyFormat DetectKeyFormat(const uint8_t * key, uint32_t keyLen)
static const char * ecPEMMarker = "-----BEGIN EC PRIVATE KEY-----";
static const char * pkcs8PEMMarker = "-----BEGIN PRIVATE KEY-----";
static const char * ecPUBPEMMarker = "-----BEGIN PUBLIC KEY-----";
static const char * chipHexPrefix = "04c2";
static const size_t chipHexPrefixLen = strlen(chipHexPrefix);
static const size_t chipHexMinLen = HEX_ENCODED_LENGTH(p256SerializedKeypairLen);

if (keyLen == p256SerializedKeypairLen)
{
Expand All @@ -63,6 +68,11 @@ KeyFormat DetectKeyFormat(const uint8_t * key, uint32_t keyLen)
return kKeyFormat_X509_PUBKEY_PEM;
}

if (keyLen >= chipHexMinLen && memcmp(key, chipHexPrefix, chipHexPrefixLen) == 0)
{
return kKeyFormat_Chip_Hex;
}

return kKeyFormat_X509_DER;
}

Expand Down Expand Up @@ -166,6 +176,16 @@ bool ReadKey(const char * fileName, EVP_PKEY * key, bool ignorErrorIfUnsupported

keyFormat = kKeyFormat_Chip_Raw;
}
else if (keyFormat == kKeyFormat_Chip_Hex)
{
const char * keyChars = reinterpret_cast<const char *>(keyData.get());

keyDataLen = static_cast<uint32_t>(Encoding::HexToBytes(keyChars, keyDataLen, keyData.get(), keyDataLen));
res = (keyDataLen > 0);
VerifyTrueOrExit(res);

keyFormat = kKeyFormat_Chip_Raw;
}

if (keyFormat == kKeyFormat_Chip_Raw)
{
Expand Down Expand Up @@ -267,10 +287,10 @@ bool WritePrivateKey(const char * fileName, EVP_PKEY * key, KeyFormat keyFmt)
uint8_t * keyToWrite = nullptr;
uint32_t keyToWriteLen = 0;
P256SerializedKeypair serializedKeypair;
uint32_t chipKeySize = serializedKeypair.Capacity();
uint32_t chipKeyBase64Size = BASE64_ENCODED_LEN(chipKeySize);
uint32_t chipKeySize = serializedKeypair.Capacity();
uint32_t chipKeyDecodedSize = HEX_ENCODED_LENGTH(chipKeySize);
std::unique_ptr<uint8_t[]> chipKey(new uint8_t[chipKeySize]);
std::unique_ptr<uint8_t[]> chipKeyBase64(new uint8_t[chipKeyBase64Size]);
std::unique_ptr<uint8_t[]> chipKeyDecoded(new uint8_t[chipKeyDecodedSize]);

VerifyOrExit(key != nullptr, res = false);

Expand Down Expand Up @@ -298,20 +318,29 @@ bool WritePrivateKey(const char * fileName, EVP_PKEY * key, KeyFormat keyFmt)
}
break;
case kKeyFormat_Chip_Raw:
case kKeyFormat_Chip_Hex:
case kKeyFormat_Chip_Base64:
res = SerializeKeyPair(key, serializedKeypair);
VerifyTrueOrExit(res);

if (keyFmt == kKeyFormat_Chip_Base64)
{
uint32_t chipKeyBase64Len;

res = Base64Encode(serializedKeypair.Bytes(), static_cast<uint32_t>(serializedKeypair.Length()), chipKeyBase64.get(),
chipKeyBase64Size, chipKeyBase64Len);
res = Base64Encode(serializedKeypair.Bytes(), static_cast<uint32_t>(serializedKeypair.Length()), chipKeyDecoded.get(),
chipKeyDecodedSize, chipKeyDecodedSize);
VerifyTrueOrExit(res);

keyToWrite = chipKeyBase64.get();
keyToWriteLen = chipKeyBase64Len;
keyToWrite = chipKeyDecoded.get();
keyToWriteLen = chipKeyDecodedSize;
}
else if (keyFmt == kKeyFormat_Chip_Hex)
{
char * keyHex = reinterpret_cast<char *>(chipKeyDecoded.get());

SuccessOrExit(Encoding::BytesToLowercaseHexBuffer(
serializedKeypair.Bytes(), static_cast<uint32_t>(serializedKeypair.Length()), keyHex, chipKeyDecodedSize));

keyToWrite = chipKeyDecoded.get();
keyToWriteLen = chipKeyDecodedSize;
}
else
{
Expand All @@ -330,6 +359,8 @@ bool WritePrivateKey(const char * fileName, EVP_PKEY * key, KeyFormat keyFmt)
ExitNow(res = false);
}

printf("\r\n");

exit:
CloseFile(file);

Expand Down
Loading

0 comments on commit 81e18a9

Please sign in to comment.