2 * Copyright (c) 2003-2010 Apple Inc. All Rights Reserved.
4 * SSL viewer tool, SecureTransport / OS X version.
7 #include <Security/SecureTransport.h>
8 #include <Security/SecureTransportPriv.h> // for SSLGetPeerSecTrust
9 #include <Security/SecCertificate.h>
10 #include <clAppUtils/sslAppUtils.h>
11 #include <clAppUtils/ioSock.h>
12 #include <security_cdsa_utils/cuPrintCert.h>
13 #include <utilLib/fileIo.h>
15 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
21 #include <CoreFoundation/CoreFoundation.h>
23 #define DEFAULT_GETMSG "GET"
24 #define DEFAULT_PATH "/"
25 #define DEFAULT_GET_SUFFIX "HTTP/1.0\r\n\r\n"
27 #define DEFAULT_HOST "www.amazon.com"
28 #define DEFAULT_PORT 443
30 #define CFRELEASE(cf) if (cf) { CFRelease(cf); cf = NULL; }
32 /* true when using SSLCopyPeerCertificates() per Radar 3311892 */
33 #define USE_COPY_PEER_CERTS 1
35 static void usageNorm(char **argv
)
37 printf("Usage: %s [hostname|-] [path] [option ...]\n", argv
[0]);
38 printf(" %s hostname [path] [option ...]\n", argv
[0]);
39 printf("Specifying '-' for hostname, or no args, uses default of %s.\n",
41 printf("Optional path argument must start with leading '/'.\n");
43 printf(" e Allow Expired Certs\n");
44 printf(" E Allow Expired Roots\n");
45 printf(" r Allow any root cert\n");
46 printf(" c Display peer certs\n");
47 printf(" d Display received data\n");
48 printf(" S Display enabled cipher suites\n");
49 printf(" 2 SSLv2 only (default is TLSv1)\n");
50 printf(" 3 SSLv3 only w/SSLv2 enabled (default is TLSv1)\n");
51 printf(" t TLSv1 only w/SSLv2,SSLv3 enabled (this is the default)\n");
52 printf(" L all - TLSv1, SSLv3, SSLv2 (default = TLSv1)\n");
53 printf(" o TLSv1, SSLv3 use kSSLProtocol__X__Only\n");
54 printf(" g={prot...} Specify legal protocols; prot = any combo of"
56 printf(" k=keychain Contains (client|server) cert and keys. Optional.\n");
57 printf(" l=loopCount Perform loopCount ops (default = 1)\n");
58 printf(" P=port Default = %d\n", DEFAULT_PORT
);
59 printf(" p Pause after each loop\n");
60 printf(" q Quiet/diagnostic mode (site names and errors"
62 printf(" a fileName Add fileName to list of trusted roots\n");
63 printf(" A fileName fileName is ONLY trusted root\n");
64 printf(" Z fileName fileName is a trusted leaf cert\n");
65 printf(" x Disable Cert Verification\n");
66 printf(" z=password Unlock client keychain with password.\n");
67 printf(" 8 Complete cert chains (default is out cert is a root)\n");
68 printf(" s Silent\n");
69 printf(" V Verbose\n");
71 printf(" hv More, verbose help\n");
74 static void usageVerbose(char **argv
)
77 printf("Obscure Usage:\n");
78 printf(" u kSSLProtocolUnknown only (TLSv1)\n");
79 printf(" M Manual cert verification via "
80 "SecTrustEvaluate\n");
81 printf(" f fileBase Write Peer Certs to fileBase*\n");
82 printf(" D fileBase Write DNList to fileBase*\n");
83 printf(" C=cipherSuite (e=40-bit d=DES D=40-bit DES 3=3DES 4=RC4"
85 " 2=RC2 a=AES128 A=AES256 h=DH H=Anon DH r=DHE/RSA s=DH/DSS\n"
86 " n=RSA/NULL E=ECDHE F=ECDH\n");
87 printf(" y=keychain Encryption-only cert and keys. Optional.\n");
88 printf(" K Keep connected until server disconnects\n");
89 printf(" n Require closure notify message in TLSv1, "
90 "SSLv3 mode (implies K)\n");
91 printf(" R Disable resumable session support\n");
92 printf(" i=timeout Session cache timeout\n");
93 printf(" b Non-blocking I/O\n");
94 printf(" v Verify negotiated protocol equals attempted\n");
95 printf(" m=[23t] Max protocol supported as specified; implies "
97 printf(" T=[nrsj] Verify client cert state = "
98 "none/requested/sent/rejected\n");
99 printf(" H allow hostname spoofing\n");
100 printf(" F=vfyHost Verify certs with specified host name\n");
101 printf(" G=getMsg Specify entire GET, POST, etc.\n");
102 printf(" I Interactive client authentication\n");
103 printf(" N Log handshake timing\n");
104 printf(" 4 Disable anonymous ciphers\n");
105 printf(" 7 Pause only after first loop\n");
109 static void usage(char **argv
)
116 * Arguments to top-level sslPing()
119 SSLProtocol tryVersion
; // only used if acceptedProts NULL
120 // uses SSLSetProtocolVersion
121 char *acceptedProts
; // optional, any combo of {2,3,t}
122 // uses SSLSetProtocolVersionEnabled
123 const char *hostName
; // e.g., "www.amazon.com"
124 const char *vfyHostName
; // use this for cert vfy if non-NULL,
127 const char *getMsg
; // e.g.,
128 // "GET / HTTP/1.0\r\n\r\n"
131 bool allowExpiredRoot
;
132 bool disableCertVerify
;
133 bool manualCertVerify
;
134 bool dumpRxData
; // display server data
135 char cipherRestrict
; // '2', 'd'. etc...; '\0' for
138 bool requireNotify
; // require closure notify
140 bool resumableEnable
;
141 bool allowHostnameSpoof
;
144 char *trustedLeafFile
;
146 bool interactiveAuth
;
147 CFArrayRef clientCerts
; // optional
148 CFArrayRef encryptClientCerts
; // optional
149 uint32 sessionCacheTimeout
;// optional
150 bool disableAnonCiphers
;
151 bool showCipherSuites
;
152 bool quiet
; // minimal stdout
153 bool silent
; // no stdout
155 SSLProtocol negVersion
; // RETURNED
156 SSLCipherSuite negCipher
; // RETURNED
157 CFArrayRef peerCerts
; // mallocd & RETURNED
158 SecTrustRef peerTrust
; // RETURNED
159 SSLClientCertificateState certState
; // RETURNED
160 SSLClientAuthenticationType authType
; // RETURNED
161 CFArrayRef dnList
; // RETURNED
162 char *password
; // optional to open clientCerts
164 Boolean sessionWasResumed
;
165 unsigned char sessionID
[MAX_SESSION_ID_LENGTH
];
166 size_t sessionIDLength
;
167 CFAbsoluteTime handshakeTimeOp
; // time for this op
168 CFAbsoluteTime handshakeTimeFirst
; // time for FIRST op, not averaged
169 CFAbsoluteTime handshakeTimeTotal
; // time for all ops except first
170 unsigned numHandshakes
;
175 static void sigpipe(int sig
)
178 printf("***SIGPIPE***\n");
182 * Start up a CFRunLoop. This is needed to field keychain event callbacks, used
183 * to maintain root cert cache coherency.
186 /* first we need something to register so we *have* a run loop */
187 static OSStatus
kcCacheCallback (
188 SecKeychainEvent keychainEvent
,
189 SecKeychainCallbackInfo
*info
,
195 /* main thread has to wait for this to be set to know a run loop has been set up */
196 static int runLoopInitialized
= 0;
198 /* this is the thread which actually runs the CFRunLoop */
199 void *cfRunLoopThread(void *arg
)
201 OSStatus ortn
= SecKeychainAddCallback(kcCacheCallback
,
202 kSecTrustSettingsChangedEventMask
, NULL
);
204 printf("registerCacheCallbacks: SecKeychainAddCallback returned %d", (int32_t)ortn
);
205 /* Not sure how this could ever happen - maybe if there is no run loop active? */
208 runLoopInitialized
= 1;
210 /* should not be reached */
211 printf("\n*** Hey! CFRunLoopRun() exited!***\n");
215 static int startCFRunLoop()
217 pthread_t runLoopThread
;
219 int result
= pthread_create(&runLoopThread
, NULL
, cfRunLoopThread
, NULL
);
221 printf("***pthread_create returned %d, aborting\n", result
);
228 * Snag a copy of current connection's peer certs so we can
229 * examine them later after the connection is closed.
230 * SecureTransport actually does the create and retain for us.
232 static OSStatus
copyPeerCerts(
234 CFArrayRef
*peerCerts
) // mallocd & RETURNED
236 #if USE_COPY_PEER_CERTS
237 OSStatus ortn
= SSLCopyPeerCertificates(ctx
, peerCerts
);
239 OSStatus ortn
= SSLGetPeerCertificates(ctx
, peerCerts
);
242 printf("***Error obtaining peer certs: %s\n",
243 sslGetSSLErrString(ortn
));
248 /* free the cert array obtained via SSLGetPeerCertificates() */
249 /* necessary due to a buggy SSLGetPeerCertificates which really should
250 * release its certs after they get added to this array */
251 static void freePeerCerts(
252 CFArrayRef peerCerts
)
254 if(peerCerts
== NULL
) {
258 #if USE_COPY_PEER_CERTS
260 /* Voila! Problem fixed. */
261 CFRelease(peerCerts
);
266 SecCertificateRef certData
;
269 numCerts
= CFArrayGetCount(peerCerts
);
270 for(i
=0; i
<numCerts
; i
++) {
271 certData
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
);
274 CFRelease(peerCerts
);
275 #endif /* USE_COPY_PEER_CERTS */
279 * Manually evaluate session's SecTrustRef.
281 #define SSL_SEC_TRUST 1
283 static OSStatus
sslEvaluateTrust(
287 CFArrayRef
*peerCerts
) // fetched and retained
290 SecTrustRef secTrust
= NULL
;
293 ortn
= SSLGetPeerSecTrust(ctx
, &secTrust
);
298 printf("\n***Error obtaining peer SecTrustRef: %s\n",
299 sslGetSSLErrString(ortn
));
302 if(secTrust
== NULL
) {
303 /* this is the normal case for resumed sessions, in which
304 * no cert evaluation is performed */
306 printf("...No SecTrust available - this is a resumed session, right?\n");
310 SecTrustResultType secTrustResult
;
311 ortn
= SecTrustEvaluate(secTrust
, &secTrustResult
);
313 printf("\n***Error on SecTrustEvaluate: %d\n", (int)ortn
);
317 const char *res
= NULL
;
318 switch(secTrustResult
) {
319 case kSecTrustResultInvalid
:
320 res
= "kSecTrustResultInvalid"; break;
321 case kSecTrustResultProceed
:
322 res
= "kSecTrustResultProceed"; break;
323 case kSecTrustResultConfirm
:
324 res
= "kSecTrustResultConfirm"; break;
325 case kSecTrustResultDeny
:
326 res
= "kSecTrustResultDeny"; break;
327 case kSecTrustResultUnspecified
:
328 res
= "kSecTrustResultUnspecified"; break;
329 case kSecTrustResultRecoverableTrustFailure
:
330 res
= "kSecTrustResultRecoverableTrustFailure"; break;
331 case kSecTrustResultFatalTrustFailure
:
332 res
= "kSecTrustResultFatalTrustFailure"; break;
333 case kSecTrustResultOtherError
:
334 res
= "kSecTrustResultOtherError"; break;
336 res
= "UNKNOWN"; break;
338 printf("\nSecTrustEvaluate(): secTrustResult %s\n", res
);
341 switch(secTrustResult
) {
342 case kSecTrustResultUnspecified
:
343 /* cert chain valid, no special UserTrust assignments */
344 case kSecTrustResultProceed
:
345 /* cert chain valid AND user explicitly trusts this */
348 printf("\n***SecTrustEvaluate reported secTrustResult %d\n",
349 (int)secTrustResult
);
350 ortn
= errSSLXCertChainInvalid
;
356 /* one more thing - get peer certs in the form of an evidence chain */
357 CSSM_TP_APPLE_EVIDENCE_INFO
*dummyEv
;
358 OSStatus thisRtn
= SecTrustGetResult(secTrust
, &secTrustResult
,
359 peerCerts
, &dummyEv
);
361 printSslErrStr("SecTrustGetResult", thisRtn
);
363 #if !USE_COPY_PEER_CERTS
365 /* workaround for the fact that SSLGetPeerCertificates()
366 * leaves a retain count on each element in the returned array,
367 * requiring us to do a release on each cert.
369 CFIndex numCerts
= CFArrayGetCount(*peerCerts
);
370 for(CFIndex dex
=0; dex
<numCerts
; dex
++) {
371 CFRetain(CFArrayGetValueAtIndex(*peerCerts
, dex
));
374 #endif /* !USE_COPY_PEER_CERTS */
378 static void sslShowEnabledCipherSuites(
382 SSLCipherSuite
*ciphers
;
383 size_t numCiphers
, totalCiphers
;
387 status
= SSLGetNumberSupportedCiphers(ctx
, &totalCiphers
);
388 status
= SSLGetNumberEnabledCiphers(ctx
, &numCiphers
);
389 ciphers
= (SSLCipherSuite
*)malloc(sizeof(SSLCipherSuite
) * numCiphers
);
390 status
= SSLGetEnabledCiphers(ctx
, ciphers
, &numCiphers
);
392 printf(" Total enabled ciphers : %ld of %ld\n", numCiphers
, totalCiphers
);
394 for(i
=0; i
<numCiphers
; i
++) {
396 case SSL_NULL_WITH_NULL_NULL
: c
="SSL_NULL_WITH_NULL_NULL"; break;
397 case SSL_RSA_WITH_NULL_MD5
: c
="SSL_RSA_WITH_NULL_MD5"; break;
398 case SSL_RSA_WITH_NULL_SHA
: c
="SSL_RSA_WITH_NULL_SHA"; break;
399 case SSL_RSA_EXPORT_WITH_RC4_40_MD5
: c
="SSL_RSA_EXPORT_WITH_RC4_40_MD5"; break;
400 case SSL_RSA_WITH_RC4_128_MD5
: c
="SSL_RSA_WITH_RC4_128_MD5"; break;
401 case SSL_RSA_WITH_RC4_128_SHA
: c
="SSL_RSA_WITH_RC4_128_SHA"; break;
402 case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5
: c
="SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5"; break;
403 case SSL_RSA_WITH_IDEA_CBC_SHA
: c
="SSL_RSA_WITH_IDEA_CBC_SHA"; break;
404 case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA
: c
="SSL_RSA_EXPORT_WITH_DES40_CBC_SHA"; break;
405 case SSL_RSA_WITH_DES_CBC_SHA
: c
="SSL_RSA_WITH_DES_CBC_SHA"; break;
406 case SSL_RSA_WITH_3DES_EDE_CBC_SHA
: c
="SSL_RSA_WITH_3DES_EDE_CBC_SHA"; break;
407 case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA
: c
="SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"; break;
408 case SSL_DH_DSS_WITH_DES_CBC_SHA
: c
="SSL_DH_DSS_WITH_DES_CBC_SHA"; break;
409 case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA
: c
="SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA"; break;
410 case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA
: c
="SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"; break;
411 case SSL_DH_RSA_WITH_DES_CBC_SHA
: c
="SSL_DH_RSA_WITH_DES_CBC_SHA"; break;
412 case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA
: c
="SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA"; break;
413 case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA
: c
="SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"; break;
414 case SSL_DHE_DSS_WITH_DES_CBC_SHA
: c
="SSL_DHE_DSS_WITH_DES_CBC_SHA"; break;
415 case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA
: c
="SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; break;
416 case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA
: c
="SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"; break;
417 case SSL_DHE_RSA_WITH_DES_CBC_SHA
: c
="SSL_DHE_RSA_WITH_DES_CBC_SHA"; break;
418 case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA
: c
="SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; break;
419 case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5
: c
="SSL_DH_anon_EXPORT_WITH_RC4_40_MD5"; break;
420 case SSL_DH_anon_WITH_RC4_128_MD5
: c
="SSL_DH_anon_WITH_RC4_128_MD5"; break;
421 case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA
: c
="SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA"; break;
422 case SSL_DH_anon_WITH_DES_CBC_SHA
: c
="SSL_DH_anon_WITH_DES_CBC_SHA"; break;
423 case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA
: c
="SSL_DH_anon_WITH_3DES_EDE_CBC_SHA"; break;
424 case SSL_FORTEZZA_DMS_WITH_NULL_SHA
: c
="SSL_FORTEZZA_DMS_WITH_NULL_SHA"; break;
425 case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA
:c
="SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA"; break;
427 /* TLS addenda using AES, per RFC 3268 */
428 case TLS_RSA_WITH_AES_128_CBC_SHA
: c
="TLS_RSA_WITH_AES_128_CBC_SHA"; break;
429 case TLS_DH_DSS_WITH_AES_128_CBC_SHA
: c
="TLS_DH_DSS_WITH_AES_128_CBC_SHA"; break;
430 case TLS_DH_RSA_WITH_AES_128_CBC_SHA
: c
="TLS_DH_RSA_WITH_AES_128_CBC_SHA"; break;
431 case TLS_DHE_DSS_WITH_AES_128_CBC_SHA
: c
="TLS_DHE_DSS_WITH_AES_128_CBC_SHA"; break;
432 case TLS_DHE_RSA_WITH_AES_128_CBC_SHA
: c
="TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; break;
433 case TLS_DH_anon_WITH_AES_128_CBC_SHA
: c
="TLS_DH_anon_WITH_AES_128_CBC_SHA"; break;
434 case TLS_RSA_WITH_AES_256_CBC_SHA
: c
="TLS_RSA_WITH_AES_256_CBC_SHA"; break;
435 case TLS_DH_DSS_WITH_AES_256_CBC_SHA
: c
="TLS_DH_DSS_WITH_AES_256_CBC_SHA"; break;
436 case TLS_DH_RSA_WITH_AES_256_CBC_SHA
: c
="TLS_DH_RSA_WITH_AES_256_CBC_SHA"; break;
437 case TLS_DHE_DSS_WITH_AES_256_CBC_SHA
: c
="TLS_DHE_DSS_WITH_AES_256_CBC_SHA"; break;
438 case TLS_DHE_RSA_WITH_AES_256_CBC_SHA
: c
="TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; break;
439 case TLS_DH_anon_WITH_AES_256_CBC_SHA
: c
="TLS_DH_anon_WITH_AES_256_CBC_SHA"; break;
441 /* ECDSA addenda, RFC 4492 */
442 case TLS_ECDH_ECDSA_WITH_NULL_SHA
: c
="TLS_ECDH_ECDSA_WITH_NULL_SHA"; break;
443 case TLS_ECDH_ECDSA_WITH_RC4_128_SHA
: c
="TLS_ECDH_ECDSA_WITH_RC4_128_SHA"; break;
444 case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
: c
="TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"; break;
445 case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
: c
="TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"; break;
446 case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
: c
="TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"; break;
447 case TLS_ECDHE_ECDSA_WITH_NULL_SHA
: c
="TLS_ECDHE_ECDSA_WITH_NULL_SHA"; break;
448 case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
: c
="TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"; break;
449 case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
: c
="TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"; break;
450 case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
: c
="TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"; break;
451 case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
: c
="TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"; break;
452 case TLS_ECDH_RSA_WITH_NULL_SHA
: c
="TLS_ECDH_RSA_WITH_NULL_SHA"; break;
453 case TLS_ECDH_RSA_WITH_RC4_128_SHA
: c
="TLS_ECDH_RSA_WITH_RC4_128_SHA"; break;
454 case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
: c
="TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"; break;
455 case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
: c
="TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"; break;
456 case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
: c
="TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"; break;
457 case TLS_ECDHE_RSA_WITH_NULL_SHA
: c
="TLS_ECDHE_RSA_WITH_NULL_SHA"; break;
458 case TLS_ECDHE_RSA_WITH_RC4_128_SHA
: c
="TLS_ECDHE_RSA_WITH_RC4_128_SHA"; break;
459 case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
: c
="TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"; break;
460 case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
: c
="TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"; break;
461 case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
: c
="TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"; break;
462 case TLS_ECDH_anon_WITH_NULL_SHA
: c
="TLS_ECDH_anon_WITH_NULL_SHA"; break;
463 case TLS_ECDH_anon_WITH_RC4_128_SHA
: c
="TLS_ECDH_anon_WITH_RC4_128_SHA"; break;
464 case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA
: c
="TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"; break;
465 case TLS_ECDH_anon_WITH_AES_128_CBC_SHA
: c
="TLS_ECDH_anon_WITH_AES_128_CBC_SHA"; break;
466 case TLS_ECDH_anon_WITH_AES_256_CBC_SHA
: c
="TLS_ECDH_anon_WITH_AES_256_CBC_SHA"; break;
469 * Tags for SSL 2 cipher kinds which are not specified
472 case SSL_RSA_WITH_RC2_CBC_MD5
: c
="SSL_RSA_WITH_RC2_CBC_MD5"; break;
473 case SSL_RSA_WITH_IDEA_CBC_MD5
: c
="SSL_RSA_WITH_IDEA_CBC_MD5"; break;
474 case SSL_RSA_WITH_DES_CBC_MD5
: c
="SSL_RSA_WITH_DES_CBC_MD5"; break;
475 case SSL_RSA_WITH_3DES_EDE_CBC_MD5
: c
="SSL_RSA_WITH_3DES_EDE_CBC_MD5"; break;
476 case SSL_NO_SUCH_CIPHERSUITE
:
478 c
="SSL_NO_SUCH_CIPHERSUITE"; break;
486 /* print reply received from server, safely */
487 static void dumpAscii(
491 char *cp
= (char *)rcvBuf
;
495 for(i
=0; i
<len
; i
++) {
508 if(isprint(c
) && (c
!= '\n')) {
512 printf("<%02X>", ((unsigned)c
) & 0xff);
522 * Perform one SSL diagnostic session. Returns nonzero on error. Normally no
523 * output to stdout except initial "connecting to" message, unless there
524 * is a really screwed up error (i.e., something not directly related
525 * to the SSL connection).
527 #define RCV_BUF_SIZE 256
529 static OSStatus
sslPing(
535 SSLContextRef ctx
= NULL
;
538 uint8_t rcvBuf
[RCV_BUF_SIZE
];
539 CFAbsoluteTime startHandshake
;
540 CFAbsoluteTime endHandshake
;
542 pargs
->negVersion
= kSSLProtocolUnknown
;
543 pargs
->negCipher
= SSL_NULL_WITH_NULL_NULL
;
544 pargs
->peerCerts
= NULL
;
546 /* first make sure requested server is there */
547 ortn
= MakeServerConnection(pargs
->hostName
, pargs
->port
, pargs
->nonBlocking
,
550 printf("MakeServerConnection returned %d; aborting\n", (int)ortn
);
554 printf("...connected to server; starting SecureTransport\n");
558 * Set up a SecureTransport session.
559 * First the standard calls.
561 ortn
= SSLNewContext(false, &ctx
);
563 printSslErrStr("SSLNewContext", ortn
);
566 ortn
= SSLSetIOFuncs(ctx
, SocketRead
, SocketWrite
);
568 printSslErrStr("SSLSetIOFuncs", ortn
);
571 ortn
= SSLSetConnection(ctx
, (SSLConnectionRef
)sock
);
573 printSslErrStr("SSLSetConnection", ortn
);
576 SSLConnectionRef getConn
;
577 ortn
= SSLGetConnection(ctx
, &getConn
);
579 printSslErrStr("SSLGetConnection", ortn
);
582 if(getConn
!= (SSLConnectionRef
)sock
) {
583 printf("***SSLGetConnection error\n");
587 if(!pargs
->allowHostnameSpoof
) {
588 /* if this isn't set, it isn't checked by AppleX509TP */
589 const char *vfyHost
= pargs
->hostName
;
590 if(pargs
->vfyHostName
) {
591 /* generally means we're expecting an error */
592 vfyHost
= pargs
->vfyHostName
;
594 ortn
= SSLSetPeerDomainName(ctx
, vfyHost
, strlen(vfyHost
));
596 printSslErrStr("SSLSetPeerDomainName", ortn
);
602 * SecureTransport options.
604 if(pargs
->acceptedProts
) {
605 ortn
= SSLSetProtocolVersionEnabled(ctx
, kSSLProtocolAll
, false);
607 printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn
);
610 for(const char *cp
= pargs
->acceptedProts
; *cp
; cp
++) {
614 prot
= kSSLProtocol2
;
617 prot
= kSSLProtocol3
;
620 prot
= kTLSProtocol1
;
625 ortn
= SSLSetProtocolVersionEnabled(ctx
, prot
, true);
627 printSslErrStr("SSLSetProtocolVersionEnabled", ortn
);
633 ortn
= SSLSetProtocolVersion(ctx
, pargs
->tryVersion
);
635 printSslErrStr("SSLSetProtocolVersion", ortn
);
639 ortn
= SSLGetProtocolVersion(ctx
, &getVers
);
641 printSslErrStr("SSLSetProtocolVersion", ortn
);
644 if(getVers
!= pargs
->tryVersion
) {
645 printf("***SSLGetProtocolVersion screwup: try %s get %s\n",
646 sslGetProtocolVersionString(pargs
->tryVersion
),
647 sslGetProtocolVersionString(getVers
));
652 if(pargs
->resumableEnable
) {
653 const void *rtnId
= NULL
;
656 ortn
= SSLSetPeerID(ctx
, &peerId
, sizeof(PeerSpec
));
658 printSslErrStr("SSLSetPeerID", ortn
);
661 /* quick test of the get fcn */
662 ortn
= SSLGetPeerID(ctx
, &rtnId
, &rtnIdLen
);
664 printSslErrStr("SSLGetPeerID", ortn
);
667 if((rtnId
== NULL
) || (rtnIdLen
!= sizeof(PeerSpec
))) {
668 printf("***SSLGetPeerID screwup\n");
670 else if(memcmp(&peerId
, rtnId
, rtnIdLen
) != 0) {
671 printf("***SSLGetPeerID data mismatch\n");
674 if(pargs
->allowExpired
) {
675 ortn
= SSLSetAllowsExpiredCerts(ctx
, true);
677 printSslErrStr("SSLSetAllowExpiredCerts", ortn
);
681 if(pargs
->allowExpiredRoot
) {
682 ortn
= SSLSetAllowsExpiredRoots(ctx
, true);
684 printSslErrStr("SSLSetAllowsExpiredRoots", ortn
);
688 if(pargs
->disableCertVerify
) {
689 ortn
= SSLSetEnableCertVerify(ctx
, false);
691 printSslErrStr("SSLSetEnableCertVerify", ortn
);
695 if(pargs
->allowAnyRoot
) {
696 ortn
= SSLSetAllowsAnyRoot(ctx
, true);
698 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
702 if(pargs
->cipherRestrict
!= '\0') {
703 ortn
= sslSetCipherRestrictions(ctx
, pargs
->cipherRestrict
);
708 if(pargs
->anchorFile
) {
709 ortn
= sslAddTrustedRoot(ctx
, pargs
->anchorFile
, pargs
->replaceAnchors
);
711 printf("***Error obtaining anchor file %s\n", pargs
->anchorFile
);
715 if(pargs
->trustedLeafFile
) {
716 SecCertificateRef leafCertRef
= NULL
;
717 CFMutableArrayRef leafCerts
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
718 /* sslReadAnchor is a misnomer; it just creates a SecCertificateRef from a file */
719 ortn
= sslReadAnchor(pargs
->trustedLeafFile
, &leafCertRef
);
721 CFArrayAppendValue(leafCerts
, leafCertRef
);
722 CFRelease(leafCertRef
);
723 ortn
= SSLSetTrustedLeafCertificates(ctx
, leafCerts
);
724 CFRelease(leafCerts
);
730 if(pargs
->interactiveAuth
) {
731 /* we want to get errSSLServerAuthCompleted from SSLHandshake on server auth completion */
732 SSLSetSessionOption(ctx
, kSSLSessionOptionBreakOnServerAuth
, true);
733 /* we want to get errSSLClientCertRequested from SSLHandshake on client auth request */
734 SSLSetSessionOption(ctx
, kSSLSessionOptionBreakOnCertRequested
, true);
736 else if(pargs
->clientCerts
) {
738 if(pargs
->anchorFile
== NULL
) {
739 /* assume this is a root we want to implicitly trust */
740 ortn
= addIdentityAsTrustedRoot(ctx
, pargs
->clientCerts
);
745 ortn
= SSLSetCertificate(ctx
, pargs
->clientCerts
);
747 printSslErrStr("SSLSetCertificate", ortn
);
750 /* quickie test for this new function */
751 ortn
= SSLGetCertificate(ctx
, &dummy
);
753 printSslErrStr("SSLGetCertificate", ortn
);
756 if(dummy
!= pargs
->clientCerts
) {
757 printf("***SSLGetCertificate error\n");
762 if(pargs
->encryptClientCerts
) {
763 if(pargs
->anchorFile
== NULL
) {
764 ortn
= addIdentityAsTrustedRoot(ctx
, pargs
->encryptClientCerts
);
769 ortn
= SSLSetEncryptionCertificate(ctx
, pargs
->encryptClientCerts
);
771 printSslErrStr("SSLSetEncryptionCertificate", ortn
);
775 if(pargs
->sessionCacheTimeout
) {
776 ortn
= SSLSetSessionCacheTimeout(ctx
, pargs
->sessionCacheTimeout
);
778 printSslErrStr("SSLSetSessionCacheTimeout", ortn
);
782 if(pargs
->disableAnonCiphers
) {
783 ortn
= SSLSetAllowAnonymousCiphers(ctx
, false);
785 printSslErrStr("SSLSetAllowAnonymousCiphers", ortn
);
788 /* quickie test of the getter */
790 ortn
= SSLGetAllowAnonymousCiphers(ctx
, &e
);
792 printSslErrStr("SSLGetAllowAnonymousCiphers", ortn
);
796 printf("***SSLGetAllowAnonymousCiphers() returned true; expected false\n");
801 if(pargs
->showCipherSuites
) {
802 sslShowEnabledCipherSuites(ctx
);
804 /*** end options ***/
807 printf("...starting SSL handshake\n");
809 startHandshake
= CFAbsoluteTimeGetCurrent();
812 { ortn
= SSLHandshake(ctx
);
813 if((ortn
== errSSLWouldBlock
) && !pargs
->silent
) {
814 /* keep UI responsive */
817 else if(ortn
== errSSLServerAuthCompleted
) {
819 printf("...server authentication completed\n");
822 else if(ortn
== errSSLClientCertRequested
) {
824 printf("...received client cert request\n");
826 /* %%% could prompt interactively here for client cert to use;
827 * for now, just use the client cert passed on the command line
829 if(pargs
->clientCerts
) {
831 if(pargs
->anchorFile
== NULL
) {
832 /* assume this is a root we want to implicitly trust */
833 ortn
= addIdentityAsTrustedRoot(ctx
, pargs
->clientCerts
);
839 printf("...setting client certificate\n");
841 ortn
= SSLSetCertificate(ctx
, pargs
->clientCerts
);
843 printSslErrStr("SSLSetCertificate", ortn
);
846 /* quickie test for this new function */
847 ortn
= SSLGetCertificate(ctx
, &dummy
);
849 printSslErrStr("SSLGetCertificate", ortn
);
852 if(dummy
!= pargs
->clientCerts
) {
853 printf("***SSLGetCertificate error\n");
859 printf("***no client certificate specified!\n");
862 } while (ortn
== errSSLWouldBlock
||
863 ortn
== errSSLServerAuthCompleted
||
864 ortn
== errSSLClientCertRequested
);
866 endHandshake
= CFAbsoluteTimeGetCurrent();
867 pargs
->handshakeTimeOp
= endHandshake
- startHandshake
;
868 if(pargs
->numHandshakes
== 0) {
869 /* special case, this one is always way longer */
870 pargs
->handshakeTimeFirst
= pargs
->handshakeTimeOp
;
873 /* normal running total */
874 pargs
->handshakeTimeTotal
+= pargs
->handshakeTimeOp
;
876 pargs
->numHandshakes
++;
878 /* this works even if handshake failed due to cert chain invalid */
879 CFRELEASE(pargs
->peerCerts
);
880 if(!pargs
->manualCertVerify
) {
881 copyPeerCerts(ctx
, &pargs
->peerCerts
);
884 /* else fetched via SecTrust later */
885 pargs
->peerCerts
= NULL
;
888 ortn
= SSLCopyPeerTrust(ctx
, &pargs
->peerTrust
);
890 printf("***SSLCopyPeerTrust error %d\n", (int)ortn
);
891 pargs
->peerTrust
= NULL
;
895 SSLGetClientCertificateState(ctx
, &pargs
->certState
);
896 SSLGetNegotiatedClientAuthType(ctx
, &pargs
->authType
);
897 SSLGetNegotiatedCipher(ctx
, &pargs
->negCipher
);
898 SSLGetNegotiatedProtocolVersion(ctx
, &pargs
->negVersion
);
899 CFRELEASE(pargs
->dnList
);
900 SSLCopyDistinguishedNames(ctx
, &pargs
->dnList
);
901 pargs
->sessionIDLength
= MAX_SESSION_ID_LENGTH
;
902 SSLGetResumableSessionInfo(ctx
, &pargs
->sessionWasResumed
, pargs
->sessionID
,
903 &pargs
->sessionIDLength
);
904 if(pargs
->manualCertVerify
) {
905 OSStatus certRtn
= sslEvaluateTrust(ctx
, pargs
->verbose
, pargs
->silent
,
907 if(certRtn
&& !ortn
) {
920 printf("...SSL handshake complete\n");
923 /* Write our GET request */
924 length
= strlen(pargs
->getMsg
);
925 ortn
= SSLWrite(ctx
, pargs
->getMsg
, length
, &actLen
);
927 printf("***SSLWrite error: %d\n", (int)ortn
);
928 } else if((actLen
> 0) && pargs
->dumpRxData
) {
929 dumpAscii((uint8_t*)pargs
->getMsg
, actLen
);
933 * Try to snag RCV_BUF_SIZE bytes. Exit if (!keepConnected and we get any data
934 * at all), or (keepConnected and err != (none, wouldBlock)).
936 while (ortn
== noErr
) {
938 if(pargs
->dumpRxData
) {
941 ortn
= SSLGetBufferedReadSize(ctx
, &avail
);
943 printf("***SSLGetBufferedReadSize error\n");
947 printf("\n%d bytes available: ", (int)avail
);
950 ortn
= SSLRead(ctx
, rcvBuf
, RCV_BUF_SIZE
, &actLen
);
951 if((actLen
== 0) && !pargs
->silent
) {
954 if((actLen
== 0) && (ortn
== noErr
)) {
955 printf("***Radar 2984932 confirmed***\n");
957 if (ortn
== errSSLWouldBlock
) {
958 /* for this loop, these are identical */
961 if(ortn
== errSSLServerAuthCompleted
||
962 ortn
== errSSLClientCertRequested
) {
963 /* should never get these once the handshake is complete */
964 printf("***SSLRead returned unexpected handshake error!\n");
967 if((actLen
> 0) && pargs
->dumpRxData
) {
968 dumpAscii(rcvBuf
, actLen
);
971 /* connection closed by server or by error */
974 if(!pargs
->keepConnected
&& (actLen
> 0)) {
975 /* good enough, we connected */
983 /* snag these again in case of renegotiate */
984 SSLGetClientCertificateState(ctx
, &pargs
->certState
);
985 SSLGetNegotiatedCipher(ctx
, &pargs
->negCipher
);
986 SSLGetNegotiatedProtocolVersion(ctx
, &pargs
->negVersion
);
987 CFRELEASE(pargs
->dnList
);
988 SSLCopyDistinguishedNames(ctx
, &pargs
->dnList
);
990 /* convert normal "shutdown" into zero err rtn */
991 if(ortn
== errSSLClosedGraceful
) {
994 if((ortn
== errSSLClosedNoNotify
) && !pargs
->requireNotify
) {
995 /* relaxed disconnect rules */
1000 * always do close, even on error - to flush outgoing write queue
1002 OSStatus cerr
= SSLClose(ctx
);
1007 endpointShutdown(sock
);
1010 SSLDisposeContext(ctx
);
1015 static void showPeerCerts(
1016 CFArrayRef peerCerts
,
1020 SecCertificateRef certRef
;
1025 if(peerCerts
== NULL
) {
1028 numCerts
= CFArrayGetCount(peerCerts
);
1029 for(i
=0; i
<numCerts
; i
++) {
1030 certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
);
1031 ortn
= SecCertificateGetData(certRef
, &certData
);
1033 printf("***SecCertificateGetData returned %d\n", (int)ortn
);
1036 printf("\n================== Server Cert %lu ===================\n\n", i
);
1037 printCert(certData
.Data
, certData
.Length
, verbose
);
1038 printf("\n=============== End of Server Cert %lu ===============\n", i
);
1042 static void writePeerCerts(
1043 CFArrayRef peerCerts
,
1044 const char *fileBase
)
1047 SecCertificateRef certRef
;
1053 if(peerCerts
== NULL
) {
1056 numCerts
= CFArrayGetCount(peerCerts
);
1057 for(i
=0; i
<numCerts
; i
++) {
1058 sprintf(fileName
, "%s%02d.cer", fileBase
, (int)i
);
1059 certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
);
1060 ortn
= SecCertificateGetData(certRef
, &certData
);
1062 printf("***SecCertificateGetData returned %d\n", (int)ortn
);
1065 cspWriteFile(fileName
, certData
.Data
, certData
.Length
);
1067 printf("...wrote %lu certs to fileBase %s\n", numCerts
, fileBase
);
1070 static void writeDnList(
1072 const char *fileBase
)
1079 if(dnList
== NULL
) {
1082 numDns
= CFArrayGetCount(dnList
);
1083 for(i
=0; i
<numDns
; i
++) {
1084 sprintf(fileName
, "%s%02d.der", fileBase
, (int)i
);
1085 cfDn
= (CFDataRef
)CFArrayGetValueAtIndex(dnList
, i
);
1086 cspWriteFile(fileName
, CFDataGetBytePtr(cfDn
), CFDataGetLength(cfDn
));
1088 printf("...wrote %lu RDNs to fileBase %s\n", numDns
, fileBase
);
1092 * Show result of an sslPing().
1093 * Assumes the following from sslPingArgs:
1108 static void showSSLResult(
1109 const sslPingArgs
&pargs
,
1111 bool displayPeerCerts
,
1112 const char *fileBase
, // non-NULL: write certs to file
1113 const char *dnFileBase
) // non-NULL: write DNList to file
1115 CFIndex numPeerCerts
;
1119 if(pargs
.acceptedProts
) {
1120 printf(" Allowed SSL versions : %s\n", pargs
.acceptedProts
);
1123 printf(" Attempted SSL version : %s\n",
1124 sslGetProtocolVersionString(pargs
.tryVersion
));
1127 printf(" Result : %s\n", sslGetSSLErrString(err
));
1128 printf(" Negotiated SSL version : %s\n",
1129 sslGetProtocolVersionString(pargs
.negVersion
));
1130 printf(" Negotiated CipherSuite : %s\n",
1131 sslGetCipherSuiteString(pargs
.negCipher
));
1132 if(pargs
.certState
!= kSSLClientCertNone
) {
1133 printf(" Client Cert State : %s\n",
1134 sslGetClientCertStateString(pargs
.certState
));
1135 printf(" Client Auth Type : %s\n",
1136 sslGetClientAuthTypeString(pargs
.authType
));
1139 printf(" Resumed Session : ");
1140 if(pargs
.sessionWasResumed
) {
1141 for(unsigned dex
=0; dex
<pargs
.sessionIDLength
; dex
++) {
1142 printf("%02X ", pargs
.sessionID
[dex
]);
1143 if(((dex
% 8) == 7) && (dex
!= (pargs
.sessionIDLength
- 1))) {
1150 printf("NOT RESUMED\n");
1152 printf(" Handshake time : %f seconds\n", pargs
.handshakeTimeOp
);
1154 if(pargs
.peerCerts
== NULL
) {
1158 numPeerCerts
= CFArrayGetCount(pargs
.peerCerts
);
1160 printf(" Number of server certs : %lu\n", numPeerCerts
);
1161 if(numPeerCerts
!= 0) {
1162 if(displayPeerCerts
) {
1163 showPeerCerts(pargs
.peerCerts
, false);
1165 if(fileBase
!= NULL
) {
1166 writePeerCerts(pargs
.peerCerts
, fileBase
);
1169 if(dnFileBase
!= NULL
) {
1170 writeDnList(pargs
.dnList
, dnFileBase
);
1176 static int verifyProtocol(
1178 SSLProtocol maxProtocol
,
1179 SSLProtocol reqProtocol
,
1180 SSLProtocol negProtocol
)
1185 if(reqProtocol
> maxProtocol
) {
1186 /* known not to support this attempt, relax */
1187 reqProtocol
= maxProtocol
;
1189 if(reqProtocol
!= negProtocol
) {
1190 printf("***Expected protocol %s; negotiated %s\n",
1191 sslGetProtocolVersionString(reqProtocol
),
1192 sslGetProtocolVersionString(negProtocol
));
1200 static int verifyClientCertState(
1201 bool verifyCertState
,
1202 SSLClientCertificateState expectState
,
1203 SSLClientCertificateState gotState
)
1205 if(!verifyCertState
) {
1208 if(expectState
== gotState
) {
1211 printf("***Expected clientCertState %s; got %s\n",
1212 sslGetClientCertStateString(expectState
),
1213 sslGetClientCertStateString(gotState
));
1218 * Free everything allocated by sslPing in an sslPingArgs.
1219 * Mainly for looping and malloc debugging.
1221 static void freePingArgs(
1224 freePeerCerts(pargs
->peerCerts
);
1225 pargs
->peerCerts
= NULL
;
1226 CFRELEASE(pargs
->peerTrust
);
1227 CFRELEASE(pargs
->dnList
);
1228 /* more, later, for client retry/identity fetch */
1231 static SSLProtocol
charToProt(
1237 return kSSLProtocol2
;
1239 return kSSLProtocol3
;
1241 return kTLSProtocol1
;
1246 return kSSLProtocolUnknown
;
1249 int main(int argc
, char **argv
)
1255 char fullFileBase
[100];
1256 int ourRtn
= 0; // exit status - sum of all errors
1258 SecKeychainRef serverKc
= nil
;
1259 SecKeychainRef encryptKc
= nil
;
1262 /* user-spec'd parameters */
1263 char *getPath
= (char *)DEFAULT_PATH
;
1264 char *fileBase
= NULL
;
1265 bool displayCerts
= false;
1266 bool doSslV2
= false;
1267 bool doSslV3
= false;
1268 bool doTlsV1
= true;
1269 bool protXOnly
= false; // kSSLProtocol3Only, kTLSProtocol1Only
1270 bool doProtUnknown
= false;
1271 unsigned loopCount
= 1;
1272 bool doPause
= false;
1273 bool pauseFirstLoop
= false;
1274 bool verifyProt
= false;
1275 SSLProtocol maxProtocol
= kTLSProtocol1
; // for verifying negotiated
1277 char *acceptedProts
= NULL
;
1278 char *keyChainName
= NULL
;
1279 char *encryptKeyChainName
= NULL
;
1280 char *getMsgSpec
= NULL
;
1281 bool vfyCertState
= false;
1282 SSLClientCertificateState expectCertState
;
1283 bool displayHandshakeTimes
= false;
1284 bool completeCertChain
= false;
1285 char *dnFileBase
= NULL
;
1287 /* special case - one arg of "h" or "-h" or "hv" */
1289 if((strcmp(argv
[1], "h") == 0) || (strcmp(argv
[1], "-h") == 0)) {
1292 if(strcmp(argv
[1], "hv") == 0) {
1297 /* set up defaults */
1298 memset(&pargs
, 0, sizeof(sslPingArgs
));
1299 pargs
.hostName
= DEFAULT_HOST
;
1300 pargs
.port
= DEFAULT_PORT
;
1301 pargs
.resumableEnable
= true;
1304 for(arg
=1; arg
<argc
; arg
++) {
1307 /* first arg, is always hostname; '-' means default */
1308 if(argp
[0] != '-') {
1309 pargs
.hostName
= argp
;
1313 if(argp
[0] == '/') {
1314 /* path always starts with leading slash */
1321 pargs
.allowExpired
= true;
1324 pargs
.allowExpiredRoot
= true;
1327 pargs
.disableCertVerify
= true;
1330 pargs
.disableCertVerify
= true; // implied
1331 pargs
.manualCertVerify
= true;
1334 pargs
.interactiveAuth
= true;
1338 /* requires another arg */
1341 pargs
.anchorFile
= argv
[arg
];
1345 /* requires another arg */
1348 pargs
.anchorFile
= argv
[arg
];
1349 pargs
.replaceAnchors
= true;
1353 /* requires another arg */
1356 pargs
.trustedLeafFile
= argv
[arg
];
1359 pargs
.allowAnyRoot
= true;
1362 pargs
.dumpRxData
= true;
1365 displayCerts
= true;
1369 /* requires another arg */
1372 fileBase
= argv
[arg
];
1375 pargs
.cipherRestrict
= argp
[2];
1378 pargs
.showCipherSuites
= true;
1381 doSslV3
= doTlsV1
= false;
1385 doSslV2
= doTlsV1
= false;
1389 /* currently the default... */
1390 doSslV2
= doSslV3
= false;
1394 doSslV2
= doSslV3
= doTlsV1
= true;
1400 doSslV2
= doSslV3
= doTlsV1
= false;
1401 doProtUnknown
= true;
1404 pargs
.keepConnected
= true;
1407 pargs
.requireNotify
= true;
1408 pargs
.keepConnected
= true;
1411 pargs
.resumableEnable
= false;
1414 pargs
.nonBlocking
= true;
1420 if(argp
[1] != '=') {
1423 verifyProt
= true; // implied
1424 maxProtocol
= charToProt(argp
[2], argv
);
1427 if(argp
[1] != '=') {
1430 acceptedProts
= &argp
[2];
1431 doSslV3
= doSslV2
= doTlsV1
= false;
1434 loopCount
= atoi(&argp
[2]);
1435 if(loopCount
== 0) {
1436 printf("***bad loopCount\n");
1441 pargs
.port
= atoi(&argp
[2]);
1444 pargs
.allowHostnameSpoof
= true;
1447 pargs
.vfyHostName
= &argp
[2];
1450 keyChainName
= &argp
[2];
1453 encryptKeyChainName
= &argp
[2];
1456 getMsgSpec
= &argp
[2];
1459 if(argp
[1] != '=') {
1462 vfyCertState
= true;
1465 expectCertState
= kSSLClientCertNone
;
1468 expectCertState
= kSSLClientCertRequested
;
1471 expectCertState
= kSSLClientCertSent
;
1474 expectCertState
= kSSLClientCertRejected
;
1481 pargs
.password
= &argp
[2];
1487 pauseFirstLoop
= true;
1493 pargs
.verbose
= true;
1496 pargs
.silent
= pargs
.quiet
= true;
1499 displayHandshakeTimes
= true;
1502 completeCertChain
= true;
1505 pargs
.sessionCacheTimeout
= atoi(&argp
[2]);
1508 pargs
.disableAnonCiphers
= true;
1512 /* requires another arg */
1515 dnFileBase
= argv
[arg
];
1518 if(pargs
.verbose
|| (argp
[1] == 'v')) {
1529 pargs
.getMsg
= getMsgSpec
;
1532 sprintf(getMsg
, "%s %s %s",
1533 DEFAULT_GETMSG
, getPath
, DEFAULT_GET_SUFFIX
);
1534 pargs
.getMsg
= getMsg
;
1537 /* get client cert and optional encryption cert as CFArrayRef */
1539 pargs
.clientCerts
= getSslCerts(keyChainName
, false, completeCertChain
,
1540 pargs
.anchorFile
, &serverKc
);
1541 if(pargs
.clientCerts
== nil
) {
1544 if(pargs
.password
) {
1545 OSStatus ortn
= SecKeychainUnlock(serverKc
,
1546 strlen(pargs
.password
), pargs
.password
, true);
1548 printf("SecKeychainUnlock returned %d\n", (int)ortn
);
1553 if(encryptKeyChainName
) {
1554 pargs
.encryptClientCerts
= getSslCerts(encryptKeyChainName
, true,
1555 completeCertChain
, pargs
.anchorFile
, &encryptKc
);
1556 if(pargs
.encryptClientCerts
== nil
) {
1560 signal(SIGPIPE
, sigpipe
);
1562 if(loopCount
!= 0) {
1563 /* prepare to handle KC callbacks for root cert cache invalidation */
1564 if(startCFRunLoop()) {
1568 /* give that thread a chance right now */
1569 while(!runLoopInitialized
) {
1577 printf("Before main loop. Hit a to abort, c to continue: ");
1584 for(loop
=0; loop
<loopCount
; loop
++) {
1586 * One pass for each protocol version, skipping any explicit version if
1587 * an attempt at a higher version and succeeded in doing so successfully fell
1592 protXOnly
? kTLSProtocol1Only
: kTLSProtocol1
;
1593 pargs
.acceptedProts
= NULL
;
1595 printf("Connecting to host %s with TLS V1...\n", pargs
.hostName
);
1598 err
= sslPing(&pargs
);
1604 sprintf(fullFileBase
, "%s_v3.1", fileBase
);
1606 showSSLResult(pargs
,
1609 fileBase
? fullFileBase
: NULL
,
1612 freePingArgs(&pargs
);
1614 /* deal with fallbacks, skipping redundant tests */
1615 switch(pargs
.negVersion
) {
1626 ourRtn
+= verifyProtocol(verifyProt
, maxProtocol
, kTLSProtocol1
,
1629 /* note we do this regardless since the client state might be
1630 * the cause of a failure */
1631 ourRtn
+= verifyClientCertState(vfyCertState
, expectCertState
,
1635 pargs
.tryVersion
= protXOnly
? kSSLProtocol3Only
: kSSLProtocol3
;
1636 pargs
.acceptedProts
= NULL
;
1638 printf("Connecting to host %s with SSL V3...\n", pargs
.hostName
);
1641 err
= sslPing(&pargs
);
1647 sprintf(fullFileBase
, "%s_v3.0", fileBase
);
1649 showSSLResult(pargs
,
1652 fileBase
? fullFileBase
: NULL
,
1655 freePingArgs(&pargs
);
1657 /* deal with fallbacks, skipping redundant tests */
1658 switch(pargs
.negVersion
) {
1665 ourRtn
+= verifyProtocol(verifyProt
, maxProtocol
, kSSLProtocol3
,
1668 /* note we do this regardless since the client state might be
1669 * the cause of a failure */
1670 ourRtn
+= verifyClientCertState(vfyCertState
, expectCertState
,
1676 sprintf(fullFileBase
, "%s_v2", fileBase
);
1679 printf("Connecting to host %s with SSL V2...\n", pargs
.hostName
);
1682 pargs
.tryVersion
= kSSLProtocol2
;
1683 pargs
.acceptedProts
= NULL
;
1684 err
= sslPing(&pargs
);
1690 sprintf(fullFileBase
, "%s_v2", fileBase
);
1692 showSSLResult(pargs
,
1695 fileBase
? fullFileBase
: NULL
,
1698 freePingArgs(&pargs
);
1700 ourRtn
+= verifyProtocol(verifyProt
, maxProtocol
, kSSLProtocol2
,
1703 /* note we do this regardless since the client state might be
1704 * the cause of a failure */
1705 ourRtn
+= verifyClientCertState(vfyCertState
, expectCertState
,
1710 printf("Connecting to host %s with kSSLProtocolUnknown...\n",
1714 pargs
.tryVersion
= kSSLProtocolUnknown
;
1715 pargs
.acceptedProts
= NULL
;
1716 err
= sslPing(&pargs
);
1722 sprintf(fullFileBase
, "%s_def", fileBase
);
1724 showSSLResult(pargs
,
1727 fileBase
? fullFileBase
: NULL
,
1730 freePingArgs(&pargs
);
1732 if(acceptedProts
!= NULL
) {
1733 pargs
.acceptedProts
= acceptedProts
;
1734 pargs
.tryVersion
= kSSLProtocolUnknown
; // not used
1736 printf("Connecting to host %s with acceptedProts %s...\n",
1737 pargs
.hostName
, pargs
.acceptedProts
);
1740 err
= sslPing(&pargs
);
1746 sprintf(fullFileBase
, "%s_def", fileBase
);
1748 showSSLResult(pargs
,
1751 fileBase
? fullFileBase
: NULL
,
1754 freePingArgs(&pargs
);
1758 /* pause after first, before last to grab trace */
1759 ((loop
== 0) || (loop
== loopCount
- 1))
1764 printf("a to abort, c to continue: ");
1771 if(displayHandshakeTimes
) {
1772 CFAbsoluteTime totalTime
;
1773 unsigned numHandshakes
;
1774 if(pargs
.numHandshakes
== 1) {
1775 /* just display the first one */
1776 totalTime
= pargs
.handshakeTimeFirst
;
1780 /* skip the first one */
1781 totalTime
= pargs
.handshakeTimeTotal
;
1782 numHandshakes
= pargs
.numHandshakes
- 1;
1784 if(numHandshakes
!= 0) {
1785 printf(" %u handshakes in %f seconds; %f seconds per handshake\n",
1786 numHandshakes
, totalTime
,
1787 (totalTime
/ numHandshakes
));
1790 printCertShutdown();
1792 printf("===%s exiting with %d %s for host %s\n", argv
[0], ourRtn
,
1793 (ourRtn
> 1) ? "errors" : "error", pargs
.hostName
);