add wc_GetPubKeyDerFromCert(), get pub key DER from DecodedCert

This commit is contained in:
Chris Conlon
2021-12-08 16:47:04 -07:00
parent a6c7d56c32
commit 5172130287
6 changed files with 263 additions and 7 deletions

View File

@@ -1249,6 +1249,29 @@ WOLFSSL_API int wc_KeyPemToDer(const unsigned char*, int,
WOLFSSL_API int wc_CertPemToDer(const unsigned char*, int,
unsigned char*, int, int);
/*!
\ingroup CertsKeys
\brief This function gets the public key in DER format from a populated
DecodedCert struct. Users must call wc_InitDecodedCert() and wc_ParseCert()
before calling this API. wc_InitDecodedCert() accepts a DER/ASN.1 encoded
certificate. To convert a PEM cert to DER, first use wc_CertPemToDer()
before calling wc_InitDecodedCert().
\return 0 on success, negative on error. LENGTH_ONLY_E if derKey is NULL
and returning length only.
\param cert populated DecodedCert struct holding X.509 certificate
\param derKey output buffer to place DER encoded public key
\param derKeySz [IN/OUT] size of derKey buffer on input, size of public key
on return. If derKey is passed in as NULL, derKeySz will be set to required
buffer size for public key and LENGTH_ONLY_E will be returned from function.
\sa wc_GetPubKeyDerFromCert
*/
WOLFSSL_API int wc_GetPubKeyDerFromCert(struct DecodedCert* cert,
byte* derKey, word32* derKeySz);
/*!
\ingroup ASN

View File

@@ -30094,6 +30094,8 @@ static void test_wc_CertPemToDer(void)
free(cert_der);
if (cert_buf)
free(cert_buf);
printf(resultFmt, passed);
#endif
}
@@ -30129,6 +30131,8 @@ static void test_wc_PubKeyPemToDer(void)
free(cert_der);
if (cert_buf)
free(cert_buf);
printf(resultFmt, passed);
#endif
#endif
}
@@ -30152,9 +30156,172 @@ static void test_wc_PemPubKeyToDer(void)
free(cert_der);
}
printf(resultFmt, passed);
#endif
}
static void test_wc_GetPubKeyDerFromCert(void)
{
#if !defined(NO_RSA) || defined(HAVE_ECC)
int ret;
word32 idx = 0;
byte keyDer[TWOK_BUF]; /* large enough for up to RSA 2048 */
word32 keyDerSz = (word32)sizeof(keyDer);
DecodedCert decoded;
#if !defined(NO_RSA) && defined(WOLFSSL_CERT_REQ)
byte certBuf[6000]; /* for PEM and CSR, client-cert.pem is 5-6kB */
word32 certBufSz = sizeof(certBuf);
#endif
#if (!defined(USE_CERT_BUFFERS_2048) && !defined(USE_CERT_BUFFERS_1024)) || \
defined(WOLFSSL_CERT_REQ)
XFILE fp;
#endif
#ifndef NO_RSA
RsaKey rsaKey;
#if defined(USE_CERT_BUFFERS_2048)
byte* rsaCertDer = (byte*)client_cert_der_2048;
word32 rsaCertDerSz = sizeof_client_cert_der_2048;
#elif defined(USE_CERT_BUFFERS_1024)
byte* rsaCertDer = (byte*)client_cert_der_1024;
word32 rsaCertDerSz = sizeof_client_cert_der_1024;
#else
unsigned char rsaCertDer[TWOK_BUF];
word32 rsaCertDerSz;
#endif
#endif
#ifdef HAVE_ECC
ecc_key eccKey;
#if defined(USE_CERT_BUFFERS_256)
byte* eccCert = (byte*)cliecc_cert_der_256;
word32 eccCertSz = sizeof_cliecc_cert_der_256;
#else
unsigned char eccCert[ONEK_BUF];
word32 eccCertSz;
XFILE fp2;
#endif
#endif
printf(testingFmt, "wc_GetPubKeyDerFromCert()");
#ifndef NO_RSA
#if !defined(USE_CERT_BUFFERS_1024) && !defined(USE_CERT_BUFFERS_2048)
fp = XFOPEN("./certs/1024/client-cert.der", "rb");
AssertTrue((fp != XBADFILE));
rsaCertDerSz = (word32)XFREAD(rsaCertDer, 1, sizeof(rsaCertDer), fp);
XFCLOSE(fp);
#endif
/* good test case - RSA DER cert */
wc_InitDecodedCert(&decoded, rsaCertDer, rsaCertDerSz, NULL);
ret = wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL);
AssertIntEQ(ret, 0);
ret = wc_GetPubKeyDerFromCert(&decoded, keyDer, &keyDerSz);
AssertIntEQ(ret, 0);
AssertIntGT(keyDerSz, 0);
/* sanity check, verify we can import DER public key */
ret = wc_InitRsaKey(&rsaKey, NULL);
AssertIntEQ(ret, 0);
ret = wc_RsaPublicKeyDecode(keyDer, &idx, &rsaKey, keyDerSz);
AssertIntEQ(ret, 0);
wc_FreeRsaKey(&rsaKey);
/* test LENGTH_ONLY_E case */
keyDerSz = 0;
ret = wc_GetPubKeyDerFromCert(&decoded, NULL, &keyDerSz);
AssertIntEQ(ret, LENGTH_ONLY_E);
AssertIntGT(keyDerSz, 0);
/* bad args: DecodedCert NULL */
ret = wc_GetPubKeyDerFromCert(NULL, keyDer, &keyDerSz);
AssertIntEQ(ret, BAD_FUNC_ARG);
/* bad args: output key buff size */
ret = wc_GetPubKeyDerFromCert(&decoded, keyDer, NULL);
AssertIntEQ(ret, BAD_FUNC_ARG);
/* bad args: zero size output key buffer */
keyDerSz = 0;
ret = wc_GetPubKeyDerFromCert(&decoded, keyDer, &keyDerSz);
AssertIntEQ(ret, BAD_FUNC_ARG);
wc_FreeDecodedCert(&decoded);
/* Certificate Request Tests */
#ifdef WOLFSSL_CERT_REQ
{
XMEMSET(certBuf, 0, sizeof(certBuf));
fp = XFOPEN("./certs/csr.signed.der", "rb");
AssertTrue((fp != XBADFILE));
certBufSz = (word32)XFREAD(certBuf, 1, certBufSz, fp);
XFCLOSE(fp);
wc_InitDecodedCert(&decoded, certBuf, certBufSz, NULL);
ret = wc_ParseCert(&decoded, CERTREQ_TYPE, NO_VERIFY, NULL);
AssertIntEQ(ret, 0);
/* good test case - RSA DER certificate request */
keyDerSz = sizeof(keyDer);
ret = wc_GetPubKeyDerFromCert(&decoded, keyDer, &keyDerSz);
AssertIntEQ(ret, 0);
AssertIntGT(keyDerSz, 0);
/* sanity check, verify we can import DER public key */
ret = wc_InitRsaKey(&rsaKey, NULL);
AssertIntEQ(ret, 0);
idx = 0;
ret = wc_RsaPublicKeyDecode(keyDer, &idx, &rsaKey, keyDerSz);
AssertIntEQ(ret, 0);
wc_FreeRsaKey(&rsaKey);
wc_FreeDecodedCert(&decoded);
}
#endif /* WOLFSSL_CERT_REQ */
#endif /* NO_RSA */
#ifdef HAVE_ECC
#ifndef USE_CERT_BUFFERS_256
fp2 = XFOPEN("./certs/client-ecc-cert.der", "rb");
AssertTrue((fp2 != XBADFILE));
eccCertSz = (word32)XFREAD(eccCert, 1, ONEK_BUF, fp2);
XFCLOSE(fp2);
#endif
wc_InitDecodedCert(&decoded, eccCert, eccCertSz, NULL);
ret = wc_ParseCert(&decoded, CERT_TYPE, NO_VERIFY, NULL);
AssertIntEQ(ret, 0);
/* good test case - ECC */
XMEMSET(keyDer, 0, sizeof(keyDer));
keyDerSz = sizeof(keyDer);
ret = wc_GetPubKeyDerFromCert(&decoded, keyDer, &keyDerSz);
AssertIntEQ(ret, 0);
AssertIntGT(keyDerSz, 0);
/* sanity check, verify we can import DER public key */
ret = wc_ecc_init(&eccKey);
AssertIntEQ(ret, 0);
idx = 0; /* reset idx to 0, used above in RSA case */
ret = wc_EccPublicKeyDecode(keyDer, &idx, &eccKey, keyDerSz);
AssertIntEQ(ret, 0);
wc_ecc_free(&eccKey);
/* test LENGTH_ONLY_E case */
keyDerSz = 0;
ret = wc_GetPubKeyDerFromCert(&decoded, NULL, &keyDerSz);
AssertIntEQ(ret, LENGTH_ONLY_E);
AssertIntGT(keyDerSz, 0);
wc_FreeDecodedCert(&decoded);
#endif
printf(resultFmt, passed);
#endif /* !NO_RSA || HAVE_ECC */
}
static void test_wolfSSL_certs(void)
{
@@ -51933,6 +52100,7 @@ void ApiTest(void)
test_wc_CertPemToDer();
test_wc_PubKeyPemToDer();
test_wc_PemPubKeyToDer();
test_wc_GetPubKeyDerFromCert();
/*OCSP Stapling. */
AssertIntEQ(test_wolfSSL_UseOCSPStapling(), WOLFSSL_SUCCESS);

View File

@@ -17245,12 +17245,16 @@ static int DecodeCertReq(DecodedCert* cert, int* criticalExt)
int ParseCert(DecodedCert* cert, int type, int verify, void* cm)
{
int ret;
#ifndef WOLFSSL_NO_MALLOC
char* ptr;
#endif
ret = ParseCertRelative(cert, type, verify, cm);
if (ret < 0)
return ret;
#ifndef WOLFSSL_NO_MALLOC
/* cert->subjectCN not stored as copy of WOLFSSL_NO_MALLOC defind */
if (cert->subjectCNLen > 0) {
ptr = (char*) XMALLOC(cert->subjectCNLen + 1, cert->heap,
DYNAMIC_TYPE_SUBJECT_CN);
@@ -17261,7 +17265,10 @@ int ParseCert(DecodedCert* cert, int type, int verify, void* cm)
cert->subjectCN = ptr;
cert->subjectCNStored = 1;
}
#endif
#ifndef WOLFSSL_NO_MALLOC
/* cert->publicKey not stored as copy if WOLFSSL_NO_MALLOC defined */
if (cert->keyOID == RSAk &&
cert->publicKey != NULL && cert->pubKeySize > 0) {
ptr = (char*) XMALLOC(cert->pubKeySize, cert->heap,
@@ -17272,6 +17279,7 @@ int ParseCert(DecodedCert* cert, int type, int verify, void* cm)
cert->publicKey = (byte *)ptr;
cert->pubKeyStored = 1;
}
#endif
return ret;
}
@@ -19950,6 +19958,57 @@ int wc_PemPubKeyToDer(const char* fileName,
#endif /* !NO_FILESYSTEM && WOLFSSL_PEM_TO_DER */
/* Get public key in DER format from a populated DecodedCert struct.
*
* Users must call wc_InitDecodedCert() and wc_ParseCert() before calling
* this API. wc_InitDecodedCert() accepts a DER/ASN.1 encoded certificate.
* To convert a PEM cert to DER first use wc_CertPemToDer() before calling
* wc_InitDecodedCert().
*
* cert - populated DecodedCert struct holding X.509 certificate
* derKey - output buffer to place DER/ASN.1 encoded public key
* derKeySz [IN/OUT] - size of derKey buffer on input, size of public key
* on return. If derKey is passed in as NULL, derKeySz
* will be set to required buffer size for public key
* and LENGTH_ONLY_E will be returned from function.
* Returns 0 on success, or negative error code on failure. LENGTH_ONLY_E
* if derKey is NULL and returning length only.
*/
int wc_GetPubKeyDerFromCert(struct DecodedCert* cert,
byte* derKey, word32* derKeySz)
{
int ret = 0;
/* derKey may be NULL to return length only */
if (cert == NULL || derKeySz == NULL ||
(derKey != NULL && *derKeySz == 0)) {
return BAD_FUNC_ARG;
}
if (cert->publicKey == NULL) {
WOLFSSL_MSG("DecodedCert does not contain public key\n");
return BAD_FUNC_ARG;
}
/* if derKey is NULL, return required output buffer size in derKeySz */
if (derKey == NULL) {
*derKeySz = cert->pubKeySize;
ret = LENGTH_ONLY_E;
}
if (ret == 0) {
if (cert->pubKeySize > *derKeySz) {
WOLFSSL_MSG("Output buffer not large enough for public key DER");
ret = BAD_FUNC_ARG;
}
else {
XMEMCPY(derKey, cert->publicKey, cert->pubKeySize);
*derKeySz = cert->pubKeySize;
}
}
return ret;
}
#if !defined(NO_RSA) && (defined(WOLFSSL_CERT_GEN) || \
defined(WOLFSSL_KCAPI_RSA) || \

View File

@@ -12238,10 +12238,10 @@ WOLFSSL_TEST_SUBROUTINE int memory_test(void)
#ifdef WOLFSSL_CERT_GEN
static const char* otherCertPemFile = CERT_WRITE_TEMP_DIR "othercert.pem";
static const char* certPemFile = CERT_WRITE_TEMP_DIR "cert.pem";
#endif
#ifdef WOLFSSL_CERT_REQ
static const char* certReqDerFile = CERT_WRITE_TEMP_DIR "certreq.der";
static const char* certReqPemFile = CERT_WRITE_TEMP_DIR "certreq.pem";
#ifdef WOLFSSL_CERT_REQ
static const char* certReqDerFile = CERT_WRITE_TEMP_DIR "certreq.der";
static const char* certReqPemFile = CERT_WRITE_TEMP_DIR "certreq.pem";
#endif
#endif
#endif /* !NO_RSA */

View File

@@ -2327,9 +2327,9 @@ enum { /* ssl Constants */
WOLFSSL_UNKNOWN = -2,
WOLFSSL_FATAL_ERROR = -1,
WOLFSSL_FILETYPE_ASN1 = 2,
WOLFSSL_FILETYPE_PEM = 1,
WOLFSSL_FILETYPE_DEFAULT = 2, /* ASN1 */
WOLFSSL_FILETYPE_ASN1 = CTC_FILETYPE_ASN1,
WOLFSSL_FILETYPE_PEM = CTC_FILETYPE_PEM,
WOLFSSL_FILETYPE_DEFAULT = CTC_FILETYPE_ASN1, /* ASN1 */
WOLFSSL_VERIFY_NONE = 0,
WOLFSSL_VERIFY_PEER = 1 << 0,

View File

@@ -200,6 +200,9 @@ enum Ctc_Misc {
CTC_MAX_ALT_SIZE = WC_CTC_MAX_ALT_SIZE, /* may be huge, default: 16384 */
CTC_SERIAL_SIZE = 20,
CTC_GEN_SERIAL_SZ = 16,
CTC_FILETYPE_ASN1 = 2,
CTC_FILETYPE_PEM = 1,
CTC_FILETYPE_DEFAULT = 2,
#ifdef WOLFSSL_CERT_EXT
/* AKID could contains: hash + (Option) AuthCertIssuer,AuthCertSerialNum
* We support only hash */
@@ -766,6 +769,9 @@ WOLFSSL_API void wc_InitDecodedCert(struct DecodedCert*, const byte*, word32, vo
WOLFSSL_API void wc_FreeDecodedCert(struct DecodedCert*);
WOLFSSL_API int wc_ParseCert(struct DecodedCert*, int, int, void*);
WOLFSSL_API int wc_GetPubKeyDerFromCert(struct DecodedCert* cert,
byte* derKey, word32* derKeySz);
#ifdef __cplusplus
} /* extern "C" */
#endif