]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+renegotiate.m
Security-58286.260.20.tar.gz
[apple/security.git] / OSX / libsecurity_ssl / regressions / SecureTransportTests / STLegacyTests+renegotiate.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 (renegotiation)
38
39 /*
40 SSL Renegotiation tests:
41
42 Test both the client and server side.
43
44 Test Goal:
45 - Make sure that renegotiation works on both client and server.
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 bool renegotiate;
103 } ssl_client_handle;
104
105 static ssl_client_handle *
106 ssl_client_handle_create(int comm, bool renegotiate)
107 {
108 ssl_client_handle *handle = calloc(1, sizeof(ssl_client_handle));
109 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
110
111 require(handle, out);
112 require(ctx, out);
113
114 require_noerr(SSLSetIOFuncs(ctx,
115 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
116 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
117 static const char *peer_domain_name = "localhost";
118 require_noerr(SSLSetPeerDomainName(ctx, peer_domain_name,
119 strlen(peer_domain_name)), out);
120
121 require_noerr(SSLSetSessionOption(ctx, kSSLSessionOptionBreakOnServerAuth, TRUE), out);
122
123 require_noerr(SSLSetAllowsAnyRoot(ctx, TRUE), out);
124
125
126 handle->comm = comm;
127 handle->st = ctx;
128 handle->renegotiate = renegotiate;
129
130 return handle;
131
132 out:
133 if (ctx)
134 CFRelease(ctx);
135 if (handle)
136 free(handle);
137
138 return NULL;
139 }
140
141 static void
142 ssl_client_handle_destroy(ssl_client_handle *handle)
143 {
144 if(handle) {
145 SSLClose(handle->st);
146 CFRelease(handle->st);
147 free(handle);
148 }
149 }
150
151 static void *securetransport_ssl_client_thread(void *arg)
152 {
153 OSStatus ortn;
154 ssl_client_handle * ssl = (ssl_client_handle *)arg;
155 SSLContextRef ctx = ssl->st;
156 SSLSessionState ssl_state;
157 bool peer_auth_received = false;
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 == errSSLPeerAuthCompleted) {
169 require_action(!peer_auth_received, out, ortn = -1);
170 peer_auth_received = true;
171 }
172 if (ortn == errSSLWouldBlock) {
173 require_string(ssl_state==kSSLHandshake, out, "Wrong client handshake state after errSSLWouldBlock");
174 }
175 } while (ortn == errSSLWouldBlock || ortn == errSSLPeerAuthCompleted);
176
177 require_noerr(ortn, out);
178 require_action(ssl_state==kSSLConnected, out, ortn = -1);
179 require_action(peer_auth_received, out, ortn = -1);
180
181 if(ssl->renegotiate) {
182 // Renegotiate then write
183 require_noerr(SSLReHandshake(ctx), out);
184
185 peer_auth_received = false;
186
187 do {
188 ortn = SSLHandshake(ctx);
189 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
190 if (ortn == errSSLPeerAuthCompleted) {
191 require_action(!peer_auth_received, out, ortn = -1);
192 peer_auth_received = true;
193 }
194 if (ortn == errSSLWouldBlock) {
195 require_action(ssl_state==kSSLHandshake, out, ortn = -1);
196 }
197 } while (ortn == errSSLWouldBlock || ortn == errSSLPeerAuthCompleted);
198
199 require_noerr(ortn, out);
200 require_action(ssl_state==kSSLConnected, out, ortn = -1);
201 require_action(peer_auth_received, out, ortn = -1);
202
203 unsigned char obuf[100];
204
205 size_t len = sizeof(obuf);
206 size_t olen;
207 unsigned char *p = obuf;
208
209 require_action(errSecSuccess==SecRandomCopyBytes(kSecRandomDefault, len, p), out, ortn = -1);
210
211 while (len) {
212 require_noerr(ortn = SSLWrite(ctx, p, len, &olen), out);
213 len -= olen;
214 p += olen;
215 }
216 } else {
217 // just read.
218 unsigned char ibuf[100];
219
220 peer_auth_received = false;
221
222 size_t len = sizeof(ibuf);
223 size_t olen;
224 unsigned char *p = ibuf;
225 while (len) {
226 ortn = SSLRead(ctx, p, len, &olen);
227
228 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
229
230 if (ortn == errSSLPeerAuthCompleted) {
231 require_action(!peer_auth_received, out, ortn = -1);
232 peer_auth_received = true;
233 } else {
234 require_noerr(ortn, out);
235 }
236
237 /* If we get data, we should have renegotiated */
238 if(olen) {
239 require_noerr(ortn, out);
240 require_action(ssl_state==kSSLConnected, out, ortn = -1);
241 require_action(peer_auth_received, out, ortn = -1);
242 }
243
244 len -= olen;
245 p += olen;
246 }
247 }
248
249 out:
250 SSLClose(ssl->st);
251 close(ssl->comm);
252 pthread_exit((void *)(intptr_t)ortn);
253 return NULL;
254 }
255
256
257 typedef struct {
258 SSLContextRef st;
259 int comm;
260 CFArrayRef certs;
261 bool renegotiate;
262 } ssl_server_handle;
263
264 static ssl_server_handle *
265 ssl_server_handle_create(int comm, CFArrayRef certs, bool renegotiate)
266 {
267 ssl_server_handle *handle = calloc(1, sizeof(ssl_server_handle));
268 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
269 SSLCipherSuite cipher = TLS_RSA_WITH_AES_256_CBC_SHA256;
270
271 require(handle, out);
272 require(ctx, out);
273
274 require_noerr(SSLSetIOFuncs(ctx,
275 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
276 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
277
278 require_noerr(SSLSetCertificate(ctx, certs), out);
279
280 require_noerr(SSLSetEnabledCiphers(ctx, &cipher, 1), out);
281
282 require_noerr(SSLSetSessionOption(ctx, kSSLSessionOptionBreakOnClientHello, TRUE), out);
283 require_noerr(SSLSetSessionOption(ctx, kSSLSessionOptionAllowRenegotiation, TRUE), out);
284
285 handle->comm = comm;
286 handle->certs = certs;
287 handle->st = ctx;
288 handle->renegotiate = renegotiate;
289
290 return handle;
291
292 out:
293 if (ctx)
294 CFRelease(ctx);
295 if (handle)
296 free(handle);
297
298 return NULL;
299 }
300
301 static void
302 ssl_server_handle_destroy(ssl_server_handle *handle)
303 {
304 if(handle) {
305 SSLClose(handle->st);
306 CFRelease(handle->st);
307 free(handle);
308 }
309 }
310
311 static void *securetransport_ssl_server_thread(void *arg)
312 {
313 OSStatus ortn;
314 ssl_server_handle * ssl = (ssl_server_handle *)arg;
315 SSLContextRef ctx = ssl->st;
316 SSLSessionState ssl_state;
317 bool client_hello_received = false;
318
319 pthread_setname_np("server thread");
320
321 require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out);
322 require_action(ssl_state==kSSLIdle, out, ortn = -1);
323
324 do {
325 ortn = SSLHandshake(ctx);
326 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
327 if (ortn == errSSLClientHelloReceived) {
328 require_action(!client_hello_received, out, ortn = -1);
329 client_hello_received = true;
330 }
331 if (ortn == errSSLWouldBlock) {
332 require_action(ssl_state==kSSLHandshake, out, ortn = -1);
333 }
334 } while (ortn == errSSLWouldBlock || ortn == errSSLClientHelloReceived);
335
336 require_noerr(ortn, out);
337 require_action(ssl_state==kSSLConnected, out, ortn = -1);
338 require_action(client_hello_received, out, ortn = -1);
339
340 if(ssl->renegotiate) {
341 // Renegotiate then write
342 require_noerr(SSLReHandshake(ctx), out);
343
344 client_hello_received = false;
345
346 do {
347 ortn = SSLHandshake(ctx);
348 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
349 if (ortn == errSSLClientHelloReceived) {
350 require_action(!client_hello_received, out, ortn = -1);
351 client_hello_received = true;
352 }
353 if (ortn == errSSLWouldBlock) {
354 require_action(ssl_state==kSSLHandshake, out, ortn = -1);
355 }
356 } while (ortn == errSSLWouldBlock || ortn == errSSLClientHelloReceived);
357
358 require_noerr(ortn, out);
359 require_action(ssl_state==kSSLConnected, out, ortn = -1);
360 require_action(client_hello_received, out, ortn = -1);
361
362 unsigned char obuf[100];
363
364 size_t len = sizeof(obuf);
365 size_t olen;
366 unsigned char *p = obuf;
367
368 require_action(errSecSuccess==SecRandomCopyBytes(kSecRandomDefault, len, p), out, ortn = -1);
369
370 while (len) {
371 require_noerr(ortn = SSLWrite(ctx, p, len, &olen), out);
372 len -= olen;
373 p += olen;
374 }
375 } else {
376 // just read
377 unsigned char ibuf[100];
378
379 client_hello_received = false;
380
381 size_t len = sizeof(ibuf);
382 size_t olen;
383 unsigned char *p = ibuf;
384 while (len) {
385 ortn = SSLRead(ctx, p, len, &olen);
386
387 require_noerr(SSLGetSessionState(ctx,&ssl_state), out);
388
389 if (ortn == errSSLClientHelloReceived) {
390 require_action(!client_hello_received, out, ortn = -1);
391 client_hello_received = true;
392 } else {
393 require_noerr(ortn, out);
394 }
395
396 /* If we get data, we should have renegotiated */
397 if(olen) {
398 require_noerr(ortn, out);
399 require_action(ssl_state==kSSLConnected, out, ortn = -1);
400 require_action(client_hello_received, out, ortn = -1);
401 }
402
403 len -= olen;
404 p += olen;
405 }
406 }
407
408 out:
409 SSLClose(ssl->st);
410 close(ssl->comm);
411 pthread_exit((void *)(intptr_t)ortn);
412 return NULL;
413 }
414
415
416 -(void) test_renego: (bool) client_renego
417 {
418 pthread_t client_thread, server_thread;
419 CFArrayRef server_certs = server_chain();
420
421 XCTAssert(server_certs, "renego: got server certs");
422
423
424 int sp[2];
425 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno);
426 fcntl(sp[0], F_SETNOSIGPIPE, 1);
427 fcntl(sp[1], F_SETNOSIGPIPE, 1);
428
429 ssl_client_handle *client;
430 client = ssl_client_handle_create(sp[0], client_renego);
431 XCTAssert(client!=NULL, "renego: could not create client handle");
432
433
434 ssl_server_handle *server;
435 server = ssl_server_handle_create(sp[1], server_certs, !client_renego);
436 XCTAssert(server!=NULL, "renego: could not create server handle");
437
438 pthread_create(&client_thread, NULL, securetransport_ssl_client_thread, client);
439 pthread_create(&server_thread, NULL, securetransport_ssl_server_thread, server);
440
441 intptr_t server_err, client_err;
442
443 pthread_join(client_thread, (void*)&client_err);
444 pthread_join(server_thread, (void*)&server_err);
445
446 XCTAssert(client_err==0, "renego: unexpected error %ld (client)", client_err);
447 XCTAssert(server_err==0, "renego: unexpected error %ld (server)", server_err);
448
449 ssl_server_handle_destroy(server);
450 ssl_client_handle_destroy(client);
451
452
453 CFReleaseSafe(server_certs);
454 }
455
456
457 -(void) testRenegotiation
458 {
459
460 [self test_renego:false]; // server side trigger renego.
461 [self test_renego:true]; // client side trigger renego.
462
463 }
464 @end
465