Skip to content

Commit b3424c4

Browse files
Merge pull request #10966 from ejohnstown/upd-ocsp
Reject CR/LF and obs-fold in OCSP requests
2 parents 7dcc3de + 6b78c59 commit b3424c4

3 files changed

Lines changed: 68 additions & 0 deletions

File tree

src/ocsp.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,20 @@ WOLFSSL_OCSP_REQ_CTX* wolfSSL_OCSP_sendreq_new(WOLFSSL_BIO *bio,
17701770
return NULL;
17711771
}
17721772

1773+
/* Returns 0 if the string has no CR or LF, -1 if it does. */
1774+
static int OCSP_REQ_CTX_no_crlf(const char* value)
1775+
{
1776+
if (value != NULL) {
1777+
const char* c;
1778+
for (c = value; *c != '\0'; c++) {
1779+
if (*c == '\r' || *c == '\n')
1780+
return -1;
1781+
}
1782+
}
1783+
1784+
return 0;
1785+
}
1786+
17731787
int wolfSSL_OCSP_REQ_CTX_add1_header(WOLFSSL_OCSP_REQ_CTX *ctx,
17741788
const char *name, const char *value)
17751789
{
@@ -1779,6 +1793,16 @@ int wolfSSL_OCSP_REQ_CTX_add1_header(WOLFSSL_OCSP_REQ_CTX *ctx,
17791793
WOLFSSL_MSG("Bad parameter");
17801794
return WOLFSSL_FAILURE;
17811795
}
1796+
if (OCSP_REQ_CTX_no_crlf(name) != 0 || OCSP_REQ_CTX_no_crlf(value) != 0) {
1797+
WOLFSSL_MSG("CR/LF in header name or value");
1798+
return WOLFSSL_FAILURE;
1799+
}
1800+
/* A name starting with whitespace is an obs-fold continuation line
1801+
* (RFC 7230 Section 3.2.4) appending to the previous header's value. */
1802+
if (*name == ' ' || *name == '\t') {
1803+
WOLFSSL_MSG("Leading whitespace in header name");
1804+
return WOLFSSL_FAILURE;
1805+
}
17821806
if (wolfSSL_BIO_puts(ctx->reqResp, name) <= 0) {
17831807
WOLFSSL_MSG("wolfSSL_BIO_puts error");
17841808
return WOLFSSL_FAILURE;
@@ -1818,6 +1842,11 @@ int wolfSSL_OCSP_REQ_CTX_http(WOLFSSL_OCSP_REQ_CTX *ctx, const char *op,
18181842
if (path == NULL)
18191843
path = "/";
18201844

1845+
if (OCSP_REQ_CTX_no_crlf(op) != 0 || OCSP_REQ_CTX_no_crlf(path) != 0) {
1846+
WOLFSSL_MSG("CR/LF in HTTP op or path");
1847+
return WOLFSSL_FAILURE;
1848+
}
1849+
18211850
if (wolfSSL_BIO_printf(ctx->reqResp, http_hdr, op, path) <= 0) {
18221851
WOLFSSL_MSG("WOLFSSL_OCSP_REQ_CTX: wolfSSL_BIO_printf error");
18231852
return WOLFSSL_FAILURE;

src/ssl_api_crl_ocsp.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,6 +650,7 @@ int wolfSSL_OCSP_parse_url(const char* url, char** host, char** port,
650650
char** path, int* ssl)
651651
{
652652
const char* u;
653+
const char* c;
653654
const char* upath; /* path in u */
654655
const char* uport; /* port in u */
655656
const char* hostEnd;
@@ -667,6 +668,15 @@ int wolfSSL_OCSP_parse_url(const char* url, char** host, char** port,
667668
*path = NULL;
668669
*ssl = 0;
669670

671+
/* CR/LF in the parsed out host or path would split a request built from
672+
* them into extra header lines. */
673+
for (c = url; *c != '\0'; c++) {
674+
if (*c == '\r' || *c == '\n') {
675+
WOLFSSL_MSG("CR/LF in URL");
676+
goto err;
677+
}
678+
}
679+
670680
if (*(u++) != 'h') goto err;
671681
if (*(u++) != 't') goto err;
672682
if (*(u++) != 't') goto err;

tests/api.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22691,6 +22691,13 @@ static int test_wolfSSL_OCSP_parse_url(void)
2269122691
CK_OPU_FAIL("http/""/localhost");
2269222692
CK_OPU_FAIL("http:/localhost");
2269322693
CK_OPU_FAIL("https://localhost/path:1234");
22694+
/* CR/LF anywhere in the URL, paired or bare. */
22695+
CK_OPU_FAIL("http://localhost/\r\nX-Injected: yes");
22696+
CK_OPU_FAIL("http://localhost\r\n:1234/");
22697+
CK_OPU_FAIL("http://localhost/\nX-Injected: yes");
22698+
CK_OPU_FAIL("http://localhost/\rX-Injected: yes");
22699+
CK_OPU_FAIL("http://localhost\n:1234/");
22700+
CK_OPU_FAIL("http://localhost:12\r\n34/");
2269422701

2269522702
#undef CK_OPU_OK
2269622703
#undef CK_OPU_FAIL
@@ -23035,6 +23042,28 @@ static int test_wolfSSL_OCSP_REQ_CTX(void)
2303523042
ExpectNotNull(OCSP_request_add0_id(req, cid));
2303623043
ExpectIntEQ(OCSP_request_add1_nonce(req, NULL, -1), 1);
2303723044

23045+
ExpectNull(OCSP_sendreq_new(bio1, "/\r\nX-Injected: yes", NULL, -1));
23046+
ExpectNull(OCSP_sendreq_new(bio1, "/\nX-Injected: yes", NULL, -1));
23047+
23048+
/* Reject CR/LF and obs-fold, on a context that is thrown away so that the
23049+
* request assembled below stays clean. */
23050+
ExpectNotNull(ctx = OCSP_sendreq_new(bio1, "/", NULL, -1));
23051+
ExpectIntEQ(OCSP_REQ_CTX_http(ctx, "POST", "/\r\nX-Injected: yes"), 0);
23052+
ExpectIntEQ(OCSP_REQ_CTX_http(ctx, "POST\r\nX-Injected: yes", "/"), 0);
23053+
ExpectIntEQ(OCSP_REQ_CTX_add1_header(ctx, "X-Injected\r\nHost", "h"), 0);
23054+
ExpectIntEQ(OCSP_REQ_CTX_add1_header(ctx, "Host", "h\r\nX-Injected: yes"),
23055+
0);
23056+
ExpectIntEQ(OCSP_REQ_CTX_http(ctx, "POST", "/\nX-Injected: yes"), 0);
23057+
ExpectIntEQ(OCSP_REQ_CTX_http(ctx, "POST", "/\rX-Injected: yes"), 0);
23058+
ExpectIntEQ(OCSP_REQ_CTX_add1_header(ctx, "Host", "h\nX-Injected: yes"), 0);
23059+
ExpectIntEQ(OCSP_REQ_CTX_add1_header(ctx, "Host", "h\rX-Injected: yes"), 0);
23060+
ExpectIntEQ(OCSP_REQ_CTX_add1_header(ctx, " Host", "h"), 0);
23061+
ExpectIntEQ(OCSP_REQ_CTX_add1_header(ctx, "\tHost", "h"), 0);
23062+
/* A NULL value is allowed and emits just the name. */
23063+
ExpectIntEQ(OCSP_REQ_CTX_add1_header(ctx, "X-No-Value", NULL), 1);
23064+
OCSP_REQ_CTX_free(ctx);
23065+
ctx = NULL;
23066+
2303823067
ExpectNotNull(ctx = OCSP_sendreq_new(bio1, "/", NULL, -1));
2303923068
ExpectIntEQ(OCSP_REQ_CTX_add1_header(ctx, "Host", "127.0.0.1"), 1);
2304023069
ExpectIntEQ(OCSP_REQ_CTX_set1_req(ctx, req), 1);

0 commit comments

Comments
 (0)