Skip to content

Commit

Permalink
chip-cert: Updated Tool to Support Comand Line Key/Cert Inputs. (#22142)
Browse files Browse the repository at this point in the history
Other text updates.
  • Loading branch information
emargolis committed Sep 6, 2022
1 parent ef75ba4 commit a63c0a9
Show file tree
Hide file tree
Showing 13 changed files with 383 additions and 299 deletions.
84 changes: 45 additions & 39 deletions src/tools/chip-cert/CertUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,51 +508,52 @@ bool AddAuthorityKeyId(X509 * cert, X509 * caCert)
return res;
}

bool ReadCertPEM(const char * fileName, X509 * cert)
{
bool res = true;
FILE * file = nullptr;

res = OpenFile(fileName, file);
VerifyTrueOrExit(res);

if (PEM_read_X509(file, &cert, nullptr, nullptr) == nullptr)
{
ReportOpenSSLErrorAndExit("PEM_read_X509", res = false);
}

exit:
CloseFile(file);
return res;
}

} // namespace

bool ReadCert(const char * fileName, X509 * cert)
bool ReadCert(const char * fileNameOrStr, X509 * cert)
{
CertFormat origCertFmt;
return ReadCert(fileName, cert, origCertFmt);
return ReadCert(fileNameOrStr, cert, origCertFmt);
}

