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 <clAppUtils/sslAppUtils.h>
16 #include <clAppUtils/ioSock.h>
17 #include <utilLib/common.h>
19 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
26 #include <sys/param.h>
28 static void usage(char **argv
)
30 printf("Usage: %s [options]\n", argv
[0]);
32 printf(" -t testNum -- only do test testNum; default is all\n");
33 printf(" -q -- quiet\n");
34 printf(" -b -- non blocking I/O\n");
35 printf(" -p -- pause for malloc debug\n");
39 #define IGNORE_SIGPIPE 1
46 #endif /* IGNORE_SIGPIPE */
53 /* We enable exacly one CipherSuite and require that to work */
54 SSLCipherSuite cipherSuite
;
56 /* Curve to specify; SSL_Curve_None means use default */
57 SSL_ECDSA_NamedCurve specCurve
;
59 /* Curve to verify; SSL_Curve_None means don't check */
60 SSL_ECDSA_NamedCurve expCurve
;
63 * keychain containing client-side cert, located in LOCAL_BUILD_DIR.
64 * NULL means no keychain.
68 /* password for above keychain */
69 const char *kcPassword
;
72 static const EcdsaTestParams ecdsaTestParams
[] =
76 "tls.secg.org", 8443, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
77 SSL_Curve_None
, SSL_Curve_None
,
78 "ecdsa.keychain", "password"
80 /* tla.secg.org -- port 40023 - secp256r1 */
82 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
83 SSL_Curve_None
, SSL_Curve_secp256r1
86 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
87 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
90 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
91 SSL_Curve_None
, SSL_Curve_secp256r1
94 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
95 SSL_Curve_None
, SSL_Curve_secp256r1
98 "tls.secg.org", 40023, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
,
99 SSL_Curve_None
, SSL_Curve_secp256r1
102 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
103 SSL_Curve_None
, SSL_Curve_secp256r1
106 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
107 SSL_Curve_None
, SSL_Curve_secp256r1
110 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
111 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
114 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_RC4_128_SHA
,
115 SSL_Curve_None
, SSL_Curve_secp256r1
118 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
119 SSL_Curve_None
, SSL_Curve_secp256r1
122 "tls.secg.org", 40023, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
123 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
126 /* tla.secg.org -- port 40024 - secp384r1 */
127 /* This one doesn't let you specify a curve */
129 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
130 SSL_Curve_None
, SSL_Curve_secp384r1
133 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
134 SSL_Curve_None
, SSL_Curve_secp384r1
137 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
138 SSL_Curve_None
, SSL_Curve_secp384r1
141 "tls.secg.org", 40024, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
,
142 SSL_Curve_None
, SSL_Curve_secp384r1
145 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
146 SSL_Curve_None
, SSL_Curve_secp384r1
149 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
150 SSL_Curve_None
, SSL_Curve_secp384r1
153 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_RC4_128_SHA
,
154 SSL_Curve_None
, SSL_Curve_secp384r1
157 "tls.secg.org", 40024, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
158 SSL_Curve_None
, SSL_Curve_secp384r1
161 /* tla.secg.org -- port 40025 - secp521r1 */
163 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
164 SSL_Curve_None
, SSL_Curve_secp521r1
167 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
168 SSL_Curve_None
, SSL_Curve_secp521r1
171 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
172 SSL_Curve_None
, SSL_Curve_secp521r1
175 "tls.secg.org", 40025, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
,
176 SSL_Curve_None
, SSL_Curve_secp521r1
179 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
180 SSL_Curve_None
, SSL_Curve_secp521r1
183 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
184 SSL_Curve_None
, SSL_Curve_secp521r1
187 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_RC4_128_SHA
,
188 SSL_Curve_None
, SSL_Curve_secp521r1
191 "tls.secg.org", 40025, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
192 SSL_Curve_None
, SSL_Curve_secp521r1
196 /* ecc.fedora.redhat.com - port 8443 - secp256r1 */
198 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
,
199 SSL_Curve_None
, SSL_Curve_secp256r1
202 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
203 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
206 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
207 SSL_Curve_None
, SSL_Curve_secp256r1
210 "ecc.fedora.redhat.com", 8443, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
,
211 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
214 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
215 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
218 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
219 SSL_Curve_None
, SSL_Curve_secp256r1
222 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_RC4_128_SHA
,
223 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
226 "ecc.fedora.redhat.com", 8443, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
227 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
230 /* ecc.fedora.redhat.com - port 8444 - SSL_Curve_secp384r1 */
231 /* This doesn't work, the server requires a redirect ...
233 "ecc.fedora.redhat.com", 8444, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
234 SSL_Curve_None, SSL_Curve_secp384r1
238 "ecc.fedora.redhat.com", 8445, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
239 SSL_Curve_None
, SSL_Curve_secp521r1
242 "ecc.fedora.redhat.com", 8444, TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
,
243 SSL_Curve_secp384r1
, SSL_Curve_secp384r1
246 "ecc.fedora.redhat.com", 8444, TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
,
247 SSL_Curve_secp384r1
, SSL_Curve_secp384r1
250 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
251 SSL_Curve_None
, SSL_Curve_secp384r1
254 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
,
255 SSL_Curve_None
, SSL_Curve_secp384r1
258 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_RC4_128_SHA
,
259 SSL_Curve_secp384r1
, SSL_Curve_secp384r1
262 "ecc.fedora.redhat.com", 8444, TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
,
263 SSL_Curve_secp384r1
, SSL_Curve_secp384r1
266 /* ecc.fedora.redhat.com - port 8445 - SSL_Curve_secp521r1 */
267 /* This one can't do RC4_128 without some HTTP redirection */
269 "ecc.fedora.redhat.com", 8445, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
270 SSL_Curve_None
, SSL_Curve_secp521r1
273 "ecc.fedora.redhat.com", 8445, TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
,
274 SSL_Curve_secp521r1
, SSL_Curve_secp521r1
277 "ecc.fedora.redhat.com", 8445, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
,
278 SSL_Curve_secp521r1
, SSL_Curve_secp521r1
281 /* ecc.fedora.redhat.com - port 443 - secp256r1 with RSA authentication */
283 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
,
284 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
287 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
,
288 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
291 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_RC4_128_SHA
,
292 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
295 "ecc.fedora.redhat.com", 443, TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
,
296 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
299 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
,
300 SSL_Curve_None
, SSL_Curve_secp256r1
303 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
,
304 SSL_Curve_secp256r1
, SSL_Curve_secp256r1
307 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_RC4_128_SHA
,
308 SSL_Curve_None
, SSL_Curve_secp256r1
311 "ecc.fedora.redhat.com", 443, TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
,
312 SSL_Curve_None
, SSL_Curve_secp256r1
317 #define NUM_TEST_PARAMS (sizeof(ecdsaTestParams) / sizeof(ecdsaTestParams[0]))
319 static void dumpParams(
320 const EcdsaTestParams
*testParams
)
322 printf("%s:%d %-33s ",
323 testParams
->hostName
, testParams
->port
,
324 /* skip leading "TLS_" */
325 sslGetCipherSuiteString(testParams
->cipherSuite
)+4);
326 if(testParams
->expCurve
!= SSL_Curve_None
) {
327 printf("expCurve = %s ", sslCurveString(testParams
->expCurve
));
329 if(testParams
->specCurve
!= SSL_Curve_None
) {
330 printf("specCurve = %s ", sslCurveString(testParams
->specCurve
));
332 if(testParams
->keychain
) {
333 printf("Client Auth Enabled");
338 static void dumpErrInfo(
340 const EcdsaTestParams
*testParams
,
343 printf("***%s failed for ", op
);
344 dumpParams(testParams
);
345 printf(" error: %s\n", sslGetSSLErrString(ortn
));
349 * Custom ping for this test.
351 #define RCV_BUF_SIZE 256
353 static int doSslPing(
354 const EcdsaTestParams
*testParams
,
361 SSLContextRef ctx
= NULL
;
362 SSLCipherSuite negCipher
;
364 /* first make sure requested server is there */
365 ortn
= MakeServerConnection(testParams
->hostName
, testParams
->port
,
366 nonBlocking
, &sock
, &peerId
);
368 printf("MakeServerConnection(%s) returned %d\n",
369 testParams
->hostName
, (int)ortn
);
374 * Set up a SecureTransport session.
375 * First the standard calls.
377 ortn
= SSLNewContext(false, &ctx
);
379 printSslErrStr("SSLNewContext", ortn
);
382 ortn
= SSLSetIOFuncs(ctx
, SocketRead
, SocketWrite
);
384 printSslErrStr("SSLSetIOFuncs", ortn
);
388 /* Restrict to only TLSv1 - we have to do this because of Radar 6133465 */
389 ortn
= SSLSetProtocolVersionEnabled(ctx
, kSSLProtocolAll
, false);
391 printSslErrStr("SSLSetProtocolVersionEnabled", ortn
);
394 ortn
= SSLSetProtocolVersionEnabled(ctx
, kTLSProtocol1
, true);
396 printSslErrStr("SSLSetProtocolVersionEnabled", ortn
);
400 /* Restrict to only one CipherSuite */
401 ortn
= SSLSetEnabledCiphers(ctx
, &testParams
->cipherSuite
, 1);
403 printSslErrStr("SSLSetEnabledCiphers", ortn
);
407 ortn
= SSLSetConnection(ctx
, (SSLConnectionRef
)sock
);
409 printSslErrStr("SSLSetConnection", ortn
);
413 /* These test servers have custom roots, just allow any roots for this test */
414 ortn
= SSLSetAllowsExpiredCerts(ctx
, true);
416 printSslErrStr("SSLSetAllowExpiredCerts", ortn
);
419 ortn
= SSLSetAllowsAnyRoot(ctx
, true);
421 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
425 if(testParams
->specCurve
!= SSL_Curve_None
) {
426 ortn
= SSLSetECDSACurves(ctx
, &testParams
->specCurve
, 1);
428 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
433 if(testParams
->keychain
) {
435 const char *lbd
= getenv("LOCAL_BUILD_DIR");
437 printf("WARNING: no LOCAL_BUILD_DIR env var faound\n");
440 snprintf(kcPath
, 2000, "%s/%s", lbd
, testParams
->keychain
);
441 SecKeychainRef kcRef
= NULL
;
442 CFArrayRef certArray
= getSslCerts(kcPath
,
443 CSSM_FALSE
, // encryptOnly
444 CSSM_FALSE
, // completeCertChain
449 ortn
= SecKeychainUnlock(kcRef
,
450 strlen(testParams
->kcPassword
), testParams
->kcPassword
,
453 cssmPerror("SecKeychainUnlock", ortn
);
458 if(certArray
== NULL
) {
459 printf("***WARNING no keychain found at %s\n", kcPath
);
461 ortn
= SSLSetCertificate(ctx
, certArray
);
463 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
466 CFRelease(certArray
);
469 ortn
= SSLHandshake(ctx
);
470 } while (ortn
== errSSLWouldBlock
);
472 /* convert normal "shutdown" into zero err rtn */
476 case errSSLClosedGraceful
:
477 case errSSLClosedNoNotify
:
481 dumpErrInfo("SSLHandshake", testParams
, ortn
);
487 * Unlike other ping tests we don't bother with a GET - just validate
490 ortn
= SSLGetNegotiatedCipher(ctx
, &negCipher
);
492 dumpErrInfo("SSLHandshake", testParams
, ortn
);
496 /* here is really what we're testing */
497 if(negCipher
!= testParams
->cipherSuite
) {
498 printf("***Cipher mismatch for ");
499 dumpParams(testParams
);
500 printf("Negotiated cipher: %s\n", sslGetCipherSuiteString(negCipher
));
504 if(testParams
->expCurve
!= SSL_Curve_None
) {
505 SSL_ECDSA_NamedCurve actNegCurve
;
506 ortn
= SSLGetNegotiatedCurve(ctx
, &actNegCurve
);
508 printSslErrStr("SSLGetNegotiatedCurve", ortn
);
511 if(actNegCurve
!= testParams
->expCurve
) {
512 printf("***Negotiated curve error\n");
513 printf("Specified curve: %s\n", sslCurveString(testParams
->specCurve
));
514 printf("Expected curve: %s\n", sslCurveString(testParams
->expCurve
));
515 printf("Obtained curve: %s\n", sslCurveString(actNegCurve
));
520 if(testParams
->keychain
) {
521 /* Verify client auth */
522 SSLClientCertificateState authState
;
523 ortn
= SSLGetClientCertificateState(ctx
, &authState
);
525 printSslErrStr("SSLGetClientCertificateState", ortn
);
528 if(authState
!= kSSLClientCertSent
) {
529 printf("***Unexpected ClientCertificateState\n");
530 printf(" Expected: ClientCertSent\n");
531 printf(" Received: %s\n", sslGetClientCertStateString(authState
));
537 ortn
= SSLClose(ctx
);
541 endpointShutdown(sock
);
544 SSLDisposeContext(ctx
);
550 int main(int argc
, char **argv
)
554 int nonBlocking
= false;
556 unsigned maxDex
= NUM_TEST_PARAMS
-1;
557 bool doPause
= false;
561 while ((arg
= getopt(argc
, argv
, "t:bpqh")) != -1) {
564 minDex
= maxDex
= atoi(optarg
);
565 if(minDex
> (NUM_TEST_PARAMS
- 1)) {
566 printf("***max test number is %u.\n", (unsigned)NUM_TEST_PARAMS
);
588 signal(SIGPIPE
, sigpipe
);
591 testStartBanner("sslEcdsa", argc
, argv
);
595 printf("Pausing at top of loop; CR to continue: ");
600 for(unsigned dex
=minDex
; dex
<=maxDex
; dex
++) {
601 const EcdsaTestParams
*testParams
= &ecdsaTestParams
[dex
];
603 printf("[%u]: ", dex
);
604 dumpParams(testParams
);
606 ourRtn
= doSslPing(testParams
, quiet
, nonBlocking
);
608 if(testError(quiet
)) {
616 printf("Pausing at end of loop; CR to continue: ");
623 printf("===== sslEcdsa test PASSED =====\n");
626 printf("****sslEcdsa test FAILED\n");