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
2 changes: 2 additions & 0 deletions .wolfssl_known_macro_extras
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,7 @@ NO_WOLFSSL_AUTOSAR_CSM
NO_WOLFSSL_BASE64_DECODE
NO_WOLFSSL_BN_CTX
NO_WOLFSSL_CURVE25519_BLINDING
NO_WOLFSSL_DYNAMIC_PEER_CERT
NO_WOLFSSL_MSG_EX
NO_WOLFSSL_RENESAS_FSPSM_AES
NO_WOLFSSL_RENESAS_FSPSM_HASH
Expand Down Expand Up @@ -980,6 +981,7 @@ WOLFSSL_DTLS_DISALLOW_FUTURE
WOLFSSL_DTLS_RESEND_ONLY_TIMEOUT
WOLFSSL_DUMP_MEMIO_STREAM
WOLFSSL_DUP_CERTPOL
WOLFSSL_DYNAMIC_PEER_CERT
WOLFSSL_EARLY_DATA_NO_ANTI_REPLAY
WOLFSSL_ECC_GEN_REJECT_SAMPLING
WOLFSSL_ECC_NO_SMALL_STACK
Expand Down
11 changes: 8 additions & 3 deletions doc/dox_comments/header_files/ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -7492,9 +7492,13 @@ int wolfSSL_state(WOLFSSL* ssl);

\brief This function gets the peer’s certificate.

\return pointer a pointer to the peerCert member of the WOLFSSL_X509
structure if it exists.
\return 0 returned if the peer certificate issuer size is not defined.
\return pointer to the peer's WOLFSSL_X509 certificate if one was kept.
With WOLFSSL_DYNAMIC_PEER_CERT (on by default with WOLFSSL_SMALL_STACK)
and OPENSSL_EXTRA or OPENSSL_EXTRA_X509_SMALL this is the certificate
object kept by the WOLFSSL with its reference count incremented, as
OpenSSL does; otherwise it is a copy. Either way the caller must free it
with wolfSSL_X509_free(), and it stays valid after wolfSSL_free().
\return NULL if there is no peer certificate or memory allocation fails.

\param ssl a pointer to a WOLFSSL structure, created using wolfSSL_new().

Expand All @@ -7507,6 +7511,7 @@ int wolfSSL_state(WOLFSSL* ssl);

if(peerCert){
// You have a pointer peerCert to the peer certification
wolfSSL_X509_free(peerCert);
}
\endcode

Expand Down
86 changes: 65 additions & 21 deletions src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -6168,6 +6168,52 @@ void ReinitX509(WOLFSSL_X509* x509)
}


#ifdef KEEP_PEER_CERT
/* Release the kept peer certificate so that none is kept.
*
* With WOLFSSL_DYNAMIC_PEER_CERT this drops the SSL's reference; references
* handed out by wolfSSL_get_peer_certificate() keep the object alive.
* Otherwise the embedded object is emptied for reuse.
*/
void FreePeerCert(WOLFSSL* ssl)
{
#ifdef WOLFSSL_DYNAMIC_PEER_CERT
if (ssl->peerCert != NULL) {
wolfSSL_X509_free(ssl->peerCert);
ssl->peerCert = NULL;
}
#else
FreeX509(&ssl->peerCert);
InitX509(&ssl->peerCert, 0, ssl->heap);
#endif
}

#ifndef NO_ASN
/* Make the certificate in dCert the kept peer certificate.
*
* With WOLFSSL_DYNAMIC_PEER_CERT the previous certificate is released, not
* overwritten, and a new object allocated, so references to the previous one
* stay valid. Otherwise the embedded object is emptied and filled again. A
* copy that fails part way is still kept and the error is returned.
*
* @return 0 on success.
* @return MEMORY_E when the object cannot be allocated; no cert is kept.
* @return Other error from CopyDecodedToX509().
*/
int SetPeerCert(WOLFSSL* ssl, DecodedCert* dCert)
{
FreePeerCert(ssl);
#ifdef WOLFSSL_DYNAMIC_PEER_CERT
ssl->peerCert = wolfSSL_X509_new_ex(ssl->heap);
if (ssl->peerCert == NULL)
return MEMORY_E;
#endif
return CopyDecodedToX509(GetPeerCert(ssl), dCert);
}
#endif /* !NO_ASN */
#endif /* KEEP_PEER_CERT */


