]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_ssl/regressions/SecureTransportTests/STLegacyTests+clientauth.m
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_ssl / regressions / SecureTransportTests / STLegacyTests+clientauth.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 (clientauth)
42
43 /*
44 SSL Client Auth tests:
45
46 Test both the client and server side.
47
48 Server side test goals:
49 Verify Server behavior in the following cases:
50 Server configuration:
51 - when using kTryAuthenticate vs kAlwaysAuthenticate
52 - with or without breakOnClientAuth.
53 - AnonDH and PSK ciphersuites.
54 Client configuration:
55 - Client sends back no cert vs a cert.
56 - Client sends back an unsupported cert.
57 - Client sends back a malformed cert.
58 - Client cert is trusted vs untrusted.
59 - Client does not have private key (ie: Certificate Verify message should fail).
60 Behavior to verify:
61 - handshake pass or fail
62 - SSLGetClientCertificateState returns expected results
63
64 Client side test goals:
65 Client configuration:
66 - with or without breakOnCertRequest.
67 - no cert, vs cert.
68 Server config:
69 - No client cert requested, vs client cert requested vs client cert required.
70 Behavior to verify:
71 - handshake pass or fail
72 - SSLGetClientCertificateState returns expected results
73
74 */
75
76
77 static OSStatus SocketWrite(SSLConnectionRef conn, const void *data, size_t *length)
78 {
79 size_t len = *length;
80 uint8_t *ptr = (uint8_t *)data;
81
82 do {
83 ssize_t ret;
84 do {
85 ret = write((int)conn, ptr, len);
86 } while ((ret < 0) && (errno == EAGAIN || errno == EINTR));
87 if (ret > 0) {
88 len -= ret;
89 ptr += ret;
90 }
91 else {
92 return -36;
93 }
94 } while (len > 0);
95
96 *length = *length - len;
97 return errSecSuccess;
98 }
99
100 static OSStatus SocketRead(SSLConnectionRef conn, void *data, size_t *length)
101 {
102 size_t len = *length;
103 uint8_t *ptr = (uint8_t *)data;
104
105 do {
106 ssize_t ret;
107 do {
108 ret = read((int)conn, ptr, len);
109 } while ((ret < 0) && (errno == EINPROGRESS || errno == EAGAIN || errno == EINTR));
110 if (ret > 0) {
111 len -= ret;
112 ptr += ret;
113 } else {
114 printf("read error(%d): ret=%zd, errno=%d\n", (int)conn, ret, errno);
115 return -errno;
116 }
117 } while (len > 0);
118
119 *length = *length - len;
120 return errSecSuccess;
121 }
122
123 typedef struct {
124 SSLContextRef st;
125 int comm;
126 bool break_on_req;
127 CFArrayRef certs;
128 int auth; //expected client auth behavior of the server (0=no request, 1=optional , 2=required)
129 } ssl_client_handle;
130
131 static ssl_client_handle *
132 ssl_client_handle_create(bool break_on_req, int comm, CFArrayRef certs, CFArrayRef trustedCA, int auth)
133 {
134 ssl_client_handle *handle = calloc(1, sizeof(ssl_client_handle));
135 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
136
137 require(handle, out);
138 require(ctx, out);
139
140 require_noerr(SSLSetIOFuncs(ctx,
141 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
142 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
143 static const char *peer_domain_name = "localhost";
144 require_noerr(SSLSetPeerDomainName(ctx, peer_domain_name,
145 strlen(peer_domain_name)), out);
146
147 CFArrayRef trustedRoots = NULL;
148 require_noerr(SSLCopyTrustedRoots(ctx, &trustedRoots), out);
149 #if (TARGET_OS_MAC && !TARGET_OS_IPHONE)
150 require(trustedRoots, out);
151 #endif
152 CFReleaseNull(trustedRoots);
153 require_noerr(SSLSetTrustedRoots(ctx, trustedCA, true), out);
154 require_noerr(SSLCopyTrustedRoots(ctx, &trustedRoots), out);
155 CFReleaseNull(trustedRoots);
156
157 /* Setting client certificate in advance */
158 if (!break_on_req && certs) {
159 require_noerr(SSLSetCertificate(ctx, certs), out);
160 }
161
162 if (break_on_req) {
163 require_noerr(SSLSetSessionOption(ctx,
164 kSSLSessionOptionBreakOnCertRequested, true), out);
165 }
166
167 handle->break_on_req = break_on_req;
168 handle->comm = comm;
169 handle->certs = certs;
170 handle->st = ctx;
171 handle->auth = auth;
172
173 return handle;
174
175 out:
176 CFReleaseNull(ctx);
177 if (handle) {
178 free(handle);
179 }
180 return NULL;
181 }
182
183 static void
184 ssl_client_handle_destroy(ssl_client_handle *handle)
185 {
186 if(handle) {
187 SSLClose(handle->st);
188 CFRelease(handle->st);
189 free(handle);
190 }
191 }
192
193 static void *securetransport_ssl_client_thread(void *arg)
194 {
195 OSStatus ortn;
196 ssl_client_handle * ssl = (ssl_client_handle *)arg;
197 SSLContextRef ctx = ssl->st;
198 bool got_client_cert_req = false;
199 SSLSessionState ssl_state;
200 SSLSignatureAndHashAlgorithm *sigAlgs;
201 unsigned int numSigAlgs, numTypes;
202 SSLClientAuthenticationType *authTypes;
203
204 pthread_setname_np("client thread");
205
206 require_noerr(ortn = SSLGetSessionState(ctx, &ssl_state), out);
207 require_action(ssl_state == kSSLIdle, out, ortn = -1);
208
209 do {
210 ortn = SSLHandshake(ctx);
211 require_noerr(SSLGetSessionState(ctx, &ssl_state), out);
212
213 if (ortn == errSSLClientCertRequested) {
214 require_noerr(SSLGetNumberOfSignatureAlgorithms(ctx, &numSigAlgs), out);
215 sigAlgs = malloc(numSigAlgs * sizeof(SSLSignatureAndHashAlgorithm));
216 require_noerr(SSLGetSignatureAlgorithms(ctx, sigAlgs, &numSigAlgs), out);
217 require_noerr(SSLGetNumberOfClientAuthTypes(ctx, &numTypes), out);
218 authTypes = malloc(numTypes * sizeof(SSLClientAuthenticationType));
219 require_noerr(SSLGetClientAuthTypes(ctx, authTypes, &numTypes), out);
220 require_string(ssl->auth, out, "cert req not expected");
221 require_string(ssl_state == kSSLHandshake, out, "wrong client handshake state after errSSLClientCertRequested");
222 require_string(!got_client_cert_req, out, "second client cert req");
223 got_client_cert_req = true;
224
225 SSLClientCertificateState clientState;
226 SSLGetClientCertificateState(ctx, &clientState);
227 require_string(clientState == kSSLClientCertRequested, out, "Wrong client cert state after cert request");
228
229 require_string(ssl->break_on_req, out, "errSSLClientCertRequested in run not testing that");
230 if(ssl->certs) {
231 require_noerr(SSLSetCertificate(ctx, ssl->certs), out);
232 }
233
234 } else if (ortn == errSSLWouldBlock) {
235 require_string(ssl_state == kSSLHandshake, out, "Wrong client handshake state after errSSLWouldBlock");
236 }
237 } while (ortn == errSSLWouldBlock || ortn == errSSLClientCertRequested);
238
239 require_string((got_client_cert_req || !ssl->auth || !ssl->break_on_req), out, "didn't get client cert req as expected");
240
241
242 out:
243 SSLClose(ssl->st);
244 close(ssl->comm);
245 pthread_exit((void *)(intptr_t)ortn);
246 return NULL;
247 }
248
249
250 typedef struct {
251 SSLContextRef st;
252 int comm;
253 SSLAuthenticate client_auth;
254 CFArrayRef certs;
255 } ssl_server_handle;
256
257 static ssl_server_handle *
258 ssl_server_handle_create(SSLAuthenticate client_auth, int comm, CFArrayRef certs, CFArrayRef trustedCA)
259 {
260 ssl_server_handle *handle = calloc(1, sizeof(ssl_server_handle));
261 SSLContextRef ctx = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
262
263 require(handle, out);
264 require(ctx, out);
265
266 require_noerr(SSLSetIOFuncs(ctx,
267 (SSLReadFunc)SocketRead, (SSLWriteFunc)SocketWrite), out);
268 require_noerr(SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)comm), out);
269
270 require_noerr(SSLSetCertificate(ctx, certs), out);
271
272 require_noerr(SSLSetTrustedRoots(ctx, trustedCA, true), out);
273
274 SSLAuthenticate auth;
275 require_noerr(SSLSetClientSideAuthenticate(ctx, client_auth), out);
276 require_noerr(SSLGetClientSideAuthenticate(ctx, &auth), out);
277 require(auth == client_auth, out);
278
279 handle->client_auth = client_auth;
280 handle->comm = comm;
281 handle->certs = certs;
282 handle->st = ctx;
283
284 return handle;
285
286 out:
287 if (ctx)
288 CFRelease(ctx);
289 if (handle)
290 free(handle);
291
292 return NULL;
293 }
294
295 static void
296 ssl_server_handle_destroy(ssl_server_handle *handle)
297 {
298 if (handle) {
299 SSLClose(handle->st);
300 CFRelease(handle->st);
301 free(handle);
302 }
303 }
304
305 static void *securetransport_ssl_server_thread(void *arg)
306 {
307 OSStatus ortn;
308 ssl_server_handle * ssl = (ssl_server_handle *)arg;
309 SSLContextRef ctx = ssl->st;
310 SSLSessionState ssl_state;
311
312 pthread_setname_np("server thread");
313
314 require_noerr(ortn = SSLGetSessionState(ctx, &ssl_state), out);
315 require_action(ssl_state == kSSLIdle, out, ortn = -1);
316
317 do {
318 ortn = SSLHandshake(ctx);
319 require_noerr(SSLGetSessionState(ctx, &ssl_state), out);
320
321 if (ortn == errSSLWouldBlock) {
322 require_action(ssl_state == kSSLHandshake, out, ortn = -1);
323 }
324 } while (ortn == errSSLWouldBlock);
325
326 require_noerr_quiet(ortn, out);
327
328 require_action(ssl_state == kSSLConnected, out, ortn = -1);
329
330 out:
331 SSLClose(ssl->st);
332 close(ssl->comm);
333 pthread_exit((void *)(intptr_t)ortn);
334 return NULL;
335 }
336
337
338
339 -(void)testClientAuth
340 {
341 pthread_t client_thread, server_thread;
342 CFArrayRef server_certs = server_chain();
343 CFArrayRef trusted_ca = trusted_roots();
344
345 XCTAssert(server_certs, "got server certs");
346 XCTAssert(trusted_ca, "got trusted roots");
347
348 int i, j, k;
349
350 for (i = 0; i < 3; i++) {/* client side cert: 0 = no cert, 1 = trusted cert, 2 = untrusted cert. */
351 for (j = 0; j < 2; j++) { /* break on cert request */
352 for (k = 0; k < 3; k++) { /* server behvior: 0 = no cert request, 1 = optional cert, 2 = required cert */
353
354 int sp[2];
355 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp)) exit(errno);
356 fcntl(sp[0], F_SETNOSIGPIPE, 1);
357 fcntl(sp[1], F_SETNOSIGPIPE, 1);
358
359 bool break_on_req = (j != 0);
360 SSLAuthenticate auth = (k == 0) ? kNeverAuthenticate
361 : (k == 1) ? kTryAuthenticate
362 : kAlwaysAuthenticate;
363
364 CFArrayRef client_certs = (i == 0) ? NULL
365 : (i == 1) ? trusted_client_chain()
366 : untrusted_client_chain();
367
368 ssl_client_handle *client;
369 client = ssl_client_handle_create(break_on_req, sp[0], client_certs, trusted_ca, auth);
370
371 ssl_server_handle *server;
372 server = ssl_server_handle_create(auth, sp[1], server_certs, trusted_ca);
373
374 pthread_create(&client_thread, NULL, securetransport_ssl_client_thread, client);
375 pthread_create(&server_thread, NULL, securetransport_ssl_server_thread, server);
376
377 intptr_t server_err, client_err;
378 int expected_server_err = 0, expected_client_err = 0;
379 SSLClientCertificateState client_cauth_state, server_cauth_state;
380 SSLClientCertificateState expected_client_cauth_state = 0, expected_server_cauth_state = 0;
381
382
383 if(((k == 2) && (i != 1)) // Server requires good cert, but client not sending good cert,
384 || ((k == 1) && (i == 2)) // Or server request optionally, and client sending bad cert.
385 ) {
386 expected_client_err = errSSLPeerCertUnknown;
387 expected_server_err = errSSLXCertChainInvalid;
388 }
389
390
391 if(k != 0) {
392 if(i == 0) {
393 expected_client_cauth_state = kSSLClientCertRequested;
394 expected_server_cauth_state = kSSLClientCertRequested;
395 } else {
396 expected_client_cauth_state = kSSLClientCertSent;
397 expected_server_cauth_state = kSSLClientCertSent;
398 }
399 }
400
401 pthread_join(client_thread, (void*)&client_err);
402 pthread_join(server_thread, (void*)&server_err);
403
404
405 XCTAssertEqual(errSecSuccess, SSLGetClientCertificateState(client->st, &client_cauth_state), "SSLGetClientCertificateState (client %d:%d:%d)", i, j, k);
406 XCTAssertEqual(errSecSuccess, SSLGetClientCertificateState(client->st, &server_cauth_state), "SSLGetClientCertificateState (server %d:%d:%d)", i, j, k);
407
408 XCTAssertEqual(client_err, expected_client_err, "unexpected error %d!=%d (client %d:%d:%d)", (int)client_err, expected_client_err, i, j, k);
409 XCTAssertEqual(server_err, expected_server_err, "unexpected error %d!=%d (server %d:%d:%d)", (int)server_err, expected_server_err, i, j, k);
410
411 XCTAssertEqual(client_cauth_state, expected_client_cauth_state, "unexpected client auth state %d!=%d (client %d:%d:%d)", client_cauth_state, expected_client_cauth_state, i, j, k);
412 XCTAssertEqual(server_cauth_state, expected_server_cauth_state, "unexpected client auth state %d!=%d (server %d:%d:%d)", server_cauth_state, expected_server_cauth_state, i, j, k);
413
414
415 ssl_server_handle_destroy(server);
416 ssl_client_handle_destroy(client);
417
418 CFReleaseSafe(client_certs);
419 }
420 }
421 }
422
423 CFReleaseSafe(server_certs);
424 CFReleaseSafe(trusted_ca);
425 }
426
427 @end
428
429 #pragma clang diagnostic pop