]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ssl/regressions/ssl-55-sessioncache.c
Security-58286.51.6.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 <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_regressions.h"
35 #include "ssl-utils.h"
36
37 /*
38 SSL Session Cache tests:
39
40 Test both the client and server side.
41
42 Test Goal:
43 - Make sure that resumption fails after session cache TTL.
44
45 Behavior to verify:
46 - handshake pass or fail
47
48 */
49
50
51 static OSStatus SocketWrite(SSLConnectionRef conn, const void *data, size_t *length)
52 {
53 size_t len = *length;
54 uint8_t *ptr = (uint8_t *)data;
55
56 do {
57 ssize_t ret;
58 do {
59 ret = write((int)conn, ptr, len);
60 } while ((ret < 0) && (errno == EAGAIN || errno == EINTR));
61 if (ret > 0) {
62 len -= ret;
63 ptr += ret;
64 }
65 else
66 return -36;
67 } while (len > 0);
68
69 *length = *length - len;
70 return errSecSuccess;
71 }
72
73 static OSStatus SocketRead(SSLConnectionRef conn, void *data, size_t *length)
74 {
75 size_t len = *length;
76 uint8_t *ptr = (uint8_t *)data;
77
78 do {
79 ssize_t ret;
80 do {
81 ret = read((int)conn, ptr, len);
82 } while ((ret < 0) && (errno == EINPROGRESS || errno == EAGAIN || errno == EINTR));
83 if (ret > 0) {
84 len -= ret;
85 ptr += ret;
86 } else {
87 printf("read error(%d): ret=%zd, errno=%d\n", (int)conn, ret, errno);
88 return -errno;
89 }
90 } while (len > 0);
91
92 *length = *length - len;
93 return errSecSuccess;
94 }
95
96 typedef struct {
97 SSLContextRef st;
98 int comm;
99 unsigned dhe_size;
100 } ssl_client_handle;
101
102 static ssl_client_handle *
103 ssl_client_handle_create(int comm, bool anyRoot, CFArrayRef trustedCA, bool trustedCAOnly, CFArrayRef trustedLeafs, uint32_t cache_ttl, uintptr_t peerID)
104 {
105 ssl_client_handle *handle = calloc(1, sizeof(ssl_client_handle));
106 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
107
108 require(handle, out);
109 require(ctx, out);
110
111 require_noerr(SSLSetIOFuncs(ctx,
112 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
113 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
114 static const char *peer_domain_name = "localhost";
115 require_noerr(SSLSetPeerDomainName(ctx, peer_domain_name,
116 strlen(peer_domain_name)), out);
117
118 require_noerr(SSLSetAllowsAnyRoot(ctx, anyRoot), out);
119 require_noerr(SSLSetTrustedRoots(ctx, trustedCA, trustedCAOnly), out);
120 #if !TARGET_OS_IPHONE
121 require_noerr(SSLSetTrustedLeafCertificates(ctx, trustedLeafs), out);
122 #endif
123
124 require_noerr(SSLSetSessionCacheTimeout(ctx, cache_ttl), out);
125
126 require_noerr(SSLSetPeerID(ctx, &peerID, sizeof(peerID)), out);
127
128 handle->comm = comm;
129 handle->st = ctx;
130
131 return handle;
132
133 out:
134 if (ctx)
135 CFRelease(ctx);
136 if (handle)
137 free(handle);
138
139 return NULL;
140 }
141
142 static void
143 ssl_client_handle_destroy(ssl_client_handle *handle)
144 {
145 if(handle) {
146 SSLClose(handle->st);
147 CFRelease(handle->st);
148 free(handle);
149 }
150 }
151
152 static void *securetransport_ssl_client_thread(void *arg)
153 {
154 OSStatus ortn;
155 ssl_client_handle * ssl = (ssl_client_handle *)arg;
156 SSLContextRef ctx = ssl->st;
157 SSLSessionState ssl_state;
158
159 pthread_setname_np("client thread");
160
161 require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out);
162 require_action(ssl_state==kSSLIdle, out, ortn = -1);
163
164 do {
165 ortn = SSLHandshake(ctx);
166 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
167
168 if (ortn == errSSLWouldBlock) {
169 require_string(ssl_state==kSSLHandshake, out, "Wrong client handshake state after errSSLWouldBlock");
170 }
171 } while (ortn == errSSLWouldBlock);
172
173 out:
174 SSLClose(ssl->st);
175 close(ssl->comm);
176 pthread_exit((void *)(intptr_t)ortn);
177 return NULL;
178 }
179
180
181 typedef struct {
182 SSLContextRef st;
183 int comm;
184 CFArrayRef certs;
185
186 } ssl_server_handle;
187
188 static ssl_server_handle *
189 ssl_server_handle_create(int comm, CFArrayRef certs, uint32_t cache_ttl)
190 {
191 ssl_server_handle *handle = calloc(1, sizeof(ssl_server_handle));
192 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
193 SSLCipherSuite cipher = TLS_RSA_WITH_AES_256_CBC_SHA256;
194 uintptr_t peerID = 0xdeadbeef;
195
196 require(handle, out);
197 require(ctx, out);
198
199 require_noerr(SSLSetIOFuncs(ctx,
200 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
201 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
202
203 require_noerr(SSLSetCertificate(ctx, certs), out);
204
205 require_noerr(SSLSetEnabledCiphers(ctx, &cipher, 1), out);
206
207 require_noerr(SSLSetSessionCacheTimeout(ctx, cache_ttl), out);
208
209 require_noerr(SSLSetPeerID(ctx, &peerID, sizeof(peerID)), out);
210
211 handle->comm = comm;
212 handle->certs = certs;
213 handle->st = ctx;
214
215 return handle;
216
217 out:
218 if (ctx)
219 CFRelease(ctx);
220 if (handle)
221 free(handle);
222
223 return NULL;
224 }
225
226 static void
227 ssl_server_handle_destroy(ssl_server_handle *handle)
228 {
229 if(handle) {
230 SSLClose(handle->st);
231 CFRelease(handle->st);
232 free(handle);
233 }
234 }
235
236 static void *securetransport_ssl_server_thread(void *arg)
237 {
238 OSStatus ortn;
239 ssl_server_handle * ssl = (ssl_server_handle *)arg;
240 SSLContextRef ctx = ssl->st;
241 SSLSessionState ssl_state;
242
243 pthread_setname_np("server thread");
244
245 require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out);
246 require_action(ssl_state==kSSLIdle, out, ortn = -1);
247
248 do {
249 ortn = SSLHandshake(ctx);
250 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
251
252 if (ortn == errSSLWouldBlock) {
253 require_action(ssl_state==kSSLHandshake, out, ortn = -1);
254 }
255 } while (ortn == errSSLWouldBlock);
256
257 require_noerr_quiet(ortn, out);
258
259 require_action(ssl_state==kSSLConnected, out, ortn = -1);
260
261 out:
262 SSLClose(ssl->st);
263 close(ssl->comm);
264 pthread_exit((void *)(intptr_t)ortn);
265 return NULL;
266 }
267
268
269 static void
270 tests_cache_ttl(void)
271 {
272 pthread_t client_thread, server_thread;
273 CFArrayRef server_certs = server_chain();
274 CFArrayRef trusted_ca = trusted_roots();
275
276 ok(server_certs, "ttl: got server certs");
277 ok(trusted_ca, "ttl: got trusted roots");
278
279 int i, j, k;
280
281 for (i=0; i<2; i++) { // client cache TTL
282 for (j=0; j<2; j++) { // Server cache TTL
283 for (k=0; k<2; k++) {
284 ssl_client_handle *client = NULL;
285 ssl_server_handle *server = NULL;
286
287 int sp[2];
288 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno);
289 fcntl(sp[0], F_SETNOSIGPIPE, 1);
290 fcntl(sp[1], F_SETNOSIGPIPE, 1);
291
292 client = ssl_client_handle_create(sp[0], false, trusted_ca, true, NULL, i, (i<<8)|(j+1));
293 ok(client!=NULL, "ttl: could not create client handle (%d:%d:%d)", i, j, k);
294 require(client, errOut);
295
296 server = ssl_server_handle_create(sp[1], server_certs, j);
297 ok(server!=NULL, "ttl: could not create server handle (%d:%d:%d)", i, j, k);
298 require(server, errOut);
299 pthread_create(&client_thread, NULL, securetransport_ssl_client_thread, client);
300 pthread_create(&server_thread, NULL, securetransport_ssl_server_thread, server);
301
302 intptr_t server_err, client_err;
303
304 pthread_join(client_thread, (void*)&client_err);
305 pthread_join(server_thread, (void*)&server_err);
306
307 Boolean resumed;
308 unsigned char sessionID[32];
309 size_t sessionIDLength = sizeof(sessionID);
310
311 ok(client_err==0, "ttl: unexpected error %ld (client %d:%d:%d)", client_err, i, j, k);
312 ok(server_err==0, "ttl: unexpected error %ld (server %d:%d:%d)", server_err, i, j, k);
313 ok_status(SSLGetResumableSessionInfo(client->st, &resumed, sessionID, &sessionIDLength), "SSLGetResumableSessionInfo");
314
315 ok((bool)resumed == (bool)(k && (!i) && (!j)), "ttl: Unexpected resumption state=%d (%d:%d:%d)", resumed, i, j, k);
316
317 errOut:
318 ssl_server_handle_destroy(server);
319 ssl_client_handle_destroy(client);
320
321 /* Sleep two seconds so that Session cache TTL can expire */
322 sleep(2);
323 }
324 }
325 }
326
327 CFReleaseSafe(server_certs);
328 CFReleaseSafe(trusted_ca);
329 }
330
331 static void
332 tests_cache_trust(void)
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 ok(server_certs, "trust: got server certs");
341 ok(trusted_ca, "trust: got trusted roots");
342 ok(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 ok(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 ok(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 ok(client_err==0, "trust: unexpected error %ld (client %d:%d:%d:%d:%d)", client_err, any, ca, caonly, leaf, k);
390 ok(server_err==0, "trust: unexpected error %ld (server %d:%d:%d:%d:%d)", server_err, any, ca, caonly, leaf, k);
391 ok_status(SSLGetResumableSessionInfo(client->st, &resumed, sessionID, &sessionIDLength), "SSLGetResumableSessionInfo");
392
393 ok((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 int ssl_55_sessioncache(int argc, char *const *argv)
407 {
408
409 #if TARGET_OS_IPHONE
410 #define N_TRUST_TESTS 8
411 #else
412 #define N_TRUST_TESTS 16
413 #endif
414
415 plan_tests(/*ttl :*/ 6 * 8 + 2 + /* trust:*/ N_TRUST_TESTS*6*2 + 3);
416
417
418 tests_cache_ttl();
419
420 tests_cache_trust();
421
422 return 0;
423 }