CSR example using crypto callbacks (HSM).

pull/297/head
David Garske 2022-02-23 12:58:53 -08:00
parent 3ebf31bf4d
commit 042956c74b
8 changed files with 531 additions and 3 deletions

1
.gitignore vendored
View File

@ -109,6 +109,7 @@ signature/signature
#cergen
certgen/newCert*
certgen/certgen_example
certgen/csr_cryptocb
certgen/csr_example
certgen/csr_sign
certgen/csr_w_ed25519_example

View File

@ -13,7 +13,7 @@ CFLAGS=-I$(WOLF_INSTALL_DIR)/include -Wall
LIBS=-L$(WOLF_INSTALL_DIR)/lib -lwolfssl
all:certgen_example csr_example csr_w_ed25519_example csr_sign
all:certgen_example csr_example csr_w_ed25519_example csr_sign csr_cryptocb
certgen_example:certgen_example.o
$(CC) -o $@ $^ $(CFLAGS) $(CPPFLAGS) $(LIBS)
@ -27,8 +27,11 @@ csr_w_ed25519_example:csr_w_ed25519_example.o
csr_sign:csr_sign.o
$(CC) -o $@ $^ $(CFLAGS) $(CPPFLAGS) $(LIBS)
csr_cryptocb:csr_cryptocb.o
$(CC) -o $@ $^ $(CFLAGS) $(CPPFLAGS) $(LIBS)
.PHONY: clean all
clean:
rm -f *.o certgen_example csr_example csr_w_ed25519_example csr_sign
rm -f *.o certgen_example csr_example csr_w_ed25519_example csr_sign csr_cryptocb
rm -f newCert.*

View File

