]> git.saurik.com Git - apple/security.git/blob - sslViewer/sslEcdsa.cpp
Security-59754.41.1.tar.gz
[apple/security.git] / sslViewer / sslEcdsa.cpp
1 /*
2 * sslEcdsa.cpp - test SSL connections to a number of known servers.
3 *
4 * Note this uses the keychain ecdsa.keychain in cwd; it contains an
5 * SSL client auth identity. To avoid ACL hassles and to allow this
6 * program to run hands-off, the identity is imported into this keychain
7 * with no ACL on the private key. This is done with the kcImport tool
8 * like so:
9 *
10 * % kcImport ecc-secp256r1-client.pfx -k ___path_to_cwd___/ecdsa.keychain -f pkcs12 -z password -n
11 */
12 #include <Security/SecureTransport.h>
13 #include <Security/SecureTransportPriv.h>
14 #include <Security/Security.h>
15 #include "sslAppUtils.h"
16 #include "ioSock.h"
17 //#include <utilLib/common.h>
18
19 #include <Security/SecBase.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <string.h>
25 #include <time.h>
26 #include <ctype.h>
27 #include <sys/param.h>
28
29 #if NO_SERVER
30 #include "keychain/securityd/spi.h"
31 #endif
32
33
34 static void usage(char **argv)
35 {
36 printf("Usage: %s [options]\n", argv[0]);
37 printf("options:\n");
38 printf(" -t testNum -- only do test testNum; default is all\n");
39 printf(" -q -- quiet\n");
40 printf(" -b -- non blocking I/O\n");
41 printf(" -p -- pause for malloc debug\n");
42 exit(1);
43 }
44
45 #define IGNORE_SIGPIPE 1
46 #if IGNORE_SIGPIPE
47 #include <signal.h>
48
49 static void sigpipe(int sig)
50 {
51 }
52 #endif /* IGNORE_SIGPIPE */
53
54 /* Test params */
55 typedef struct {
56 const char *hostName;
57 int port;
58
59 /* We enable exacly one CipherSuite and require that to work */
60 SSLCipherSuite cipherSuite;
61
62 /* Curve to specify; SSL_Curve_None means use default */
63 SSL_ECDSA_NamedCurve specCurve;
64
65 /* Curve to verify; SSL_Curve_None means don't check */
66 SSL_ECDSA_NamedCurve expCurve;
67
68 /*
69 * keychain containing client-side cert, located in LOCAL_BUILD_DIR.
70 * NULL means no keychain.
71 */
72 const char *keychain;
73
74 /* password for above keychain */
75 const char *kcPassword;
76 } EcdsaTestParams;
77
78 static const EcdsaTestParams ecdsaTestParams[] =
79 {
80 /* client auth */
81 {
82 "tls.secg.org", 8443, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
83 SSL_Curve_None, SSL_Curve_None,
84 "ecdsa.keychain", "password"
85 },
86 /* tla.secg.org -- port 40023 - secp256r1 */
87 {
88 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
89 SSL_Curve_None, SSL_Curve_secp256r1
90 },
91 {
92 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
93 SSL_Curve_secp256r1, SSL_Curve_secp256r1
94 },
95 {
96 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
97 SSL_Curve_None, SSL_Curve_secp256r1
98 },
99 {
100 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
101 SSL_Curve_None, SSL_Curve_secp256r1
102 },
103 {
104 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
105 SSL_Curve_None, SSL_Curve_secp256r1
106 },
107 {
108 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
109 SSL_Curve_None, SSL_Curve_secp256r1
110 },
111 {
112 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
113 SSL_Curve_None, SSL_Curve_secp256r1
114 },
115 {
116 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
117 SSL_Curve_secp256r1, SSL_Curve_secp256r1
118 },
119 {
120 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
121 SSL_Curve_None, SSL_Curve_secp256r1
122 },
123 {
124 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
125 SSL_Curve_None, SSL_Curve_secp256r1
126 },
127 {
128 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
129 SSL_Curve_secp256r1, SSL_Curve_secp256r1
130 },
131
132 /* tla.secg.org -- port 40024 - secp384r1 */
133 /* This one doesn't let you specify a curve */
134 {
135 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
136 SSL_Curve_None, SSL_Curve_secp384r1
137 },
138 {
139 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
140 SSL_Curve_None, SSL_Curve_secp384r1
141 },
142 {
143 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
144 SSL_Curve_None, SSL_Curve_secp384r1
145 },
146 {
147 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
148 SSL_Curve_None, SSL_Curve_secp384r1
149 },
150 {
151 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
152 SSL_Curve_None, SSL_Curve_secp384r1
153 },
154 {
155 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
156 SSL_Curve_None, SSL_Curve_secp384r1
157 },
158 {
159 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
160 SSL_Curve_None, SSL_Curve_secp384r1
161 },
162 {
163 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
164 SSL_Curve_None, SSL_Curve_secp384r1
165 },
166
167 /* tla.secg.org -- port 40025 - secp521r1 */
168 {
169 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
170 SSL_Curve_None, SSL_Curve_secp521r1
171 },
172 {
173 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
174 SSL_Curve_None, SSL_Curve_secp521r1
175 },
176 {
177 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
178 SSL_Curve_None, SSL_Curve_secp521r1
179 },
180 {
181 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
182 SSL_Curve_None, SSL_Curve_secp521r1
183 },
184 {
185 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
186 SSL_Curve_None, SSL_Curve_secp521r1
187 },
188 {
189 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
190 SSL_Curve_None, SSL_Curve_secp521r1
191 },
192 {
193 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
194 SSL_Curve_None, SSL_Curve_secp521r1
195 },
196 {
197 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
198 SSL_Curve_None, SSL_Curve_secp521r1
199 },
200
201
202 /* ecc.fedora.redhat.com - port 8443 - secp256r1 */
203 {
204 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
205 SSL_Curve_None, SSL_Curve_secp256r1
206 },
207 {
208 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
209 SSL_Curve_secp256r1, SSL_Curve_secp256r1
210 },
211 {
212 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
213 SSL_Curve_None, SSL_Curve_secp256r1
214 },
215 {
216 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
217 SSL_Curve_secp256r1, SSL_Curve_secp256r1
218 },
219 {
220 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
221 SSL_Curve_secp256r1, SSL_Curve_secp256r1
222 },
223 {
224 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
225 SSL_Curve_None, SSL_Curve_secp256r1
226 },
227 {
228 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
229 SSL_Curve_secp256r1, SSL_Curve_secp256r1
230 },
231 {
232 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
233 SSL_Curve_secp256r1, SSL_Curve_secp256r1
234 },
235
236 /* ecc.fedora.redhat.com - port 8444 - SSL_Curve_secp384r1 */
237 /* This doesn't work, the server requires a redirect ...
238 {
239 "ecc.fedora.redhat.com", 8444, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
240 SSL_Curve_None, SSL_Curve_secp384r1
241 },
242 */
243 {
244 "ecc.fedora.redhat.com", 8445, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
245 SSL_Curve_None, SSL_Curve_secp521r1
246 },
247 {
248 "ecc.fedora.redhat.com", 8444, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
249 SSL_Curve_secp384r1, SSL_Curve_secp384r1
250 },
251 {
252 "ecc.fedora.redhat.com", 8444, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
253 SSL_Curve_secp384r1, SSL_Curve_secp384r1
254 },
255 {
256 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
257 SSL_Curve_None, SSL_Curve_secp384r1
258 },
259 {
260 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
261 SSL_Curve_None, SSL_Curve_secp384r1
262 },
263 {
264 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_RC4_128_SHA,
265 SSL_Curve_secp384r1, SSL_Curve_secp384r1
266 },
267 {
268 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
269 SSL_Curve_secp384r1, SSL_Curve_secp384r1
270 },
271
272 /* ecc.fedora.redhat.com - port 8445 - SSL_Curve_secp521r1 */
273 /* This one can't do RC4_128 without some HTTP redirection */
274 {
275 "ecc.fedora.redhat.com", 8445, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
276 SSL_Curve_None, SSL_Curve_secp521r1
277 },
278 {
279 "ecc.fedora.redhat.com", 8445, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
280 SSL_Curve_secp521r1, SSL_Curve_secp521r1
281 },
282 {
283 "ecc.fedora.redhat.com", 8445, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
284 SSL_Curve_secp521r1, SSL_Curve_secp521r1
285 },
286
287 /* ecc.fedora.redhat.com - port 443 - secp256r1 with RSA authentication */
288 {
289 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
290 SSL_Curve_secp256r1, SSL_Curve_secp256r1
291 },
292 {
293 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
294 SSL_Curve_secp256r1, SSL_Curve_secp256r1
295 },
296 {
297 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_RC4_128_SHA,
298 SSL_Curve_secp256r1, SSL_Curve_secp256r1
299 },
300 {
301 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
302 SSL_Curve_secp256r1, SSL_Curve_secp256r1
303 },
304 {
305 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
306 SSL_Curve_None, SSL_Curve_secp256r1
307 },
308 {
309 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
310 SSL_Curve_secp256r1, SSL_Curve_secp256r1
311 },
312 {
313 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_RC4_128_SHA,
314 SSL_Curve_None, SSL_Curve_secp256r1
315 },
316 {
317 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
318 SSL_Curve_None, SSL_Curve_secp256r1
319 },
320
321 /* etc. */
322 };
323 #define NUM_TEST_PARAMS (sizeof(ecdsaTestParams) / sizeof(ecdsaTestParams[0]))
324
325 static void dumpParams(
326 const EcdsaTestParams *testParams)
327 {
328 printf("%s:%d %-33s ",
329 testParams->hostName, testParams->port,
330 /* skip leading "TLS_" */
331 sslGetCipherSuiteString(testParams->cipherSuite)+4);
332 if(testParams->expCurve != SSL_Curve_None) {
333 printf("expCurve = %s ", sslCurveString(testParams->expCurve));
334 }
335 if(testParams->specCurve != SSL_Curve_None) {
336 printf("specCurve = %s ", sslCurveString(testParams->specCurve));
337 }
338 if(testParams->keychain) {
339 printf("Client Auth Enabled");
340 }
341 putchar('\n');
342 }
343
344 static void dumpErrInfo(
345 const char *op,
346 const EcdsaTestParams *testParams,
347 OSStatus ortn)
348 {
349 printf("***%s failed for ", op);
350 dumpParams(testParams);
351 printf(" error: %s\n", sslGetSSLErrString(ortn));
352 }
353
354 /*
355 * Custom ping for this test.
356 */
357 #define RCV_BUF_SIZE 256
358
359 static int doSslPing(
360 const EcdsaTestParams *testParams,
361 bool quiet,
362 int nonBlocking)
363 {
364 PeerSpec peerId;
365 otSocket sock = 0;
366 OSStatus ortn;
367 SSLContextRef ctx = NULL;
368 SSLCipherSuite negCipher;
369
370 /* first make sure requested server is there */
371 ortn = MakeServerConnection(testParams->hostName, testParams->port,
372 nonBlocking, &sock, &peerId);
373 if(ortn) {
374 printf("MakeServerConnection(%s) returned %d\n",
375 testParams->hostName, (int)ortn);
376 return -1;
377 }
378
379 /*
380 * Set up a SecureTransport session.
381 * First the standard calls.
382 */
383 #pragma clang diagnostic push
384 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
385 ortn = SSLNewContext(false, &ctx);
386 if(ortn) {
387 printSslErrStr("SSLNewContext", ortn);
388 goto cleanup;
389 }
390 ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
391 if(ortn) {
392 printSslErrStr("SSLSetIOFuncs", ortn);
393 goto cleanup;
394 }
395
396 /* Restrict to only TLSv1 - we have to do this because of Radar 6133465 */
397 ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false);
398 if(ortn) {
399 printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
400 goto cleanup;
401 }
402 ortn = SSLSetProtocolVersionEnabled(ctx, kTLSProtocol1, true);
403 if(ortn) {
404 printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
405 goto cleanup;
406 }
407
408 /* Restrict to only one CipherSuite */
409 ortn = SSLSetEnabledCiphers(ctx, &testParams->cipherSuite, 1);
410 if(ortn) {
411 printSslErrStr("SSLSetEnabledCiphers", ortn);
412 goto cleanup;
413 }
414
415 ortn = SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)sock);
416 if(ortn) {
417 printSslErrStr("SSLSetConnection", ortn);
418 goto cleanup;
419 }
420
421 /* These test servers have custom roots, just allow any roots for this test */
422 ortn = SSLSetAllowsExpiredCerts(ctx, true);
423 if(ortn) {
424 printSslErrStr("SSLSetAllowExpiredCerts", ortn);
425 goto cleanup;
426 }
427 ortn = SSLSetAllowsAnyRoot(ctx, true);
428 if(ortn) {
429 printSslErrStr("SSLSetAllowAnyRoot", ortn);
430 goto cleanup;
431 }
432
433 if(testParams->specCurve != SSL_Curve_None) {
434 ortn = SSLSetECDSACurves(ctx, &testParams->specCurve, 1);
435 if(ortn) {
436 printSslErrStr("SSLSetAllowAnyRoot", ortn);
437 goto cleanup;
438 }
439 }
440
441 do {
442 ortn = SSLHandshake(ctx);
443 } while (ortn == errSSLWouldBlock);
444
445 /* convert normal "shutdown" into zero err rtn */
446 switch(ortn) {
447 case errSecSuccess:
448 break;
449 case errSSLClosedGraceful:
450 case errSSLClosedNoNotify:
451 ortn = errSecSuccess;
452 goto cleanup;
453 default:
454 dumpErrInfo("SSLHandshake", testParams, ortn);
455 goto cleanup;
456 }
457
458
459 /*
460 * Unlike other ping tests we don't bother with a GET - just validate
461 * the handshake
462 */
463 ortn = SSLGetNegotiatedCipher(ctx, &negCipher);
464 if(ortn) {
465 dumpErrInfo("SSLHandshake", testParams, ortn);
466 goto cleanup;
467 }
468
469 /* here is really what we're testing */
470 if(negCipher != testParams->cipherSuite) {
471 printf("***Cipher mismatch for ");
472 dumpParams(testParams);
473 printf("Negotiated cipher: %s\n", sslGetCipherSuiteString(negCipher));
474 ortn = errSecIO;
475 goto cleanup;
476 }
477 if(testParams->expCurve != SSL_Curve_None) {
478 SSL_ECDSA_NamedCurve actNegCurve;
479 ortn = SSLGetNegotiatedCurve(ctx, &actNegCurve);
480 if(ortn) {
481 printSslErrStr("SSLGetNegotiatedCurve", ortn);
482 goto cleanup;
483 }
484 if(actNegCurve != testParams->expCurve) {
485 printf("***Negotiated curve error\n");
486 printf("Specified curve: %s\n", sslCurveString(testParams->specCurve));
487 printf("Expected curve: %s\n", sslCurveString(testParams->expCurve));
488 printf("Obtained curve: %s\n", sslCurveString(actNegCurve));
489 ortn = errSecIO;
490 goto cleanup;
491 }
492 }
493 if(testParams->keychain) {
494 /* Verify client auth */
495 SSLClientCertificateState authState;
496 ortn = SSLGetClientCertificateState(ctx, &authState);
497 if(ortn) {
498 printSslErrStr("SSLGetClientCertificateState", ortn);
499 goto cleanup;
500 }
501 if(authState != kSSLClientCertSent) {
502 printf("***Unexpected ClientCertificateState\n");
503 printf(" Expected: ClientCertSent\n");
504 printf(" Received: %s\n", sslGetClientCertStateString(authState));
505 ortn = errSecIO;
506 goto cleanup;
507 }
508 }
509
510 ortn = SSLClose(ctx);
511
512 #pragma clang diagnostic pop
513
514 cleanup:
515 if(sock) {
516 endpointShutdown(sock);
517 }
518 if(ctx) {
519 SSLDisposeContext(ctx);
520 }
521 return (int)ortn;
522 }
523
524
525 int main(int argc, char **argv)
526 {
527 int ourRtn = 0;
528 bool quiet = false;
529 int nonBlocking = false;
530 unsigned minDex = 0;
531 unsigned maxDex = NUM_TEST_PARAMS-1;
532 bool doPause = false;
533
534 extern char *optarg;
535 int arg;
536 while ((arg = getopt(argc, argv, "t:bpqh")) != -1) {
537 switch (arg) {
538 case 't':
539 minDex = maxDex = atoi(optarg);
540 if(minDex > (NUM_TEST_PARAMS - 1)) {
541 printf("***max test number is %u.\n", (unsigned)NUM_TEST_PARAMS);
542 exit(1);
543 }
544 break;
545 case 'q':
546 quiet = true;
547 break;
548 case 'b':
549 nonBlocking = true;
550 break;
551 case 'p':
552 doPause = true;
553 break;
554 default:
555 usage(argv);
556 }
557 }
558 if(optind != argc) {
559 usage(argv);
560 }
561
562 #if NO_SERVER
563 # if DEBUG
564 securityd_init(NULL);
565 # endif
566 #endif
567
568 #if IGNORE_SIGPIPE
569 signal(SIGPIPE, sigpipe);
570 #endif
571
572 //testStartBanner("sslEcdsa", argc, argv);
573
574 if(doPause) {
575 fpurge(stdin);
576 printf("Pausing at top of loop; CR to continue: ");
577 fflush(stdout);
578 getchar();
579 }
580
581 for(unsigned dex=minDex; dex<=maxDex; dex++) {
582 const EcdsaTestParams *testParams = &ecdsaTestParams[dex];
583 if(!quiet) {
584 printf("[%u]: ", dex);
585 dumpParams(testParams);
586 }
587 ourRtn = doSslPing(testParams, quiet, nonBlocking);
588 if(ourRtn) {
589 //printf("** Test %u failed **\n", dex);
590 //if(testError(quiet)) {
591 // break;
592 //}
593 }
594 }
595
596 if(doPause) {
597 fpurge(stdin);
598 printf("Pausing at end of loop; CR to continue: ");
599 fflush(stdout);
600 getchar();
601 }
602
603 if(!quiet) {
604 if(ourRtn == 0) {
605 printf("===== sslEcdsa test PASSED =====\n");
606 }
607 else {
608 printf("****sslEcdsa test FAILED\n");
609 }
610 }
611
612 return ourRtn;
613 }