Skip to content

Commit 1ae2480

Browse files
committed
Implement untrusted certs in wolfSSL_X509_STORE_CTX_init
1 parent a3bf7a6 commit 1ae2480

5 files changed

Lines changed: 229 additions & 63 deletions

File tree

src/ssl.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24265,6 +24265,38 @@ WOLFSSL_STACK* wolfSSL_sk_dup(WOLFSSL_STACK* sk)
2426524265
return NULL;
2426624266
}
2426724267

24268+
24269+
WOLFSSL_STACK* wolfSSL_shallow_sk_dup(WOLFSSL_STACK* sk)
24270+
{
24271+
24272+
WOLFSSL_STACK* ret = NULL;
24273+
WOLFSSL_STACK** prev = &ret;
24274+
24275+
WOLFSSL_ENTER("wolfSSL_sk_dup");
24276+
24277+
for (; sk != NULL; sk = sk->next) {
24278+
WOLFSSL_STACK* cur = wolfSSL_sk_new_node(sk->heap);
24279+
24280+
if (!cur) {
24281+
WOLFSSL_MSG("wolfSSL_sk_new_node error");
24282+
goto error;
24283+
}
24284+
24285+
XMEMCPY(cur, sk, sizeof(WOLFSSL_STACK));
24286+
cur->next = NULL;
24287+
24288+
*prev = cur;
24289+
prev = &cur->next;
24290+
}
24291+
return ret;
24292+
24293+
error:
24294+
if (ret) {
24295+
wolfSSL_sk_free(ret);
24296+
}
24297+
return NULL;
24298+
}
24299+
2426824300
/* Free the just the stack structure */
2426924301
void wolfSSL_sk_free(WOLFSSL_STACK* sk)
2427024302
{

src/ssl_certman.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1648,6 +1648,7 @@ int wolfSSL_CertManagerDisableCRL(WOLFSSL_CERT_MANAGER* cm)
16481648
if (ret == WOLFSSL_SUCCESS) {
16491649
/* Disable CRL checking. */
16501650
cm->crlEnabled = 0;
1651+
cm->crlCheckAll = 0;
16511652
}
16521653

16531654
return ret;

src/x509_str.c

Lines changed: 80 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,40 @@ int wolfSSL_X509_STORE_CTX_init(WOLFSSL_X509_STORE_CTX* ctx,
8484
#endif
8585

8686
ctx->chain = sk;
87-
/* Add intermediate certificates from stack to store */
88-
while (sk != NULL) {
89-
WOLFSSL_X509* x509_cert = sk->data.x509;
90-
if (x509_cert != NULL && x509_cert->isCa) {
91-
ret = wolfSSL_X509_STORE_add_cert(store, x509_cert);
92-
if (ret < 0) {
93-
return WOLFSSL_FAILURE;
87+
/* Add intermediate certs, that verify to a loaded CA, to the store */
88+
if (sk != NULL) {
89+
byte addedAtLeastOne = 1;
90+
WOLF_STACK_OF(WOLFSSL_X509)* head = wolfSSL_shallow_sk_dup(sk);
91+
if (head == NULL)
92+
return WOLFSSL_FAILURE;
93+
while (addedAtLeastOne) {
94+
WOLF_STACK_OF(WOLFSSL_X509)* cur = head;
95+
WOLF_STACK_OF(WOLFSSL_X509)** prev = &head;
96+
addedAtLeastOne = 0;
97+
while (cur) {
98+
WOLFSSL_X509* cert = cur->data.x509;
99+
if (cert != NULL && cert->derCert != NULL &&
100+
wolfSSL_CertManagerVerifyBuffer(store->cm,
101+
cert->derCert->buffer,
102+
cert->derCert->length,
103+
WOLFSSL_FILETYPE_ASN1) == WOLFSSL_SUCCESS) {
104+
ret = wolfSSL_X509_STORE_add_cert(store, cert);
105+
if (ret < 0) {
106+
wolfSSL_sk_free(head);
107+
return WOLFSSL_FAILURE;
108+
}
109+
addedAtLeastOne = 1;
110+
*prev = cur->next;
111+
wolfSSL_sk_free_node(cur);
112+
cur = *prev;
113+
}
114+
else {
115+
prev = &cur->next;
116+
cur = cur->next;
117+
}
94118
}
95119
}
96-
sk = sk->next;
120+
wolfSSL_sk_free(head);
97121
}
98122

99123
ctx->sesChain = NULL;
@@ -140,7 +164,9 @@ void wolfSSL_X509_STORE_CTX_free(WOLFSSL_X509_STORE_CTX* ctx)
140164
}
141165
}
142166

143-
167+
/* Its recommended to use a full free -> init cycle of all the objects
168+
* because wolfSSL_X509_STORE_CTX_init may modify the store too which doesn't
169+
* get reset here. */
144170
void wolfSSL_X509_STORE_CTX_cleanup(WOLFSSL_X509_STORE_CTX* ctx)
145171
{
146172
if (ctx != NULL) {
@@ -168,7 +194,7 @@ int GetX509Error(int e)
168194
{
169195
switch (e) {
170196
case ASN_BEFORE_DATE_E:
171-
return WOLFSSL_X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD;
197+
return WOLFSSL_X509_V_ERR_CERT_NOT_YET_VALID;
172198
case ASN_AFTER_DATE_E:
173199
return WOLFSSL_X509_V_ERR_CERT_HAS_EXPIRED;
174200
case ASN_NO_SIGNER_E: /* get issuer error if no CA found locally */
@@ -185,6 +211,9 @@ int GetX509Error(int e)
185211
return WOLFSSL_X509_V_ERR_CERT_SIGNATURE_FAILURE;
186212
case CRL_CERT_REVOKED:
187213
return WOLFSSL_X509_V_ERR_CERT_REVOKED;
214+
case 0:
215+
case 1:
216+
return 0;
188217
default:
189218
#ifdef HAVE_WOLFSSL_MSG_EX
190219
WOLFSSL_MSG_EX("Error not configured or implemented yet: %d", e);
@@ -195,6 +224,19 @@ int GetX509Error(int e)
195224
}
196225
}
197226

227+
static void SetupStoreCtxError(WOLFSSL_X509_STORE_CTX* ctx, int ret)
228+
{
229+
int depth = 0;
230+
int error = GetX509Error(ret);
231+
232+
/* Set error depth */
233+
if (ctx->chain)
234+
depth = (int)ctx->chain->num;
235+
236+
wolfSSL_X509_STORE_CTX_set_error(ctx, error);
237+
wolfSSL_X509_STORE_CTX_set_error_depth(ctx, depth);
238+
}
239+
198240
/* Verifies certificate chain using WOLFSSL_X509_STORE_CTX
199241
* returns 0 on success or < 0 on failure.
200242
*/
@@ -204,66 +246,39 @@ int wolfSSL_X509_verify_cert(WOLFSSL_X509_STORE_CTX* ctx)
204246

205247
if (ctx != NULL && ctx->store != NULL && ctx->store->cm != NULL
206248
&& ctx->current_cert != NULL && ctx->current_cert->derCert != NULL) {
207-
int ret = 0;
208-
int depth = 0;
209-
int error;
210-
#ifndef NO_ASN_TIME
211-
byte *afterDate, *beforeDate;
212-
#endif
213-
214-
ret = wolfSSL_CertManagerVerifyBuffer(ctx->store->cm,
249+
int ret = wolfSSL_CertManagerVerifyBuffer(ctx->store->cm,
215250
ctx->current_cert->derCert->buffer,
216251
ctx->current_cert->derCert->length,
217252
WOLFSSL_FILETYPE_ASN1);
218-
/* If there was an error, process it and add it to CTX */
219-
if (ret < 0) {
220-
/* Get corresponding X509 error */
221-
error = GetX509Error(ret);
222-
/* Set error depth */
223-
if (ctx->chain)
224-
depth = (int)ctx->chain->num;
225-
226-
wolfSSL_X509_STORE_CTX_set_error(ctx, error);
227-
wolfSSL_X509_STORE_CTX_set_error_depth(ctx, depth);
228-
#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
229-
if (ctx->store && ctx->store->verify_cb)
230-
ctx->store->verify_cb(0, ctx);
231-
#endif
232-
}
253+
SetupStoreCtxError(ctx, ret);
233254

234255
#ifndef NO_ASN_TIME
235-
error = 0;
236-
/* wolfSSL_CertManagerVerifyBuffer only returns ASN_AFTER_DATE_E or
237-
ASN_BEFORE_DATE_E if there are no additional errors found in the
238-
cert. Therefore, check if the cert is expired or not yet valid
239-
in order to return the correct expected error. */
240-
afterDate = ctx->current_cert->notAfter.data;
241-
beforeDate = ctx->current_cert->notBefore.data;
242-
243-
if (XVALIDATE_DATE(afterDate, (byte)ctx->current_cert->notAfter.type,
244-
AFTER) < 1) {
245-
error = WOLFSSL_X509_V_ERR_CERT_HAS_EXPIRED;
246-
}
247-
else if (XVALIDATE_DATE(beforeDate,
248-
(byte)ctx->current_cert->notBefore.type, BEFORE) < 1) {
249-
error = WOLFSSL_X509_V_ERR_CERT_NOT_YET_VALID;
256+
if (ret != ASN_BEFORE_DATE_E && ret != ASN_AFTER_DATE_E) {
257+
/* wolfSSL_CertManagerVerifyBuffer only returns ASN_AFTER_DATE_E or
258+
ASN_BEFORE_DATE_E if there are no additional errors found in the
259+
cert. Therefore, check if the cert is expired or not yet valid
260+
in order to return the correct expected error. */
261+
byte *afterDate = ctx->current_cert->notAfter.data;
262+
byte *beforeDate = ctx->current_cert->notBefore.data;
263+
264+
if (XVALIDATE_DATE(afterDate,
265+
(byte)ctx->current_cert->notAfter.type, AFTER) < 1) {
266+
ret = ASN_AFTER_DATE_E;
267+
}
268+
else if (XVALIDATE_DATE(beforeDate,
269+
(byte)ctx->current_cert->notBefore.type, BEFORE) < 1) {
270+
ret = ASN_BEFORE_DATE_E;
271+
}
272+
SetupStoreCtxError(ctx, ret);
250273
}
274+
#endif
251275

252-
if (error != 0 ) {
253-
wolfSSL_X509_STORE_CTX_set_error(ctx, error);
254-
wolfSSL_X509_STORE_CTX_set_error_depth(ctx, depth);
255-
#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
256-
if (ctx->store && ctx->store->verify_cb)
257-
ctx->store->verify_cb(0, ctx);
258-
#endif
259-
}
276+
#if defined(OPENSSL_ALL) || defined(WOLFSSL_QT)
277+
if (ctx->store && ctx->store->verify_cb)
278+
ret = ctx->store->verify_cb(ret >= 0 ? 1 : 0, ctx) == 1 ? 0 : -1;
260279
#endif
261280

262-
/* OpenSSL returns 0 when a chain can't be built */
263-
if (ret == ASN_NO_SIGNER_E)
264-
return WOLFSSL_FAILURE;
265-
else
266-
return ret;
281+
return ret >= 0 ? WOLFSSL_SUCCESS : WOLFSSL_FAILURE;
267282
}
268283
return WOLFSSL_FATAL_ERROR;
269284
}
@@ -1029,8 +1044,11 @@ WOLFSSL_API int wolfSSL_X509_STORE_load_locations(WOLFSSL_X509_STORE *str,
10291044

10301045
#ifdef HAVE_CRL
10311046
if (str->cm->crl == NULL) {
1047+
/* Workaround to allocate the internals to load CRL's but don't enable
1048+
* CRL checking by default */
10321049
if (wolfSSL_CertManagerEnableCRL(str->cm, WOLFSSL_CRL_CHECK)
1033-
!= WOLFSSL_SUCCESS) {
1050+
!= WOLFSSL_SUCCESS ||
1051+
wolfSSL_CertManagerDisableCRL(str->cm) != WOLFSSL_SUCCESS) {
10341052
WOLFSSL_MSG("Enable CRL failed");
10351053
wolfSSL_CTX_free(ctx);
10361054
return WOLFSSL_FAILURE;

tests/api.c

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35528,6 +35528,118 @@ static int test_wolfSSL_X509_STORE_CTX(void)
3552835528
return EXPECT_RESULT();
3552935529
}
3553035530

35531+
#if defined(OPENSSL_EXTRA)
35532+
static int test_X509_STORE_untrusted_load_cert_to_stack(const char* filename,
35533+
STACK_OF(X509)* chain)
35534+
{
35535+
EXPECT_DECLS;
35536+
XFILE fp = XBADFILE;
35537+
X509* cert = NULL;
35538+
35539+
ExpectTrue((fp = XFOPEN(filename, "rb"))
35540+
!= XBADFILE);
35541+
ExpectNotNull(cert = PEM_read_X509(fp, 0, 0, 0 ));
35542+
if (fp != XBADFILE) {
35543+
XFCLOSE(fp);
35544+
fp = XBADFILE;
35545+
}
35546+
ExpectIntEQ(sk_X509_push(chain, cert), 1);
35547+
if (EXPECT_FAIL())
35548+
X509_free(cert);
35549+
35550+
return EXPECT_RESULT();
35551+
}
35552+
35553+
static int test_X509_STORE_untrusted_certs(const char** filenames, int ret,
35554+
int err, int loadCA)
35555+
{
35556+
EXPECT_DECLS;
35557+
X509_STORE_CTX* ctx = NULL;
35558+
X509_STORE* str = NULL;
35559+
XFILE fp = XBADFILE;
35560+
X509* cert = NULL;
35561+
STACK_OF(X509)* untrusted = NULL;
35562+
35563+
ExpectTrue((fp = XFOPEN("./certs/intermediate/server-int-cert.pem", "rb"))
35564+
!= XBADFILE);
35565+
ExpectNotNull(cert = PEM_read_X509(fp, 0, 0, 0 ));
35566+
if (fp != XBADFILE) {
35567+
XFCLOSE(fp);
35568+
fp = XBADFILE;
35569+
}
35570+
35571+
ExpectNotNull(str = X509_STORE_new());
35572+
ExpectNotNull(ctx = X509_STORE_CTX_new());
35573+
ExpectNotNull(untrusted = sk_X509_new_null());
35574+
35575+
ExpectIntEQ(X509_STORE_set_flags(str, 0), 1);
35576+
if (loadCA) {
35577+
ExpectIntEQ(X509_STORE_load_locations(str, "./certs/ca-cert.pem", NULL),
35578+
1);
35579+
}
35580+
for (; *filenames; filenames++) {
35581+
ExpectIntEQ(test_X509_STORE_untrusted_load_cert_to_stack(*filenames,
35582+
untrusted), TEST_SUCCESS);
35583+
}
35584+
35585+
ExpectIntEQ(X509_STORE_CTX_init(ctx, str, cert, untrusted), 1);
35586+
ExpectIntEQ(X509_verify_cert(ctx), ret);
35587+
ExpectIntEQ(X509_STORE_CTX_get_error(ctx), err);
35588+
35589+
X509_free(cert);
35590+
X509_STORE_free(str);
35591+
X509_STORE_CTX_free(ctx);
35592+
sk_X509_pop_free(untrusted, NULL);
35593+
35594+
return EXPECT_RESULT();
35595+
}
35596+
#endif
35597+
35598+
static int test_X509_STORE_untrusted(void)
35599+
{
35600+
EXPECT_DECLS;
35601+
#if defined(OPENSSL_EXTRA)
35602+
const char* untrusted1[] = {
35603+
"./certs/intermediate/ca-int2-cert.pem",
35604+
NULL
35605+
};
35606+
const char* untrusted2[] = {
35607+
"./certs/intermediate/ca-int-cert.pem",
35608+
"./certs/intermediate/ca-int2-cert.pem",
35609+
NULL
35610+
};
35611+
const char* untrusted3[] = {
35612+
"./certs/intermediate/ca-int-cert.pem",
35613+
"./certs/intermediate/ca-int2-cert.pem",
35614+
"./certs/ca-cert.pem",
35615+
NULL
35616+
};
35617+
/* Adding unrelated certs that should be ignored */
35618+
const char* untrusted4[] = {
35619+
"./certs/client-ca.pem",
35620+
"./certs/intermediate/ca-int-cert.pem",
35621+
"./certs/server-cert.pem",
35622+
"./certs/intermediate/ca-int2-cert.pem",
35623+
NULL
35624+
};
35625+
35626+
/* Only immediate issuer in untrusted chaing. Fails since can't build chain
35627+
* to loaded CA. */
35628+
ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted1, 0,
35629+
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, 1), TEST_SUCCESS);
35630+
/* Succeeds because path to loaded CA is available. */
35631+
ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted2, 1, 0, 1),
35632+
TEST_SUCCESS);
35633+
/* Fails because root CA is in the untrusted stack */
35634+
ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted3, 0,
35635+
X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY, 0), TEST_SUCCESS);
35636+
/* Succeeds because path to loaded CA is available. */
35637+
ExpectIntEQ(test_X509_STORE_untrusted_certs(untrusted4, 1, 0, 1),
35638+
TEST_SUCCESS);
35639+
#endif
35640+
return EXPECT_RESULT();
35641+
}
35642+
3553135643
static int test_wolfSSL_X509_STORE_set_flags(void)
3553235644
{
3553335645
EXPECT_DECLS;
@@ -51485,7 +51597,8 @@ static int test_X509_LOOKUP_add_dir(void)
5148551597

5148651598
/* Now we SHOULD get CRL_MISSING, because we looked for PEM
5148751599
* in dir containing only ASN1/DER. */
51488-
ExpectIntEQ(X509_verify_cert(storeCtx), CRL_MISSING);
51600+
ExpectIntEQ(X509_verify_cert(storeCtx), WOLFSSL_FAILURE);
51601+
ExpectIntEQ(X509_STORE_CTX_get_error(storeCtx), CRL_MISSING);
5148951602

5149051603
X509_CRL_free(crl);
5149151604
X509_STORE_free(store);
@@ -67663,6 +67776,7 @@ TEST_CASE testCases[] = {
6766367776
TEST_DECL(test_wolfSSL_TBS),
6766467777

6766567778
TEST_DECL(test_wolfSSL_X509_STORE_CTX),
67779+
TEST_DECL(test_X509_STORE_untrusted),
6766667780
TEST_DECL(test_wolfSSL_X509_STORE_CTX_trusted_stack_cleanup),
6766767781
TEST_DECL(test_wolfSSL_X509_STORE_CTX_get0_current_issuer),
6766867782
TEST_DECL(test_wolfSSL_X509_STORE_set_flags),

wolfssl/ssl.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,7 @@ WOLFSSL_API WOLFSSL_STACK* wolfSSL_sk_new_node(void* heap);
15261526
WOLFSSL_API void wolfSSL_sk_free(WOLFSSL_STACK* sk);
15271527
WOLFSSL_API void wolfSSL_sk_free_node(WOLFSSL_STACK* in);
15281528
WOLFSSL_API WOLFSSL_STACK* wolfSSL_sk_dup(WOLFSSL_STACK* sk);
1529+
WOLFSSL_API WOLFSSL_STACK* wolfSSL_shallow_sk_dup(WOLFSSL_STACK* sk);
15291530
WOLFSSL_API int wolfSSL_sk_push_node(WOLFSSL_STACK** stack, WOLFSSL_STACK* in);
15301531
WOLFSSL_API WOLFSSL_STACK* wolfSSL_sk_get_node(WOLFSSL_STACK* sk, int idx);
15311532
WOLFSSL_API int wolfSSL_sk_push(WOLFSSL_STACK *st, const void *data);

0 commit comments

Comments
 (0)