@ -0,0 +1,505 @@
/* csr_cryptocb.c
*
* Copyright (C) 2006-2022 wolfSSL Inc.
*
* This file is part of wolfSSL.
*
* wolfSSL is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfSSL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* Example of generating a PEM-encoded certificate signing request (CSR). */
#ifndef WOLFSSL_USER_SETTINGS
#include <wolfssl/options.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/rsa.h>
#include <wolfssl/wolfcrypt/ed25519.h>
#include <wolfssl/wolfcrypt/asn_public.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/cryptocb.h>
#define LARGE_TEMP_SZ 4096
#define DEBUG_CRYPTOCB
#if defined(WOLF_CRYPTO_CB) && defined(WOLFSSL_CERT_REQ) && \
defined(WOLFSSL_CERT_EXT) && defined(WOLFSSL_CERT_GEN)
static void usage(void)
{
printf("Invalid input supplied try one of the below examples\n");
printf("Examples:\n\n");
printf("./csr_cryptocb rsa\n");
printf("./csr_cryptocb ecc\n");
printf("./csr_cryptocb ed25519\n");
}
/* Example custom context for crypto callback */
typedef struct {
const char* keyFilePub;
const char* keyFilePriv;
} myCryptoCbCtx;
#ifdef DEBUG_CRYPTOCB
static const char* GetAlgoTypeStr(int algo)
{
switch (algo) { /* enum wc_AlgoType */
case WC_ALGO_TYPE_HASH: return "Hash";
case WC_ALGO_TYPE_CIPHER: return "Cipher";
case WC_ALGO_TYPE_PK: return "PK";
case WC_ALGO_TYPE_RNG: return "RNG";
case WC_ALGO_TYPE_SEED: return "Seed";
case WC_ALGO_TYPE_HMAC: return "HMAC";
}
return NULL;
}
static const char* GetPkTypeStr(int pk)
{
switch (pk) {
case WC_PK_TYPE_RSA: return "RSA";
case WC_PK_TYPE_DH: return "DH";
case WC_PK_TYPE_ECDH: return "ECDH";
case WC_PK_TYPE_ECDSA_SIGN: return "ECDSA-Sign";
case WC_PK_TYPE_ECDSA_VERIFY: return "ECDSA-Verify";
case WC_PK_TYPE_ED25519_SIGN: return "ED25519-Sign";
case WC_PK_TYPE_ED25519_VERIFY: return "ED25519-Verify";
case WC_PK_TYPE_CURVE25519: return "CURVE25519";
case WC_PK_TYPE_RSA_KEYGEN: return "RSA KeyGen";
case WC_PK_TYPE_EC_KEYGEN: return "ECC KeyGen";
}
return NULL;
}
#endif /* DEBUG_CRYPTOCB */
/* reads file size, allocates buffer, reads into buffer, returns buffer */
static int load_file(const char* fname, byte** buf, size_t* bufLen)
{
int ret;
long int fileSz;
XFILE lFile;
if (fname == NULL || buf == NULL || bufLen == NULL)
return BAD_FUNC_ARG;
/* set defaults */
*buf = NULL;
*bufLen = 0;
/* open file (read-only binary) */
lFile = XFOPEN(fname, "rb");
if (!lFile) {
printf("Error loading %s\n", fname);
return BAD_PATH_ERROR;
}
fseek(lFile, 0, SEEK_END);
fileSz = (int)ftell(lFile);
rewind(lFile);
if (fileSz > 0) {
*bufLen = (size_t)fileSz;
*buf = (byte*)malloc(*bufLen);
if (*buf == NULL) {
ret = MEMORY_E;
printf("Error allocating %lu bytes\n", (unsigned long)*bufLen);
}
else {
size_t readLen = fread(*buf, *bufLen, 1, lFile);
/* check response code */
ret = (readLen > 0) ? 0 : -1;
}
}
else {
ret = BUFFER_E;
}
fclose(lFile);
return ret;
}
static int load_key_file(const char* fname, byte* derBuf, word32* derLen,
int isPubKey)
{
int ret;
byte* buf = NULL;
size_t bufLen;
ret = load_file(fname, &buf, &bufLen);
if (ret != 0)
return ret;
if (isPubKey) {
ret = wc_PubKeyPemToDer(buf, (word32)bufLen, derBuf, (word32)bufLen);
} else {
ret = wc_KeyPemToDer(buf, (word32)bufLen, derBuf, (word32)bufLen, NULL);
}
if (ret < 0) {
free(buf);
return ret;
}
*derLen = ret;
free(buf);
return 0;
}
#ifdef WOLFSSL_DER_TO_PEM
static int save_der_as_pem(const byte* der, word32 derSz, const char* arg1,
int type)
{
int ret;
byte pem[LARGE_TEMP_SZ];
int pemSz;
FILE* file = NULL;
char outFile[255];
memset(pem, 0, sizeof(pem));
ret = wc_DerToPem(der, derSz, pem, sizeof(pem), type);
if (ret <= 0) {
printf("CSR DER to PEM failed: %d\n", ret);
return ret;
}
pemSz = ret;
printf("%s (%d)\n", pem, pemSz);
snprintf(outFile, sizeof(outFile), "%s-csr.pem", arg1);
printf("Saved CSR PEM to \"%s\"\n", outFile);
file = fopen(outFile, "wb");
if (file) {
ret = (int)fwrite(pem, 1, pemSz, file);
if (ret == pemSz) {
ret = 0;
}
fclose(file);
}
else {
ret = -1;
}
return ret;
}
#endif
/* Example crypto dev callback function that calls software version */
/* This is where you would plug-in calls to your own hardware crypto */
static int myCryptoDevCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
{
int ret = CRYPTOCB_UNAVAILABLE; /* return this to bypass HW and use SW */
myCryptoCbCtx* myCtx = (myCryptoCbCtx*)ctx;
byte der[LARGE_TEMP_SZ];
word32 derSz;
word32 idx = 0;
if (info == NULL)
return BAD_FUNC_ARG;
ret = load_key_file(myCtx->keyFilePriv, der, &derSz, 0);
if (ret != 0) {
printf("Error %d loading %s\n", ret, myCtx->keyFilePriv);
return ret;
}
if (info->algo_type == WC_ALGO_TYPE_PK) {
#ifdef DEBUG_CRYPTOCB
printf("CryptoCb: %s %s (%d)\n", GetAlgoTypeStr(info->algo_type),
GetPkTypeStr(info->pk.type), info->pk.type);
#endif
#ifndef NO_RSA
if (info->pk.type == WC_PK_TYPE_RSA) {
RsaKey rsaPriv;
ret = wc_InitRsaKey_ex(&rsaPriv, NULL, INVALID_DEVID);
if (ret != 0) {
return ret;
}
ret = wc_RsaPrivateKeyDecode(der, &idx, &rsaPriv, derSz);
if (ret != 0) {
wc_FreeRsaKey(&rsaPriv);
return ret;
}
switch (info->pk.rsa.type) {
case RSA_PUBLIC_ENCRYPT:
case RSA_PUBLIC_DECRYPT:
/* perform software based RSA public op */
ret = wc_RsaFunction(
info->pk.rsa.in, info->pk.rsa.inLen,
info->pk.rsa.out, info->pk.rsa.outLen,
info->pk.rsa.type, &rsaPriv, info->pk.rsa.rng);
break;
case RSA_PRIVATE_ENCRYPT:
case RSA_PRIVATE_DECRYPT:
/* perform software based RSA private op */
ret = wc_RsaFunction(
info->pk.rsa.in, info->pk.rsa.inLen,
info->pk.rsa.out, info->pk.rsa.outLen,
info->pk.rsa.type, &rsaPriv, info->pk.rsa.rng);
break;
}
wc_FreeRsaKey(&rsaPriv);
}
#endif /* !NO_RSA */
#ifdef HAVE_ECC
if (info->pk.type == WC_PK_TYPE_ECDSA_SIGN) {
ecc_key eccPriv;
ret = wc_ecc_init_ex(&eccPriv, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_EccPrivateKeyDecode(der, &idx, &eccPriv, derSz);
if (ret == 0) {
ret = wc_ecc_sign_hash(
info->pk.eccsign.in, info->pk.eccsign.inlen,
info->pk.eccsign.out, info->pk.eccsign.outlen,
info->pk.eccsign.rng, &eccPriv);
}
wc_ecc_free(&eccPriv);
}
}
#endif /* HAVE_ECC */
#ifdef HAVE_ED25519
if (info->pk.type == WC_PK_TYPE_ED25519_SIGN) {
ed25519_key edPriv;
ret = wc_ed25519_init_ex(&edPriv, NULL, INVALID_DEVID);
if (ret == 0) {
ret = wc_Ed25519PrivateKeyDecode(der, &idx, &edPriv, derSz);
if (ret == 0) {
/* calculate public key */
ret = wc_ed25519_make_public(&edPriv, edPriv.p,
ED25519_PUB_KEY_SIZE);
}
if (ret == 0) {
edPriv.pubKeySet = 1;
ret = wc_ed25519_sign_msg_ex(
info->pk.ed25519sign.in, info->pk.ed25519sign.inLen,
info->pk.ed25519sign.out, info->pk.ed25519sign.outLen,
&edPriv, info->pk.ed25519sign.type,
info->pk.ed25519sign.context,
info->pk.ed25519sign.contextLen);
}
wc_ed25519_free(&edPriv);
}
}
#endif /* HAVE_ED25519 */
}
(void)devIdArg;
(void)myCtx;
return ret;
}
static int gen_csr(const char* arg1)
{
int ret;
int type;
#ifdef HAVE_ECC
ecc_key ecKeyPub;
#endif
#ifndef NO_RSA
RsaKey rsaKeyPub;
#endif
#ifdef HAVE_ED25519
ed25519_key edKeyPub;
#endif
void* keyPtr = NULL;
WC_RNG rng;
Cert req;
byte der[LARGE_TEMP_SZ];
word32 derSz;
word32 idx = 0;
myCryptoCbCtx myCtx;
int devId = 1; /* any value besides INVALID_DEVID */
if (XSTRNCMP(arg1, "rsa", 3) == 0)
type = RSA_TYPE;
else if (XSTRNCMP(arg1, "ecc", 3) == 0)
type = ECC_TYPE;
else if (XSTRNCMP(arg1, "ed25519", 7) == 0)
type = ED25519_TYPE;
else
return NOT_COMPILED_IN;
wolfCrypt_Init();
/* register a devID for crypto callbacks */
ret = wc_CryptoCb_RegisterDevice(devId, myCryptoDevCb, &myCtx);
if (ret != 0) {
printf("Crypto callback register failed: %d\n", ret);
goto exit;
}
ret = wc_InitRng(&rng);
if (ret != 0) {
printf("RNG initialization failed: %d\n", ret);
goto exit;
}
/* setup test key */
#ifdef HAVE_ECC
if (type == ECC_TYPE) {
myCtx.keyFilePub = "../certs/ecc-keyPub.pem";
myCtx.keyFilePriv = "../certs/ecc-key.pem";
}
#endif
#ifndef NO_RSA
if (type == RSA_TYPE) {
myCtx.keyFilePub = "../certs/client-keyPub.pem";
myCtx.keyFilePriv = "../certs/client-key.pem";
}
#endif
#ifdef HAVE_ED25519
if (type == ED25519_TYPE) {
myCtx.keyFilePub = "../certs/ed25519-keyPub.pem";
myCtx.keyFilePriv = "../certs/ed25519-keyPriv.pem";
}
#endif
/* convert PEM to DER */
derSz = sizeof(der);
ret = load_key_file(myCtx.keyFilePub, der, &derSz, 1);
if (ret != 0) {
printf("Error %d loading the public key %s\n", ret, myCtx.keyFilePub);
goto exit;
}
/* setup public key */
#ifdef HAVE_ECC
if (type == ECC_TYPE) {
keyPtr = &ecKeyPub;
ret = wc_ecc_init_ex(&ecKeyPub, NULL, devId);
}
#endif
#ifndef NO_RSA
if (type == RSA_TYPE) {
keyPtr = &rsaKeyPub;
ret = wc_InitRsaKey_ex(&rsaKeyPub, NULL, devId);
}
#endif
#ifdef HAVE_ED25519
if (type == ED25519_TYPE) {
keyPtr = &edKeyPub;
ret = wc_ed25519_init_ex(&edKeyPub, NULL, devId);
}
#endif
if (ret != 0) {
printf("Key initialization failed: %d\n", ret);
goto exit;
}
/* decode public key */
#ifdef HAVE_ECC
if (type == ECC_TYPE) {
ret = wc_EccPublicKeyDecode(der, &idx, &ecKeyPub, derSz);
}
#endif
#ifndef NO_RSA
if (type == RSA_TYPE) {
ret = wc_RsaPublicKeyDecode(der, &idx, &rsaKeyPub, derSz);
}
#endif
#ifdef HAVE_ED25519
if (type == ED25519_TYPE) {
ret = wc_Ed25519PublicKeyDecode(der, &idx, &edKeyPub, derSz);
}
#endif
if (ret != 0) {
printf("Key decode failed: %d\n", ret);
goto exit;
}
/* setup the CSR data */
ret = wc_InitCert(&req);
if (ret != 0) {
printf("Init Cert failed: %d\n", ret);
goto exit;
}
strncpy(req.subject.country, "US", CTC_NAME_SIZE);
strncpy(req.subject.state, "OR", CTC_NAME_SIZE);
strncpy(req.subject.locality, "Portland", CTC_NAME_SIZE);
strncpy(req.subject.org, "wolfSSL", CTC_NAME_SIZE);
strncpy(req.subject.unit, "Development", CTC_NAME_SIZE);
strncpy(req.subject.commonName, "www.wolfssl.com", CTC_NAME_SIZE);
strncpy(req.subject.email, "info@wolfssl.com", CTC_NAME_SIZE);
ret = wc_MakeCertReq_ex(&req, der, sizeof(der), type, keyPtr);
if (ret <= 0) {
printf("Make Cert Req failed: %d\n", ret);
goto exit;
}
derSz = ret;
#ifdef HAVE_ECC
if (type == ECC_TYPE)
req.sigType = CTC_SHA256wECDSA;
#endif
#ifndef NO_RSA
if (type == RSA_TYPE)
req.sigType = CTC_SHA256wRSA;
#endif
#ifdef HAVE_ED25519
if (type == ED25519_TYPE)
req.sigType = CTC_ED25519;
#endif
/* Because the key has devId set, it will call myCryptoDevCb for signing */
ret = wc_SignCert_ex(req.bodySz, req.sigType, der, sizeof(der), type,
keyPtr, &rng);
if (ret <= 0) {
printf("Sign Cert failed: %d\n", ret);
goto exit;
}
derSz = ret;
#ifdef WOLFSSL_DER_TO_PEM
ret = save_der_as_pem(der, derSz, arg1, CERTREQ_TYPE);
#endif
ret = 0; /* success */
exit:
#ifdef HAVE_ECC
if (type == ECC_TYPE)
wc_ecc_free(&ecKeyPub);
#endif
#ifndef NO_RSA
if (type == RSA_TYPE)
wc_FreeRsaKey(&rsaKeyPub);
#endif
#ifdef HAVE_ED25519
if (type == ED25519_TYPE)
wc_ed25519_free(&edKeyPub);
#endif
wc_FreeRng(&rng);
wolfCrypt_Cleanup();
return ret;
}
#endif
int main(int argc, char** argv)
{
#if !defined(WOLF_CRYPTO_CB) || !defined(WOLFSSL_CERT_REQ) || \
!defined(WOLFSSL_CERT_EXT) || !defined(WOLFSSL_CERT_GEN)
printf("Please compile wolfSSL with --enable-certreq --enable-certgen --enable-certext --enable-cryptocb\n");
return 0;
#else
if (argc != 2) {
usage();
return 1;
}
return gen_csr(argv[1]);
#endif
}

