]>
Commit | Line | Data |
---|---|---|
5c19dc3a A |
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> | |
b54c578e | 23 | #include <utilities/SecCFRelease.h> |
5c19dc3a A |
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_regressions.h" | |
36 | #include "ssl-utils.h" | |
37 | ||
38 | /* | |
39 | SSL DHE tests: | |
40 | ||
41 | Test both the client and server side. | |
42 | ||
43 | Test Goal: | |
44 | - Make sure that handshake fail when dh param size is too small. | |
45 | ||
46 | Behavior to verify: | |
47 | - handshake pass or fail | |
48 | ||
49 | */ | |
50 | ||
51 | ||
52 | static OSStatus SocketWrite(SSLConnectionRef conn, const void *data, size_t *length) | |
53 | { | |
54 | size_t len = *length; | |
55 | uint8_t *ptr = (uint8_t *)data; | |
56 | ||
57 | do { | |
58 | ssize_t ret; | |
59 | do { | |
60 | ret = write((int)conn, ptr, len); | |
61 | } while ((ret < 0) && (errno == EAGAIN || errno == EINTR)); | |
62 | if (ret > 0) { | |
63 | len -= ret; | |
64 | ptr += ret; | |
65 | } | |
66 | else | |
67 | return -36; | |
68 | } while (len > 0); | |
69 | ||
70 | *length = *length - len; | |
71 | return errSecSuccess; | |
72 | } | |
73 | ||
74 | static OSStatus SocketRead(SSLConnectionRef conn, void *data, size_t *length) | |
75 | { | |
76 | size_t len = *length; | |
77 | uint8_t *ptr = (uint8_t *)data; | |
78 | ||
79 | do { | |
80 | ssize_t ret; | |
81 | do { | |
82 | ret = read((int)conn, ptr, len); | |
83 | } while ((ret < 0) && (errno == EINPROGRESS || errno == EAGAIN || errno == EINTR)); | |
84 | if (ret > 0) { | |
85 | len -= ret; | |
86 | ptr += ret; | |
87 | } else { | |
88 | printf("read error(%d): ret=%zd, errno=%d\n", (int)conn, ret, errno); | |
89 | return -errno; | |
90 | } | |
91 | } while (len > 0); | |
92 | ||
93 | *length = *length - len; | |
94 | return errSecSuccess; | |
95 | } | |
96 | ||
97 | typedef struct { | |
98 | SSLContextRef st; | |
99 | int comm; | |
100 | unsigned dhe_size; | |
101 | } ssl_client_handle; | |
102 | ||
103 | static ssl_client_handle * | |
104 | ssl_client_handle_create(int comm, CFArrayRef trustedCA, unsigned dhe_size) | |
105 | { | |
106 | ssl_client_handle *handle = calloc(1, sizeof(ssl_client_handle)); | |
107 | SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType); | |
108 | ||
109 | require(handle, out); | |
110 | require(ctx, out); | |
111 | ||
112 | require_noerr(SSLSetIOFuncs(ctx, | |
113 | (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out); | |
114 | require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out); | |
115 | static const char *peer_domain_name = "localhost"; | |
116 | require_noerr(SSLSetPeerDomainName(ctx, peer_domain_name, | |
117 | strlen(peer_domain_name)), out); | |
118 | ||
119 | require_noerr(SSLSetTrustedRoots(ctx, trustedCA, true), out); | |
120 | ||
121 | require_noerr(SSLSetDHEEnabled(ctx, true), out); | |
122 | ||
123 | if(dhe_size) | |
124 | require_noerr(SSLSetMinimumDHGroupSize(ctx, dhe_size), out); | |
125 | ||
126 | handle->comm = comm; | |
127 | handle->st = ctx; | |
128 | handle->dhe_size = dhe_size; | |
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 | ||
158 | pthread_setname_np("client thread"); | |
159 | ||
160 | require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out); | |
161 | require_action(ssl_state==kSSLIdle, out, ortn = -1); | |
162 | ||
163 | do { | |
164 | ortn = SSLHandshake(ctx); | |
165 | require_noerr(SSLGetSessionState(ctx,&ssl_state), out); | |
166 | ||
167 | if (ortn == errSSLWouldBlock) { | |
168 | require_string(ssl_state==kSSLHandshake, out, "Wrong client handshake state after errSSLWouldBlock"); | |
169 | } | |
170 | } while (ortn == errSSLWouldBlock); | |
171 | ||
172 | out: | |
173 | SSLClose(ssl->st); | |
174 | close(ssl->comm); | |
175 | pthread_exit((void *)(intptr_t)ortn); | |
176 | return NULL; | |
177 | } | |
178 | ||
179 | ||
180 | typedef struct { | |
181 | SSLContextRef st; | |
182 | int comm; | |
183 | CFArrayRef certs; | |
184 | ||
185 | } ssl_server_handle; | |
186 | ||
187 | static ssl_server_handle * | |
188 | ssl_server_handle_create(int comm, CFArrayRef certs, const void *dhParams, size_t dhParamsLen) | |
189 | { | |
190 | ssl_server_handle *handle = calloc(1, sizeof(ssl_server_handle)); | |
191 | SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType); | |
192 | SSLCipherSuite cipher = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256; | |
193 | ||
194 | require(handle, out); | |
195 | require(ctx, out); | |
196 | ||
197 | require_noerr(SSLSetIOFuncs(ctx, | |
198 | (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out); | |
199 | require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out); | |
200 | ||
201 | require_noerr(SSLSetCertificate(ctx, certs), out); | |
202 | ||
203 | require_noerr(SSLSetEnabledCiphers(ctx, &cipher, 1), out); | |
204 | ||
205 | if(dhParams) | |
206 | require_noerr(SSLSetDiffieHellmanParams(ctx, dhParams, dhParamsLen), out); | |
207 | ||
208 | handle->comm = comm; | |
209 | handle->certs = certs; | |
210 | handle->st = ctx; | |
211 | ||
212 | return handle; | |
213 | ||
214 | out: | |
215 | if (ctx) | |
216 | CFRelease(ctx); | |
217 | if (handle) | |
218 | free(handle); | |
219 | ||
220 | return NULL; | |
221 | } | |
222 | ||
223 | static void | |
224 | ssl_server_handle_destroy(ssl_server_handle *handle) | |
225 | { | |
226 | if(handle) { | |
227 | SSLClose(handle->st); | |
228 | CFRelease(handle->st); | |
229 | free(handle); | |
230 | } | |
231 | } | |
232 | ||
233 | static void *securetransport_ssl_server_thread(void *arg) | |
234 | { | |
235 | OSStatus ortn; | |
236 | ssl_server_handle * ssl = (ssl_server_handle *)arg; | |
237 | SSLContextRef ctx = ssl->st; | |
238 | SSLSessionState ssl_state; | |
239 | ||
240 | pthread_setname_np("server thread"); | |
241 | ||
242 | require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out); | |
243 | require_action(ssl_state==kSSLIdle, out, ortn = -1); | |
244 | ||
245 | do { | |
246 | ortn = SSLHandshake(ctx); | |
247 | require_noerr(SSLGetSessionState(ctx,&ssl_state), out); | |
248 | ||
249 | if (ortn == errSSLWouldBlock) { | |
250 | require_action(ssl_state==kSSLHandshake, out, ortn = -1); | |
251 | } | |
252 | } while (ortn == errSSLWouldBlock); | |
253 | ||
254 | require_noerr_quiet(ortn, out); | |
255 | ||
256 | require_action(ssl_state==kSSLConnected, out, ortn = -1); | |
257 | ||
258 | out: | |
259 | SSLClose(ssl->st); | |
260 | close(ssl->comm); | |
261 | pthread_exit((void *)(intptr_t)ortn); | |
262 | return NULL; | |
263 | } | |
264 | ||
265 | ||
266 | ||
267 | static | |
268 | unsigned client_dhe_sizes[] = { | |
269 | 0, // default, don't set. | |
270 | 256, // will resolve to 512. | |
271 | 512, | |
272 | 768, | |
273 | 1024, | |
274 | 2048, | |
275 | 4096, // will resolve to 2048. | |
276 | }; | |
277 | ||
278 | ||
279 | static const unsigned n_client_dhe_sizes = sizeof(client_dhe_sizes)/sizeof(client_dhe_sizes[0]); | |
280 | ||
281 | static uint8_t dh_parameters_256_data[] = { | |
282 | 0x30, 0x26, 0x02, 0x21, 0x00, 0xd8, 0x23, 0xeb, 0xcb, 0x41, 0xd0, 0x3a, | |
283 | 0xc4, 0x9a, 0x2a, 0x2a, 0x4f, 0x35, 0xf7, 0x4f, 0xd9, 0xc5, 0x2e, 0xf8, | |
284 | 0x44, 0xa7, 0x74, 0xe3, 0x84, 0x98, 0x9f, 0xad, 0x58, 0xd5, 0x15, 0xb4, | |
285 | 0xf3, 0x02, 0x01, 0x02 | |
286 | }; | |
287 | ||
288 | static uint8_t dh_parameters_512_data[] = { | |
289 | 0x30, 0x46, 0x02, 0x41, 0x00, 0x85, 0xcd, 0xc1, 0x7e, 0x26, 0xeb, 0x37, | |
290 | 0x84, 0x13, 0xd0, 0x3b, 0x07, 0xc1, 0x57, 0x7d, 0xf3, 0x55, 0x8d, 0xa0, | |
291 | 0xc4, 0xa5, 0x03, 0xc4, 0x2c, 0xc6, 0xd5, 0xa6, 0x31, 0xcb, 0x68, 0xdf, | |
292 | 0x5d, 0x96, 0x20, 0x1a, 0x15, 0x57, 0x49, 0x7d, 0xd7, 0x51, 0x65, 0x6e, | |
293 | 0x37, 0xa8, 0xe3, 0xe9, 0xe1, 0x59, 0x2e, 0xd4, 0x57, 0x4a, 0xf0, 0xcb, | |
294 | 0x0e, 0x85, 0x07, 0xdd, 0x35, 0xa7, 0xe3, 0xc6, 0xbb, 0x02, 0x01, 0x02 | |
295 | }; | |
296 | ||
297 | static uint8_t dh_parameters_768_data[] = { | |
298 | 0x30, 0x66, 0x02, 0x61, 0x00, 0xe1, 0xa2, 0x50, 0xab, 0xb0, 0xdc, 0xef, | |
299 | 0xe1, 0x2f, 0xd9, 0xde, 0x59, 0x86, 0x24, 0x43, 0x3b, 0xf3, 0x40, 0x9d, | |
300 | 0x02, 0xcc, 0xe2, 0x70, 0x63, 0x46, 0x8d, 0x0f, 0xf3, 0x8a, 0xc6, 0xa0, | |
301 | 0x1d, 0x7b, 0x30, 0x83, 0x10, 0x48, 0x40, 0x28, 0xa4, 0x3e, 0xbe, 0x4d, | |
302 | 0xb6, 0xea, 0x90, 0x02, 0xae, 0x25, 0x93, 0xc0, 0xe8, 0x36, 0x5c, 0xc8, | |
303 | 0xc8, 0x0b, 0x04, 0xd5, 0x05, 0xac, 0x67, 0x24, 0x4b, 0xa9, 0x42, 0x5a, | |
304 | 0x03, 0x65, 0x4d, 0xd0, 0xc0, 0xbd, 0x78, 0x32, 0xd0, 0x8c, 0x0a, 0xf4, | |
305 | 0xbf, 0xd1, 0x61, 0x86, 0x13, 0x13, 0x3b, 0x83, 0xce, 0xbf, 0x3b, 0xbc, | |
306 | 0x8f, 0xf9, 0x4e, 0x50, 0xe3, 0x02, 0x01, 0x02 | |
307 | }; | |
308 | ||
309 | static uint8_t dh_parameters_1024_data[] = { | |
310 | 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0xd5, 0x06, 0x69, 0xc6, 0xd4, | |
311 | 0x98, 0x2b, 0xe3, 0x49, 0xe2, 0xa1, 0x9b, 0x82, 0xaf, 0x3f, 0xaa, 0xc3, | |
312 | 0x86, 0x2a, 0x7a, 0xfa, 0x62, 0x12, 0x33, 0x45, 0x9f, 0x34, 0x57, 0xc6, | |
313 | 0x6c, 0x88, 0x81, 0xa6, 0x5d, 0xa3, 0x43, 0xe5, 0x4d, 0x87, 0x4f, 0x69, | |
314 | 0x3d, 0x2b, 0xc8, 0x18, 0xb6, 0xd7, 0x29, 0x53, 0x94, 0x0d, 0x73, 0x9b, | |
315 | 0x08, 0x22, 0x73, 0x84, 0x7b, 0x5a, 0x03, 0x2e, 0xfc, 0x10, 0x9b, 0x35, | |
316 | 0xc6, 0xa1, 0xca, 0x36, 0xd0, 0xcc, 0x3e, 0xa2, 0x04, 0x3a, 0x8a, 0xe8, | |
317 | 0x87, 0xe8, 0x60, 0x72, 0xee, 0x99, 0xf3, 0x04, 0x0a, 0xd8, 0x1a, 0xe6, | |
318 | 0xfc, 0xbc, 0xe1, 0xc5, 0x9d, 0x3a, 0xca, 0xf9, 0xfd, 0xbf, 0x58, 0xd3, | |
319 | 0x4d, 0xde, 0x8b, 0x4a, 0xb5, 0x37, 0x1e, 0x6d, 0xf4, 0x22, 0x0f, 0xb7, | |
320 | 0x48, 0x0a, 0xda, 0x82, 0x40, 0xc9, 0x55, 0x20, 0x01, 0x3b, 0x35, 0xb2, | |
321 | 0x94, 0x68, 0xab, 0x02, 0x01, 0x02 | |
322 | }; | |
323 | ||
324 | ||
325 | static | |
326 | struct { | |
327 | const void *dhParams; | |
328 | size_t dhParamsLen; | |
329 | } server_dhe_params[] = { | |
330 | {dh_parameters_256_data, sizeof(dh_parameters_256_data)}, | |
331 | {dh_parameters_512_data, sizeof(dh_parameters_512_data)}, | |
332 | {dh_parameters_768_data, sizeof(dh_parameters_768_data)}, | |
333 | {dh_parameters_1024_data, sizeof(dh_parameters_1024_data)}, | |
334 | {NULL, 0}, // default is a 2048 | |
335 | }; | |
336 | ||
337 | static const unsigned n_server_dhe_params = sizeof(server_dhe_params)/sizeof(server_dhe_params[0]); | |
338 | ||
339 | static | |
340 | int expected_client_error[n_server_dhe_params][n_client_dhe_sizes] = { | |
341 | //Client: | |
342 | // (default) | |
343 | // 1024, 512, 512, 768, 1024, 2048, 2048 // Server: | |
344 | { -9850, -9850, -9850, -9850, -9850, -9850, -9850}, // 256 | |
345 | { -9850, 0, 0, -9850, -9850, -9850, -9850}, // 512 | |
346 | { -9850, 0, 0, 0, -9850, -9850, -9850}, // 768 | |
347 | { 0, 0, 0, 0, 0, -9850, -9850}, // 1024 | |
348 | { 0, 0, 0, 0, 0, 0, 0}, // default(2048) | |
349 | }; | |
350 | ||
351 | static void | |
352 | tests(void) | |
353 | { | |
354 | pthread_t client_thread, server_thread; | |
355 | CFArrayRef server_certs = server_chain(); | |
356 | CFArrayRef trusted_ca = trusted_roots(); | |
357 | ||
358 | ok(server_certs, "got server certs"); | |
359 | ok(trusted_ca, "got trusted roots"); | |
360 | ||
361 | int i, j; | |
362 | ||
363 | for (i=0; i<n_server_dhe_params; i++) { | |
364 | for (j=0; j<n_client_dhe_sizes; j++) { | |
365 | ||
366 | int sp[2]; | |
367 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno); | |
368 | fcntl(sp[0], F_SETNOSIGPIPE, 1); | |
369 | fcntl(sp[1], F_SETNOSIGPIPE, 1); | |
370 | ||
371 | ssl_client_handle *client; | |
372 | client = ssl_client_handle_create(sp[0], trusted_ca, client_dhe_sizes[j]); | |
373 | ok(client!=NULL, "could not create client handle (%d:%d)", i, j); | |
374 | ||
375 | ||
376 | ssl_server_handle *server; | |
377 | server = ssl_server_handle_create(sp[1], server_certs, server_dhe_params[i].dhParams, server_dhe_params[i].dhParamsLen); | |
378 | ok(server!=NULL, "could not create server handle (%d:%d)", i, j); | |
379 | ||
380 | pthread_create(&client_thread, NULL, securetransport_ssl_client_thread, client); | |
381 | pthread_create(&server_thread, NULL, securetransport_ssl_server_thread, server); | |
382 | ||
383 | intptr_t server_err, client_err; | |
384 | ||
385 | pthread_join(client_thread, (void*)&client_err); | |
386 | pthread_join(server_thread, (void*)&server_err); | |
387 | ||
388 | ||
389 | ok(client_err==expected_client_error[i][j], "unexpected error %d!=%d (client %d:%d)", (int)client_err, expected_client_error[i][j], i, j); | |
390 | ||
391 | ssl_server_handle_destroy(server); | |
392 | ssl_client_handle_destroy(client); | |
5c19dc3a A |
393 | } |
394 | } | |
395 | ||
396 | CFReleaseSafe(server_certs); | |
397 | CFReleaseSafe(trusted_ca); | |
398 | } | |
399 | ||
400 | int ssl_54_dhe(int argc, char *const *argv) | |
401 | { | |
402 | ||
403 | plan_tests(n_server_dhe_params * n_client_dhe_sizes * 3 + 2 /*cert*/); | |
404 | ||
405 | ||
406 | tests(); | |
407 | ||
408 | return 0; | |
409 | } |