8 #include <CoreFoundation/CoreFoundation.h>
10 #include <AssertMacros.h>
11 #include <Security/SecureTransportPriv.h> /* SSLSetOption */
12 #include <Security/SecureTransport.h>
13 #include <Security/SecPolicy.h>
14 #include <Security/SecTrust.h>
15 #include <Security/SecIdentity.h>
16 #include <Security/SecIdentityPriv.h>
17 #include <Security/SecCertificatePriv.h>
18 #include <Security/SecKeyPriv.h>
19 #include <Security/SecItem.h>
20 #include <Security/SecRandom.h>
22 #include <utilities/array_size.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
28 #include <mach/mach_time.h>
31 #include <Security/SecRSAKey.h>
34 #include "ssl-utils.h"
35 #import "STLegacyTests.h"
37 @implementation STLegacyTests (sessioncache)
40 SSL Session Cache tests:
42 Test both the client and server side.
45 - Make sure that resumption fails after session cache TTL.
48 - handshake pass or fail
53 static OSStatus SocketWrite(SSLConnectionRef conn, const void *data, size_t *length)
56 uint8_t *ptr = (uint8_t *)data;
61 ret = write((int)conn, ptr, len);
62 } while ((ret < 0) && (errno == EAGAIN || errno == EINTR));
71 *length = *length - len;
75 static OSStatus SocketRead(SSLConnectionRef conn, void *data, size_t *length)
78 uint8_t *ptr = (uint8_t *)data;
83 ret = read((int)conn, ptr, len);
84 } while ((ret < 0) && (errno == EINPROGRESS || errno == EAGAIN || errno == EINTR));
89 printf("read error(%d): ret=%zd, errno=%d\n", (int)conn, ret, errno);
94 *length = *length - len;
104 static ssl_client_handle *
105 ssl_client_handle_create(int comm, bool anyRoot, CFArrayRef trustedCA, bool trustedCAOnly, CFArrayRef trustedLeafs, uint32_t cache_ttl, uintptr_t peerID)
107 ssl_client_handle *handle = calloc(1, sizeof(ssl_client_handle));
108 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
110 require(handle, out);
113 require_noerr(SSLSetIOFuncs(ctx,
114 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
115 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
116 static const char *peer_domain_name = "localhost";
117 require_noerr(SSLSetPeerDomainName(ctx, peer_domain_name,
118 strlen(peer_domain_name)), out);
120 require_noerr(SSLSetAllowsAnyRoot(ctx, anyRoot), out);
121 require_noerr(SSLSetTrustedRoots(ctx, trustedCA, trustedCAOnly), out);
122 #if !TARGET_OS_IPHONE
123 require_noerr(SSLSetTrustedLeafCertificates(ctx, trustedLeafs), out);
126 require_noerr(SSLSetSessionCacheTimeout(ctx, cache_ttl), out);
128 require_noerr(SSLSetPeerID(ctx, &peerID, sizeof(peerID)), out);
145 ssl_client_handle_destroy(ssl_client_handle *handle)
148 SSLClose(handle->st);
149 CFRelease(handle->st);
154 static void *securetransport_ssl_client_thread(void *arg)
157 ssl_client_handle * ssl = (ssl_client_handle *)arg;
158 SSLContextRef ctx = ssl->st;
159 SSLSessionState ssl_state;
161 pthread_setname_np("client thread");
163 require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out);
164 require_action(ssl_state==kSSLIdle, out, ortn = -1);
167 ortn = SSLHandshake(ctx);
168 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
170 if (ortn == errSSLWouldBlock) {
171 require_string(ssl_state==kSSLHandshake, out, "Wrong client handshake state after errSSLWouldBlock");
173 } while (ortn == errSSLWouldBlock);
178 pthread_exit((void *)(intptr_t)ortn);
190 static ssl_server_handle *
191 ssl_server_handle_create(int comm, CFArrayRef certs, uint32_t cache_ttl)
193 ssl_server_handle *handle = calloc(1, sizeof(ssl_server_handle));
194 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
195 SSLCipherSuite cipher = TLS_RSA_WITH_AES_256_CBC_SHA256;
196 uintptr_t peerID = 0xdeadbeef;
198 require(handle, out);
201 require_noerr(SSLSetIOFuncs(ctx,
202 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
203 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
205 require_noerr(SSLSetCertificate(ctx, certs), out);
207 require_noerr(SSLSetEnabledCiphers(ctx, &cipher, 1), out);
209 require_noerr(SSLSetSessionCacheTimeout(ctx, cache_ttl), out);
211 require_noerr(SSLSetPeerID(ctx, &peerID, sizeof(peerID)), out);
214 handle->certs = certs;
229 ssl_server_handle_destroy(ssl_server_handle *handle)
232 SSLClose(handle->st);
233 CFRelease(handle->st);
238 static void *securetransport_ssl_server_thread(void *arg)
241 ssl_server_handle * ssl = (ssl_server_handle *)arg;
242 SSLContextRef ctx = ssl->st;
243 SSLSessionState ssl_state;
245 pthread_setname_np("server thread");
247 require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out);
248 require_action(ssl_state==kSSLIdle, out, ortn = -1);
251 ortn = SSLHandshake(ctx);
252 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
254 if (ortn == errSSLWouldBlock) {
255 require_action(ssl_state==kSSLHandshake, out, ortn = -1);
257 } while (ortn == errSSLWouldBlock);
259 require_noerr_quiet(ortn, out);
261 require_action(ssl_state==kSSLConnected, out, ortn = -1);
266 pthread_exit((void *)(intptr_t)ortn);
271 -(void)cache_ttl_test
273 pthread_t client_thread, server_thread;
274 CFArrayRef server_certs = server_chain();
275 CFArrayRef trusted_ca = trusted_roots();
277 XCTAssert(server_certs, "ttl: got server certs");
278 XCTAssert(trusted_ca, "ttl: got trusted roots");
282 for (i=0; i<2; i++) { // client cache TTL
283 for (j=0; j<2; j++) { // Server cache TTL
284 for (k=0; k<2; k++) {
285 ssl_client_handle *client = NULL;
286 ssl_server_handle *server = NULL;
289 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno);
290 fcntl(sp[0], F_SETNOSIGPIPE, 1);
291 fcntl(sp[1], F_SETNOSIGPIPE, 1);
293 client = ssl_client_handle_create(sp[0], false, trusted_ca, true, NULL, i, (i<<8)|(j+1));
294 XCTAssert(client!=NULL, "ttl: could not create client handle (%d:%d:%d)", i, j, k);
295 require(client, errOut);
297 server = ssl_server_handle_create(sp[1], server_certs, j);
298 XCTAssert(server!=NULL, "ttl: could not create server handle (%d:%d:%d)", i, j, k);
299 require(server, errOut);
300 pthread_create(&client_thread, NULL, securetransport_ssl_client_thread, client);
301 pthread_create(&server_thread, NULL, securetransport_ssl_server_thread, server);
303 intptr_t server_err, client_err;
305 pthread_join(client_thread, (void*)&client_err);
306 pthread_join(server_thread, (void*)&server_err);
309 unsigned char sessionID[32];
310 size_t sessionIDLength = sizeof(sessionID);
312 XCTAssertEqual(client_err, 0, "ttl: unexpected error %ld (client %d:%d:%d)", client_err, i, j, k);
313 XCTAssertEqual(server_err, 0, "ttl: unexpected error %ld (server %d:%d:%d)", server_err, i, j, k);
314 XCTAssertEqual(errSecSuccess, SSLGetResumableSessionInfo(client->st, &resumed, sessionID, &sessionIDLength), "SSLGetResumableSessionInfo");
316 XCTAssertEqual((bool)resumed, (bool)(k && (!i) && (!j)), "ttl: Unexpected resumption state=%d (%d:%d:%d)", resumed, i, j, k);
319 ssl_server_handle_destroy(server);
320 ssl_client_handle_destroy(client);
322 /* Sleep two seconds so that Session cache TTL can expire */
328 CFReleaseSafe(server_certs);
329 CFReleaseSafe(trusted_ca);
332 -(void) cache_trust_test
334 pthread_t client_thread, server_thread;
335 CFArrayRef server_certs = server_chain();
336 CFArrayRef trusted_ca = trusted_roots();
337 CFMutableArrayRef trusted_ca2 = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, trusted_ca);
338 CFArrayAppendArray(trusted_ca2, trusted_ca, CFRangeMake(0, CFArrayGetCount(trusted_ca)));
340 XCTAssert(server_certs, "trust: got server certs");
341 XCTAssert(trusted_ca, "trust: got trusted roots");
342 XCTAssert(trusted_ca2, "trust: got trusted roots extra");
344 int any, ca, caonly, leaf, k;
346 // Test cache and trust options:
349 for (any=0; any<2; any++) // any root ?
350 for (ca=0; ca<2; ca++) // trustedCA ?
351 for (caonly=0; caonly<2; caonly++) // leaf>
356 for (leaf=0; leaf<2; leaf++)
359 // attempt initial connection, then resumed connection, but all with same peer id (0xdeadbeef)
360 for (k=0; k<2; k++) {
361 ssl_client_handle *client = NULL;
362 ssl_server_handle *server = NULL;
365 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno);
366 fcntl(sp[0], F_SETNOSIGPIPE, 1);
367 fcntl(sp[1], F_SETNOSIGPIPE, 1);
369 client = ssl_client_handle_create(sp[0], any, ca?trusted_ca:trusted_ca2, caonly, leaf?NULL:trusted_ca, 300, 0xdeadbeef);
370 XCTAssert(client!=NULL, "trust: could not create client handle (%d:%d:%d:%d:%d)", any, ca, caonly, leaf, k);
371 require(client, errOut);
373 server = ssl_server_handle_create(sp[1], server_certs, 300);
374 XCTAssert(server!=NULL, "trust: could not create server handle (%d:%d:%d:%d:%d)", any, ca, caonly, leaf, k);
375 require(server, errOut);
377 pthread_create(&client_thread, NULL, securetransport_ssl_client_thread, client);
378 pthread_create(&server_thread, NULL, securetransport_ssl_server_thread, server);
380 intptr_t server_err, client_err;
382 pthread_join(client_thread, (void*)&client_err);
383 pthread_join(server_thread, (void*)&server_err);
386 unsigned char sessionID[32];
387 size_t sessionIDLength = sizeof(sessionID);
389 XCTAssertEqual(client_err, 0, "trust: unexpected error %ld (client %d:%d:%d:%d:%d)", client_err, any, ca, caonly, leaf, k);
390 XCTAssertEqual(server_err, 0, "trust: unexpected error %ld (server %d:%d:%d:%d:%d)", server_err, any, ca, caonly, leaf, k);
391 XCTAssertEqual(errSecSuccess, SSLGetResumableSessionInfo(client->st, &resumed, sessionID, &sessionIDLength), "SSLGetResumableSessionInfo");
393 XCTAssertEqual((bool)resumed, (bool)(k), "trust: Unexpected resumption state=%d (%d:%d:%d:%d:%d)", resumed, any, ca, caonly, leaf, k);
396 ssl_server_handle_destroy(server);
397 ssl_client_handle_destroy(client);
402 CFReleaseSafe(server_certs);
403 CFReleaseSafe(trusted_ca);
406 -(void) testSessionCache
409 [self cache_ttl_test];
411 [self cache_trust_test];