Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions doc/dox_comments/header_files/asn_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
168 changes: 168 additions & 0 deletions tests/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -30094,6 +30094,8 @@ static void test_wc_CertPemToDer(void)
free(cert_der);
if (cert_buf)
free(cert_buf);

printf(resultFmt, passed);
#endif
}

Expand Down Expand Up @@ -30129,6 +30131,8 @@ static void test_wc_PubKeyPemToDer(void)
free(cert_der);
if (cert_buf)
free(cert_buf);

printf(resultFmt, passed);
#endif
#endif
}
Expand All @@ -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)
Comment thread
dgarske marked this conversation as resolved.
Outdated
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)
{
Expand Down Expand Up @@ -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);
Expand Down
59 changes: 59 additions & 0 deletions wolfcrypt/src/asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -17272,6 +17279,7 @@ int ParseCert(DecodedCert* cert, int type, int verify, void* cm)
cert->publicKey = (byte *)ptr;
cert->pubKeyStored = 1;
}
#endif

return ret;
}
Expand Down Expand Up @@ -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) || \
Expand Down
8 changes: 4 additions & 4 deletions wolfcrypt/test/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
6 changes: 3 additions & 3 deletions wolfssl/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions wolfssl/wolfcrypt/asn_public.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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
Expand Down