2 * sslEcdsa.cpp - test SSL connections to a number of known servers.
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
10 * % kcImport ecc-secp256r1-client.pfx -k ___path_to_cwd___/ecdsa.keychain -f pkcs12 -z password -n
12 #include <Security/SecureTransport.h>
13 #include <Security/SecureTransportPriv.h>
14 #include <Security/Security.h>
15 #include "sslAppUtils.h"
17 //#include <utilLib/common.h>
19 #include <Security/SecBase.h>
27 #include <sys/param.h>
30 #include "keychain/securityd/spi.h"
34 static void usage(char **argv
)
36 printf("Usage: %s [options]\n", argv
[0]);
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");
45 #define IGNORE_SIGPIPE 1
49 static void sigpipe(int sig
)
52 #endif /* IGNORE_SIGPIPE */
59 /* We enable exacly one CipherSuite and require that to work */
60 SSLCipherSuite cipherSuite
;
62 /* Curve to specify; SSL_Curve_None means use default */
63 SSL_ECDSA_NamedCurve specCurve
;
65 /* Curve to verify; SSL_Curve_None means don't check */
66 SSL_ECDSA_NamedCurve expCurve
;
69 * keychain containing client-side cert, located in LOCAL_BUILD_DIR.
70 * NULL means no keychain.
74 /* password for above keychain */
75 const char *kcPassword
;
78 static const EcdsaTestParams ecdsaTestParams
[] =
82 "tls.secg.org", 8443, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
83 SSL_Curve_None
, SSL_Curve_None
,
84 "ecdsa.keychain", "password"
86 /* tla.secg.org -- port 40023 - secp256r1 */
88 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
89 SSL_Curve_None
, SSL_Curve_secp256r1
92 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
93 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
96 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
97 SSL_Curve_None
, SSL_Curve_secp256r1
100 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
101 SSL_Curve_None
, SSL_Curve_secp256r1
104 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
,
105 SSL_Curve_None
, SSL_Curve_secp256r1
108 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
109 SSL_Curve_None
, SSL_Curve_secp256r1
112 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
113 SSL_Curve_None
, SSL_Curve_secp256r1
116 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
117 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
120 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_RC4_128_SHA
,
121 SSL_Curve_None
, SSL_Curve_secp256r1
124 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
125 SSL_Curve_None
, SSL_Curve_secp256r1
128 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
129 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
132 /* tla.secg.org -- port 40024 - secp384r1 */
133 /* This one doesn't let you specify a curve */
135 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
136 SSL_Curve_None
, SSL_Curve_secp384r1
139 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
140 SSL_Curve_None
, SSL_Curve_secp384r1
143 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
144 SSL_Curve_None
, SSL_Curve_secp384r1
147 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
,
148 SSL_Curve_None
, SSL_Curve_secp384r1
151 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
152 SSL_Curve_None
, SSL_Curve_secp384r1
155 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
156 SSL_Curve_None
, SSL_Curve_secp384r1
159 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_RC4_128_SHA
,
160 SSL_Curve_None
, SSL_Curve_secp384r1
163 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
164 SSL_Curve_None
, SSL_Curve_secp384r1
167 /* tla.secg.org -- port 40025 - secp521r1 */
169 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
170 SSL_Curve_None
, SSL_Curve_secp521r1
173 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
174 SSL_Curve_None
, SSL_Curve_secp521r1
177 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
178 SSL_Curve_None
, SSL_Curve_secp521r1
181 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
,
182 SSL_Curve_None
, SSL_Curve_secp521r1
185 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
186 SSL_Curve_None
, SSL_Curve_secp521r1
189 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
190 SSL_Curve_None
, SSL_Curve_secp521r1
193 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_RC4_128_SHA
,
194 SSL_Curve_None
, SSL_Curve_secp521r1
197 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
198 SSL_Curve_None
, SSL_Curve_secp521r1
202 /* ecc.fedora.redhat.com - port 8443 - secp256r1 */
204 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
205 SSL_Curve_None
, SSL_Curve_secp256r1
208 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
209 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
212 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
213 SSL_Curve_None
, SSL_Curve_secp256r1
216 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
,
217 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
220 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
221 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
224 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
225 SSL_Curve_None
, SSL_Curve_secp256r1
228 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_RC4_128_SHA
,
229 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
232 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
233 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
236 /* ecc.fedora.redhat.com - port 8444 - SSL_Curve_secp384r1 */
237 /* This doesn't work, the server requires a redirect ...
239 "ecc.fedora.redhat.com", 8444, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
240 SSL_Curve_None, SSL_Curve_secp384r1
244 "ecc.fedora.redhat.com", 8445, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
245 SSL_Curve_None
, SSL_Curve_secp521r1
248 "ecc.fedora.redhat.com", 8444, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
249 SSL_Curve_secp384r1
, SSL_Curve_secp384r1
252 "ecc.fedora.redhat.com", 8444, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
,
253 SSL_Curve_secp384r1
, SSL_Curve_secp384r1
256 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
257 SSL_Curve_None
, SSL_Curve_secp384r1
260 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
261 SSL_Curve_None
, SSL_Curve_secp384r1
264 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_RC4_128_SHA
,
265 SSL_Curve_secp384r1
, SSL_Curve_secp384r1
268 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
269 SSL_Curve_secp384r1
, SSL_Curve_secp384r1
272 /* ecc.fedora.redhat.com - port 8445 - SSL_Curve_secp521r1 */
273 /* This one can't do RC4_128 without some HTTP redirection */
275 "ecc.fedora.redhat.com", 8445, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
276 SSL_Curve_None
, SSL_Curve_secp521r1
279 "ecc.fedora.redhat.com", 8445, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
280 SSL_Curve_secp521r1
, SSL_Curve_secp521r1
283 "ecc.fedora.redhat.com", 8445, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
284 SSL_Curve_secp521r1
, SSL_Curve_secp521r1
287 /* ecc.fedora.redhat.com - port 443 - secp256r1 with RSA authentication */
289 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
,
290 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
293 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
,
294 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
297 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_RC4_128_SHA
,
298 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
301 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
,
302 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
305 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
,
306 SSL_Curve_None
, SSL_Curve_secp256r1
309 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
,
310 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
313 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_RC4_128_SHA
,
314 SSL_Curve_None
, SSL_Curve_secp256r1
317 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
,
318 SSL_Curve_None
, SSL_Curve_secp256r1
323 #define NUM_TEST_PARAMS (sizeof(ecdsaTestParams) / sizeof(ecdsaTestParams[0]))
325 static void dumpParams(
326 const EcdsaTestParams
*testParams
)
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
));
335 if(testParams
->specCurve
!= SSL_Curve_None
) {
336 printf("specCurve = %s ", sslCurveString(testParams
->specCurve
));
338 if(testParams
->keychain
) {
339 printf("Client Auth Enabled");
344 static void dumpErrInfo(
346 const EcdsaTestParams
*testParams
,
349 printf("***%s failed for ", op
);
350 dumpParams(testParams
);
351 printf(" error: %s\n", sslGetSSLErrString(ortn
));
355 * Custom ping for this test.
357 #define RCV_BUF_SIZE 256
359 static int doSslPing(
360 const EcdsaTestParams
*testParams
,
367 SSLContextRef ctx
= NULL
;
368 SSLCipherSuite negCipher
;
370 /* first make sure requested server is there */
371 ortn
= MakeServerConnection(testParams
->hostName
, testParams
->port
,
372 nonBlocking
, &sock
, &peerId
);
374 printf("MakeServerConnection(%s) returned %d\n",
375 testParams
->hostName
, (int)ortn
);
380 * Set up a SecureTransport session.
381 * First the standard calls.
383 #pragma clang diagnostic push
384 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
385 ortn
= SSLNewContext(false, &ctx
);
387 printSslErrStr("SSLNewContext", ortn
);
390 ortn
= SSLSetIOFuncs(ctx
, SocketRead
, SocketWrite
);
392 printSslErrStr("SSLSetIOFuncs", ortn
);
396 /* Restrict to only TLSv1 - we have to do this because of Radar 6133465 */
397 ortn
= SSLSetProtocolVersionEnabled(ctx
, kSSLProtocolAll
, false);
399 printSslErrStr("SSLSetProtocolVersionEnabled", ortn
);
402 ortn
= SSLSetProtocolVersionEnabled(ctx
, kTLSProtocol1
, true);
404 printSslErrStr("SSLSetProtocolVersionEnabled", ortn
);
408 /* Restrict to only one CipherSuite */
409 ortn
= SSLSetEnabledCiphers(ctx
, &testParams
->cipherSuite
, 1);
411 printSslErrStr("SSLSetEnabledCiphers", ortn
);
415 ortn
= SSLSetConnection(ctx
, (SSLConnectionRef
)(intptr_t)sock
);
417 printSslErrStr("SSLSetConnection", ortn
);
421 /* These test servers have custom roots, just allow any roots for this test */
422 ortn
= SSLSetAllowsExpiredCerts(ctx
, true);
424 printSslErrStr("SSLSetAllowExpiredCerts", ortn
);
427 ortn
= SSLSetAllowsAnyRoot(ctx
, true);
429 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
433 if(testParams
->specCurve
!= SSL_Curve_None
) {
434 ortn
= SSLSetECDSACurves(ctx
, &testParams
->specCurve
, 1);
436 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
442 ortn
= SSLHandshake(ctx
);
443 } while (ortn
== errSSLWouldBlock
);
445 /* convert normal "shutdown" into zero err rtn */
449 case errSSLClosedGraceful
:
450 case errSSLClosedNoNotify
:
451 ortn
= errSecSuccess
;
454 dumpErrInfo("SSLHandshake", testParams
, ortn
);
460 * Unlike other ping tests we don't bother with a GET - just validate
463 ortn
= SSLGetNegotiatedCipher(ctx
, &negCipher
);
465 dumpErrInfo("SSLHandshake", testParams
, ortn
);
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
));
477 if(testParams
->expCurve
!= SSL_Curve_None
) {
478 SSL_ECDSA_NamedCurve actNegCurve
;
479 ortn
= SSLGetNegotiatedCurve(ctx
, &actNegCurve
);
481 printSslErrStr("SSLGetNegotiatedCurve", ortn
);
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
));
493 if(testParams
->keychain
) {
494 /* Verify client auth */
495 SSLClientCertificateState authState
;
496 ortn
= SSLGetClientCertificateState(ctx
, &authState
);
498 printSslErrStr("SSLGetClientCertificateState", ortn
);
501 if(authState
!= kSSLClientCertSent
) {
502 printf("***Unexpected ClientCertificateState\n");
503 printf(" Expected: ClientCertSent\n");
504 printf(" Received: %s\n", sslGetClientCertStateString(authState
));
510 ortn
= SSLClose(ctx
);
512 #pragma clang diagnostic pop
516 endpointShutdown(sock
);
519 SSLDisposeContext(ctx
);
525 int main(int argc
, char **argv
)
529 int nonBlocking
= false;
531 unsigned maxDex
= NUM_TEST_PARAMS
-1;
532 bool doPause
= false;
536 while ((arg
= getopt(argc
, argv
, "t:bpqh")) != -1) {
539 minDex
= maxDex
= atoi(optarg
);
540 if(minDex
> (NUM_TEST_PARAMS
- 1)) {
541 printf("***max test number is %u.\n", (unsigned)NUM_TEST_PARAMS
);
564 securityd_init(NULL
);
569 signal(SIGPIPE
, sigpipe
);
572 //testStartBanner("sslEcdsa", argc, argv);
576 printf("Pausing at top of loop; CR to continue: ");
581 for(unsigned dex
=minDex
; dex
<=maxDex
; dex
++) {
582 const EcdsaTestParams
*testParams
= &ecdsaTestParams
[dex
];
584 printf("[%u]: ", dex
);
585 dumpParams(testParams
);
587 ourRtn
= doSslPing(testParams
, quiet
, nonBlocking
);
589 //printf("** Test %u failed **\n", dex);
590 //if(testError(quiet)) {
598 printf("Pausing at end of loop; CR to continue: ");
605 printf("===== sslEcdsa test PASSED =====\n");
608 printf("****sslEcdsa test FAILED\n");