Skip to content

Commit 16bb32e

Browse files
icingbagder
authored andcommitted
sectransp: fix for incomplete read/writes
SecureTransport expects result code errSSLWouldBlock when the requested length could not be sent/recieved in full. The previous code returned noErr, which let SecureTransport to believe that the IO had terminated prematurely. Fixes #10227 Closes #10235
1 parent 21f5b6b commit 16bb32e

File tree

1 file changed

+88
-40
lines changed

1 file changed

+88
-40
lines changed

lib/vtls/sectransp.c

Lines changed: 88 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,15 @@
136136
/* The last #include file should be: */
137137
#include "memdebug.h"
138138

139+
140+
#define DEBUG_CF 0
141+
142+
#if DEBUG_CF
143+
#define CF_DEBUGF(x) x
144+
#else
145+
#define CF_DEBUGF(x) do { } while(0)
146+
#endif
147+
139148
/* From MacTypes.h (which we can't include because it isn't present in iOS: */
140149
#define ioErr -36
141150
#define paramErr -50
@@ -838,6 +847,8 @@ static OSStatus bio_cf_in_read(SSLConnectionRef connection,
838847

839848
DEBUGASSERT(data);
840849
nread = Curl_conn_cf_recv(cf->next, data, buf, *dataLength, &result);
850+
CF_DEBUGF(infof(data, CFMSG(cf, "bio_read(len=%zu) -> %zd, result=%d"),
851+
*dataLength, nread, result));
841852
if(nread < 0) {
842853
switch(result) {
843854
case CURLE_OK:
@@ -851,6 +862,9 @@ static OSStatus bio_cf_in_read(SSLConnectionRef connection,
851862
}
852863
nread = 0;
853864
}
865+
else if((size_t)nread < *dataLength) {
866+
rtn = errSSLWouldBlock;
867+
}
854868
*dataLength = nread;
855869
return rtn;
856870
}
@@ -865,22 +879,27 @@ static OSStatus bio_cf_out_write(SSLConnectionRef connection,
865879
struct Curl_easy *data = connssl->call_data;
866880
ssize_t nwritten;
867881
CURLcode result;
868-
OSStatus ortn = noErr;
882+
OSStatus rtn = noErr;
869883

870884
DEBUGASSERT(data);
871885
nwritten = Curl_conn_cf_send(cf->next, data, buf, *dataLength, &result);
886+
CF_DEBUGF(infof(data, CFMSG(cf, "bio_send(len=%zu) -> %zd, result=%d"),
887+
*dataLength, nwritten, result));
872888
if(nwritten <= 0) {
873889
if(result == CURLE_AGAIN) {
874-
ortn = errSSLWouldBlock;
890+
rtn = errSSLWouldBlock;
875891
backend->ssl_direction = true;
876892
}
877893
else {
878-
ortn = ioErr;
894+
rtn = ioErr;
879895
}
880896
nwritten = 0;
881897
}
898+
else if((size_t)nwritten < *dataLength) {
899+
rtn = errSSLWouldBlock;
900+
}
882901
*dataLength = nwritten;
883-
return ortn;
902+
return rtn;
884903
}
885904

886905
#ifndef CURL_DISABLE_VERBOSE_STRINGS
@@ -1638,6 +1657,7 @@ static CURLcode sectransp_connect_step1(struct Curl_cfilter *cf,
16381657

16391658
DEBUGASSERT(backend);
16401659

1660+
CF_DEBUGF(infof(data, CFMSG(cf, "connect_step1")));
16411661
GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
16421662
#endif /* CURL_BUILD_MAC */
16431663

@@ -2236,15 +2256,21 @@ static int append_cert_to_array(struct Curl_easy *data,
22362256
return CURLE_OK;
22372257
}
22382258

2239-
static CURLcode verify_cert_buf(struct Curl_easy *data,
2259+
static CURLcode verify_cert_buf(struct Curl_cfilter *cf,
2260+
struct Curl_easy *data,
22402261
const unsigned char *certbuf, size_t buflen,
22412262
SSLContextRef ctx)
22422263
{
22432264
int n = 0, rc;
22442265
long res;
22452266
unsigned char *der;
22462267
size_t derlen, offset = 0;
2247-
2268+
OSStatus ret;
2269+
SecTrustResultType trust_eval;
2270+
CFMutableArrayRef array = NULL;
2271+
SecTrustRef trust = NULL;
2272+
CURLcode result = CURLE_PEER_FAILED_VERIFICATION;
2273+
(void)cf;
22482274
/*
22492275
* Certbuf now contains the contents of the certificate file, which can be
22502276
* - a single DER certificate,
@@ -2254,11 +2280,11 @@ static CURLcode verify_cert_buf(struct Curl_easy *data,
22542280
* Go through certbuf, and convert any PEM certificate in it into DER
22552281
* format.
22562282
*/
2257-
CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
2258-
&kCFTypeArrayCallBacks);
2283+
array = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
22592284
if(!array) {
22602285
failf(data, "SSL: out of memory creating CA certificate array");
2261-
return CURLE_OUT_OF_MEMORY;
2286+
result = CURLE_OUT_OF_MEMORY;
2287+
goto out;
22622288
}
22632289

22642290
while(offset < buflen) {
@@ -2270,19 +2296,20 @@ static CURLcode verify_cert_buf(struct Curl_easy *data,
22702296
*/
22712297
res = pem_to_der((const char *)certbuf + offset, &der, &derlen);
22722298
if(res < 0) {
2273-
CFRelease(array);
22742299
failf(data, "SSL: invalid CA certificate #%d (offset %zu) in bundle",
22752300
n, offset);
2276-
return CURLE_SSL_CACERT_BADFILE;
2301+
result = CURLE_SSL_CACERT_BADFILE;
2302+
goto out;
22772303
}
22782304
offset += res;
22792305

22802306
if(res == 0 && offset == 0) {
22812307
/* This is not a PEM file, probably a certificate in DER format. */
22822308
rc = append_cert_to_array(data, certbuf, buflen, array);
22832309
if(rc != CURLE_OK) {
2284-
CFRelease(array);
2285-
return rc;
2310+
CF_DEBUGF(infof(data, CFMSG(cf, "append_cert for CA failed")));
2311+
result = rc;
2312+
goto out;
22862313
}
22872314
break;
22882315
}
@@ -2294,63 +2321,73 @@ static CURLcode verify_cert_buf(struct Curl_easy *data,
22942321
rc = append_cert_to_array(data, der, derlen, array);
22952322
free(der);
22962323
if(rc != CURLE_OK) {
2297-
CFRelease(array);
2298-
return rc;
2324+
CF_DEBUGF(infof(data, CFMSG(cf, "append_cert for CA failed")));
2325+
result = rc;
2326+
goto out;
22992327
}
23002328
}
23012329

2302-
SecTrustRef trust;
2303-
OSStatus ret = SSLCopyPeerTrust(ctx, &trust);
2330+
ret = SSLCopyPeerTrust(ctx, &trust);
23042331
if(!trust) {
23052332
failf(data, "SSL: error getting certificate chain");
2306-
CFRelease(array);
2307-
return CURLE_PEER_FAILED_VERIFICATION;
2333+
goto out;
23082334
}
23092335
else if(ret != noErr) {
2310-
CFRelease(array);
23112336
failf(data, "SSLCopyPeerTrust() returned error %d", ret);
2312-
return CURLE_PEER_FAILED_VERIFICATION;
2337+
goto out;
23132338
}
23142339

2340+
CF_DEBUGF(infof(data, CFMSG(cf, "setting %d trust anchors"), n));
23152341
ret = SecTrustSetAnchorCertificates(trust, array);
23162342
if(ret != noErr) {
2317-
CFRelease(array);
2318-
CFRelease(trust);
23192343
failf(data, "SecTrustSetAnchorCertificates() returned error %d", ret);
2320-
return CURLE_PEER_FAILED_VERIFICATION;
2344+
goto out;
23212345
}
23222346
ret = SecTrustSetAnchorCertificatesOnly(trust, true);
23232347
if(ret != noErr) {
2324-
CFRelease(array);
2325-
CFRelease(trust);
23262348
failf(data, "SecTrustSetAnchorCertificatesOnly() returned error %d", ret);
2327-
return CURLE_PEER_FAILED_VERIFICATION;
2349+
goto out;
23282350
}
23292351

2330-
SecTrustResultType trust_eval = 0;
2352+
trust_eval = 0;
23312353
ret = SecTrustEvaluate(trust, &trust_eval);
2332-
CFRelease(array);
2333-
CFRelease(trust);
23342354
if(ret != noErr) {
23352355
failf(data, "SecTrustEvaluate() returned error %d", ret);
2336-
return CURLE_PEER_FAILED_VERIFICATION;
2356+
goto out;
23372357
}
23382358

23392359
switch(trust_eval) {
23402360
case kSecTrustResultUnspecified:
2361+
/* what does this really mean? */
2362+
CF_DEBUGF(infof(data, CFMSG(cf, "trust result: Unspecified")));
2363+
result = CURLE_OK;
2364+
goto out;
23412365
case kSecTrustResultProceed:
2342-
return CURLE_OK;
2366+
CF_DEBUGF(infof(data, CFMSG(cf, "trust result: Proceed")));
2367+
result = CURLE_OK;
2368+
goto out;
23432369

23442370
case kSecTrustResultRecoverableTrustFailure:
2371+
failf(data, "SSL: peer not verified: RecoverableTrustFailure");
2372+
goto out;
23452373
case kSecTrustResultDeny:
2374+
failf(data, "SSL: peer not verified: Deny");
2375+
goto out;
23462376
default:
2347-
failf(data, "SSL: certificate verification failed (result: %d)",
2348-
trust_eval);
2349-
return CURLE_PEER_FAILED_VERIFICATION;
2377+
failf(data, "SSL: perr not verified: result=%d", trust_eval);
2378+
goto out;
23502379
}
2380+
2381+
out:
2382+
if(trust)
2383+
CFRelease(trust);
2384+
if(array)
2385+
CFRelease(array);
2386+
return result;
23512387
}
23522388

2353-
static CURLcode verify_cert(struct Curl_easy *data, const char *cafile,
2389+
static CURLcode verify_cert(struct Curl_cfilter *cf,
2390+
struct Curl_easy *data, const char *cafile,
23542391
const struct curl_blob *ca_info_blob,
23552392
SSLContextRef ctx)
23562393
{
@@ -2359,6 +2396,7 @@ static CURLcode verify_cert(struct Curl_easy *data, const char *cafile,
23592396
size_t buflen;
23602397

23612398
if(ca_info_blob) {
2399+
CF_DEBUGF(infof(data, CFMSG(cf, "verify_peer, CA from config blob")));
23622400
certbuf = (unsigned char *)malloc(ca_info_blob->len + 1);
23632401
if(!certbuf) {
23642402
return CURLE_OUT_OF_MEMORY;
@@ -2368,6 +2406,8 @@ static CURLcode verify_cert(struct Curl_easy *data, const char *cafile,
23682406
certbuf[ca_info_blob->len]='\0';
23692407
}
23702408
else if(cafile) {
2409+
CF_DEBUGF(infof(data, CFMSG(cf, "verify_peer, CA from file '%s'"),
2410+
cafile));
23712411
if(read_cert(cafile, &certbuf, &buflen) < 0) {
23722412
failf(data, "SSL: failed to read or invalid CA certificate");
23732413
return CURLE_SSL_CACERT_BADFILE;
@@ -2376,7 +2416,7 @@ static CURLcode verify_cert(struct Curl_easy *data, const char *cafile,
23762416
else
23772417
return CURLE_SSL_CACERT_BADFILE;
23782418

2379-
result = verify_cert_buf(data, certbuf, buflen, ctx);
2419+
result = verify_cert_buf(cf, data, certbuf, buflen, ctx);
23802420
free(certbuf);
23812421
return result;
23822422
}
@@ -2503,8 +2543,10 @@ static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
25032543
|| ssl_connect_2_reading == connssl->connecting_state
25042544
|| ssl_connect_2_writing == connssl->connecting_state);
25052545
DEBUGASSERT(backend);
2546+
CF_DEBUGF(infof(data, CFMSG(cf, "connect_step2")));
25062547

25072548
/* Here goes nothing: */
2549+
check_handshake:
25082550
err = SSLHandshake(backend->ssl_ctx);
25092551

25102552
if(err != noErr) {
@@ -2519,14 +2561,14 @@ static CURLcode sectransp_connect_step2(struct Curl_cfilter *cf,
25192561
case -9841:
25202562
if((conn_config->CAfile || conn_config->ca_info_blob) &&
25212563
conn_config->verifypeer) {
2522-
CURLcode result = verify_cert(data, conn_config->CAfile,
2564+
CURLcode result = verify_cert(cf, data, conn_config->CAfile,
25232565
conn_config->ca_info_blob,
25242566
backend->ssl_ctx);
25252567
if(result)
25262568
return result;
25272569
}
25282570
/* the documentation says we need to call SSLHandshake() again */
2529-
return sectransp_connect_step2(cf, data);
2571+
goto check_handshake;
25302572

25312573
/* Problem with encrypt / decrypt */
25322574
case errSSLPeerDecodeError:
@@ -2966,6 +3008,7 @@ static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf,
29663008
{
29673009
struct ssl_connect_data *connssl = cf->ctx;
29683010

3011+
CF_DEBUGF(infof(data, CFMSG(cf, "connect_step3")));
29693012
/* There is no step 3!
29703013
* Well, okay, let's collect server certificates, and if verbose mode is on,
29713014
* let's print the details of the server certificates. */
@@ -3074,6 +3117,7 @@ sectransp_connect_common(struct Curl_cfilter *cf, struct Curl_easy *data,
30743117
}
30753118

30763119
if(ssl_connect_done == connssl->connecting_state) {
3120+
CF_DEBUGF(infof(data, CFMSG(cf, "connected")));
30773121
connssl->state = ssl_connection_complete;
30783122
*done = TRUE;
30793123
}
@@ -3119,6 +3163,7 @@ static void sectransp_close(struct Curl_cfilter *cf, struct Curl_easy *data)
31193163
DEBUGASSERT(backend);
31203164

31213165
if(backend->ssl_ctx) {
3166+
CF_DEBUGF(infof(data, CFMSG(cf, "close")));
31223167
(void)SSLClose(backend->ssl_ctx);
31233168
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
31243169
if(SSLCreateContext)
@@ -3162,6 +3207,7 @@ static int sectransp_shutdown(struct Curl_cfilter *cf,
31623207

31633208
what = SOCKET_READABLE(cf->conn->sock[cf->sockindex], SSL_SHUTDOWN_TIMEOUT);
31643209

3210+
CF_DEBUGF(infof(data, CFMSG(cf, "shutdown")));
31653211
while(loop--) {
31663212
if(what < 0) {
31673213
/* anything that gets here is fatally bad */
@@ -3230,6 +3276,7 @@ static int sectransp_check_cxn(struct Curl_cfilter *cf,
32303276
DEBUGASSERT(backend);
32313277

32323278
if(backend->ssl_ctx) {
3279+
CF_DEBUGF(infof(data, CFMSG(cf, "check connection")));
32333280
err = SSLGetSessionState(backend->ssl_ctx, &state);
32343281
if(err == noErr)
32353282
return state == kSSLConnected || state == kSSLHandshake;
@@ -3250,6 +3297,7 @@ static bool sectransp_data_pending(struct Curl_cfilter *cf,
32503297
DEBUGASSERT(backend);
32513298

32523299
if(backend->ssl_ctx) { /* SSL is in use */
3300+
CF_DEBUGF(infof(data, CFMSG(cf, "data_pending")));
32533301
err = SSLGetBufferedReadSize(backend->ssl_ctx, &buffer);
32543302
if(err == noErr)
32553303
return buffer > 0UL;
@@ -3407,7 +3455,7 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf,
34073455
case -9841:
34083456
if((conn_config->CAfile || conn_config->ca_info_blob) &&
34093457
conn_config->verifypeer) {
3410-
CURLcode result = verify_cert(data, conn_config->CAfile,
3458+
CURLcode result = verify_cert(cf, data, conn_config->CAfile,
34113459
conn_config->ca_info_blob,
34123460
backend->ssl_ctx);
34133461
if(result)

0 commit comments

Comments
 (0)