]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ssl/regressions/ssl-55-sessioncache.c
Security-57336.1.9.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, CFArrayRef trustedCA, 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(SSLSetTrustedRoots(ctx, trustedCA, true), out);
119
120 require_noerr(SSLSetSessionCacheTimeout(ctx, cache_ttl), out);
121
122 require_noerr(SSLSetPeerID(ctx, &peerID, sizeof(peerID)), out);
123
124 handle->comm = comm;
125 handle->st = ctx;
126
127 return handle;
128
129 out:
130 if (ctx)
131 CFRelease(ctx);
132 if (handle)
133 free(handle);
134
135 return NULL;
136 }
137
138 static void
139 ssl_client_handle_destroy(ssl_client_handle *handle)
140 {
141 if(handle) {
142 SSLClose(handle->st);
143 CFRelease(handle->st);
144 free(handle);
145 }
146 }
147
148 static void *securetransport_ssl_client_thread(void *arg)
149 {
150 OSStatus ortn;
151 ssl_client_handle * ssl = (ssl_client_handle *)arg;
152 SSLContextRef ctx = ssl->st;
153 SSLSessionState ssl_state;
154
155 pthread_setname_np("client thread");
156
157 require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out);
158 require_action(ssl_state==kSSLIdle, out, ortn = -1);
159
160 do {
161 ortn = SSLHandshake(ctx);
162 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
163
164 if (ortn == errSSLWouldBlock) {
165 require_string(ssl_state==kSSLHandshake, out, "Wrong client handshake state after errSSLWouldBlock");
166 }
167 } while (ortn == errSSLWouldBlock);
168
169 out:
170 SSLClose(ssl->st);
171 close(ssl->comm);
172 pthread_exit((void *)(intptr_t)ortn);
173 return NULL;
174 }
175
176
177 typedef struct {
178 SSLContextRef st;
179 int comm;
180 CFArrayRef certs;
181
182 } ssl_server_handle;
183
184 static ssl_server_handle *
185 ssl_server_handle_create(int comm, CFArrayRef certs, uint32_t cache_ttl)
186 {
187 ssl_server_handle *handle = calloc(1, sizeof(ssl_server_handle));
188 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
189 SSLCipherSuite cipher = TLS_RSA_WITH_AES_256_CBC_SHA256;
190 uintptr_t peerID = 0xdeadbeef;
191
192 require(handle, out);
193 require(ctx, out);
194
195 require_noerr(SSLSetIOFuncs(ctx,
196 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
197 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
198
199 require_noerr(SSLSetCertificate(ctx, certs), out);
200
201 require_noerr(SSLSetEnabledCiphers(ctx, &cipher, 1), out);
202
203 require_noerr(SSLSetSessionCacheTimeout(ctx, cache_ttl), out);
204
205 require_noerr(SSLSetPeerID(ctx, &peerID, sizeof(peerID)), out);
206
207 handle->comm = comm;
208 handle->certs = certs;
209 handle->st = ctx;
210
211 return handle;
212
213 out:
214 if (ctx)
215 CFRelease(ctx);
216 if (handle)
217 free(handle);
218
219 return NULL;
220 }
221
222 static void
223 ssl_server_handle_destroy(ssl_server_handle *handle)
224 {
225 if(handle) {
226 SSLClose(handle->st);
227 CFRelease(handle->st);
228 free(handle);
229 }
230 }
231
232 static void *securetransport_ssl_server_thread(void *arg)
233 {
234 OSStatus ortn;
235 ssl_server_handle * ssl = (ssl_server_handle *)arg;
236 SSLContextRef ctx = ssl->st;
237 SSLSessionState ssl_state;
238
239 pthread_setname_np("server thread");
240
241 require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out);
242 require_action(ssl_state==kSSLIdle, out, ortn = -1);
243
244 do {
245 ortn = SSLHandshake(ctx);
246 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
247
248 if (ortn == errSSLWouldBlock) {
249 require_action(ssl_state==kSSLHandshake, out, ortn = -1);
250 }
251 } while (ortn == errSSLWouldBlock);
252
253 require_noerr_quiet(ortn, out);
254
255 require_action(ssl_state==kSSLConnected, out, ortn = -1);
256
257 out:
258 SSLClose(ssl->st);
259 close(ssl->comm);
260 pthread_exit((void *)(intptr_t)ortn);
261 return NULL;
262 }
263
264
265 static void
266 tests(void)
267 {
268 pthread_t client_thread, server_thread;
269 CFArrayRef server_certs = server_chain();
270 CFArrayRef trusted_ca = trusted_roots();
271
272 ok(server_certs, "got server certs");
273 ok(trusted_ca, "got trusted roots");
274
275 int i, j, k;
276
277 for (i=0; i<2; i++) {
278 for (j=0; j<2; j++) {
279 for (k=0; k<2; k++) {
280
281 int sp[2];
282 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno);
283 fcntl(sp[0], F_SETNOSIGPIPE, 1);
284 fcntl(sp[1], F_SETNOSIGPIPE, 1);
285
286 ssl_client_handle *client;
287 client = ssl_client_handle_create(sp[0], trusted_ca, i, (i<<8)|(j+1));
288 ok(client!=NULL, "could not create client handle (%d:%d:%d)", i, j, k);
289
290
291 ssl_server_handle *server;
292 server = ssl_server_handle_create(sp[1], server_certs, j);
293 ok(server!=NULL, "could not create server handle (%d:%d:%d)", i, j, k);
294
295 pthread_create(&client_thread, NULL, securetransport_ssl_client_thread, client);
296 pthread_create(&server_thread, NULL, securetransport_ssl_server_thread, server);
297
298 intptr_t server_err, client_err;
299
300 pthread_join(client_thread, (void*)&client_err);
301 pthread_join(server_thread, (void*)&server_err);
302
303 Boolean resumed;
304 unsigned char sessionID[32];
305 size_t sessionIDLength = sizeof(sessionID);
306
307 ok(client_err==0, "unexpected error %ld (client %d:%d:%d)", client_err, i, j, k);
308 ok(server_err==0, "unexpected error %ld (server %d:%d:%d)", server_err, i, j, k);
309 ok_status(SSLGetResumableSessionInfo(client->st, &resumed, sessionID, &sessionIDLength), "SSLGetResumableSessionInfo");
310
311 ok(i || j || (!k) || resumed, "Unexpected resumption state=%d (%d:%d:%d)", resumed, i, j, k);
312
313 ssl_server_handle_destroy(server);
314 ssl_client_handle_destroy(client);
315 close(sp[0]);
316 close(sp[1]);
317
318 /* Sleep one second so that Session cache TTL can expire */
319 sleep(1);
320 }
321 }
322 }
323
324 CFReleaseSafe(server_certs);
325 CFReleaseSafe(trusted_ca);
326 }
327
328 int ssl_55_sessioncache(int argc, char *const *argv)
329 {
330
331 plan_tests(6 * 8 + 2 /*cert*/);
332
333
334 tests();
335
336 return 0;
337 }