]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ssl/regressions/ssl-55-sessioncache.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_ssl / regressions / ssl-55-sessioncache.c
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 <utilities/SecCFRelease.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <mach/mach_time.h>
30
31 #if TARGET_OS_IPHONE
32 #include <Security/SecRSAKey.h>
33 #endif
34
35 #include "ssl_regressions.h"
36 #include "ssl-utils.h"
37
38 /*
39 SSL Session Cache tests:
40
41 Test both the client and server side.
42
43 Test Goal:
44 - Make sure that resumption fails after session cache TTL.
45
46 Behavior to verify:
47 - handshake pass or fail
48
49 */
50
51
52 static OSStatus SocketWrite(SSLConnectionRef conn, const void *data, size_t *length)
53 {
54 size_t len = *length;
55 uint8_t *ptr = (uint8_t *)data;
56
57 do {
58 ssize_t ret;
59 do {
60 ret = write((int)conn, ptr, len);
61 } while ((ret < 0) && (errno == EAGAIN || errno == EINTR));
62 if (ret > 0) {
63 len -= ret;
64 ptr += ret;
65 }
66 else
67 return -36;
68 } while (len > 0);
69
70 *length = *length - len;
71 return errSecSuccess;
72 }
73
74 static OSStatus SocketRead(SSLConnectionRef conn, void *data, size_t *length)
75 {
76 size_t len = *length;
77 uint8_t *ptr = (uint8_t *)data;
78
79 do {
80 ssize_t ret;
81 do {
82 ret = read((int)conn, ptr, len);
83 } while ((ret < 0) && (errno == EINPROGRESS || errno == EAGAIN || errno == EINTR));
84 if (ret > 0) {
85 len -= ret;
86 ptr += ret;
87 } else {
88 printf("read error(%d): ret=%zd, errno=%d\n", (int)conn, ret, errno);
89 return -errno;
90 }
91 } while (len > 0);
92
93 *length = *length - len;
94 return errSecSuccess;
95 }
96
97 typedef struct {
98 SSLContextRef st;
99 int comm;
100 unsigned dhe_size;
101 } ssl_client_handle;
102
103 static ssl_client_handle *
104 ssl_client_handle_create(int comm, bool anyRoot, CFArrayRef trustedCA, bool trustedCAOnly, CFArrayRef trustedLeafs, uint32_t cache_ttl, uintptr_t peerID)
105 {
106 ssl_client_handle *handle = calloc(1, sizeof(ssl_client_handle));
107 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
108
109 require(handle, out);
110 require(ctx, out);
111
112 require_noerr(SSLSetIOFuncs(ctx,
113 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
114 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
115 static const char *peer_domain_name = "localhost";
116 require_noerr(SSLSetPeerDomainName(ctx, peer_domain_name,
117 strlen(peer_domain_name)), out);
118
119 require_noerr(SSLSetAllowsAnyRoot(ctx, anyRoot), out);
120 require_noerr(SSLSetTrustedRoots(ctx, trustedCA, trustedCAOnly), out);
121 #if !TARGET_OS_IPHONE
122 require_noerr(SSLSetTrustedLeafCertificates(ctx, trustedLeafs), out);
123 #endif
124
125 require_noerr(SSLSetSessionCacheTimeout(ctx, cache_ttl), out);
126
127 require_noerr(SSLSetPeerID(ctx, &peerID, sizeof(peerID)), out);
128
129 handle->comm = comm;
130 handle->st = ctx;
131
132 return handle;
133
134 out:
135 if (ctx)
136 CFRelease(ctx);
137 if (handle)
138 free(handle);
139
140 return NULL;
141 }
142
143 static void
144 ssl_client_handle_destroy(ssl_client_handle *handle)
145 {
146 if(handle) {
147 SSLClose(handle->st);
148 CFRelease(handle->st);
149 free(handle);
150 }
151 }
152
153 static void *securetransport_ssl_client_thread(void *arg)
154 {
155 OSStatus ortn;
156 ssl_client_handle * ssl = (ssl_client_handle *)arg;
157 SSLContextRef ctx = ssl->st;
158 SSLSessionState ssl_state;
159
160 pthread_setname_np("client thread");
161
162 require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out);
163 require_action(ssl_state==kSSLIdle, out, ortn = -1);
164
165 do {
166 ortn = SSLHandshake(ctx);
167 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
168
169 if (ortn == errSSLWouldBlock) {
170 require_string(ssl_state==kSSLHandshake, out, "Wrong client handshake state after errSSLWouldBlock");
171 }
172 } while (ortn == errSSLWouldBlock);
173
174 out:
175 SSLClose(ssl->st);
176 close(ssl->comm);
177 pthread_exit((void *)(intptr_t)ortn);
178 return NULL;
179 }
180
181
182 typedef struct {
183 SSLContextRef st;
184 int comm;
185 CFArrayRef certs;
186
187 } ssl_server_handle;
188
189 static ssl_server_handle *
190 ssl_server_handle_create(int comm, CFArrayRef certs, uint32_t cache_ttl)
191 {
192 ssl_server_handle *handle = calloc(1, sizeof(ssl_server_handle));
193 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
194 SSLCipherSuite cipher = TLS_RSA_WITH_AES_256_CBC_SHA256;
195 uintptr_t peerID = 0xdeadbeef;
196
197 require(handle, out);
198 require(ctx, out);
199
200 require_noerr(SSLSetIOFuncs(ctx,
201 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
202 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
203
204 require_noerr(SSLSetCertificate(ctx, certs), out);
205
206 require_noerr(SSLSetEnabledCiphers(ctx, &cipher, 1), out);
207
208 require_noerr(SSLSetSessionCacheTimeout(ctx, cache_ttl), out);
209
210 require_noerr(SSLSetPeerID(ctx, &peerID, sizeof(peerID)), out);
211
212 handle->comm = comm;
213 handle->certs = certs;
214 handle->st = ctx;
215
216 return handle;
217
218 out:
219 if (ctx)
220 CFRelease(ctx);
221 if (handle)
222 free(handle);
223
224 return NULL;
225 }
226
227 static void
228 ssl_server_handle_destroy(ssl_server_handle *handle)
229 {
230 if(handle) {
231 SSLClose(handle->st);
232 CFRelease(handle->st);
233 free(handle);
234 }
235 }
236
237 static void *securetransport_ssl_server_thread(void *arg)
238 {
239 OSStatus ortn;
240 ssl_server_handle * ssl = (ssl_server_handle *)arg;
241 SSLContextRef ctx = ssl->st;
242 SSLSessionState ssl_state;
243
244 pthread_setname_np("server thread");
245
246 require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out);
247 require_action(ssl_state==kSSLIdle, out, ortn = -1);
248
249 do {
250 ortn = SSLHandshake(ctx);
251 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
252
253 if (ortn == errSSLWouldBlock) {
254 require_action(ssl_state==kSSLHandshake, out, ortn = -1);
255 }
256 } while (ortn == errSSLWouldBlock);
257
258 require_noerr_quiet(ortn, out);
259
260 require_action(ssl_state==kSSLConnected, out, ortn = -1);
261
262 out:
263 SSLClose(ssl->st);
264 close(ssl->comm);
265 pthread_exit((void *)(intptr_t)ortn);
266 return NULL;
267 }
268
269
270 static void
271 tests_cache_ttl(void)
272 {
273 pthread_t client_thread, server_thread;
274 CFArrayRef server_certs = server_chain();
275 CFArrayRef trusted_ca = trusted_roots();
276
277 ok(server_certs, "ttl: got server certs");
278 ok(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 ok(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 ok(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 ok(client_err==0, "ttl: unexpected error %ld (client %d:%d:%d)", client_err, i, j, k);
313 ok(server_err==0, "ttl: unexpected error %ld (server %d:%d:%d)", server_err, i, j, k);
314 ok_status(SSLGetResumableSessionInfo(client->st, &resumed, sessionID, &sessionIDLength), "SSLGetResumableSessionInfo");
315
316 ok((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 static void
333 tests_cache_trust(void)
334 {
335 pthread_t client_thread, server_thread;
336 CFArrayRef server_certs = server_chain();
337 CFArrayRef trusted_ca = trusted_roots();
338 CFMutableArrayRef trusted_ca2 = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, trusted_ca);
339 CFArrayAppendArray(trusted_ca2, trusted_ca, CFRangeMake(0, CFArrayGetCount(trusted_ca)));
340
341 ok(server_certs, "trust: got server certs");
342 ok(trusted_ca, "trust: got trusted roots");
343 ok(trusted_ca2, "trust: got trusted roots extra");
344
345 int any, ca, caonly, leaf, k;
346
347 // Test cache and trust options:
348
349
350 for (any=0; any<2; any++) // any root ?
351 for (ca=0; ca<2; ca++) // trustedCA ?
352 for (caonly=0; caonly<2; caonly++) // leaf>
353 #if TARGET_OS_IPHONE
354 {
355 leaf = 0;
356 #else
357 for (leaf=0; leaf<2; leaf++)
358 {
359 #endif
360 // attempt initial connection, then resumed connection, but all with same peer id (0xdeadbeef)
361 for (k=0; k<2; k++) {
362 ssl_client_handle *client = NULL;
363 ssl_server_handle *server = NULL;
364
365 int sp[2];
366 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno);
367 fcntl(sp[0], F_SETNOSIGPIPE, 1);
368 fcntl(sp[1], F_SETNOSIGPIPE, 1);
369
370 client = ssl_client_handle_create(sp[0], any, ca?trusted_ca:trusted_ca2, caonly, leaf?NULL:trusted_ca, 300, 0xdeadbeef);
371 ok(client!=NULL, "trust: could not create client handle (%d:%d:%d:%d:%d)", any, ca, caonly, leaf, k);
372 require(client, errOut);
373
374 server = ssl_server_handle_create(sp[1], server_certs, 300);
375 ok(server!=NULL, "trust: could not create server handle (%d:%d:%d:%d:%d)", any, ca, caonly, leaf, k);
376 require(server, errOut);
377
378 pthread_create(&client_thread, NULL, securetransport_ssl_client_thread, client);
379 pthread_create(&server_thread, NULL, securetransport_ssl_server_thread, server);
380
381 intptr_t server_err, client_err;
382
383 pthread_join(client_thread, (void*)&client_err);
384 pthread_join(server_thread, (void*)&server_err);
385
386 Boolean resumed;
387 unsigned char sessionID[32];
388 size_t sessionIDLength = sizeof(sessionID);
389
390 ok(client_err==0, "trust: unexpected error %ld (client %d:%d:%d:%d:%d)", client_err, any, ca, caonly, leaf, k);
391 ok(server_err==0, "trust: unexpected error %ld (server %d:%d:%d:%d:%d)", server_err, any, ca, caonly, leaf, k);
392 ok_status(SSLGetResumableSessionInfo(client->st, &resumed, sessionID, &sessionIDLength), "SSLGetResumableSessionInfo");
393
394 ok((bool)resumed == (bool)(k), "trust: Unexpected resumption state=%d (%d:%d:%d:%d:%d)", resumed, any, ca, caonly, leaf, k);
395
396 errOut:
397 ssl_server_handle_destroy(server);
398 ssl_client_handle_destroy(client);
399
400 }
401 }
402
403 CFReleaseSafe(server_certs);
404 CFReleaseSafe(trusted_ca);
405 }
406
407 int ssl_55_sessioncache(int argc, char *const *argv)
408 {
409
410 #if TARGET_OS_IPHONE
411 #define N_TRUST_TESTS 8
412 #else
413 #define N_TRUST_TESTS 16
414 #endif
415
416 plan_tests(/*ttl :*/ 6 * 8 + 2 + /* trust:*/ N_TRUST_TESTS*6*2 + 3);
417
418
419 tests_cache_ttl();
420
421 tests_cache_trust();
422
423 return 0;
424 }