bool ReadCert(const char * fileName, X509 * cert, CertFormat & certFmt)
bool ReadCert(const char * fileNameOrStr, X509 * cert, CertFormat & certFmt)
{
bool res = true;
uint32_t certLen = 0;
std::unique_ptr<uint8_t[]> certBuf;

res = ReadFileIntoMem(fileName, nullptr, certLen);
VerifyTrueOrExit(res);
// If fileNameOrStr is a file name
if (access(fileNameOrStr, R_OK) == 0)
{
res = ReadFileIntoMem(fileNameOrStr, nullptr, certLen);
VerifyTrueOrExit(res);

certBuf = std::unique_ptr<uint8_t[]>(new uint8_t[certLen]);
certBuf = std::unique_ptr<uint8_t[]>(new uint8_t[certLen]);

res = ReadFileIntoMem(fileName, certBuf.get(), certLen);
VerifyTrueOrExit(res);
res = ReadFileIntoMem(fileNameOrStr, certBuf.get(), certLen);
VerifyTrueOrExit(res);

certFmt = DetectCertFormat(certBuf.get(), certLen);
if (certFmt == kCertFormat_Unknown)
certFmt = DetectCertFormat(certBuf.get(), certLen);
if (certFmt == kCertFormat_Unknown)
{
fprintf(stderr, "Unrecognized Cert Format in File: %s\n", fileNameOrStr);
return false;
}
}
// Otherwise, treat fileNameOrStr as a pointer to the certificate string
else
{
fprintf(stderr, "Unrecognized Cert Format in File: %s\n", fileName);
return false;
certLen = static_cast<uint32_t>(strlen(fileNameOrStr));

certFmt = DetectCertFormat(reinterpret_cast<const uint8_t *>(fileNameOrStr), certLen);
if (certFmt == kCertFormat_Unknown)
{
fprintf(stderr, "Unrecognized Cert Format in the Input Argument: %s\n", fileNameOrStr);
return false;
}

certBuf = std::unique_ptr<uint8_t[]>(new uint8_t[certLen]);
memcpy(certBuf.get(), fileNameOrStr, certLen);
}

if ((certFmt == kCertFormat_X509_Hex) || (certFmt == kCertFormat_Chip_Hex))
Expand All @@ -565,8 +566,15 @@ bool ReadCert(const char * fileName, X509 * cert, CertFormat & certFmt)

if (certFmt == kCertFormat_X509_PEM)
{
res = ReadCertPEM(fileName, cert);
VerifyTrueOrExit(res);
VerifyOrReturnError(chip::CanCastTo<int>(certLen), false);

std::unique_ptr<BIO, void (*)(BIO *)> certBIO(
BIO_new_mem_buf(static_cast<const void *>(certBuf.get()), static_cast<int>(certLen)), &BIO_free_all);

if (PEM_read_bio_X509(certBIO.get(), &cert, nullptr, nullptr) == nullptr)
{
ReportOpenSSLErrorAndExit("PEM_read_bio_X509", res = false);
}
}
else if ((certFmt == kCertFormat_X509_DER) || (certFmt == kCertFormat_X509_Hex))
{
Expand Down Expand Up @@ -612,12 +620,12 @@ bool ReadCert(const char * fileName, X509 * cert, CertFormat & certFmt)
return res;
}

bool ReadCertDERRaw(const char * fileName, MutableByteSpan & cert)
bool ReadCertDER(const char * fileNameOrStr, MutableByteSpan & cert)
{
bool res = true;
std::unique_ptr<X509, void (*)(X509 *)> certX509(X509_new(), &X509_free);

VerifyOrReturnError(ReadCertPEM(fileName, certX509.get()) == true, false);
VerifyOrReturnError(ReadCert(fileNameOrStr, certX509.get()), false);

uint8_t * certPtr = cert.data();
int certLen = i2d_X509(certX509.get(), &certPtr);
Expand Down Expand Up @@ -660,14 +668,14 @@ bool X509ToChipCert(X509 * cert, MutableByteSpan & chipCert)
return res;
}

bool LoadChipCert(const char * fileName, bool isTrused, ChipCertificateSet & certSet, MutableByteSpan & chipCert)
bool LoadChipCert(const char * fileNameOrStr, bool isTrused, ChipCertificateSet & certSet, MutableByteSpan & chipCert)
{
bool res = true;
CHIP_ERROR err;
BitFlags<CertDecodeFlags> decodeFlags;
std::unique_ptr<X509, void (*)(X509 *)> cert(X509_new(), &X509_free);

res = ReadCert(fileName, cert.get());
res = ReadCert(fileNameOrStr, cert.get());
VerifyTrueOrExit(res);

res = X509ToChipCert(cert.get(), chipCert);
Expand All @@ -685,7 +693,7 @@ bool LoadChipCert(const char * fileName, bool isTrused, ChipCertificateSet & cer
err = certSet.LoadCert(chipCert, decodeFlags);
if (err != CHIP_NO_ERROR)
{
fprintf(stderr, "Error reading %s\n%s\n", fileName, chip::ErrorStr(err));
fprintf(stderr, "Error reading %s\n%s\n", fileNameOrStr, chip::ErrorStr(err));
ExitNow(res = false);
}

Expand Down Expand Up @@ -747,8 +755,6 @@ bool WriteCert(const char * fileName, X509 * cert, CertFormat certFmt)
ExitNow(res = false);
}

printf("\r\n");

exit:
OPENSSL_free(derCert);
CloseFile(file);
Expand Down
30 changes: 15 additions & 15 deletions src/tools/chip-cert/Cmd_ConvertCert.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,21 +87,21 @@ OptionSet gCmdOptions =

HelpOptions gHelpOptions(
CMD_NAME,
"Usage: " CMD_NAME " [ <options...> ] <in-file> <out-file>\n",
"Usage: " CMD_NAME " [ <options...> ] <in-file/str> <out-file/stdout>\n",
CHIP_VERSION_STRING "\n" COPYRIGHT_STRING,
"Convert a certificate between CHIP and X509 forms.\n"
"Convert operational certificate between CHIP and X.509 formats.\n"
"\n"
"ARGUMENTS\n"
"\n"
" <in-file>\n"
" <in-file/str>\n"
"\n"
" The input certificate file name, or - to read from stdin. The\n"
" format of the input certificate is auto-detected and can be any\n"
" of: X.509 PEM, X.509 DER, CHIP base-64 or CHIP raw TLV.\n"
" File or string containing certificate to be converted.\n"
" The format of the input certificate is auto-detected and can be any of:\n"
" X.509 PEM, X.509 DER, X.509 HEX, CHIP base-64, CHIP raw TLV or CHIP HEX.\n"
"\n"
" <out-file>\n"
" <out-file/stdout>\n"
"\n"
" The output certificate file name, or - to write to stdout.\n"
" The output certificate file name, or '-' to write to stdout.\n"
"\n"
);

Expand All @@ -113,9 +113,9 @@ OptionSet * gCmdOptionSets[] =
};
// clang-format on

const char * gInFileName = nullptr;
const char * gOutFileName = nullptr;
CertFormat gOutCertFormat = kCertFormat_Default;
const char * gInFileNameOrStr = nullptr;
const char * gOutFileName = nullptr;
CertFormat gOutCertFormat = kCertFormat_Default;

bool HandleOption(const char * progName, OptionSet * optSet, int id, const char * name, const char * arg)
{
Expand Down Expand Up @@ -151,7 +151,7 @@ bool HandleNonOptionArgs(const char * progName, int argc, char * const argv[])
{
if (argc == 0)
{
PrintArgError("%s: Please specify the name of the input certificate file, or - for stdin.\n", progName);
PrintArgError("%s: Please specify the name of the input certificate file or the certificate string.\n", progName);
return false;
}

Expand All @@ -167,8 +167,8 @@ bool HandleNonOptionArgs(const char * progName, int argc, char * const argv[])
return false;
}

gInFileName = argv[0];
gOutFileName = argv[1];
gInFileNameOrStr = argv[0];
gOutFileName = argv[1];

return true;
}
Expand All @@ -192,7 +192,7 @@ bool Cmd_ConvertCert(int argc, char * argv[])
res = InitOpenSSL();
VerifyTrueOrExit(res);

res = ReadCert(gInFileName, cert.get());
res = ReadCert(gInFileNameOrStr, cert.get());
VerifyTrueOrExit(res);

res = WriteCert(gOutFileName, cert.get(), gOutCertFormat);
Expand Down
27 changes: 16 additions & 11 deletions src/tools/chip-cert/Cmd_ConvertKey.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,21 +110,26 @@ OptionSet gCmdOptions =

HelpOptions gHelpOptions(
CMD_NAME,
"Usage: " CMD_NAME " [ <options...> ] <in-file> <out-file>\n",
"Usage: " CMD_NAME " [ <options...> ] <in-file/str> <out-file/stdout>\n",
CHIP_VERSION_STRING "\n" COPYRIGHT_STRING,
"Convert a private key between CHIP and PEM/DER forms."
"Convert private/public key between CHIP and X.509 formats.\n"
"\n"
"ARGUMENTS\n"
"\n"
" <in-file>\n"
" <in-file/str>\n"
"\n"
" The input private key file name, or - to read from stdin. The\n"
" format of the input key is auto-detected and can be any\n"
" of: PEM, DER, CHIP base-64 or CHIP raw.\n"
" File or string containing private/public key to be converted.\n"
" The format of the input key is auto-detected and can be any of:\n"
" X.509 PEM, X.509 DER, X.509 HEX, CHIP base-64, CHIP raw TLV or CHIP HEX.\n"
"\n"
" <out-file>\n"
" Note: the private key formats include both private and public keys, while\n"
" the public key formats include only public keys. Therefore, conversion from any\n"
" private key format to public key is supported but conversion from public key\n"
" to private CANNOT be done.\n"
"\n"
" The output private key file name, or - to write to stdout.\n"
" <out-file/stdout>\n"
"\n"
" The output private key file name, or '-' to write to stdout.\n"
"\n"
);

Expand All @@ -136,7 +141,7 @@ OptionSet *gCmdOptionSets[] =
};
// clang-ormat on

const char * gInFileName = nullptr;
const char * gInFileNameOrStr = nullptr;
const char * gOutFileName = nullptr;
KeyFormat gOutFormat = kKeyFormat_Chip_Base64;

Expand Down Expand Up @@ -203,7 +208,7 @@ bool HandleNonOptionArgs(const char * progName, int argc, char * const argv[])
return false;
}

gInFileName = argv[0];
gInFileNameOrStr = argv[0];
gOutFileName = argv[1];

return true;
Expand All @@ -228,7 +233,7 @@ bool Cmd_ConvertKey(int argc, char * argv[])
res = InitOpenSSL();
VerifyTrueOrExit(res);

res = ReadKey(gInFileName, key);
res = ReadKey(gInFileNameOrStr, key);
VerifyTrueOrExit(res);

if (IsPrivateKeyFormat(gOutFormat) && EC_KEY_get0_private_key(EVP_PKEY_get1_EC_KEY(key.get())) == nullptr)
Expand Down
Loading

0 comments on commit a63c0a9

Please sign in to comment.