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