]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+sessioncache.m
Security-58286.240.4.tar.gz
[apple/security.git] / OSX / libsecurity_ssl / regressions / SecureTransportTests / STLegacyTests+sessioncache.m
1
2 #include <stdbool.h>
3 #include <pthread.h>
4 #include <fcntl.h>
5 #include <sys/mman.h>
6 #include <unistd.h>
7
8 #include <CoreFoundation/CoreFoundation.h>
9
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>
21
22 #include <utilities/array_size.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <mach/mach_time.h>
29
30 #if TARGET_OS_IPHONE
31 #include <Security/SecRSAKey.h>
32 #endif
33
34 #include "ssl-utils.h"
35 #import "STLegacyTests.h"
36
37 @implementation STLegacyTests (sessioncache)
38
39 /*
40 SSL Session Cache tests:
41
42 Test both the client and server side.
43
44 Test Goal:
45 - Make sure that resumption fails after session cache TTL.
46
47 Behavior to verify:
48 - handshake pass or fail
49
50 */
51
52
53 static OSStatus SocketWrite(SSLConnectionRef conn, const void *data, size_t *length)
54 {
55 size_t len = *length;
56 uint8_t *ptr = (uint8_t *)data;
57
58 do {
59 ssize_t ret;
60 do {
61 ret = write((int)conn, ptr, len);
62 } while ((ret < 0) && (errno == EAGAIN || errno == EINTR));
63 if (ret > 0) {
64 len -= ret;
65 ptr += ret;
66 }
67 else
68 return -36;
69 } while (len > 0);
70
71 *length = *length - len;
72 return errSecSuccess;
73 }
74
75 static OSStatus SocketRead(SSLConnectionRef conn, void *data, size_t *length)
76 {
77 size_t len = *length;
78 uint8_t *ptr = (uint8_t *)data;
79
80 do {
81 ssize_t ret;
82 do {
83 ret = read((int)conn, ptr, len);
84 } while ((ret < 0) && (errno == EINPROGRESS || errno == EAGAIN || errno == EINTR));
85 if (ret > 0) {
86 len -= ret;
87 ptr += ret;
88 } else {
89 printf("read error(%d): ret=%zd, errno=%d\n", (int)conn, ret, errno);
90 return -errno;
91 }
92 } while (len > 0);
93
94 *length = *length - len;
95 return errSecSuccess;
96 }
97
98 typedef struct {
99 SSLContextRef st;
100 int comm;
101 unsigned dhe_size;
102 } ssl_client_handle;
103
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)
106 {
107 ssl_client_handle *handle = calloc(1, sizeof(ssl_client_handle));
108 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
109
110 require(handle, out);
111 require(ctx, out);
112
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);
119
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);
124 #endif
125
126 require_noerr(SSLSetSessionCacheTimeout(ctx, cache_ttl), out);
127
128 require_noerr(SSLSetPeerID(ctx, &peerID, sizeof(peerID)), out);
129
130 handle->comm = comm;
131 handle->st = ctx;
132
133 return handle;
134
135 out:
136 if (ctx)
137 CFRelease(ctx);
138 if (handle)
139 free(handle);
140
141 return NULL;
142 }
143
144 static void
145 ssl_client_handle_destroy(ssl_client_handle *handle)
146 {
147 if(handle) {
148 SSLClose(handle->st);
149 CFRelease(handle->st);
150 free(handle);
151 }
152 }
153
154 static void *securetransport_ssl_client_thread(void *arg)
155 {
156 OSStatus ortn;
157 ssl_client_handle * ssl = (ssl_client_handle *)arg;
158 SSLContextRef ctx = ssl->st;
159 SSLSessionState ssl_state;
160
161 pthread_setname_np("client thread");
162
163 require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out);
164 require_action(ssl_state==kSSLIdle, out, ortn = -1);
165
166 do {
167 ortn = SSLHandshake(ctx);
168 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
169
170 if (ortn == errSSLWouldBlock) {
171 require_string(ssl_state==kSSLHandshake, out, "Wrong client handshake state after errSSLWouldBlock");
172 }
173 } while (ortn == errSSLWouldBlock);
174
175 out:
176 SSLClose(ssl->st);
177 close(ssl->comm);
178 pthread_exit((void *)(intptr_t)ortn);
179 return NULL;
180 }
181
182
183 typedef struct {
184 SSLContextRef st;
185 int comm;
186 CFArrayRef certs;
187
188 } ssl_server_handle;
189
190 static ssl_server_handle *
191 ssl_server_handle_create(int comm, CFArrayRef certs, uint32_t cache_ttl)
192 {
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;
197
198 require(handle, out);
199 require(ctx, out);
200
201 require_noerr(SSLSetIOFuncs(ctx,
202 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
203 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
204
205 require_noerr(SSLSetCertificate(ctx, certs), out);
206
207 require_noerr(SSLSetEnabledCiphers(ctx, &cipher, 1), out);
208
209 require_noerr(SSLSetSessionCacheTimeout(ctx, cache_ttl), out);
210
211 require_noerr(SSLSetPeerID(ctx, &peerID, sizeof(peerID)), out);
212
213 handle->comm = comm;
214 handle->certs = certs;
215 handle->st = ctx;
216
217 return handle;
218
219 out:
220 if (ctx)
221 CFRelease(ctx);
222 if (handle)
223 free(handle);
224
225 return NULL;
226 }
227
228 static void
229 ssl_server_handle_destroy(ssl_server_handle *handle)
230 {
231 if(handle) {
232 SSLClose(handle->st);
233 CFRelease(handle->st);
234 free(handle);
235 }
236 }
237
238 static void *securetransport_ssl_server_thread(void *arg)
239 {
240 OSStatus ortn;
241 ssl_server_handle * ssl = (ssl_server_handle *)arg;
242 SSLContextRef ctx = ssl->st;
243 SSLSessionState ssl_state;
244
245 pthread_setname_np("server thread");
246
247 require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out);
248 require_action(ssl_state==kSSLIdle, out, ortn = -1);
249
250 do {
251 ortn = SSLHandshake(ctx);
252 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
253
254 if (ortn == errSSLWouldBlock) {
255 require_action(ssl_state==kSSLHandshake, out, ortn = -1);
256 }
257 } while (ortn == errSSLWouldBlock);
258
259 require_noerr_quiet(ortn, out);
260
261 require_action(ssl_state==kSSLConnected, out, ortn = -1);
262
263 out:
264 SSLClose(ssl->st);
265 close(ssl->comm);
266 pthread_exit((void *)(intptr_t)ortn);
267 return NULL;
268 }
269
270
271 -(void)cache_ttl_test
272 {
273 pthread_t client_thread, server_thread;
274 CFArrayRef server_certs = server_chain();
275 CFArrayRef trusted_ca = trusted_roots();
276
277 XCTAssert(server_certs, "ttl: got server certs");
278 XCTAssert(trusted_ca, "ttl: got trusted roots");
279
280 int i, j, k;
281
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;
287
288 int sp[2];
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);
292
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);
296
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);
302
303 intptr_t server_err, client_err;
304
305 pthread_join(client_thread, (void*)&client_err);
306 pthread_join(server_thread, (void*)&server_err);
307
308 Boolean resumed;
309 unsigned char sessionID[32];
310 size_t sessionIDLength = sizeof(sessionID);
311
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");
315
316 XCTAssertEqual((bool)resumed, (bool)(k && (!i) && (!j)), "ttl: Unexpected resumption state=%d (%d:%d:%d)", resumed, i, j, k);
317
318 errOut:
319 ssl_server_handle_destroy(server);
320 ssl_client_handle_destroy(client);
321
322 /* Sleep two seconds so that Session cache TTL can expire */
323 sleep(2);
324 }
325 }
326 }
327
328 CFReleaseSafe(server_certs);
329 CFReleaseSafe(trusted_ca);
330 }
331
332 -(void) cache_trust_test
333 {
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)));
339
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");
343
344 int any, ca, caonly, leaf, k;
345
346 // Test cache and trust options:
347
348
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>
352 #if TARGET_OS_IPHONE
353 {
354 leaf = 0;
355 #else
356 for (leaf=0; leaf<2; leaf++)
357 {
358 #endif
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;
363
364 int sp[2];
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);
368
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);
372
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);
376
377 pthread_create(&client_thread, NULL, securetransport_ssl_client_thread, client);
378 pthread_create(&server_thread, NULL, securetransport_ssl_server_thread, server);
379
380 intptr_t server_err, client_err;
381
382 pthread_join(client_thread, (void*)&client_err);
383 pthread_join(server_thread, (void*)&server_err);
384
385 Boolean resumed;
386 unsigned char sessionID[32];
387 size_t sessionIDLength = sizeof(sessionID);
388
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");
392
393 XCTAssertEqual((bool)resumed, (bool)(k), "trust: Unexpected resumption state=%d (%d:%d:%d:%d:%d)", resumed, any, ca, caonly, leaf, k);
394
395 errOut:
396 ssl_server_handle_destroy(server);
397 ssl_client_handle_destroy(client);
398
399 }
400 }
401
402 CFReleaseSafe(server_certs);
403 CFReleaseSafe(trusted_ca);
404 }
405
406 -(void) testSessionCache
407 {
408
409 [self cache_ttl_test];
410
411 [self cache_trust_test];
412
413 }
414 @end
415