]>
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> | |
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 DHE tests: | |
39 | ||
40 | Test both the client and server side. | |
41 | ||
42 | Test Goal: | |
43 | - Make sure that handshake fail when dh param size is too small. | |
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, unsigned dhe_size) | |
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(SSLSetDHEEnabled(ctx, true), out); | |
121 | ||
122 | if(dhe_size) | |
123 | require_noerr(SSLSetMinimumDHGroupSize(ctx, dhe_size), out); | |
124 | ||
125 | handle->comm = comm; | |
126 | handle->st = ctx; | |
127 | handle->dhe_size = dhe_size; | |
128 | ||
129 | return handle; | |
130 | ||
131 | out: | |
132 | if (ctx) | |
133 | CFRelease(ctx); | |
134 | if (handle) | |
135 | free(handle); | |
136 | ||
137 | return NULL; | |
138 | } | |
139 | ||
140 | static void | |
141 | ssl_client_handle_destroy(ssl_client_handle *handle) | |
142 | { | |
143 | if(handle) { | |
144 | SSLClose(handle->st); | |
145 | CFRelease(handle->st); | |
146 | free(handle); | |
147 | } | |
148 | } | |
149 | ||
150 | static void *securetransport_ssl_client_thread(void *arg) | |
151 | { | |
152 | OSStatus ortn; | |
153 | ssl_client_handle * ssl = (ssl_client_handle *)arg; | |
154 | SSLContextRef ctx = ssl->st; | |
155 | SSLSessionState ssl_state; | |
156 | ||
157 | pthread_setname_np("client thread"); | |
158 | ||
159 | require_noerr(ortn=SSLGetSessionState(ctx,&ssl_state), out); | |
160 | require_action(ssl_state==kSSLIdle, out, ortn = -1); | |
161 | ||
162 | do { | |
163 | ortn = SSLHandshake(ctx); | |
164 | require_noerr(SSLGetSessionState(ctx,&ssl_state), out); | |
165 | ||
166 | if (ortn == errSSLWouldBlock) { | |
167 | require_string(ssl_state==kSSLHandshake, out, "Wrong client handshake state after errSSLWouldBlock"); | |
168 | } | |
169 | } while (ortn == errSSLWouldBlock); | |
170 | ||
171 | out: | |
172 | SSLClose(ssl->st); | |
173 | close(ssl->comm); | |
174 | pthread_exit((void *)(intptr_t)ortn); | |
175 | return NULL; | |
176 | } | |
177 | ||
178 | ||
179 | typedef struct { | |
180 | SSLContextRef st; | |
181 | int comm; | |
182 | CFArrayRef certs; | |
183 | ||
184 | } ssl_server_handle; | |
185 | ||
186 | static ssl_server_handle * | |
187 | ssl_server_handle_create(int comm, CFArrayRef certs, const void *dhParams, size_t dhParamsLen) | |
188 | { | |
189 | ssl_server_handle *handle = calloc(1, sizeof(ssl_server_handle)); | |
190 | SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType); | |
191 | SSLCipherSuite cipher = TLS_DHE_RSA_WITH_AES_256_CBC_SHA256; | |
192 | ||
193 | require(handle, out); | |
194 | require(ctx, out); | |
195 | ||
196 | require_noerr(SSLSetIOFuncs(ctx, | |
197 | (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out); | |
198 | require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out); | |
199 | ||
200 | require_noerr(SSLSetCertificate(ctx, certs), out); | |
201 | ||
202 | require_noerr(SSLSetEnabledCiphers(ctx, &cipher, 1), out); | |
203 | ||
204 | if(dhParams) | |
205 | require_noerr(SSLSetDiffieHellmanParams(ctx, dhParams, dhParamsLen), 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 | ||
266 | static | |
267 | unsigned client_dhe_sizes[] = { | |
268 | 0, // default, don't set. | |
269 | 256, // will resolve to 512. | |
270 | 512, | |
271 | 768, | |
272 | 1024, | |
273 | 2048, | |
274 | 4096, // will resolve to 2048. | |
275 | }; | |
276 | ||
277 | ||
278 | static const unsigned n_client_dhe_sizes = sizeof(client_dhe_sizes)/sizeof(client_dhe_sizes[0]); | |
279 | ||
280 | static uint8_t dh_parameters_256_data[] = { | |
281 | 0x30, 0x26, 0x02, 0x21, 0x00, 0xd8, 0x23, 0xeb, 0xcb, 0x41, 0xd0, 0x3a, | |
282 | 0xc4, 0x9a, 0x2a, 0x2a, 0x4f, 0x35, 0xf7, 0x4f, 0xd9, 0xc5, 0x2e, 0xf8, | |
283 | 0x44, 0xa7, 0x74, 0xe3, 0x84, 0x98, 0x9f, 0xad, 0x58, 0xd5, 0x15, 0xb4, | |
284 | 0xf3, 0x02, 0x01, 0x02 | |
285 | }; | |
286 | ||
287 | static uint8_t dh_parameters_512_data[] = { | |
288 | 0x30, 0x46, 0x02, 0x41, 0x00, 0x85, 0xcd, 0xc1, 0x7e, 0x26, 0xeb, 0x37, | |
289 | 0x84, 0x13, 0xd0, 0x3b, 0x07, 0xc1, 0x57, 0x7d, 0xf3, 0x55, 0x8d, 0xa0, | |
290 | 0xc4, 0xa5, 0x03, 0xc4, 0x2c, 0xc6, 0xd5, 0xa6, 0x31, 0xcb, 0x68, 0xdf, | |
291 | 0x5d, 0x96, 0x20, 0x1a, 0x15, 0x57, 0x49, 0x7d, 0xd7, 0x51, 0x65, 0x6e, | |
292 | 0x37, 0xa8, 0xe3, 0xe9, 0xe1, 0x59, 0x2e, 0xd4, 0x57, 0x4a, 0xf0, 0xcb, | |
293 | 0x0e, 0x85, 0x07, 0xdd, 0x35, 0xa7, 0xe3, 0xc6, 0xbb, 0x02, 0x01, 0x02 | |
294 | }; | |
295 | ||
296 | static uint8_t dh_parameters_768_data[] = { | |
297 | 0x30, 0x66, 0x02, 0x61, 0x00, 0xe1, 0xa2, 0x50, 0xab, 0xb0, 0xdc, 0xef, | |
298 | 0xe1, 0x2f, 0xd9, 0xde, 0x59, 0x86, 0x24, 0x43, 0x3b, 0xf3, 0x40, 0x9d, | |
299 | 0x02, 0xcc, 0xe2, 0x70, 0x63, 0x46, 0x8d, 0x0f, 0xf3, 0x8a, 0xc6, 0xa0, | |
300 | 0x1d, 0x7b, 0x30, 0x83, 0x10, 0x48, 0x40, 0x28, 0xa4, 0x3e, 0xbe, 0x4d, | |
301 | 0xb6, 0xea, 0x90, 0x02, 0xae, 0x25, 0x93, 0xc0, 0xe8, 0x36, 0x5c, 0xc8, | |
302 | 0xc8, 0x0b, 0x04, 0xd5, 0x05, 0xac, 0x67, 0x24, 0x4b, 0xa9, 0x42, 0x5a, | |
303 | 0x03, 0x65, 0x4d, 0xd0, 0xc0, 0xbd, 0x78, 0x32, 0xd0, 0x8c, 0x0a, 0xf4, | |
304 | 0xbf, 0xd1, 0x61, 0x86, 0x13, 0x13, 0x3b, 0x83, 0xce, 0xbf, 0x3b, 0xbc, | |
305 | 0x8f, 0xf9, 0x4e, 0x50, 0xe3, 0x02, 0x01, 0x02 | |
306 | }; | |
307 | ||
308 | static uint8_t dh_parameters_1024_data[] = { | |
309 | 0x30, 0x81, 0x87, 0x02, 0x81, 0x81, 0x00, 0xd5, 0x06, 0x69, 0xc6, 0xd4, | |
310 | 0x98, 0x2b, 0xe3, 0x49, 0xe2, 0xa1, 0x9b, 0x82, 0xaf, 0x3f, 0xaa, 0xc3, | |
311 | 0x86, 0x2a, 0x7a, 0xfa, 0x62, 0x12, 0x33, 0x45, 0x9f, 0x34, 0x57, 0xc6, | |
312 | 0x6c, 0x88, 0x81, 0xa6, 0x5d, 0xa3, 0x43, 0xe5, 0x4d, 0x87, 0x4f, 0x69, | |
313 | 0x3d, 0x2b, 0xc8, 0x18, 0xb6, 0xd7, 0x29, 0x53, 0x94, 0x0d, 0x73, 0x9b, | |
314 | 0x08, 0x22, 0x73, 0x84, 0x7b, 0x5a, 0x03, 0x2e, 0xfc, 0x10, 0x9b, 0x35, | |
315 | 0xc6, 0xa1, 0xca, 0x36, 0xd0, 0xcc, 0x3e, 0xa2, 0x04, 0x3a, 0x8a, 0xe8, | |
316 | 0x87, 0xe8, 0x60, 0x72, 0xee, 0x99, 0xf3, 0x04, 0x0a, 0xd8, 0x1a, 0xe6, | |
317 | 0xfc, 0xbc, 0xe1, 0xc5, 0x9d, 0x3a, 0xca, 0xf9, 0xfd, 0xbf, 0x58, 0xd3, | |
318 | 0x4d, 0xde, 0x8b, 0x4a, 0xb5, 0x37, 0x1e, 0x6d, 0xf4, 0x22, 0x0f, 0xb7, | |
319 | 0x48, 0x0a, 0xda, 0x82, 0x40, 0xc9, 0x55, 0x20, 0x01, 0x3b, 0x35, 0xb2, | |
320 | 0x94, 0x68, 0xab, 0x02, 0x01, 0x02 | |
321 | }; | |
322 | ||
323 | ||
324 | static | |
325 | struct { | |
326 | const void *dhParams; | |
327 | size_t dhParamsLen; | |
328 | } server_dhe_params[] = { | |
329 | {dh_parameters_256_data, sizeof(dh_parameters_256_data)}, | |
330 | {dh_parameters_512_data, sizeof(dh_parameters_512_data)}, | |
331 | {dh_parameters_768_data, sizeof(dh_parameters_768_data)}, | |
332 | {dh_parameters_1024_data, sizeof(dh_parameters_1024_data)}, | |
333 | {NULL, 0}, // default is a 2048 | |
334 | }; | |
335 | ||
336 | static const unsigned n_server_dhe_params = sizeof(server_dhe_params)/sizeof(server_dhe_params[0]); | |
337 | ||
338 | static | |
339 | int expected_client_error[n_server_dhe_params][n_client_dhe_sizes] = { | |
340 | //Client: | |
341 | // (default) | |
342 | // 1024, 512, 512, 768, 1024, 2048, 2048 // Server: | |
343 | { -9850, -9850, -9850, -9850, -9850, -9850, -9850}, // 256 | |
344 | { -9850, 0, 0, -9850, -9850, -9850, -9850}, // 512 | |
345 | { -9850, 0, 0, 0, -9850, -9850, -9850}, // 768 | |
346 | { 0, 0, 0, 0, 0, -9850, -9850}, // 1024 | |
347 | { 0, 0, 0, 0, 0, 0, 0}, // default(2048) | |
348 | }; | |
349 | ||
350 | static void | |
351 | tests(void) | |
352 | { | |
353 | pthread_t client_thread, server_thread; | |
354 | CFArrayRef server_certs = server_chain(); | |
355 | CFArrayRef trusted_ca = trusted_roots(); | |
356 | ||
357 | ok(server_certs, "got server certs"); | |
358 | ok(trusted_ca, "got trusted roots"); | |
359 | ||
360 | int i, j; | |
361 | ||
362 | for (i=0; i<n_server_dhe_params; i++) { | |
363 | for (j=0; j<n_client_dhe_sizes; j++) { | |
364 | ||
365 | int sp[2]; | |
366 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno); | |
367 | fcntl(sp[0], F_SETNOSIGPIPE, 1); | |
368 | fcntl(sp[1], F_SETNOSIGPIPE, 1); | |
369 | ||
370 | ssl_client_handle *client; | |
371 | client = ssl_client_handle_create(sp[0], trusted_ca, client_dhe_sizes[j]); | |
372 | ok(client!=NULL, "could not create client handle (%d:%d)", i, j); | |
373 | ||
374 | ||
375 | ssl_server_handle *server; | |
376 | server = ssl_server_handle_create(sp[1], server_certs, server_dhe_params[i].dhParams, server_dhe_params[i].dhParamsLen); | |
377 | ok(server!=NULL, "could not create server handle (%d:%d)", i, j); | |
378 | ||
379 | pthread_create(&client_thread, NULL, securetransport_ssl_client_thread, client); | |
380 | pthread_create(&server_thread, NULL, securetransport_ssl_server_thread, server); | |
381 | ||
382 | intptr_t server_err, client_err; | |
383 | ||
384 | pthread_join(client_thread, (void*)&client_err); | |
385 | pthread_join(server_thread, (void*)&server_err); | |
386 | ||
387 | ||
388 | 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); | |
389 | ||
390 | ssl_server_handle_destroy(server); | |
391 | ssl_client_handle_destroy(client); | |
392 | close(sp[0]); | |
393 | close(sp[1]); | |
394 | ||
395 | } | |
396 | } | |
397 | ||
398 | CFReleaseSafe(server_certs); | |
399 | CFReleaseSafe(trusted_ca); | |
400 | } | |
401 | ||
402 | int ssl_54_dhe(int argc, char *const *argv) | |
403 | { | |
404 | ||
405 | plan_tests(n_server_dhe_params * n_client_dhe_sizes * 3 + 2 /*cert*/); | |
406 | ||
407 | ||
408 | tests(); | |
409 | ||
410 | return 0; | |
411 | } |