]>
Commit | Line | Data |
---|---|---|
427c49bc 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 CipherSuite tests | |
39 | ||
40 | Below are all the ciphers that are individually tested. The first element | |
41 | is the SecureTransport/RFC name; the second is what openssl calls it, which | |
42 | can be looked up in ciphers(1). | |
43 | ||
44 | All SSL_DH_* and TLS_DH_* are disabled because neither openssl nor | |
45 | securetranport support them: | |
46 | SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, SSL_DH_DSS_WITH_DES_CBC_SHA, | |
47 | SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA, SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, | |
48 | SSL_DH_RSA_WITH_DES_CBC_SHA, SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA, | |
49 | TLS_DH_DSS_WITH_AES_128_CBC_SHA, TLS_DH_RSA_WITH_AES_128_CBC_SHA, | |
50 | TLS_DH_DSS_WITH_AES_256_CBC_SHA, TLS_DH_RSA_WITH_AES_256_CBC_SHA, | |
51 | ||
52 | DSS is unimplemented by securetransport on the phone: | |
53 | SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, | |
54 | SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, | |
55 | TLS_DHE_DSS_WITH_AES_256_CBC_SHA, | |
56 | ||
57 | SSLv2 ciphersuites disabled by securetransport on phone: | |
58 | SSL_RSA_WITH_RC2_CBC_MD5, SSL_RSA_WITH_IDEA_CBC_MD5, | |
59 | SSL_RSA_WITH_DES_CBC_MD5, SSL_RSA_WITH_3DES_EDE_CBC_MD5, | |
60 | ||
61 | SSLv3 ciphersuites disabled by securetransport on phone: | |
62 | SSL_RSA_WITH_IDEA_CBC_SHA, SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 | |
63 | ||
64 | Export ciphersuites disabled on iOS 5.0: | |
65 | SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, | |
66 | SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, | |
67 | SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, | |
68 | SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, SSL_DH_anon_WITH_DES_CBC_SHA | |
69 | ||
70 | */ | |
71 | ||
72 | typedef struct _CipherSuiteName { | |
73 | SSLCipherSuite cipher; | |
74 | const char *name; | |
75 | bool dh_anonymous; | |
76 | } CipherSuiteName; | |
77 | ||
78 | #define CIPHER(cipher, dh_anonymous) { cipher, #cipher, dh_anonymous }, | |
79 | ||
80 | static const CipherSuiteName ciphers[] = { | |
81 | //SSL_NULL_WITH_NULL_NULL, unsupported | |
82 | CIPHER(SSL_RSA_WITH_NULL_SHA, false) | |
83 | CIPHER(SSL_RSA_WITH_NULL_MD5, false) | |
84 | CIPHER(TLS_RSA_WITH_NULL_SHA256, false) | |
85 | ||
86 | CIPHER(SSL_RSA_WITH_RC4_128_MD5, false) | |
87 | CIPHER(SSL_RSA_WITH_RC4_128_SHA, false) | |
88 | CIPHER(SSL_RSA_WITH_3DES_EDE_CBC_SHA, false) | |
89 | ||
90 | CIPHER(SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, false) | |
91 | CIPHER(SSL_DH_anon_WITH_RC4_128_MD5, true) | |
92 | CIPHER(SSL_DH_anon_WITH_3DES_EDE_CBC_SHA, true) | |
93 | CIPHER(TLS_DHE_RSA_WITH_AES_128_CBC_SHA, false) | |
94 | CIPHER(TLS_DH_anon_WITH_AES_128_CBC_SHA, true) | |
95 | CIPHER(TLS_DHE_RSA_WITH_AES_256_CBC_SHA, false) | |
96 | CIPHER(TLS_DH_anon_WITH_AES_256_CBC_SHA, true) | |
97 | ||
98 | CIPHER(TLS_RSA_WITH_AES_128_CBC_SHA, false) | |
99 | CIPHER(TLS_RSA_WITH_AES_256_CBC_SHA, false) | |
100 | ||
101 | ||
102 | CIPHER(TLS_PSK_WITH_AES_128_CBC_SHA, true) | |
103 | CIPHER(TLS_PSK_WITH_AES_256_CBC_SHA384, true) | |
104 | CIPHER(TLS_PSK_WITH_AES_128_CBC_SHA256, true) | |
105 | CIPHER(TLS_PSK_WITH_AES_256_CBC_SHA, true) | |
106 | CIPHER(TLS_PSK_WITH_AES_128_CBC_SHA, true) | |
107 | CIPHER(TLS_PSK_WITH_RC4_128_SHA, true) | |
108 | CIPHER(TLS_PSK_WITH_3DES_EDE_CBC_SHA, true) | |
109 | CIPHER(TLS_PSK_WITH_NULL_SHA384, true) | |
110 | CIPHER(TLS_PSK_WITH_NULL_SHA256, true) | |
111 | CIPHER(TLS_PSK_WITH_NULL_SHA, true) | |
112 | ||
113 | ||
114 | #if 0 | |
115 | CIPHER(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, false) | |
116 | CIPHER(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, false) | |
117 | ||
118 | CIPHER(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, false) | |
119 | CIPHER(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, false) | |
120 | ||
121 | CIPHER(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, false) | |
122 | CIPHER(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, false) | |
123 | ||
124 | CIPHER(TLS_ECDH_anon_WITH_AES_128_CBC_SHA, true) | |
125 | CIPHER(TLS_ECDH_anon_WITH_AES_256_CBC_SHA, true) | |
126 | ||
127 | CIPHER(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, false) | |
128 | CIPHER(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, false) | |
129 | CIPHER(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, false) | |
130 | CIPHER(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, false) | |
131 | #endif | |
132 | ||
133 | #if 0 | |
134 | CIPHER(TLS_RSA_WITH_AES_256_GCM_SHA384, false) | |
135 | CIPHER(TLS_RSA_WITH_AES_128_GCM_SHA256, false) | |
136 | #endif | |
137 | ||
138 | /* Export ciphers are disabled */ | |
139 | #if 0 | |
140 | CIPHER(SSL_RSA_EXPORT_WITH_RC4_40_MD5, false) | |
141 | CIPHER(SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, false) | |
142 | CIPHER(SSL_RSA_WITH_DES_CBC_SHA, false) | |
143 | CIPHER(SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, false) | |
144 | CIPHER(SSL_DHE_RSA_WITH_DES_CBC_SHA, false) | |
145 | CIPHER(SSL_DH_anon_EXPORT_WITH_RC4_40_MD5, true) | |
146 | CIPHER(SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA, true) | |
147 | CIPHER(SSL_DH_anon_WITH_DES_CBC_SHA, true) | |
148 | #endif | |
149 | ||
150 | { -1 } | |
151 | }; | |
152 | ||
153 | static int ciphers_len = array_size(ciphers); | |
154 | ||
155 | ||
156 | static int protos[]={kTLSProtocol1, kTLSProtocol11, kTLSProtocol12 }; | |
157 | static int nprotos = sizeof(protos)/sizeof(protos[0]); | |
158 | ||
159 | ||
160 | #if 0 // currently unused | |
161 | static SSLCipherSuite sslcipher_atoi(const char *name) | |
162 | { | |
163 | const CipherSuiteName *a = ciphers; | |
164 | while(a->name) { | |
165 | if (0 == strcmp(a->name, name)) break; | |
166 | a++; | |
167 | } | |
168 | return a->cipher; | |
169 | } | |
170 | ||
171 | static const char * sslcipher_itoa(SSLCipherSuite num) | |
172 | { | |
173 | const CipherSuiteName *a = ciphers; | |
174 | while(a->cipher >= 0) { | |
175 | if (num == a->cipher) break; | |
176 | a++; | |
177 | } | |
178 | return a->name; | |
179 | } | |
180 | #endif // currently unused | |
181 | ||
182 | static unsigned char dh_param_512_bytes[] = { | |
183 | 0x30, 0x46, 0x02, 0x41, 0x00, 0xdb, 0x3c, 0xfa, 0x13, 0xa6, 0xd2, 0x64, | |
184 | 0xdf, 0xcc, 0x40, 0xb1, 0x21, 0xd4, 0xf2, 0xad, 0x22, 0x7f, 0xce, 0xa0, | |
185 | 0xb9, 0x5b, 0x95, 0x1c, 0x2e, 0x99, 0xb0, 0x27, 0xd0, 0xed, 0xf4, 0xbd, | |
186 | 0xbb, 0x36, 0x93, 0xd0, 0x9d, 0x2b, 0x32, 0xa3, 0x56, 0x53, 0xe3, 0x7b, | |
187 | 0xed, 0xa1, 0x71, 0x82, 0x2e, 0x83, 0x14, 0xf9, 0xc0, 0x2f, 0x15, 0xcb, | |
188 | 0xcf, 0x97, 0xab, 0x88, 0x49, 0x20, 0x28, 0x2e, 0x63, 0x02, 0x01, 0x02 | |
189 | }; | |
190 | static unsigned char *dh_param_512_der = dh_param_512_bytes; | |
191 | static unsigned int dh_param_512_der_len = 72; | |
192 | ||
193 | ||
194 | typedef struct { | |
195 | uint32_t session_id; | |
196 | bool is_session_resume; | |
197 | SSLContextRef st; | |
198 | bool is_server; | |
199 | bool is_dtls; | |
200 | bool client_side_auth; | |
201 | bool dh_anonymous; | |
202 | int comm; | |
203 | CFArrayRef certs; | |
204 | SSLProtocol proto; | |
205 | } ssl_test_handle; | |
206 | ||
207 | #if 0 // currently unused | |
208 | static CFArrayRef SecIdentityCopySSLClientAuthenticationChain(SecIdentityRef identity) | |
209 | { | |
210 | CFMutableArrayRef chain = NULL; | |
211 | SecPolicyRef policy = NULL; | |
212 | SecTrustRef trust = NULL; | |
213 | SecTrustResultType trust_result; | |
214 | ||
215 | do { | |
216 | policy = SecPolicyCreateSSL(false, NULL); | |
217 | if (!policy) | |
218 | break; | |
219 | ||
220 | SecCertificateRef cert = NULL; | |
221 | if (SecIdentityCopyCertificate(identity, &cert)) | |
222 | break; | |
223 | ||
224 | CFArrayRef certs = CFArrayCreate(NULL, (const void **)&cert, | |
225 | 1, &kCFTypeArrayCallBacks); | |
226 | CFRelease(cert); | |
227 | if (!certs) | |
228 | break; | |
229 | ||
230 | if (SecTrustCreateWithCertificates(certs, policy, &trust)) | |
231 | break; | |
232 | CFRelease(certs); | |
233 | CFRelease(policy); | |
234 | if (SecTrustEvaluate(trust, &trust_result)) | |
235 | break; | |
236 | ||
237 | int i, count = SecTrustGetCertificateCount(trust); | |
238 | chain = CFArrayCreateMutable(NULL, count, &kCFTypeArrayCallBacks); | |
239 | CFArrayAppendValue(chain, identity); | |
240 | for (i = 1; i < count; i++) { | |
241 | if ((i+1 == count) && (trust_result == kSecTrustResultUnspecified)) | |
242 | continue; /* skip anchor if chain is complete */ | |
243 | SecCertificateRef s = SecTrustGetCertificateAtIndex(trust, i); | |
244 | CFArrayAppendValue(chain, s); | |
245 | } | |
246 | } while (0); | |
247 | if (trust) | |
248 | CFRelease(trust); | |
249 | if (policy) | |
250 | CFRelease(policy); | |
251 | return chain; | |
252 | } | |
253 | #endif // currently unused | |
254 | ||
255 | // MARK: - | |
256 | // MARK: SecureTransport support | |
257 | ||
258 | #if 0 | |
259 | static void hexdump(const uint8_t *bytes, size_t len) { | |
260 | size_t ix; | |
261 | printf("socket write(%p, %lu)\n", bytes, len); | |
262 | for (ix = 0; ix < len; ++ix) { | |
263 | if (!(ix % 16)) | |
264 | printf("\n"); | |
265 | printf("%02X ", bytes[ix]); | |
266 | } | |
267 | printf("\n"); | |
268 | } | |
269 | #else | |
270 | #define hexdump(bytes, len) | |
271 | #endif | |
272 | ||
273 | static OSStatus SocketWrite(SSLConnectionRef conn, const void *data, size_t *length) | |
274 | { | |
275 | size_t len = *length; | |
276 | uint8_t *ptr = (uint8_t *)data; | |
277 | ||
278 | do { | |
279 | ssize_t ret; | |
280 | do { | |
281 | hexdump(ptr, len); | |
282 | ret = write((int)conn, ptr, len); | |
283 | } while ((ret < 0) && (errno == EAGAIN || errno == EINTR)); | |
284 | if (ret > 0) { | |
285 | len -= ret; | |
286 | ptr += ret; | |
287 | } | |
288 | else | |
289 | return -36; | |
290 | } while (len > 0); | |
291 | ||
292 | *length = *length - len; | |
293 | return errSecSuccess; | |
294 | } | |
295 | ||
296 | static OSStatus SocketRead(SSLConnectionRef conn, void *data, size_t *length) | |
297 | { | |
298 | size_t len = *length; | |
299 | uint8_t *ptr = (uint8_t *)data; | |
300 | ||
301 | do { | |
302 | ssize_t ret; | |
303 | do { | |
304 | ret = read((int)conn, ptr, len); | |
305 | } while ((ret < 0) && (errno == EAGAIN || errno == EINTR)); | |
306 | if (ret > 0) { | |
307 | len -= ret; | |
308 | ptr += ret; | |
309 | } | |
310 | else | |
311 | return -36; | |
312 | } while (len > 0); | |
313 | ||
314 | *length = *length - len; | |
315 | return errSecSuccess; | |
316 | } | |
317 | ||
318 | static unsigned char dn[] = { | |
319 | 0x30, 0x5e, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, | |
320 | 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x0a, | |
321 | 0x13, 0x0a, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x20, 0x49, 0x6e, 0x63, 0x2e, | |
322 | 0x31, 0x26, 0x30, 0x24, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x1d, 0x41, | |
323 | 0x70, 0x70, 0x6c, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, | |
324 | 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6f, | |
325 | 0x72, 0x69, 0x74, 0x79, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, | |
326 | 0x03, 0x13, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74 | |
327 | }; | |
328 | static unsigned int dn_len = 96; | |
329 | ||
330 | static SSLContextRef make_ssl_ref(bool server, bool client_side_auth, bool dh_anonymous, | |
331 | bool dtls, int sock, CFArrayRef certs, SSLProtocol proto) | |
332 | { | |
333 | SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, server?kSSLServerSide:kSSLClientSide, dtls?kSSLDatagramType:kSSLStreamType); | |
334 | require(ctx, out); | |
335 | ||
336 | if(dtls) { | |
337 | size_t mtu; | |
338 | require_noerr(SSLSetMaxDatagramRecordSize(ctx, 400), out); | |
339 | require_noerr(SSLGetMaxDatagramRecordSize(ctx, &mtu), out); | |
340 | } else { | |
341 | require_noerr(SSLSetProtocolVersionMax(ctx, proto), out); | |
342 | } | |
343 | require_noerr(SSLSetIOFuncs(ctx, | |
344 | (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out); | |
345 | require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)sock), out); | |
346 | static const char *peer_domain_name = "localhost"; | |
347 | require_noerr(SSLSetPeerDomainName(ctx, peer_domain_name, | |
348 | strlen(peer_domain_name)), out); | |
349 | ||
350 | ||
351 | if (!dh_anonymous) { | |
352 | if (server) | |
353 | require_noerr(SSLSetCertificate(ctx, certs), out); | |
354 | if (client_side_auth && server) { | |
355 | SSLAuthenticate auth; | |
356 | require_noerr(SSLSetClientSideAuthenticate(ctx, kAlwaysAuthenticate), out); | |
357 | require_noerr(SSLGetClientSideAuthenticate(ctx, &auth), out); | |
358 | require(auth==kAlwaysAuthenticate, out); | |
359 | require_noerr(SSLAddDistinguishedName(ctx, dn, dn_len), out); | |
360 | } | |
361 | #if 0 /* Setting client certificate in advance */ | |
362 | if (client_side_auth && !server) | |
363 | require_noerr(SSLSetCertificate(ctx, certs), out); | |
364 | #endif | |
365 | if (client_side_auth && !server) /* enable break from SSLHandshake */ | |
366 | require_noerr(SSLSetSessionOption(ctx, | |
367 | kSSLSessionOptionBreakOnCertRequested, true), out); | |
368 | require_noerr(SSLSetSessionOption(ctx, | |
369 | kSSLSessionOptionBreakOnServerAuth, true), out); | |
370 | } | |
371 | ||
372 | /* Tell SecureTransport to not check certs itself: it will break out of the | |
373 | handshake to let us take care of it instead. */ | |
374 | require_noerr(SSLSetEnableCertVerify(ctx, false), out); | |
375 | ||
376 | if (server) { | |
377 | require_noerr(SSLSetDiffieHellmanParams(ctx, | |
378 | dh_param_512_der, dh_param_512_der_len), out); | |
379 | } | |
380 | else /* if client */ { | |
381 | } | |
382 | ||
383 | return ctx; | |
384 | out: | |
385 | if (ctx) | |
386 | CFRelease(ctx); | |
387 | return NULL; | |
388 | } | |
389 | ||
390 | static void *securetransport_ssl_thread(void *arg) | |
391 | { | |
392 | OSStatus ortn; | |
393 | ssl_test_handle * ssl = (ssl_test_handle *)arg; | |
394 | SSLContextRef ctx = ssl->st; | |
395 | SecTrustRef trust = NULL; | |
396 | bool got_server_auth = false, got_client_cert_req = false; | |
397 | ||
398 | pthread_setname_np(ssl->is_server?"server thread":"client thread"); | |
399 | ||
400 | //uint64_t start = mach_absolute_time(); | |
401 | do { | |
402 | ortn = SSLHandshake(ctx); | |
403 | ||
404 | if (ortn == errSSLPeerAuthCompleted) | |
405 | { | |
406 | require_string(!got_server_auth, out, "second server auth"); | |
407 | require_string(!got_client_cert_req, out, "got client cert req before server auth"); | |
408 | got_server_auth = true; | |
409 | require_string(!trust, out, "Got errSSLServerAuthCompleted twice?"); | |
410 | /* verify peer cert chain */ | |
411 | require_noerr(SSLCopyPeerTrust(ctx, &trust), out); | |
412 | SecTrustResultType trust_result = 0; | |
413 | /* this won't verify without setting up a trusted anchor */ | |
414 | require_noerr(SecTrustEvaluate(trust, &trust_result), out); | |
415 | ||
416 | CFIndex n_certs = SecTrustGetCertificateCount(trust); | |
417 | /*fprintf(stderr, "%ld certs; trust_eval: %d\n", n_certs, trust_result); */ | |
418 | ||
419 | CFMutableArrayRef peer_cert_array = | |
420 | CFArrayCreateMutable(NULL, n_certs, &kCFTypeArrayCallBacks); | |
421 | CFMutableArrayRef orig_peer_cert_array = | |
422 | CFArrayCreateMutableCopy(NULL, n_certs, ssl->certs); | |
423 | while (n_certs--) | |
424 | CFArrayInsertValueAtIndex(peer_cert_array, 0, | |
425 | SecTrustGetCertificateAtIndex(trust, n_certs)); | |
426 | ||
427 | SecIdentityRef ident = | |
428 | (SecIdentityRef)CFArrayGetValueAtIndex(orig_peer_cert_array, 0); | |
429 | SecCertificateRef peer_cert = NULL; | |
430 | require_noerr(SecIdentityCopyCertificate(ident, &peer_cert), out); | |
431 | CFArraySetValueAtIndex(orig_peer_cert_array, 0, peer_cert); | |
432 | CFRelease(peer_cert); | |
433 | ||
434 | require(CFEqual(orig_peer_cert_array, peer_cert_array), out); | |
435 | CFRelease(orig_peer_cert_array); | |
436 | CFRelease(peer_cert_array); | |
437 | ||
438 | /* | |
439 | CFStringRef cert_name = SecCertificateCopySubjectSummary(cert); | |
440 | char cert_name_buffer[1024]; | |
441 | require(CFStringGetFileSystemRepresentation(cert_name, | |
442 | cert_name_buffer, sizeof(cert_name_buffer)), out); | |
443 | fprintf(stderr, "cert name: %s\n", cert_name_buffer); | |
444 | CFRelease(trust); | |
445 | */ | |
446 | } else if (ortn == errSSLClientCertRequested) { | |
447 | require_string(!got_client_cert_req, out, "second client cert req"); | |
448 | require_string(got_server_auth, out, "didn't get server auth first"); | |
449 | got_client_cert_req = true; | |
450 | ||
451 | /* set client cert */ | |
452 | require_string(!ssl->is_server, out, "errSSLClientCertRequested while running server"); | |
453 | require_string(!ssl->dh_anonymous, out, "errSSLClientCertRequested while running anon DH"); | |
454 | ||
455 | CFArrayRef DNs = NULL; | |
456 | require_noerr(SSLCopyDistinguishedNames (ctx, &DNs), out); | |
457 | require(DNs, out); | |
458 | CFRelease(DNs); | |
459 | ||
460 | require_string(ssl->client_side_auth, out, "errSSLClientCertRequested in run not testing that"); | |
461 | require_noerr(SSLSetCertificate(ctx, ssl->certs), out); | |
462 | } | |
463 | } while (ortn == errSSLWouldBlock | |
464 | || ortn == errSSLServerAuthCompleted | |
465 | || ortn == errSSLClientCertRequested); | |
466 | require_noerr_action_quiet(ortn, out, | |
467 | fprintf(stderr, "Fell out of SSLHandshake with error: %d\n", (int)ortn)); | |
468 | ||
469 | if (!ssl->is_server && !ssl->dh_anonymous && !ssl->is_session_resume) { | |
470 | require_string(got_server_auth, out, "never got server auth"); | |
471 | if (ssl->client_side_auth) | |
472 | require_string(got_client_cert_req, out, "never got client cert req"); | |
473 | } | |
474 | //uint64_t elapsed = mach_absolute_time() - start; | |
475 | //fprintf(stderr, "setr elapsed: %lld\n", elapsed); | |
476 | ||
477 | /* | |
478 | SSLProtocol proto = kSSLProtocolUnknown; | |
479 | require_noerr_quiet(SSLGetNegotiatedProtocolVersion(ctx, &proto), out); */ | |
480 | ||
481 | SSLCipherSuite cipherSuite; | |
482 | require_noerr_quiet(ortn = SSLGetNegotiatedCipher(ctx, &cipherSuite), out); | |
483 | //fprintf(stderr, "st negotiated %s\n", sslcipher_itoa(cipherSuite)); | |
484 | ||
485 | if(ssl->is_dtls) { | |
486 | size_t sz; | |
487 | SSLGetDatagramWriteSize(ctx, &sz); | |
488 | //fprintf(stderr, "Max Write Size = %ld\n", sz); | |
489 | } | |
490 | ||
491 | Boolean sessionWasResumed = false; | |
492 | uint8_t session_id_data[MAX_SESSION_ID_LENGTH]; | |
493 | size_t session_id_length = sizeof(session_id_data); | |
494 | require_noerr_quiet(ortn = SSLGetResumableSessionInfo(ctx, &sessionWasResumed, session_id_data, &session_id_length), out); | |
495 | require_action(ssl->dh_anonymous || (ssl->is_session_resume == sessionWasResumed), out, ortn = -1); | |
496 | // if (sessionWasResumed) fprintf(stderr, "st resumed session\n"); | |
497 | //hexdump(session_id_data, session_id_length); | |
498 | ||
499 | unsigned char ibuf[4096], obuf[4096]; | |
500 | size_t len; | |
501 | if (ssl->is_server) { | |
502 | SecRandomCopyBytes(kSecRandomDefault, sizeof(obuf), obuf); | |
503 | require_noerr_quiet(ortn = SSLWrite(ctx, obuf, sizeof(obuf), &len), out); | |
504 | require_action_quiet(len == sizeof(obuf), out, ortn = -1); | |
505 | } | |
506 | require_noerr_quiet(ortn = SSLRead(ctx, ibuf, sizeof(ibuf), &len), out); | |
507 | require_action_quiet(len == sizeof(ibuf), out, ortn = -1); | |
508 | ||
509 | if (ssl->is_server) { | |
510 | require_noerr(memcmp(ibuf, obuf, sizeof(ibuf)), out); | |
511 | } else { | |
512 | require_noerr_quiet(ortn = SSLWrite(ctx, ibuf, sizeof(ibuf), &len), out); | |
513 | require_action_quiet(len == sizeof(ibuf), out, ortn = -1); | |
514 | } | |
515 | ||
516 | out: | |
517 | SSLClose(ctx); | |
518 | CFRelease(ctx); | |
519 | if (trust) CFRelease(trust); | |
520 | close(ssl->comm); | |
521 | pthread_exit((void *)(intptr_t)ortn); | |
522 | return NULL; | |
523 | } | |
524 | ||
525 | ||
526 | ||
527 | static ssl_test_handle * | |
528 | ssl_test_handle_create(uint32_t session_id, bool resume, bool server, bool client_side_auth, bool dh_anonymous, bool dtls, | |
529 | int comm, CFArrayRef certs, SSLProtocol proto) | |
530 | { | |
531 | ssl_test_handle *handle = calloc(1, sizeof(ssl_test_handle)); | |
532 | if (handle) { | |
533 | handle->session_id = session_id; | |
534 | handle->is_session_resume = resume; | |
535 | handle->is_server = server; | |
536 | handle->is_dtls = dtls; | |
537 | handle->client_side_auth = client_side_auth; | |
538 | handle->dh_anonymous = dh_anonymous; | |
539 | handle->comm = comm; | |
540 | handle->certs = certs; | |
541 | handle->proto = proto; | |
542 | handle->st = make_ssl_ref(server, client_side_auth, dh_anonymous, dtls, comm, certs, proto); | |
543 | } | |
544 | return handle; | |
545 | } | |
546 | ||
547 | static void | |
548 | tests(void) | |
549 | { | |
550 | pthread_t client_thread, server_thread; | |
551 | CFArrayRef server_certs = server_chain(); | |
552 | ok(server_certs, "got server certs"); | |
553 | ||
554 | /* Enable this if you want to test a specific d/i/k/l combination */ | |
555 | #if 0 | |
556 | int d=0, i=0, l=0, k=0; { { | |
557 | #else | |
558 | int d,i,k,l,p; | |
559 | ||
560 | for (p=0; p<nprotos; p++) | |
561 | for (d=0;d<2; d++) /* dtls or not dtls */ | |
562 | for (k=0; k<2; k++) | |
563 | { | |
564 | for (i=0; ciphers[i].cipher != (SSLCipherSuite)(-1); i++) | |
565 | for (l = 0; l<2; l++) { | |
566 | #endif | |
567 | SKIP:{ | |
568 | //skip("Session resumption tests do not work at this point", 1, l != 1); | |
569 | ||
570 | int sp[2]; | |
571 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno); | |
572 | fcntl(sp[0], F_SETNOSIGPIPE, 1); | |
573 | fcntl(sp[1], F_SETNOSIGPIPE, 1); | |
574 | ||
575 | ssl_test_handle *server, *client; | |
576 | ||
577 | bool client_side_auth = (k); | |
578 | ||
579 | uint32_t session_id = (k+1) << 16 | (i+1); | |
580 | //fprintf(stderr, "session_id: %d\n", session_id); | |
581 | server = ssl_test_handle_create(session_id, (l == 1), true /*server*/, | |
582 | client_side_auth, ciphers[i].dh_anonymous, d, | |
583 | sp[0], server_certs, protos[p]); | |
584 | client = ssl_test_handle_create(session_id, (l == 1), false/*client*/, | |
585 | client_side_auth, ciphers[i].dh_anonymous, d, | |
586 | sp[1], server_certs, protos[p]); | |
587 | ||
588 | require_noerr(SSLSetPeerID(server->st, &session_id, sizeof(session_id)), out); | |
589 | require_noerr(SSLSetPeerID(client->st, &session_id, sizeof(session_id)), out); | |
590 | ||
591 | /* set fixed cipher on client and server */ | |
592 | require_noerr(SSLSetEnabledCiphers(client->st, &ciphers[i].cipher, 1), out); | |
593 | require_noerr(SSLSetEnabledCiphers(server->st, &ciphers[i].cipher, 1), out); | |
594 | ||
595 | require_noerr(SSLSetPSKSharedSecret(client->st, "123456789", 9), out); | |
596 | require_noerr(SSLSetPSKSharedSecret(server->st, "123456789", 9), out); | |
597 | ||
598 | ||
599 | pthread_create(&client_thread, NULL, securetransport_ssl_thread, client); | |
600 | pthread_create(&server_thread, NULL, securetransport_ssl_thread, server); | |
601 | ||
602 | int server_err, client_err; | |
603 | pthread_join(client_thread, (void*)&client_err); | |
604 | pthread_join(server_thread, (void*)&server_err); | |
605 | ||
606 | ||
607 | ok(!server_err && !client_err, | |
608 | "%40s ADH:%d CSA:%d DTLS:%d RESUME:%d PROTO:%d", | |
609 | ciphers[i].name, | |
610 | server->dh_anonymous, | |
611 | server->client_side_auth, | |
612 | d, l, p); | |
613 | out: | |
614 | free(client); | |
615 | free(server); | |
616 | ||
617 | } | |
618 | } /* all ciphers */ | |
619 | } /* all configs */ | |
620 | ||
621 | CFRelease(server_certs); | |
622 | } | |
623 | ||
624 | int ssl_42_ciphers(int argc, char *const *argv) | |
625 | { | |
626 | ||
627 | plan_tests(2 * 2 * 2 * nprotos * (ciphers_len-1)/* client auth on/off * #configs * #ciphers */ | |
628 | + 1 /*cert*/); | |
629 | ||
630 | ||
631 | tests(); | |
632 | ||
633 | return 0; | |
634 | } | |
635 | ||
636 | /* | |
637 | TODO: count errSSLWouldBlock | |
638 | TODO: skip tests that don't matter: client_auth and anonymous dh | |
639 | TODO: we seem to only be negotiating tls - force a round of sslv3 | |
640 | TODO: allow secure transport to also defer client side auth to client | |
641 | TODO: make sure anonymous dh is never selected if not expicitly enabled | |
642 | TODO: make sure DHE is not available if not explicitly enabled and no parameters | |
643 | are set | |
644 | TODO: resumable sessions | |
645 | */ |