View File

@ -255,7 +255,7 @@ exit:
int main(int argc, char** argv)
{
#if !defined(WOLFSSL_CERT_REQ) || !defined(WOLFSSL_CERT_GEN) || !defined(WOLFSSL_KEY_GEN)
printf("Please compile wolfSSL with --enable-certreq --enable-certgen --enable-keygen\n");
printf("Please compile wolfSSL with --enable-certreq --enable-certgen --enable-certext --enable-keygen\n");
return 0;
#else
if (argc != 2) {

View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwwPRK/45pDJFO1PIhCsq
fHSavaoqUgdH1qY2sgcyjtC6aXvGw0Se1IFI/S1oootnu6F1yDYsStIb94u6zw35
7+zxgR57mwNHmr9lzH9lJGmm6BSJW+Q098WwFJP1Z3s6enjhAVZWkaYTQo3SPECc
TO/Rht83URsMoTv18aNKNeThzpbfG36/TpfQEOioCDCBryALQxTFdGe0MoJvjYbC
iECZNoO6HkByIhfXUmUkc7DO7xnNrv94bHvAEgPUTnINUG07ozujmV6dyNkMhbPZ
itlUJttt+qy7/yVMxNF59HHThkAYE7BjtXJOMMSXhIYtVi/XFfd/wK71/Fvl+6G6
0wIDAQAB
-----END PUBLIC KEY-----

View File

@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuzOsTCdQSsZKpQTDPN6fNttyLc6U
6iv6yyAJOSwW6GEC6a9N0wKTmjFbl5Ihf/DPGNqREQI0huggWDMLgDSJ2A==
-----END PUBLIC KEY-----

View File

@ -0,0 +1,3 @@
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIJK1TOyvgca7AdbV3r03l1rSxvbDhbU75uTsMunHylLr
-----END PRIVATE KEY-----

View File

@ -0,0 +1,3 @@
-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEA5ldbExvHURRr7Tv10fqrnmy26wIJo5n1br+dPP5UOeY=
-----END PUBLIC KEY-----