Revision: 1870
Author:
lieven....@gmail.com
Date: Thu May 23 14:35:06 2013
Log: On the multiple_ssl_impls branch:
Use the asynchronous SecTrustEvaluateAsync to evaluate the server
certificate
chain, instead of the blocking SecTrustEvaluate.
Note: SecTrustEvaluateAsync requires an Objective-C block as parameter, so
I've
wrapped the implementation in an Objective-C class method. This requires gcc
or clang, but that shouldn't be a problem since it's only build on Mac OS X.
* buckets/sectrans_helper.m: New file.
* SConstruct: build the new file in Mac OS X.
* buckets/sectrans_buckets.c
(struct sectrans_context_t): Add member variables for the asynchronous
evaluation.
(sectrans_init_context): Add comment, reorganize code a bit.
(validate_server_certificate): Switch from SecTrustEvaluate to
SecTrustEvaluateAsync.
(do_handshake): Don't continue the handshake until the results of the
evaluation are available. Reset flags when handshake is finished.
(decrypt_more_data): Add TODO.
http://code.google.com/p/serf/source/detail?r=1870
Added:
/branches/multiple_ssl_impls/buckets/sectrans_helper.m
Modified:
/branches/multiple_ssl_impls/SConstruct
/branches/multiple_ssl_impls/buckets/sectrans_buckets.c
=======================================
--- /dev/null
+++ /branches/multiple_ssl_impls/buckets/sectrans_helper.m Thu May 23
14:35:06 2013
@@ -0,0 +1,34 @@
+/*
+ */
+#import <Foundation/Foundation.h>
+
+@interface SecTrans_Buckets : NSObject
+{
+}
++ (OSStatus) evaluate:(SecTrustRef)trust
+ trustResult:(SecTrustResultType *)trustResult;
+
+@end
+
+@implementation SecTrans_Buckets
+
+/* Evaluate the trust object asynchronously. When the results are received,
+ store them in the provided resultPtr address. */
++ (OSStatus) evaluate:(SecTrustRef)trust
+ trustResult:(SecTrustResultType *)resultPtr
+{
+ dispatch_queue_t queue;
+ OSStatus osstatus;
+
+ SecTrustCallback block = ^(SecTrustRef trust, SecTrustResultType
trustResult)
+ {
+ *resultPtr = trustResult;
+ };
+
+ queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0l);
+ osstatus = SecTrustEvaluateAsync(trust, queue, block);
+
+ return osstatus;
+}
+
+@end
=======================================
--- /branches/multiple_ssl_impls/SConstruct Mon May 20 14:54:34 2013
+++ /branches/multiple_ssl_impls/SConstruct Thu May 23 14:35:06 2013
@@ -106,6 +106,11 @@
Help(opts.GenerateHelpText(env))
opts.Save(SAVED_CONFIG, env)
+if sys.platform == 'darwin':
+ securetransport = True
+else:
+ securetransport = False
+
# PLATFORM-SPECIFIC BUILD TWEAKS
@@ -130,6 +135,7 @@
linkflags.append('-Wl,-compatibility_version,%d' % (MINOR+1,))
linkflags.append('-Wl,-current_version,%d.%d' % (MINOR+1, PATCH,))
+if securetransport:
# add Secure Transport library for ssl/tls on Mac OS X
env.Append(FRAMEWORKS='Security')
env.Append(FRAMEWORKS='SecurityInterface')
@@ -173,6 +179,8 @@
# PLAN THE BUILD
SOURCES = Glob('*.c') + Glob('buckets/*.c') + Glob('auth/*.c')
+if securetransport:
+ SOURCES += ['buckets/sectrans_helper.m']
lib_static = env.StaticLibrary(LIBNAME, SOURCES)
lib_shared = env.SharedLibrary(LIBNAME, SOURCES)
=======================================
--- /branches/multiple_ssl_impls/buckets/sectrans_buckets.c Tue May 21
13:02:34 2013
+++ /branches/multiple_ssl_impls/buckets/sectrans_buckets.c Thu May 23
14:35:06 2013
@@ -132,6 +132,12 @@
/* cache of the trusted certificates, added via serf_ssl_trust_cert().
*/
apr_array_header_t *anchor_certs;
+ /* Flag set when an asynchronous evaluation of the server certificate
chain
+ is ongoing. */
+ int evaluate_in_progress;
+
+ /* Result of the evaluation of the server certificate chain. */
+ SecTrustResultType result;
} sectrans_context_t;
/* Some forward declarations */
@@ -266,12 +272,15 @@
kSSLSessionOptionBreakOnServerAuth,
true))
return NULL;
+ if (SSLSetEnableCertVerify(ssl_ctx->st_ctxr, false))
+ return NULL;
+
+ /* If the handshake needs a client identity to continue, break it
+ temporarily so we can call back to the application. */
if (SSLSetSessionOption(ssl_ctx->st_ctxr,
kSSLSessionOptionBreakOnCertRequested,
true))
return NULL;
- if (SSLSetEnableCertVerify(ssl_ctx->st_ctxr, false))
- return NULL;
return ssl_ctx;
}
@@ -885,7 +894,6 @@
static int
validate_server_certificate(sectrans_context_t *ssl_ctx)
{
- SecTrustResultType result;
CFArrayRef anchor_certrefs = NULL;
size_t depth_of_error, chain_depth;
int failures = 0;
@@ -893,7 +901,6 @@
apr_status_t status;
serf__log(SSL_VERBOSE, __FILE__, "validate_server_certificate
called.\n");
-
osstatus = SSLCopyPeerTrust(ssl_ctx->st_ctxr, &ssl_ctx->trust);
if (osstatus != noErr) {
status = translate_sectrans_status(osstatus);
@@ -926,18 +933,34 @@
}
}
- /* TODO: SecTrustEvaluateAsync */
- osstatus = SecTrustEvaluate(ssl_ctx->trust, &result);
- if (osstatus != noErr) {
- status = translate_sectrans_status(osstatus);
- goto cleanup;
+ if (!ssl_ctx->evaluate_in_progress) {
+ void *sectrans_cls;
+ id tmp;
+
+ ssl_ctx->evaluate_in_progress = 1;
+
+ sectrans_cls = objc_getClass("SecTrans_Buckets");
+ tmp = objc_msgSend(sectrans_cls,
+ sel_getUid("evaluate:trustResult:"),
+ ssl_ctx->trust,
+ &ssl_ctx->result);
+ osstatus = (OSStatus)(SInt64)tmp;
+ if (osstatus != noErr) {
+ status = translate_sectrans_status(osstatus);
+ goto cleanup;
+ }
+ }
+
+ if (!ssl_ctx->result) {
+ /* No evaluation results received yet. */
+ return APR_EAGAIN;
}
/* Based on the contents of the user's Keychain, Secure Transport will
make
a first validation of this certificate chain.
The status set here is temporary, as it can be overridden by the
application. */
- switch (result)
+ switch (ssl_ctx->result)
{
case kSecTrustResultUnspecified:
case kSecTrustResultProceed:
@@ -1082,7 +1105,8 @@
serf__log(SSL_VERBOSE, __FILE__, "Chain length (%d) is longer
than "
"what we received from the server (%d). Search the "
- "remaining anchor certificate.", chain_depth,
certs_len);
+ "remaining anchor certificate.\n",
+ chain_depth, certs_len);
/* Take the last known certificate and search its issuer in the
list of trusted anchor certificates. */
@@ -1615,6 +1639,13 @@
serf__log(SSL_VERBOSE, __FILE__, "do_handshake called.\n");
+ if (ssl_ctx->evaluate_in_progress) {
+ status = validate_server_certificate(ssl_ctx);
+
+ if (status)
+ return status;
+ }
+
osstatus = SSLHandshake(ssl_ctx->st_ctxr);
if (osstatus)
serf__log(SSL_VERBOSE, __FILE__, "do_handshake returned
err %d.\n",
@@ -1651,6 +1682,9 @@
identity. */
apr_pool_destroy(ssl_ctx->handshake_pool);
ssl_ctx->handshake_pool = NULL;
+
+ ssl_ctx->result = 0;
+ ssl_ctx->evaluate_in_progress = 0;
}
}
@@ -2194,6 +2228,9 @@
if (available_len < READ_BUFSIZE)
available_len = READ_BUFSIZE;
}
+ /* TODO: SSLRead doesn't always return a lot of data in one go, so
+ it makes sense to continue receiving data in the remainder of
this
+ buffer before allocating a new buffer. */
dec_data =
serf_bucket_mem_alloc(ssl_ctx->decrypt.pending->allocator,
available_len);