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