blob: 0df462b45663e35f56cfe732a0f950c5f0f13121 [file] [log] [blame]
/*
*
* Copyright (c) 2021-2022 Project CHIP Authors
* Copyright (c) 2013-2017 Nest Labs, Inc.
* All rights reserved.
*
* 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.
*/
/**
* @file
* This file implements the command handler for the 'chip-cert' tool
* that converts a CHIP private key between CHIP serialized and
* PEM/DER formats.
*
*/
#include "chip-cert.h"
namespace {
using namespace chip::ArgParser;
using namespace chip::Credentials;
#define CMD_NAME "chip-cert convert-key"
bool HandleOption(const char * progName, OptionSet * optSet, int id, const char * name, const char * arg);
bool HandleNonOptionArgs(const char * progName, int argc, char * const argv[]);
// clang-format off
OptionDef gCmdOptionDefs[] =
{
{ "x509-pem", kNoArgument, 'p' },
{ "x509-der", kNoArgument, 'd' },
{ "x509-hex", kNoArgument, 'x' },
{ "x509-pubkey-pem", kNoArgument, 'P' },
{ "chip", kNoArgument, 'c' },
{ "chip-b64", kNoArgument, 'b' },
{ "chip-hex", kNoArgument, 'e' },
{ "chip-pubkey", kNoArgument, 'C' },
{ "chip-pubkey-b64", kNoArgument, 'B' },
{ "chip-pubkey-hex", kNoArgument, 'E' },
{ }
};
const char * const gCmdOptionHelp =
" -p, --x509-pem\n"
"\n"
" Output the private key in SEC1/RFC-5915 PEM format.\n"
"\n"
" -d, --x509-der\n"
"\n"
" Output the private key in SEC1/RFC-5915 DER format. \n"
"\n"
" -x, --x509-hex\n"
"\n"
" Output the private key in SEC1/RFC-5915 DER hex encoded format.\n"
"\n"
" -P, --x509-pubkey-pem\n"
"\n"
" Output the public key in SEC1/RFC-5915 PEM 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"
" Output the private key in base-64 encoded CHIP serialized format.\n"
" This is the default.\n"
"\n"
" -e, --chip-hex\n"
"\n"
" Output the private key in hex encoded CHIP serialized format.\n"
"\n"
" -C, --chip-pubkey\n"
"\n"
" Output the raw public key.\n"
"\n"
" -B, --chip-pubkey-b64\n"
"\n"
" Output the public key in base-64 encoded format.\n"
"\n"
" -E, --chip-pubkey-hex\n"
"\n"
" Output the public key in hex encoded format.\n"
"\n"
;
OptionSet gCmdOptions =
{
HandleOption,
gCmdOptionDefs,
"COMMAND OPTIONS",
gCmdOptionHelp
};
HelpOptions gHelpOptions(
CMD_NAME,
"Usage: " CMD_NAME " [ <options...> ] <in-file/str> <out-file/stdout>\n",
CHIP_VERSION_STRING "\n" COPYRIGHT_STRING,
"Convert private/public key between CHIP and X.509 formats.\n"
"\n"
"ARGUMENTS\n"
"\n"
" <in-file/str>\n"
"\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"
" 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"
" <out-file/stdout>\n"
"\n"
" The output private key file name, or '-' to write to stdout.\n"
"\n"
);
OptionSet *gCmdOptionSets[] =
{
&gCmdOptions,
&gHelpOptions,
nullptr
};
// clang-ormat on
const char * gInFileNameOrStr = nullptr;
const char * gOutFileName = nullptr;
KeyFormat gOutFormat = kKeyFormat_Chip_Base64;
bool HandleOption(const char * progName, OptionSet * optSet, int id, const char * name, const char * arg)
{
switch (id)
{
case 'p':
gOutFormat = kKeyFormat_X509_PEM;
break;
case 'd':
gOutFormat = kKeyFormat_X509_DER;
break;
case 'x':
gOutFormat = kKeyFormat_X509_Hex;
break;
case 'P':
gOutFormat = kKeyFormat_X509_Pubkey_PEM;
break;
case 'c':
gOutFormat = kKeyFormat_Chip_Raw;
break;
case 'b':
gOutFormat = kKeyFormat_Chip_Base64;
break;
case 'e':
gOutFormat = kKeyFormat_Chip_Hex;
break;
case 'C':
gOutFormat = kKeyFormat_Chip_Pubkey_Raw;
break;
case 'B':
gOutFormat = kKeyFormat_Chip_Pubkey_Base64;
break;
case 'E':
gOutFormat = kKeyFormat_Chip_Pubkey_Hex;
break;
default:
PrintArgError("%s: Unhandled option: %s\n", progName, name);
return false;
}
return true;
}
bool HandleNonOptionArgs(const char * progName, int argc, char * const argv[])
{
if (argc == 0)
{
PrintArgError("%s: Please specify the name of the input key file, or - for stdin.\n", progName);
return false;
}
if (argc == 1)
{
PrintArgError("%s: Please specify the name of the output key file, or - for stdout\n", progName);
return false;
}
if (argc > 2)
{
PrintArgError("%s: Unexpected argument: %s\n", progName, argv[2]);
return false;
}
gInFileNameOrStr = argv[0];
gOutFileName = argv[1];
return true;
}
} // namespace
bool Cmd_ConvertKey(int argc, char * argv[])
{
bool res = true;
std::unique_ptr<EVP_PKEY,void(*)(EVP_PKEY*)> key(EVP_PKEY_new(), &EVP_PKEY_free);
if (argc == 1)
{
gHelpOptions.PrintBriefUsage(stderr);
ExitNow(res = true);
}
res = ParseArgs(CMD_NAME, argc, argv, gCmdOptionSets, HandleNonOptionArgs);
VerifyTrueOrExit(res);
res = InitOpenSSL();
VerifyTrueOrExit(res);
res = ReadKey(gInFileNameOrStr, key);
VerifyTrueOrExit(res);
if (IsPrivateKeyFormat(gOutFormat) && EC_KEY_get0_private_key(EVP_PKEY_get1_EC_KEY(key.get())) == nullptr)
{
fprintf(stderr, "Cannot convert to the private key format as the original key doesn't include private key.\n");
return false;
}
res = WriteKey(gOutFileName, key.get(), gOutFormat);
VerifyTrueOrExit(res);
exit:
return res;
}