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 <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 ortn
= SSLNewContext(false, &ctx
);
385 printSslErrStr("SSLNewContext", ortn
);
388 ortn
= SSLSetIOFuncs(ctx
, SocketRead
, SocketWrite
);
390 printSslErrStr("SSLSetIOFuncs", ortn
);
394 /* Restrict to only TLSv1 - we have to do this because of Radar 6133465 */
395 ortn
= SSLSetProtocolVersionEnabled(ctx
, kSSLProtocolAll
, false);
397 printSslErrStr("SSLSetProtocolVersionEnabled", ortn
);
400 ortn
= SSLSetProtocolVersionEnabled(ctx
, kTLSProtocol1
, true);
402 printSslErrStr("SSLSetProtocolVersionEnabled", ortn
);
406 /* Restrict to only one CipherSuite */
407 ortn
= SSLSetEnabledCiphers(ctx
, &testParams
->cipherSuite
, 1);
409 printSslErrStr("SSLSetEnabledCiphers", ortn
);
413 ortn
= SSLSetConnection(ctx
, (SSLConnectionRef
)(intptr_t)sock
);
415 printSslErrStr("SSLSetConnection", ortn
);
419 /* These test servers have custom roots, just allow any roots for this test */
420 ortn
= SSLSetAllowsExpiredCerts(ctx
, true);
422 printSslErrStr("SSLSetAllowExpiredCerts", ortn
);
425 ortn
= SSLSetAllowsAnyRoot(ctx
, true);
427 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
431 if(testParams
->specCurve
!= SSL_Curve_None
) {
432 ortn
= SSLSetECDSACurves(ctx
, &testParams
->specCurve
, 1);
434 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
440 if(testParams
->keychain
) {
442 const char *lbd
= getenv("LOCAL_BUILD_DIR");
444 printf("WARNING: no LOCAL_BUILD_DIR env var faound\n");
447 snprintf(kcPath
, 2000, "%s/%s", lbd
, testParams
->keychain
);
448 SecKeychainRef kcRef
= NULL
;
449 CFArrayRef certArray
= getSslCerts(kcPath
,
450 false, // encryptOnly
451 false, // completeCertChain
456 ortn
= SecKeychainUnlock(kcRef
,
457 strlen(testParams
->kcPassword
), testParams
->kcPassword
,
460 cssmPerror("SecKeychainUnlock", ortn
);
465 if(certArray
== NULL
) {
466 printf("***WARNING no keychain found at %s\n", kcPath
);
468 ortn
= SSLSetCertificate(ctx
, certArray
);
470 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
473 CFRelease(certArray
);
477 ortn
= SSLHandshake(ctx
);
478 } while (ortn
== errSSLWouldBlock
);
480 /* convert normal "shutdown" into zero err rtn */
484 case errSSLClosedGraceful
:
485 case errSSLClosedNoNotify
:
486 ortn
= errSecSuccess
;
489 dumpErrInfo("SSLHandshake", testParams
, ortn
);
495 * Unlike other ping tests we don't bother with a GET - just validate
498 ortn
= SSLGetNegotiatedCipher(ctx
, &negCipher
);
500 dumpErrInfo("SSLHandshake", testParams
, ortn
);
504 /* here is really what we're testing */
505 if(negCipher
!= testParams
->cipherSuite
) {
506 printf("***Cipher mismatch for ");
507 dumpParams(testParams
);
508 printf("Negotiated cipher: %s\n", sslGetCipherSuiteString(negCipher
));
512 if(testParams
->expCurve
!= SSL_Curve_None
) {
513 SSL_ECDSA_NamedCurve actNegCurve
;
514 ortn
= SSLGetNegotiatedCurve(ctx
, &actNegCurve
);
516 printSslErrStr("SSLGetNegotiatedCurve", ortn
);
519 if(actNegCurve
!= testParams
->expCurve
) {
520 printf("***Negotiated curve error\n");
521 printf("Specified curve: %s\n", sslCurveString(testParams
->specCurve
));
522 printf("Expected curve: %s\n", sslCurveString(testParams
->expCurve
));
523 printf("Obtained curve: %s\n", sslCurveString(actNegCurve
));
528 if(testParams
->keychain
) {
529 /* Verify client auth */
530 SSLClientCertificateState authState
;
531 ortn
= SSLGetClientCertificateState(ctx
, &authState
);
533 printSslErrStr("SSLGetClientCertificateState", ortn
);
536 if(authState
!= kSSLClientCertSent
) {
537 printf("***Unexpected ClientCertificateState\n");
538 printf(" Expected: ClientCertSent\n");
539 printf(" Received: %s\n", sslGetClientCertStateString(authState
));
545 ortn
= SSLClose(ctx
);
549 endpointShutdown(sock
);
552 SSLDisposeContext(ctx
);
558 int main(int argc
, char **argv
)
562 int nonBlocking
= false;
564 unsigned maxDex
= NUM_TEST_PARAMS
-1;
565 bool doPause
= false;
569 while ((arg
= getopt(argc
, argv
, "t:bpqh")) != -1) {
572 minDex
= maxDex
= atoi(optarg
);
573 if(minDex
> (NUM_TEST_PARAMS
- 1)) {
574 printf("***max test number is %u.\n", (unsigned)NUM_TEST_PARAMS
);
597 securityd_init(NULL
);
602 signal(SIGPIPE
, sigpipe
);
605 //testStartBanner("sslEcdsa", argc, argv);
609 printf("Pausing at top of loop; CR to continue: ");
614 for(unsigned dex
=minDex
; dex
<=maxDex
; dex
++) {
615 const EcdsaTestParams
*testParams
= &ecdsaTestParams
[dex
];
617 printf("[%u]: ", dex
);
618 dumpParams(testParams
);
620 ourRtn
= doSslPing(testParams
, quiet
, nonBlocking
);
622 //printf("** Test %u failed **\n", dex);
623 //if(testError(quiet)) {
631 printf("Pausing at end of loop; CR to continue: ");
638 printf("===== sslEcdsa test PASSED =====\n");
641 printf("****sslEcdsa test FAILED\n");