#if !defined(NO_WOLFSSL_SERVER) || (!defined(NO_WOLFSSL_CLIENT) && \
!defined(WOLFSSL_NO_CLIENT_AUTH))
#if !defined(WOLFSSL_NO_TLS12)
Expand Down Expand Up @@ -9321,7 +9367,7 @@ int InitSSL(WOLFSSL* ssl, WOLFSSL_CTX* ctx, int writeDup)
}
#endif

#ifdef KEEP_PEER_CERT
#if defined(KEEP_PEER_CERT) && !defined(WOLFSSL_DYNAMIC_PEER_CERT)
InitX509(&ssl->peerCert, 0, ssl->heap);
#endif

Expand Down Expand Up @@ -10736,7 +10782,9 @@ void wolfSSL_ResourceFree(WOLFSSL* ssl)
if (ssl->x509_store_pt)
wolfSSL_X509_STORE_free(ssl->x509_store_pt);
#endif
#ifdef KEEP_PEER_CERT
#ifdef WOLFSSL_DYNAMIC_PEER_CERT
FreePeerCert(ssl);
#elif defined(KEEP_PEER_CERT)
FreeX509(&ssl->peerCert);
#endif

Expand Down Expand Up @@ -17201,14 +17249,15 @@ int SetupStoreCtxCallback(WOLFSSL_X509_STORE_CTX** store_pt,
if (args->certIdx == 0) {
/* Copy the leaf once, here or in ProcessPeerCerts(). */
if (!args->peerCertSet) {
FreeX509(&ssl->peerCert);
InitX509(&ssl->peerCert, 0, ssl->heap);
if (CopyDecodedToX509(&ssl->peerCert, args->dCert) == 0)
if (SetPeerCert(ssl, args->dCert) == 0)
args->peerCertSet = 1;
else
WOLFSSL_MSG("Unable to copy to ssl->peerCert");
}
store->current_cert = &ssl->peerCert; /* use existing X509 */
/* use the kept X509, owned by ssl */
store->current_cert = GetPeerCert(ssl);
if (store->current_cert == NULL)
goto mem_error;
}
else
#endif
Expand Down Expand Up @@ -20653,10 +20702,8 @@ int ProcessPeerCerts(WOLFSSL* ssl, byte* input, word32* inOutIdx,
if (args->fatal == 0 && !args->peerCertSet) {
int copyRet = 0;

/* free old peer cert */
FreeX509(&ssl->peerCert);
InitX509(&ssl->peerCert, 0, ssl->heap);
copyRet = CopyDecodedToX509(&ssl->peerCert, args->dCert);
/* replace old peer cert */
copyRet = SetPeerCert(ssl, args->dCert);
if (copyRet == 0) {
args->peerCertSet = 1;
}
Expand Down Expand Up @@ -45422,12 +45469,13 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
if (!ssl->options.dtls) {
const byte* certDer = NULL;
word32 certDerSz = 0;
WOLFSSL_X509* peer = GetPeerCert(ssl);

if (ssl->peerCert.derCert != NULL &&
ssl->peerCert.derCert->length > 0) {
if (peer != NULL && peer->derCert != NULL &&
peer->derCert->length > 0) {
/* Use current peer certificate */
certDer = ssl->peerCert.derCert->buffer;
certDerSz = ssl->peerCert.derCert->length;
certDer = peer->derCert->buffer;
certDerSz = peer->derCert->length;
}
#ifdef SESSION_CERTS
else if (ssl->session->chain.count > 0) {
Expand Down Expand Up @@ -45925,8 +45973,7 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)

/* Clear any peer cert state that may have been copied from the session
* cache by wolfSSL_DupSession before we got here. */
FreeX509(&ssl->peerCert);
InitX509(&ssl->peerCert, 0, ssl->heap);
FreePeerCert(ssl);
#ifdef SESSION_CERTS
ssl->session->chain.count = 0;
#endif
Expand Down Expand Up @@ -45964,12 +46011,9 @@ static int AddPSKtoPreMasterSecret(WOLFSSL* ssl)
AddSessionCertToChain(&ssl->session->chain,
it->peerCert, peerCertLen);
#endif
FreeX509(&ssl->peerCert);
InitX509(&ssl->peerCert, 0, ssl->heap);
ret = CopyDecodedToX509(&ssl->peerCert, dCert);
ret = SetPeerCert(ssl, dCert);
if (ret != 0) {
FreeX509(&ssl->peerCert);
InitX509(&ssl->peerCert, 0, ssl->heap);
FreePeerCert(ssl);
}
}
FreeDecodedCert(dCert);
Expand Down
7 changes: 3 additions & 4 deletions src/ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -4022,8 +4022,8 @@ const char *wolfSSL_get0_peername(WOLFSSL *ssl) {
else if (ssl->session && ssl->session->peer)
return ssl->session->peer->subjectCN;
#ifdef KEEP_PEER_CERT
else if (ssl->peerCert.subjectCN[0])
return ssl->peerCert.subjectCN;
else if (GetPeerCert(ssl) != NULL && GetPeerCert(ssl)->subjectCN[0])
return GetPeerCert(ssl)->subjectCN;
#endif
else {
ssl->error = NO_PEER_CERT;
Expand Down Expand Up @@ -6141,8 +6141,7 @@ size_t wolfSSL_get_client_random(const WOLFSSL* ssl, unsigned char* out,
return WOLFSSL_FAILURE;

#ifdef KEEP_PEER_CERT
FreeX509(&ssl->peerCert);
InitX509(&ssl->peerCert, 0, ssl->heap);
FreePeerCert(ssl);
#endif

#ifdef WOLFSSL_QUIC
Expand Down
100 changes: 71 additions & 29 deletions src/ssl_api_cert.c
Original file line number Diff line number Diff line change
Expand Up @@ -2227,12 +2227,12 @@ int wolfSSL_cmp_peer_cert_to_file(WOLFSSL* ssl, const char *fname)
XFILE file = XBADFILE;
long sz = 0;
void* heap = ssl->ctx->heap;
WOLFSSL_X509* peer_cert = &ssl->peerCert;
WOLFSSL_X509* peer_cert = GetPeerCert(ssl);
DerBuffer* fileDer = NULL;

/* handle gracefully if called before handshake, or if peer did not
* present a cert. */
if (peer_cert->derCert == NULL) {
if ((peer_cert == NULL) || (peer_cert->derCert == NULL)) {
WOLFSSL_MSG("wolfSSL_cmp_peer_cert_to_file without peer cert");
ret = WOLFSSL_FATAL_ERROR;
}
Expand Down Expand Up @@ -3053,11 +3053,59 @@ static int DecodeToX509(WOLFSSL_X509* x509, const byte* in, int len)


#ifdef KEEP_PEER_CERT
/* Get a copy of the peer's certificate.
/* Get the kept peer certificate, owned by the SSL/TLS object.
*
* The certificate is decoded from the session chain when not already
* available on the object. Caller must free the returned certificate with
* wolfSSL_X509_free().
* The certificate is decoded from the session chain, and kept, when not
* already available on the object.
*
* @param [in, out] ssl SSL/TLS object.
* @return Kept peer certificate on success.
* @return NULL when no peer certificate is available or it cannot be
* decoded.
*/
static WOLFSSL_X509* LoadPeerCert(WOLFSSL* ssl)
{
WOLFSSL_X509* peer = GetPeerCert(ssl);

#ifdef SESSION_CERTS
if (((peer == NULL) || (peer->issuer.sz == 0)) &&
(ssl->session->chain.count > 0)) {
#ifdef WOLFSSL_DYNAMIC_PEER_CERT
WOLFSSL_X509* x509 = wolfSSL_X509_new_ex(ssl->heap);
if ((x509 != NULL) && (DecodeToX509(x509,
ssl->session->chain.certs[0].buffer,
ssl->session->chain.certs[0].length) == 0)) {
FreePeerCert(ssl);
ssl->peerCert = x509;
peer = x509;
}
else {
wolfSSL_X509_free(x509);
peer = NULL;
}
#else
if (DecodeToX509(peer, ssl->session->chain.certs[0].buffer,
ssl->session->chain.certs[0].length) != 0) {
peer = NULL;
}
#endif
}
#endif
if ((peer != NULL) && (peer->issuer.sz == 0)) {
peer = NULL;
}

return peer;
}

/* Get the peer's certificate.
*
* The certificate is decoded from the session chain, and kept, when not
* already available on the object. With WOLFSSL_DYNAMIC_PEER_CERT and X509
* reference counting (OPENSSL_EXTRA or OPENSSL_EXTRA_X509_SMALL) the kept
* object is returned with a new reference, as OpenSSL does; otherwise a copy
* is returned. Either way the caller must free the returned certificate with
* wolfSSL_X509_free() and it stays valid after the SSL/TLS object is freed.
*
* @param [in, out] ssl SSL/TLS object.
* @return Peer's X509 certificate on success.
Expand All @@ -3068,22 +3116,22 @@ WOLFSSL_ABI
WOLFSSL_X509* wolfSSL_get_peer_certificate(WOLFSSL* ssl)
{
WOLFSSL_X509* ret = NULL;
WOLFSSL_X509* peer = NULL;

WOLFSSL_ENTER("wolfSSL_get_peer_certificate");

if (ssl != NULL) {
if (ssl->peerCert.issuer.sz > 0) {
ret = wolfSSL_X509_dup(&ssl->peerCert);
}
#ifdef SESSION_CERTS
else if (ssl->session->chain.count > 0) {
if (DecodeToX509(&ssl->peerCert,
ssl->session->chain.certs[0].buffer,
ssl->session->chain.certs[0].length) == 0) {
ret = wolfSSL_X509_dup(&ssl->peerCert);
}
peer = LoadPeerCert(ssl);
}
if (peer != NULL) {
#if defined(WOLFSSL_DYNAMIC_PEER_CERT) && \
(defined(OPENSSL_EXTRA) || defined(OPENSSL_EXTRA_X509_SMALL))
if (wolfSSL_X509_up_ref(peer) == WOLFSSL_SUCCESS) {
ret = peer;
Comment thread
LinuxJedi marked this conversation as resolved.
Resolved
}
#endif
#else
ret = wolfSSL_X509_dup(peer);
#endif
}
WOLFSSL_LEAVE("wolfSSL_get_peer_certificate", ret != NULL);
return ret;
Expand Down Expand Up @@ -3187,8 +3235,9 @@ static int PushPeerCertToChain(const WOLFSSL* ssl, int idx, WOLFSSL_STACK* sk,

if (ssl->session->chain.certs[idx].length == 0) {
#ifdef KEEP_PEER_CERT
if ((idx == 0) && (ssl->peerCert.issuer.sz > 0)) {
x509 = wolfSSL_X509_dup((WOLFSSL_X509*)&ssl->peerCert);
if ((idx == 0) && (GetPeerCert(ssl) != NULL) &&
(GetPeerCert(ssl)->issuer.sz > 0)) {
x509 = wolfSSL_X509_dup(GetPeerCert(ssl));
if (x509 == NULL) {
WOLFSSL_MSG("Error duplicating peer certificate");
ret = MEMORY_E;
Expand Down Expand Up @@ -3374,19 +3423,12 @@ WOLF_STACK_OF(WOLFSSL_X509) *wolfSSL_get0_verified_chain(const WOLFSSL *ssl)
}

if (!err) {
peerCert = wolfSSL_get_peer_certificate((WOLFSSL*)ssl);
/* Owned by ssl, so not freed here. */
peerCert = LoadPeerCert((WOLFSSL*)ssl);
if (peerCert == NULL) {
WOLFSSL_MSG("wolfSSL_get_peer_certificate error");
WOLFSSL_MSG("No peer certificate");
err = 1;
}
else {
/* wolfSSL_get_peer_certificate returns a copy. We want the
* internal member so that we don't have to worry about free'ing
* it. We call wolfSSL_get_peer_certificate so that we don't have
* to worry about setting up the internal pointer. */
wolfSSL_X509_free(peerCert);
peerCert = (WOLFSSL_X509*)&ssl->peerCert;
}
}

if (!err) {
Expand Down
Loading
Loading