2 * Copyright (c) 2006-2012 Apple Inc. All Rights Reserved.
4 * SSL viewer tool, Secure Transport.
7 #include "SecureTransport.h"
9 #include <Security/SecureTransport.h>
10 #include <Security/SecureTransportPriv.h>
11 #include <Security/SecCertificate.h>
12 #include <Security/SecTrust.h>
13 #include <Security/SecTrustPriv.h>
14 #include "sslAppUtils.h"
15 #include "printCert.h"
19 #include <MacErrors.h>
25 #include <CoreFoundation/CoreFoundation.h>
28 #include <securityd/spi.h>
31 #define DEFAULT_GETMSG "GET"
32 #define DEFAULT_PATH "/"
33 #define DEFAULT_GET_SUFFIX "HTTP/1.0\r\n\r\n"
35 #define DEFAULT_HOST "store.apple.com"
36 #define DEFAULT_PORT 443
38 #define CFReleaseSafe(CF) { CFTypeRef _cf = (CF); if (_cf) CFRelease(_cf); }
39 #define CFReleaseNull(CF) { CFTypeRef _cf = (CF); \
40 if (_cf) { (CF) = NULL; CFRelease(_cf); } }
42 static void usageNorm(char **argv
)
44 printf("Usage: %s [hostname|-] [path] [option ...]\n", argv
[0]);
45 printf(" %s hostname [path] [option ...]\n", argv
[0]);
46 printf("Specifying '-' for hostname, or no args, uses default of %s.\n",
48 printf("Optional path argument must start with leading '/'.\n");
50 printf(" e Allow Expired Certs\n");
51 printf(" E Allow Expired Roots\n");
52 printf(" r Allow any root cert\n");
53 printf(" c Display peer certs\n");
54 printf(" cc Display peer SecTrust\n");
55 printf(" d Display received data\n");
56 printf(" S Display enabled cipher suites\n");
57 printf(" 2 SSLv2 only\n");
58 printf(" 3 SSLv3 only\n");
59 printf(" tls10 | t TLSv1 only\n");
60 printf(" tls11 TLSv1.1 only\n");
61 printf(" tls12 TLSv1.2 only\n");
62 printf(" L all - TLSv1.2, TLSv1.1, TLSv1, SSLv3, SSLv2 (default = TLSv1.2)\n");
63 printf(" g={prot...} Specify legal protocols; prot = any combo of"
64 " [2|3|t|tls10|tls11|tls12]\n");
65 printf(" k=keychain Contains (client|server) cert and keys. Optional.\n");
66 printf(" l=loopCount Perform loopCount ops (default = 1)\n");
67 printf(" P=port Default = %d\n", DEFAULT_PORT
);
68 printf(" p Pause after each loop\n");
69 printf(" q Quiet/diagnostic mode (site names and errors"
71 printf(" a fileName Add fileName to list of trusted roots\n");
72 printf(" A fileName fileName is ONLY trusted root\n");
73 printf(" Z fileName fileName is a trusted leaf cert\n");
74 printf(" x Disable Cert Verification\n");
75 printf(" z=password Unlock client keychain with password.\n");
76 printf(" 8 Complete cert chains (default is out cert is a root)\n");
77 printf(" s Silent\n");
78 printf(" V Verbose\n");
80 printf(" hv More, verbose help\n");
83 static void usageVerbose(char **argv
) __attribute__((noreturn
));
84 static void usageVerbose(char **argv
)
87 printf("Obscure Usage:\n");
88 printf(" u kSSLProtocolUnknown only (TLSv1)\n");
89 printf(" M Manual cert verification via "
90 "SecTrustEvaluate\n");
91 printf(" f fileBase Write Peer Certs to fileBase*\n");
92 printf(" o TLSv1, SSLv3 use kSSLProtocol__X__Only\n");
93 printf(" C=cipherSuite (e=40-bit d=DES D=40-bit DES 3=3DES 4=RC4 "
95 " 2=RC2 a=AES128 A=AES256 h=DH H=Anon DH r=DHE/RSA s=DH/DSS\n");
96 printf(" y=keychain Encryption-only cert and keys. Optional.\n");
97 printf(" K Keep connected until server disconnects\n");
98 printf(" n Require closure notify message in TLSv1, "
99 "SSLv3 mode (implies K)\n");
100 printf(" R Disable resumable session support\n");
101 printf(" b Non-blocking I/O\n");
102 printf(" v Verify negotiated protocol equals attempted\n");
103 printf(" m=[23t] Max protocol supported as specified; implies "
105 printf(" T=[nrsj] Verify client cert state = "
106 "none/requested/sent/rejected\n");
107 printf(" H allow hostname spoofing\n");
108 printf(" F=vfyHost Verify certs with specified host name\n");
109 printf(" G=getMsg Specify entire GET, POST, etc.\n");
110 printf(" N Log handshake timing\n");
111 printf(" 7 Pause only after first loop\n");
115 static void usage(char **argv
) __attribute__((noreturn
));
116 static void usage(char **argv
)
123 * Arguments to top-level sslPing()
126 SSLProtocol tryVersion
; // only used if acceptedProts NULL
127 // uses SSLSetProtocolVersion
128 char *acceptedProts
; // optional, any combo of {2,3,t}
129 // uses SSLSetProtocolVersionEnabled
130 const char *hostName
; // e.g., "store.apple.com"
131 const char *vfyHostName
; // use this for cert vfy if non-NULL,
134 const char *getMsg
; // e.g.,
135 // "GET / HTTP/1.0\r\n\r\n"
138 bool allowExpiredRoot
;
139 bool disableCertVerify
;
140 bool manualCertVerify
;
141 bool dumpRxData
; // display server data
142 char cipherRestrict
; // '2', 'd'. etc...; '\0' for
145 bool requireNotify
; // require closure notify
147 bool resumableEnable
;
148 bool allowHostnameSpoof
;
151 char *trustedLeafFile
;
153 bool interactiveAuth
;
154 CFArrayRef clientCerts
; // optional
155 CFArrayRef encryptClientCerts
; // optional
156 uint32 sessionCacheTimeout
;// optional
157 bool disableAnonCiphers
;
158 bool showCipherSuites
;
159 bool quiet
; // minimal stdout
160 bool silent
; // no stdout
162 SSLProtocol negVersion
; // RETURNED
163 SSLCipherSuite negCipher
; // RETURNED
164 CFArrayRef peerCerts
; // mallocd & RETURNED
165 SecTrustRef peerTrust
; // RETURNED
166 SSLClientCertificateState certState
; // RETURNED
167 #if TARGET_OS_MAC && MAC_OS_X_VERSION_MAX_ALLOWED < 1060
170 SSLClientAuthenticationType authType
; // RETURNED
172 CFArrayRef dnList
; // RETURNED
173 char *password
; // optional to open clientCerts
175 Boolean sessionWasResumed
;
176 unsigned char sessionID
[MAX_SESSION_ID_LENGTH
];
177 size_t sessionIDLength
;
178 CFAbsoluteTime handshakeTimeOp
; // time for this op
179 CFAbsoluteTime handshakeTimeFirst
; // time for FIRST op, not averaged
180 CFAbsoluteTime handshakeTimeTotal
; // time for all ops except first
181 unsigned numHandshakes
;
186 static void sigpipe(int sig
)
189 printf("***SIGPIPE***\n");
193 * Snag a copy of current connection's peer certs so we can
194 * examine them later after the connection is closed.
195 * SecureTransport actually does the create and retain for us.
197 static OSStatus
copyPeerCerts(
199 CFArrayRef
*peerCerts
) // mallocd & RETURNED
201 OSStatus ortn
= SSLCopyPeerCertificates(ctx
, peerCerts
);
203 printf("***Error obtaining peer certs: %s\n",
204 sslGetSSLErrString(ortn
));
210 * Manually evaluate session's SecTrustRef.
213 static OSStatus
sslEvaluateTrust(
217 CFArrayRef
*peerCerts
) // fetched and retained
219 OSStatus ortn
= noErr
;
221 SecTrustRef secTrust
= NULL
;
222 ortn
= SSLGetPeerSecTrust(ctx
, &secTrust
);
224 printf("\n***Error obtaining peer SecTrustRef: %s\n",
225 sslGetSSLErrString(ortn
));
228 if(secTrust
== NULL
) {
229 /* this is the normal case for resumed sessions, in which
230 * no cert evaluation is performed */
232 printf("...No SecTrust available - this is a resumed session, right?\n");
236 SecTrustResultType secTrustResult
;
237 ortn
= SecTrustEvaluate(secTrust
, &secTrustResult
);
239 printf("\n***Error on SecTrustEvaluate: %d\n", (int)ortn
);
243 const char *res
= NULL
;
244 switch(secTrustResult
) {
245 case kSecTrustResultInvalid
:
246 res
= "kSecTrustResultInvalid"; break;
247 case kSecTrustResultProceed
:
248 res
= "kSecTrustResultProceed"; break;
249 case kSecTrustResultConfirm
:
250 res
= "kSecTrustResultConfirm"; break;
251 case kSecTrustResultDeny
:
252 res
= "kSecTrustResultDeny"; break;
253 case kSecTrustResultUnspecified
:
254 res
= "kSecTrustResultUnspecified"; break;
255 case kSecTrustResultRecoverableTrustFailure
:
256 res
= "kSecTrustResultRecoverableTrustFailure"; break;
257 case kSecTrustResultFatalTrustFailure
:
258 res
= "kSecTrustResultFatalTrustFailure"; break;
259 case kSecTrustResultOtherError
:
260 res
= "kSecTrustResultOtherError"; break;
262 res
= "UNKNOWN"; break;
264 printf("\nSecTrustEvaluate(): secTrustResult %s\n", res
);
267 switch(secTrustResult
) {
268 case kSecTrustResultUnspecified
:
269 /* cert chain valid, no special UserTrust assignments */
270 case kSecTrustResultProceed
:
271 /* cert chain valid AND user explicitly trusts this */
274 printf("\n***SecTrustEvaluate reported secTrustResult %d\n",
275 (int)secTrustResult
);
276 ortn
= errSSLXCertChainInvalid
;
283 #ifdef USE_CDSA_CRYPTO
284 /* one more thing - get peer certs in the form of an evidence chain */
285 CSSM_TP_APPLE_EVIDENCE_INFO
*dummyEv
;
286 OSStatus thisRtn
= SecTrustGetResult(secTrust
, &secTrustResult
,
287 peerCerts
, &dummyEv
);
289 printSslErrStr("SecTrustGetResult", thisRtn
);
295 static void sslShowEnabledCipherSuites(
299 SSLCipherSuite
*ciphers
;
300 size_t numCiphers
, totalCiphers
;
303 status
= SSLGetNumberSupportedCiphers(ctx
, &totalCiphers
);
304 status
= SSLGetNumberEnabledCiphers(ctx
, &numCiphers
);
305 ciphers
= (SSLCipherSuite
*)malloc(sizeof(SSLCipherSuite
) * numCiphers
);
306 status
= SSLGetEnabledCiphers(ctx
, ciphers
, &numCiphers
);
308 printf(" Total enabled ciphers : %ld of %ld\n", numCiphers
, totalCiphers
);
310 for(i
=0; i
<numCiphers
; i
++) {
311 printf(" %s (0x%04X)\n", sslGetCipherSuiteString(ciphers
[i
]), ciphers
[i
]);
317 /* print reply received from server, safely */
318 static void dumpAscii(
322 char *cp
= (char *)rcvBuf
;
326 for(i
=0; i
<len
; i
++) {
339 if(isprint(c
) && (c
!= '\n')) {
343 printf("<%02X>", ((unsigned)c
) & 0xff);
353 * Perform one SSL diagnostic session. Returns nonzero on error. Normally no
354 * output to stdout except initial "connecting to" message, unless there
355 * is a really screwed up error (i.e., something not directly related
356 * to the SSL connection).
358 #define RCV_BUF_SIZE 256
360 static OSStatus
sslPing(
366 SSLContextRef ctx
= NULL
;
369 uint8_t rcvBuf
[RCV_BUF_SIZE
];
370 CFAbsoluteTime startHandshake
;
371 CFAbsoluteTime endHandshake
;
373 pargs
->negVersion
= kSSLProtocolUnknown
;
374 pargs
->negCipher
= SSL_NULL_WITH_NULL_NULL
;
375 pargs
->peerCerts
= NULL
;
377 /* first make sure requested server is there */
378 ortn
= MakeServerConnection(pargs
->hostName
, pargs
->port
, pargs
->nonBlocking
,
381 printf("MakeServerConnection returned %d; aborting\n", (int)ortn
);
385 printf("...connected to server; starting SecureTransport\n");
389 * Set up a SecureTransport session.
390 * First the standard calls.
392 ortn
= SSLNewContext(false, &ctx
);
394 printSslErrStr("SSLNewContext", ortn
);
397 ortn
= SSLSetIOFuncs(ctx
, SocketRead
, SocketWrite
);
399 printSslErrStr("SSLSetIOFuncs", ortn
);
402 ortn
= SSLSetConnection(ctx
, (SSLConnectionRef
)sock
);
404 printSslErrStr("SSLSetConnection", ortn
);
407 SSLConnectionRef getConn
;
408 ortn
= SSLGetConnection(ctx
, &getConn
);
410 printSslErrStr("SSLGetConnection", ortn
);
413 if(getConn
!= (SSLConnectionRef
)sock
) {
414 printf("***SSLGetConnection error\n");
418 if(!pargs
->allowHostnameSpoof
) {
419 /* if this isn't set, it isn't checked by AppleX509TP */
420 const char *vfyHost
= pargs
->hostName
;
421 if(pargs
->vfyHostName
) {
422 /* generally means we're expecting an error */
423 vfyHost
= pargs
->vfyHostName
;
425 ortn
= SSLSetPeerDomainName(ctx
, vfyHost
, strlen(vfyHost
));
427 printSslErrStr("SSLSetPeerDomainName", ortn
);
433 * SecureTransport options.
435 if(pargs
->acceptedProts
) {
436 ortn
= SSLSetProtocolVersionEnabled(ctx
, kSSLProtocolAll
, false);
438 printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn
);
441 for(const char *cp
= pargs
->acceptedProts
; *cp
; cp
++) {
445 prot
= kSSLProtocol2
;
448 prot
= kSSLProtocol3
;
451 prot
= kTLSProtocol1
;
452 if (cp
[1] == 'l' && cp
[2] == 's' && cp
[3] == '1') {
456 prot
= kTLSProtocol11
;
458 else if (cp
[1] == '2') {
460 prot
= kTLSProtocol12
;
467 ortn
= SSLSetProtocolVersionEnabled(ctx
, prot
, true);
469 printSslErrStr("SSLSetProtocolVersionEnabled", ortn
);
475 ortn
= SSLSetProtocolVersion(ctx
, pargs
->tryVersion
);
477 printSslErrStr("SSLSetProtocolVersion", ortn
);
481 ortn
= SSLGetProtocolVersion(ctx
, &getVers
);
483 printSslErrStr("SSLGetProtocolVersion", ortn
);
486 if(getVers
!= pargs
->tryVersion
&& getVers
!= kSSLProtocolAll
) {
487 printf("***SSLGetProtocolVersion screwup: try %s get %s\n",
488 sslGetProtocolVersionString(pargs
->tryVersion
),
489 sslGetProtocolVersionString(getVers
));
494 if(pargs
->resumableEnable
) {
495 const void *rtnId
= NULL
;
498 ortn
= SSLSetPeerID(ctx
, &peerId
, sizeof(PeerSpec
));
500 printSslErrStr("SSLSetPeerID", ortn
);
503 /* quick test of the get fcn */
504 ortn
= SSLGetPeerID(ctx
, &rtnId
, &rtnIdLen
);
506 printSslErrStr("SSLGetPeerID", ortn
);
509 if((rtnId
== NULL
) || (rtnIdLen
!= sizeof(PeerSpec
))) {
510 printf("***SSLGetPeerID screwup\n");
512 else if(memcmp(&peerId
, rtnId
, rtnIdLen
) != 0) {
513 printf("***SSLGetPeerID data mismatch\n");
516 if(pargs
->allowExpired
) {
517 ortn
= SSLSetAllowsExpiredCerts(ctx
, true);
519 printSslErrStr("SSLSetAllowExpiredCerts", ortn
);
523 if(pargs
->allowExpiredRoot
) {
524 ortn
= SSLSetAllowsExpiredRoots(ctx
, true);
526 printSslErrStr("SSLSetAllowsExpiredRoots", ortn
);
530 if(pargs
->disableCertVerify
) {
531 ortn
= SSLSetEnableCertVerify(ctx
, false);
533 printSslErrStr("SSLSetEnableCertVerify", ortn
);
537 if(pargs
->allowAnyRoot
) {
538 ortn
= SSLSetAllowsAnyRoot(ctx
, true);
540 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
544 if(pargs
->cipherRestrict
!= '\0') {
545 ortn
= sslSetCipherRestrictions(ctx
, pargs
->cipherRestrict
);
550 if(pargs
->anchorFile
) {
551 ortn
= sslAddTrustedRoot(ctx
, pargs
->anchorFile
, pargs
->replaceAnchors
);
553 printf("***Error obtaining anchor file %s\n", pargs
->anchorFile
);
557 if(pargs
->trustedLeafFile
) {
558 SecCertificateRef leafCertRef
= NULL
;
559 CFMutableArrayRef leafCerts
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
560 /* sslReadAnchor is a misnomer; it just creates a SecCertificateRef from a file */
561 ortn
= sslReadAnchor(pargs
->trustedLeafFile
, &leafCertRef
);
563 CFArrayAppendValue(leafCerts
, leafCertRef
);
564 CFRelease(leafCertRef
);
565 ortn
= SSLSetTrustedLeafCertificates(ctx
, leafCerts
);
566 CFRelease(leafCerts
);
572 if(pargs
->interactiveAuth
) {
573 /* we want to get errSSLServerAuthCompleted from SSLHandshake on server auth completion */
574 SSLSetSessionOption(ctx
, kSSLSessionOptionBreakOnServerAuth
, true);
575 /* we want to get errSSLClientCertRequested from SSLHandshake on client auth request */
576 SSLSetSessionOption(ctx
, kSSLSessionOptionBreakOnCertRequested
, true);
578 else if(pargs
->clientCerts
) {
580 if(pargs
->anchorFile
== NULL
) {
581 /* assume this is a root we want to implicitly trust */
582 ortn
= addIdentityAsTrustedRoot(ctx
, pargs
->clientCerts
);
587 ortn
= SSLSetCertificate(ctx
, pargs
->clientCerts
);
589 printSslErrStr("SSLSetCertificate", ortn
);
592 /* quickie test for this new function */
593 ortn
= SSLGetCertificate(ctx
, &dummy
);
595 printSslErrStr("SSLGetCertificate", ortn
);
598 if(dummy
!= pargs
->clientCerts
) {
599 printf("***SSLGetCertificate error\n");
604 if(pargs
->encryptClientCerts
) {
605 if(pargs
->anchorFile
== NULL
) {
606 ortn
= addIdentityAsTrustedRoot(ctx
, pargs
->encryptClientCerts
);
611 ortn
= SSLSetEncryptionCertificate(ctx
, pargs
->encryptClientCerts
);
613 printSslErrStr("SSLSetEncryptionCertificate", ortn
);
617 if(pargs
->sessionCacheTimeout
) {
618 ortn
= SSLSetSessionCacheTimeout(ctx
, pargs
->sessionCacheTimeout
);
620 printSslErrStr("SSLSetSessionCacheTimeout", ortn
);
624 if(!pargs
->disableAnonCiphers
) {
625 ortn
= SSLSetAllowAnonymousCiphers(ctx
, true);
627 printSslErrStr("SSLSetAllowAnonymousCiphers", ortn
);
630 /* quickie test of the getter */
632 ortn
= SSLGetAllowAnonymousCiphers(ctx
, &e
);
634 printSslErrStr("SSLGetAllowAnonymousCiphers", ortn
);
638 printf("***SSLGetAllowAnonymousCiphers() returned false; expected true\n");
643 if(pargs
->showCipherSuites
) {
644 sslShowEnabledCipherSuites(ctx
);
646 /*** end options ***/
649 printf("...starting SSL handshake\n");
651 startHandshake
= CFAbsoluteTimeGetCurrent();
654 { ortn
= SSLHandshake(ctx
);
655 if((ortn
== errSSLWouldBlock
) && !pargs
->silent
) {
656 /* keep UI responsive */
659 else if(ortn
== errSSLServerAuthCompleted
) {
661 printf("...server authentication completed\n");
664 else if(ortn
== errSSLClientCertRequested
) {
666 printf("...received client cert request\n");
668 /* %%% could prompt interactively here for client cert to use;
669 * for now, just use the client cert passed on the command line
671 if(pargs
->clientCerts
) {
673 if(pargs
->anchorFile
== NULL
) {
674 /* assume this is a root we want to implicitly trust */
675 ortn
= addIdentityAsTrustedRoot(ctx
, pargs
->clientCerts
);
681 printf("...setting client certificate\n");
683 ortn
= SSLSetCertificate(ctx
, pargs
->clientCerts
);
685 printSslErrStr("SSLSetCertificate", ortn
);
688 /* quickie test for this new function */
689 ortn
= SSLGetCertificate(ctx
, &dummy
);
691 printSslErrStr("SSLGetCertificate", ortn
);
694 if(dummy
!= pargs
->clientCerts
) {
695 printf("***SSLGetCertificate error\n");
701 printf("***no client certificate specified!\n");
704 } while (ortn
== errSSLWouldBlock
||
705 ortn
== errSSLServerAuthCompleted
||
706 ortn
== errSSLClientCertRequested
);
708 endHandshake
= CFAbsoluteTimeGetCurrent();
709 pargs
->handshakeTimeOp
= endHandshake
- startHandshake
;
710 if(pargs
->numHandshakes
== 0) {
711 /* special case, this one is always way longer */
712 pargs
->handshakeTimeFirst
= pargs
->handshakeTimeOp
;
715 /* normal running total */
716 pargs
->handshakeTimeTotal
+= pargs
->handshakeTimeOp
;
718 pargs
->numHandshakes
++;
720 /* this works even if handshake failed due to cert chain invalid */
721 CFReleaseSafe(pargs
->peerCerts
);
722 if(!pargs
->manualCertVerify
) {
723 copyPeerCerts(ctx
, &pargs
->peerCerts
);
726 /* else fetched via SecTrust later */
727 pargs
->peerCerts
= NULL
;
730 ortn
= SSLCopyPeerTrust(ctx
, &pargs
->peerTrust
);
732 printf("***SSLCopyPeerTrust error %d\n", (int)ortn
);
733 pargs
->peerTrust
= NULL
;
737 SSLGetClientCertificateState(ctx
, &pargs
->certState
);
738 #if TARGET_OS_MAC && MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
739 SSLGetNegotiatedClientAuthType(ctx
, &pargs
->authType
);
741 SSLGetNegotiatedCipher(ctx
, &pargs
->negCipher
);
742 SSLGetNegotiatedProtocolVersion(ctx
, &pargs
->negVersion
);
743 CFReleaseSafe(pargs
->dnList
);
744 SSLCopyDistinguishedNames(ctx
, &pargs
->dnList
);
745 pargs
->sessionIDLength
= MAX_SESSION_ID_LENGTH
;
746 SSLGetResumableSessionInfo(ctx
, &pargs
->sessionWasResumed
, pargs
->sessionID
,
747 &pargs
->sessionIDLength
);
748 if(pargs
->manualCertVerify
) {
749 OSStatus certRtn
= sslEvaluateTrust(ctx
, pargs
->verbose
, pargs
->silent
,
751 if(certRtn
&& !ortn
) {
764 printf("...SSL handshake complete\n");
767 /* Write our GET request */
768 length
= strlen(pargs
->getMsg
);
769 ortn
= SSLWrite(ctx
, pargs
->getMsg
, length
, &actLen
);
771 printf("***SSLWrite error: %d\n", (int)ortn
);
772 } else if((actLen
> 0) && pargs
->dumpRxData
) {
773 dumpAscii((uint8_t*)pargs
->getMsg
, actLen
);
777 * Try to snag RCV_BUF_SIZE bytes. Exit if (!keepConnected and we get any data
778 * at all), or (keepConnected and err != (none, wouldBlock)).
780 while (ortn
== noErr
) {
782 if(pargs
->dumpRxData
) {
785 ortn
= SSLGetBufferedReadSize(ctx
, &avail
);
787 printf("***SSLGetBufferedReadSize error\n");
791 printf("\n%d bytes available: ", (int)avail
);
794 ortn
= SSLRead(ctx
, rcvBuf
, RCV_BUF_SIZE
, &actLen
);
795 if((actLen
== 0) && !pargs
->silent
) {
798 if((actLen
== 0) && (ortn
== noErr
)) {
799 printf("***Radar 2984932 confirmed***\n");
801 if (ortn
== errSSLWouldBlock
) {
802 /* for this loop, these are identical */
805 if(ortn
== errSSLServerAuthCompleted
||
806 ortn
== errSSLClientCertRequested
) {
807 /* should never get these once the handshake is complete */
808 printf("***SSLRead returned unexpected handshake error!\n");
811 if((actLen
> 0) && pargs
->dumpRxData
) {
812 dumpAscii(rcvBuf
, actLen
);
815 /* connection closed by server or by error */
818 if(!pargs
->keepConnected
&& (actLen
> 0)) {
819 /* good enough, we connected */
827 /* snag these again in case of renegotiate */
828 SSLGetClientCertificateState(ctx
, &pargs
->certState
);
829 SSLGetNegotiatedCipher(ctx
, &pargs
->negCipher
);
830 SSLGetNegotiatedProtocolVersion(ctx
, &pargs
->negVersion
);
831 CFReleaseSafe(pargs
->dnList
);
832 SSLCopyDistinguishedNames(ctx
, &pargs
->dnList
);
834 /* convert normal "shutdown" into zero err rtn */
835 if(ortn
== errSSLClosedGraceful
) {
838 if((ortn
== errSSLClosedNoNotify
) && !pargs
->requireNotify
) {
839 /* relaxed disconnect rules */
844 * always do close, even on error - to flush outgoing write queue
846 OSStatus cerr
= SSLClose(ctx
);
851 endpointShutdown(sock
);
854 SSLDisposeContext(ctx
);
859 static void add_key(const void *key
, const void *value
, void *context
) {
860 CFArrayAppendValue((CFMutableArrayRef
)context
, key
);
863 static void showInfo(CFDictionaryRef info
) {
864 CFIndex dict_count
, key_ix
, key_count
;
865 CFMutableArrayRef keys
= NULL
;
866 CFIndex maxWidth
= 20; /* Maybe precompute this or grab from context? */
868 dict_count
= CFDictionaryGetCount(info
);
869 keys
= CFArrayCreateMutable(kCFAllocatorDefault
, dict_count
,
870 &kCFTypeArrayCallBacks
);
871 CFDictionaryApplyFunction(info
, add_key
, keys
);
872 key_count
= CFArrayGetCount(keys
);
873 CFArraySortValues(keys
, CFRangeMake(0, key_count
),
874 (CFComparatorFunction
)CFStringCompare
, 0);
876 for (key_ix
= 0; key_ix
< key_count
; ++key_ix
) {
877 CFStringRef key
= (CFStringRef
)CFArrayGetValueAtIndex(keys
, key_ix
);
878 CFTypeRef value
= CFDictionaryGetValue(info
, key
);
879 CFMutableStringRef line
= CFStringCreateMutable(NULL
, 0);
881 CFStringAppend(line
, key
);
883 for (jx
= CFStringGetLength(key
);
884 jx
< maxWidth
; ++jx
) {
885 CFStringAppend(line
, CFSTR(" "));
887 CFStringAppend(line
, CFSTR(" : "));
888 if (CFStringGetTypeID() == CFGetTypeID(value
)) {
889 CFStringAppend(line
, (CFStringRef
)value
);
890 } else if (CFDateGetTypeID() == CFGetTypeID(value
)) {
891 CFLocaleRef lc
= CFLocaleCopyCurrent();
892 CFDateFormatterRef df
= CFDateFormatterCreate(NULL
, lc
,
893 kCFDateFormatterFullStyle
, kCFDateFormatterFullStyle
);
894 CFDateRef date
= (CFDateRef
)value
;
895 CFStringRef ds
= CFDateFormatterCreateStringWithDate(NULL
, df
,
897 CFStringAppend(line
, ds
);
901 } else if (CFURLGetTypeID() == CFGetTypeID(value
)) {
902 CFURLRef url
= (CFURLRef
)value
;
903 CFStringAppend(line
, CFSTR("<"));
904 CFStringAppend(line
, CFURLGetString(url
));
905 CFStringAppend(line
, CFSTR(">"));
906 } else if (CFDataGetTypeID() == CFGetTypeID(value
)) {
907 CFDataRef v_d
= (CFDataRef
)value
;
908 CFStringRef v_s
= CFStringCreateFromExternalRepresentation(
909 kCFAllocatorDefault
, v_d
, kCFStringEncodingUTF8
);
911 CFStringAppend(line
, CFSTR("/"));
912 CFStringAppend(line
, v_s
);
913 CFStringAppend(line
, CFSTR("/ "));
916 const uint8_t *bytes
= CFDataGetBytePtr(v_d
);
917 CFIndex len
= CFDataGetLength(v_d
);
918 for (jx
= 0; jx
< len
; ++jx
) {
919 CFStringAppendFormat(line
, NULL
, CFSTR("%.02X"), bytes
[jx
]);
922 CFStringAppendFormat(line
, NULL
, CFSTR("%@"), value
);
930 static void showPeerTrust(SecTrustRef peerTrust
, bool verbose
) {
934 if(peerTrust
== NULL
) {
937 #if TARGET_OS_EMBEDDED
938 printf("\n=============== Peer Trust Properties ===============\n");
939 CFArrayRef plist
= SecTrustCopyProperties(peerTrust
);
945 printf("\n================== Peer Trust Info ==================\n");
946 CFDictionaryRef info
= SecTrustCopyInfo(peerTrust
);
947 if (info
&& CFDictionaryGetCount(info
)) {
952 numCerts
= SecTrustGetCertificateCount(peerTrust
);
953 for(i
=0; i
<numCerts
; i
++) {
954 plist
= SecTrustCopySummaryPropertiesAtIndex(peerTrust
, i
);
955 printf("\n============= Peer Trust Cert %lu Summary =============\n\n", i
);
959 printf("\n============= Peer Trust Cert %lu Details =============\n\n", i
);
960 plist
= SecTrustCopyDetailedPropertiesAtIndex(peerTrust
, i
);
964 printf("\n============= End of Peer Trust Cert %lu ==============\n", i
);
969 static void showPeerCerts(
970 CFArrayRef peerCerts
,
974 SecCertificateRef certRef
;
977 if(peerCerts
== NULL
) {
980 numCerts
= CFArrayGetCount(peerCerts
);
981 for(i
=0; i
<numCerts
; i
++) {
982 certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
);
983 printf("\n==================== Peer Cert %lu ====================\n\n", i
);
984 print_cert(certRef
, verbose
);
985 printf("\n================ End of Peer Cert %lu =================\n", i
);
989 static void writePeerCerts(
990 CFArrayRef peerCerts
,
991 const char *fileBase
)
994 SecCertificateRef certRef
;
998 if(peerCerts
== NULL
) {
1001 numCerts
= CFArrayGetCount(peerCerts
);
1002 for(i
=0; i
<numCerts
; i
++) {
1003 sprintf(fileName
, "%s%02d.cer", fileBase
, (int)i
);
1004 certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
);
1005 CFDataRef derCert
= SecCertificateCopyData(certRef
);
1007 writeFile(fileName
, CFDataGetBytePtr(derCert
),
1008 CFDataGetLength(derCert
));
1012 printf("...wrote %lu certs to fileBase %s\n", numCerts
, fileBase
);
1015 static void writeDnList(
1017 const char *fileBase
)
1024 if(dnList
== NULL
) {
1027 numDns
= CFArrayGetCount(dnList
);
1028 for(i
=0; i
<numDns
; i
++) {
1029 sprintf(fileName
, "%s%02d.der", fileBase
, (int)i
);
1030 cfDn
= (CFDataRef
)CFArrayGetValueAtIndex(dnList
, i
);
1031 writeFile(fileName
, CFDataGetBytePtr(cfDn
), CFDataGetLength(cfDn
));
1033 printf("...wrote %lu RDNs to fileBase %s\n", numDns
, fileBase
);
1037 * Show result of an sslPing().
1038 * Assumes the following from sslPingArgs:
1053 static void showSSLResult(
1054 const sslPingArgs
&pargs
,
1056 int displayPeerCerts
,
1057 const char *fileBase
, // non-NULL: write certs to file
1058 const char *dnFileBase
) // non-NULL: write DNList to file
1060 CFIndex numPeerCerts
;
1064 if(pargs
.acceptedProts
) {
1065 printf(" Allowed SSL versions : %s\n", pargs
.acceptedProts
);
1068 printf(" Attempted SSL version : %s\n",
1069 sslGetProtocolVersionString(pargs
.tryVersion
));
1072 printf(" Result : %s\n", sslGetSSLErrString(err
));
1073 printf(" Negotiated SSL version : %s\n",
1074 sslGetProtocolVersionString(pargs
.negVersion
));
1075 printf(" Negotiated CipherSuite : %s\n",
1076 sslGetCipherSuiteString(pargs
.negCipher
));
1077 if(pargs
.certState
!= kSSLClientCertNone
) {
1078 printf(" Client Cert State : %s\n",
1079 sslGetClientCertStateString(pargs
.certState
));
1080 #if TARGET_OS_MAC && MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
1081 printf(" Client Auth Type : %s\n",
1082 sslGetClientAuthTypeString(pargs
.authType
));
1086 printf(" Resumed Session : ");
1087 if(pargs
.sessionWasResumed
) {
1088 for(unsigned dex
=0; dex
<pargs
.sessionIDLength
; dex
++) {
1089 printf("%02X ", pargs
.sessionID
[dex
]);
1090 if(((dex
% 8) == 7) && (dex
!= (pargs
.sessionIDLength
- 1))) {
1097 printf("NOT RESUMED\n");
1099 printf(" Handshake time : %f seconds\n", pargs
.handshakeTimeOp
);
1101 if(pargs
.peerCerts
== NULL
) {
1105 numPeerCerts
= CFArrayGetCount(pargs
.peerCerts
);
1107 printf(" Number of peer certs : %lu\n", numPeerCerts
);
1108 if(numPeerCerts
!= 0) {
1109 if (displayPeerCerts
== 1) {
1110 showPeerCerts(pargs
.peerCerts
, false);
1111 } else if (displayPeerCerts
== 2) {
1112 showPeerTrust(pargs
.peerTrust
, false);
1114 if(fileBase
!= NULL
) {
1115 writePeerCerts(pargs
.peerCerts
, fileBase
);
1118 if(dnFileBase
!= NULL
) {
1119 writeDnList(pargs
.dnList
, dnFileBase
);
1125 static int verifyProtocol(
1127 SSLProtocol maxProtocol
,
1128 SSLProtocol reqProtocol
,
1129 SSLProtocol negProtocol
)
1134 if(reqProtocol
> maxProtocol
) {
1135 /* known not to support this attempt, relax */
1136 reqProtocol
= maxProtocol
;
1138 if(reqProtocol
!= negProtocol
) {
1139 printf("***Expected protocol %s; negotiated %s\n",
1140 sslGetProtocolVersionString(reqProtocol
),
1141 sslGetProtocolVersionString(negProtocol
));
1149 static int verifyClientCertState(
1150 bool verifyCertState
,
1151 SSLClientCertificateState expectState
,
1152 SSLClientCertificateState gotState
)
1154 if(!verifyCertState
) {
1157 if(expectState
== gotState
) {
1160 printf("***Expected clientCertState %s; got %s\n",
1161 sslGetClientCertStateString(expectState
),
1162 sslGetClientCertStateString(gotState
));
1167 * Free everything allocated by sslPing in an sslPingArgs.
1168 * Mainly for looping and malloc debugging.
1170 static void freePingArgs(
1173 CFReleaseNull(pargs
->peerCerts
);
1174 CFReleaseNull(pargs
->peerTrust
);
1175 CFReleaseNull(pargs
->dnList
);
1176 /* more, later, for client retry/identity fetch */
1179 static SSLProtocol
strToProt(
1180 const char *c
, // 2, 3, t, tls10, tls11, tls12
1184 return kSSLProtocolUnknown
;
1188 return kSSLProtocol2
;
1190 return kSSLProtocol3
;
1193 return kTLSProtocol1
;
1194 if (c
[1] == 'l' && c
[2] == 's' && c
[3] == '1') {
1196 return kTLSProtocol1
;
1198 return kTLSProtocol11
;
1200 return kTLSProtocol12
;
1206 return kSSLProtocolUnknown
;
1209 int main(int argc
, char **argv
)
1215 char fullFileBase
[100];
1216 int ourRtn
= 0; // exit status - sum of all errors
1218 SecKeychainRef serverKc
= nil
;
1219 SecKeychainRef encryptKc
= nil
;
1222 /* user-spec'd parameters */
1223 char *getPath
= (char *)DEFAULT_PATH
;
1224 char *fileBase
= NULL
;
1225 bool displayCerts
= false;
1226 bool doSslV2
= false;
1227 bool doSslV3
= false;
1228 bool doTlsV1
= true;
1229 bool doTlsV11
= true;
1230 bool doTlsV12
= true;
1231 bool protXOnly
= false; // kSSLProtocol3Only, kTLSProtocol1Only
1232 bool doProtUnknown
= false;
1233 unsigned loopCount
= 1;
1234 bool doPause
= false;
1235 bool pauseFirstLoop
= false;
1236 bool verifyProt
= false;
1237 SSLProtocol maxProtocol
= kTLSProtocol12
; // for verifying negotiated
1239 char *acceptedProts
= NULL
;
1240 char *keyChainName
= NULL
;
1241 char *encryptKeyChainName
= NULL
;
1242 char *getMsgSpec
= NULL
;
1243 bool vfyCertState
= false;
1244 SSLClientCertificateState expectCertState
= kSSLClientCertNone
;
1245 bool displayHandshakeTimes
= false;
1246 bool completeCertChain
= false;
1247 char *dnFileBase
= NULL
;
1249 /* special case - one arg of "h" or "-h" or "hv" */
1251 if((strcmp(argv
[1], "h") == 0) || (strcmp(argv
[1], "-h") == 0)) {
1254 if(strcmp(argv
[1], "hv") == 0) {
1259 /* set up defaults */
1260 memset(&pargs
, 0, sizeof(sslPingArgs
));
1261 pargs
.hostName
= DEFAULT_HOST
;
1262 pargs
.port
= DEFAULT_PORT
;
1263 pargs
.resumableEnable
= true;
1266 for(arg
=1; arg
<argc
; arg
++) {
1269 /* first arg, is always hostname; '-' means default */
1270 if(argp
[0] != '-') {
1271 pargs
.hostName
= argp
;
1275 if(argp
[0] == '/') {
1276 /* path always starts with leading slash */
1283 pargs
.allowExpired
= true;
1286 pargs
.allowExpiredRoot
= true;
1289 pargs
.disableCertVerify
= true;
1292 pargs
.disableCertVerify
= true; // implied
1293 pargs
.manualCertVerify
= true;
1296 pargs
.interactiveAuth
= true;
1300 /* requires another arg */
1303 pargs
.anchorFile
= argv
[arg
];
1307 /* requires another arg */
1310 pargs
.anchorFile
= argv
[arg
];
1311 pargs
.replaceAnchors
= true;
1315 /* requires another arg */
1318 pargs
.trustedLeafFile
= argv
[arg
];
1321 pargs
.allowAnyRoot
= true;
1324 pargs
.dumpRxData
= true;
1333 /* requires another arg */
1336 fileBase
= argv
[arg
];
1339 pargs
.cipherRestrict
= argp
[2];
1342 pargs
.showCipherSuites
= true;
1345 doSslV3
= doTlsV1
= doTlsV11
= false;
1349 doSslV2
= doTlsV1
= doTlsV11
= doTlsV12
= false;
1353 if (argp
[1] == 'l' && argp
[2] == 's' && argp
[3] == '1') {
1354 if (argp
[4] == '0') {
1355 doSslV2
= doSslV3
= doTlsV11
= doTlsV12
= false;
1359 if (argp
[4] == '1') {
1360 doSslV2
= doSslV3
= doTlsV1
= doTlsV12
= false;
1364 else if (argp
[4] == '2') {
1365 doSslV2
= doSslV3
= doTlsV1
= doTlsV11
= false;
1370 if (argp
[1] != '\0') {
1373 doSslV2
= doSslV3
= doTlsV11
= doTlsV12
= false;
1377 doSslV2
= doSslV3
= doTlsV1
= doTlsV11
= doTlsV12
= true;
1383 doSslV2
= doSslV3
= doTlsV1
= doTlsV11
= doTlsV12
= false;
1384 doProtUnknown
= true;
1387 pargs
.keepConnected
= true;
1390 pargs
.requireNotify
= true;
1391 pargs
.keepConnected
= true;
1394 pargs
.resumableEnable
= false;
1397 pargs
.nonBlocking
= true;
1403 if(argp
[1] != '=') {
1406 verifyProt
= true; // implied
1407 maxProtocol
= strToProt(&argp
[2], argv
);
1410 if(argp
[1] != '=') {
1413 acceptedProts
= &argp
[2];
1414 doSslV3
= doSslV2
= doTlsV1
= doTlsV11
= doTlsV12
= false;
1417 loopCount
= atoi(&argp
[2]);
1418 if(loopCount
== 0) {
1419 printf("***bad loopCount\n");
1424 pargs
.port
= atoi(&argp
[2]);
1427 pargs
.allowHostnameSpoof
= true;
1430 pargs
.vfyHostName
= &argp
[2];
1433 keyChainName
= &argp
[2];
1436 encryptKeyChainName
= &argp
[2];
1439 getMsgSpec
= &argp
[2];
1442 if(argp
[1] != '=') {
1445 vfyCertState
= true;
1448 expectCertState
= kSSLClientCertNone
;
1451 expectCertState
= kSSLClientCertRequested
;
1454 expectCertState
= kSSLClientCertSent
;
1457 expectCertState
= kSSLClientCertRejected
;
1464 pargs
.password
= &argp
[2];
1470 pauseFirstLoop
= true;
1476 pargs
.verbose
= true;
1479 pargs
.silent
= pargs
.quiet
= true;
1482 displayHandshakeTimes
= true;
1485 completeCertChain
= true;
1488 pargs
.sessionCacheTimeout
= atoi(&argp
[2]);
1491 pargs
.disableAnonCiphers
= true;
1495 /* requires another arg */
1498 dnFileBase
= argv
[arg
];
1501 if(pargs
.verbose
|| (argp
[1] == 'v')) {
1512 pargs
.getMsg
= getMsgSpec
;
1515 sprintf(getMsg
, "%s %s %s",
1516 DEFAULT_GETMSG
, getPath
, DEFAULT_GET_SUFFIX
);
1517 pargs
.getMsg
= getMsg
;
1526 /* get client cert and optional encryption cert as CFArrayRef */
1528 pargs
.clientCerts
= getSslCerts(keyChainName
, false, completeCertChain
,
1529 pargs
.anchorFile
, &serverKc
);
1530 if(pargs
.clientCerts
== nil
) {
1533 #ifdef USE_CDSA_CRYPTO
1534 if(pargs
.password
) {
1535 OSStatus ortn
= SecKeychainUnlock(serverKc
,
1536 strlen(pargs
.password
), pargs
.password
, true);
1538 printf("SecKeychainUnlock returned %d\n", (int)ortn
);
1544 if(encryptKeyChainName
) {
1545 pargs
.encryptClientCerts
= getSslCerts(encryptKeyChainName
, true,
1546 completeCertChain
, pargs
.anchorFile
, &encryptKc
);
1547 if(pargs
.encryptClientCerts
== nil
) {
1551 signal(SIGPIPE
, sigpipe
);
1553 for(loop
=0; loop
<loopCount
; loop
++) {
1555 * One pass for each protocol version, skipping any explicit version if
1556 * an attempt at a higher version and succeeded in doing so successfully fell
1560 pargs
.tryVersion
= kTLSProtocol12
;
1561 pargs
.acceptedProts
= NULL
;
1563 printf("Connecting to host %s with TLS V1.2\n", pargs
.hostName
);
1566 err
= sslPing(&pargs
);
1572 sprintf(fullFileBase
, "%s_v3.1", fileBase
);
1574 showSSLResult(pargs
,
1577 fileBase
? fullFileBase
: NULL
,
1580 freePingArgs(&pargs
);
1582 /* deal with fallbacks, skipping redundant tests */
1583 switch(pargs
.negVersion
) {
1584 case kTLSProtocol11
:
1605 ourRtn
+= verifyProtocol(verifyProt
, maxProtocol
, kTLSProtocol12
,
1608 /* note we do this regardless since the client state might be
1609 * the cause of a failure */
1610 ourRtn
+= verifyClientCertState(vfyCertState
, expectCertState
,
1614 pargs
.tryVersion
= kTLSProtocol11
;
1615 pargs
.acceptedProts
= NULL
;
1617 printf("Connecting to host %s with TLS V1.1\n", pargs
.hostName
);
1620 err
= sslPing(&pargs
);
1626 sprintf(fullFileBase
, "%s_v3.1", fileBase
);
1628 showSSLResult(pargs
,
1631 fileBase
? fullFileBase
: NULL
,
1634 freePingArgs(&pargs
);
1636 /* deal with fallbacks, skipping redundant tests */
1637 switch(pargs
.negVersion
) {
1653 ourRtn
+= verifyProtocol(verifyProt
, maxProtocol
, kTLSProtocol11
,
1656 /* note we do this regardless since the client state might be
1657 * the cause of a failure */
1658 ourRtn
+= verifyClientCertState(vfyCertState
, expectCertState
,
1663 protXOnly
? kTLSProtocol1Only
: kTLSProtocol1
;
1664 pargs
.acceptedProts
= NULL
;
1666 printf("Connecting to host %s with TLS V1.0\n", pargs
.hostName
);
1669 err
= sslPing(&pargs
);
1675 sprintf(fullFileBase
, "%s_v3.1", fileBase
);
1677 showSSLResult(pargs
,
1680 fileBase
? fullFileBase
: NULL
,
1683 freePingArgs(&pargs
);
1685 /* deal with fallbacks, skipping redundant tests */
1686 switch(pargs
.negVersion
) {
1697 ourRtn
+= verifyProtocol(verifyProt
, maxProtocol
, kTLSProtocol1
,
1700 /* note we do this regardless since the client state might be
1701 * the cause of a failure */
1702 ourRtn
+= verifyClientCertState(vfyCertState
, expectCertState
,
1706 pargs
.tryVersion
= protXOnly
? kSSLProtocol3Only
: kSSLProtocol3
;
1707 pargs
.acceptedProts
= NULL
;
1709 printf("Connecting to host %s with SSL V3\n", pargs
.hostName
);
1712 err
= sslPing(&pargs
);
1718 sprintf(fullFileBase
, "%s_v3.0", fileBase
);
1720 showSSLResult(pargs
,
1723 fileBase
? fullFileBase
: NULL
,
1726 freePingArgs(&pargs
);
1728 /* deal with fallbacks, skipping redundant tests */
1729 switch(pargs
.negVersion
) {
1736 ourRtn
+= verifyProtocol(verifyProt
, maxProtocol
, kSSLProtocol3
,
1739 /* note we do this regardless since the client state might be
1740 * the cause of a failure */
1741 ourRtn
+= verifyClientCertState(vfyCertState
, expectCertState
,
1747 sprintf(fullFileBase
, "%s_v2", fileBase
);
1750 printf("Connecting to host %s with SSL V2\n", pargs
.hostName
);
1753 pargs
.tryVersion
= kSSLProtocol2
;
1754 pargs
.acceptedProts
= NULL
;
1755 err
= sslPing(&pargs
);
1761 sprintf(fullFileBase
, "%s_v2", fileBase
);
1763 showSSLResult(pargs
,
1766 fileBase
? fullFileBase
: NULL
,
1769 freePingArgs(&pargs
);
1771 ourRtn
+= verifyProtocol(verifyProt
, maxProtocol
, kSSLProtocol2
,
1774 /* note we do this regardless since the client state might be
1775 * the cause of a failure */
1776 ourRtn
+= verifyClientCertState(vfyCertState
, expectCertState
,
1781 printf("Connecting to host %s with kSSLProtocolUnknown\n",
1785 pargs
.tryVersion
= kSSLProtocolUnknown
;
1786 pargs
.acceptedProts
= NULL
;
1787 err
= sslPing(&pargs
);
1793 sprintf(fullFileBase
, "%s_def", fileBase
);
1795 showSSLResult(pargs
,
1798 fileBase
? fullFileBase
: NULL
,
1801 freePingArgs(&pargs
);
1803 if(acceptedProts
!= NULL
) {
1804 pargs
.acceptedProts
= acceptedProts
;
1805 pargs
.tryVersion
= kSSLProtocolUnknown
; // not used
1807 printf("Connecting to host %s with acceptedProts %s\n",
1808 pargs
.hostName
, pargs
.acceptedProts
);
1811 err
= sslPing(&pargs
);
1817 sprintf(fullFileBase
, "%s_def", fileBase
);
1819 showSSLResult(pargs
,
1822 fileBase
? fullFileBase
: NULL
,
1825 freePingArgs(&pargs
);
1829 /* pause after first, before last to grab trace */
1830 ((loop
== 0) || (loop
== loopCount
- 1))
1835 printf("a to abort, c to continue: ");
1842 if(displayHandshakeTimes
) {
1843 CFAbsoluteTime totalTime
;
1844 unsigned numHandshakes
;
1845 if(pargs
.numHandshakes
== 1) {
1846 /* just display the first one */
1847 totalTime
= pargs
.handshakeTimeFirst
;
1851 /* skip the first one */
1852 totalTime
= pargs
.handshakeTimeTotal
;
1853 numHandshakes
= pargs
.numHandshakes
- 1;
1855 if(numHandshakes
!= 0) {
1856 printf(" %u handshakes in %f seconds; %f seconds per handshake\n",
1857 numHandshakes
, totalTime
,
1858 (totalTime
/ numHandshakes
));
1861 //printCertShutdown();
1863 printf("===%s exiting with %d %s for host %s\n", argv
[0], ourRtn
,
1864 (ourRtn
> 1) ? "errors" : "error", pargs
.hostName
);