2  * Copyright (c) 2006-2013, 2015 Apple Inc. All Rights Reserved. 
   7 #include <CoreFoundation/CoreFoundation.h> 
   8 #include <Security/Security.h> 
   9 #include <Security/SecureTransport.h> 
  10 #include <Security/SecureTransportPriv.h> 
  11 #include <Security/SecTrustPriv.h> 
  12 #include <Security/SecPolicyPriv.h> 
  21 #include "sslAppUtils.h" 
  23 #include "utilities/fileIo.h" 
  24 #include "utilities/SecCFWrappers.h" 
  25 #include "utilities/SecIOFormat.h" 
  26 #include "SecurityTool/sharedTool/print_cert.h" 
  28 #define DEFAULT_GETMSG          "GET" 
  29 #define DEFAULT_PATH            "/" 
  30 #define DEFAULT_GET_SUFFIX      "HTTP/1.0\r\n\r\n" 
  32 #define DEFAULT_HOST            "www.amazon.com" 
  33 #define DEFAULT_PORT            443 
  35 static const int _maxFileStringSize 
= 100; 
  37 static void usageNorm(char **argv
) 
  39     printf("Usage: %s [hostname|-] [path] [option ...]\n", argv
[0]); 
  40     printf("       %s hostname [path] [option ...]\n", argv
[0]); 
  41         printf("Specifying '-' for hostname, or no args, uses default of %s.\n", 
  43         printf("Optional path argument must start with leading '/'.\n"); 
  45     printf("   e           Allow Expired Certs\n"); 
  46     printf("   E           Allow Expired Roots\n"); 
  47     printf("   r           Allow any root cert\n"); 
  48         printf("   c           Display peer certs\n"); 
  49         printf("   c c         Display peer SecTrust\n"); 
  50         printf("   d           Display received data\n"); 
  51         printf("   2           SSLv2 only (default is TLSv1)\n"); 
  52         printf("   3           SSLv3 only (default is TLSv1)\n"); 
  54     printf("   %%           TLSv1.1 only\n"); 
  55     printf("   ^           TLSv1.2 only\n"); 
  56         printf("   L           all - TLSv1.2, TLSv1.1, TLSv1.0, SSLv3, SSLv2 (default = TLSv1.2)\n"); 
  57         printf("   g={prot...} Specify legal protocols; prot = any combo of" 
  59         printf("   k=keychain  Contains cert and keys. Optional.\n"); 
  60         printf("   l=loopCount Perform loopCount ops (default = 1)\n"); 
  61         printf("   P=port      Default = %d\n", DEFAULT_PORT
); 
  62         printf("   p           Pause after each loop\n"); 
  63         printf("   q           Quiet/diagnostic mode (site names and errors only)\n"); 
  64     printf("   a fileName  Add fileName to list of trusted roots\n"); 
  65         printf("   A fileName  fileName is ONLY trusted root\n"); 
  66         printf("   x           Disable Cert Verification\n"); 
  67     printf("   Z string    ALPN setting\n"); 
  68         printf("   z=password  Unlock client keychain with password.\n"); 
  69         printf("   8           Complete cert chains (default is out cert is a root)\n"); 
  70         printf("   s           Silent\n"); 
  71         printf("   V           Verbose\n"); 
  73         printf("   hv          More, verbose help\n"); 
  76 static void usageVerbose(char **argv
) __attribute__((noreturn
)); 
  77 static void usageVerbose(char **argv
) 
  80         printf("Obscure Usage:\n"); 
  81         printf("   u           kSSLProtocolUnknown only (TLSv1)\n"); 
  82         printf("   M           Manual cert verification via " 
  83                                                         "SecTrustEvaluate\n"); 
  84         printf("   f fileBase  Write Peer Certs to fileBase*\n"); 
  85         printf("   o           TLSv1, SSLv3 use kSSLProtocol__X__Only\n"); 
  86         printf("   C=cipherSuite (e=40-bit d=DES D=40-bit DES 3=3DES 4=RC4 " 
  88                    "                  2=RC2 a=AES128 A=AES256 h=DH H=Anon DH r=DHE/RSA s=DH/DSS\n"); 
  89         printf("   y=keychain  Encryption-only cert and keys. Optional.\n"); 
  90         printf("   K           Keep connected until server disconnects\n"); 
  91         printf("   n           Require closure notify message in TLSv1, " 
  92                                                                 "SSLv3 mode (implies K)\n"); 
  93         printf("   R           Disable resumable session support\n"); 
  94         printf("   b           Non-blocking I/O\n"); 
  95         printf("   v           Verify negotiated protocol equals attempted\n"); 
  96         printf("   m=[23t]     Max protocol supported as specified; implies " 
  98         printf("   T=[nrsj]    Verify client cert state = " 
  99                                                                 "none/requested/sent/rejected\n"); 
 100         printf("   H           allow hostname spoofing\n"); 
 101         printf("   F=vfyHost   Verify certs with specified host name\n"); 
 102         printf("   G=getMsg    Specify entire GET, POST, etc.\n"); 
 103         printf("   N           Log handshake timing\n"); 
 104         printf("   7           Pause only after first loop\n"); 
 108 static void usage(char **argv
) __attribute__((noreturn
)); 
 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
; 
 145         CFArrayRef                              clientCerts
;            // optional 
 146         bool                            quiet
;                          // minimal stdout 
 147         bool                            silent
;                         // no stdout 
 149         SSLProtocol                             negVersion
;                     // RETURNED 
 150         SSLCipherSuite                  negCipher
;                      // RETURNED 
 151         CFArrayRef                              peerCerts
;                      // mallocd & RETURNED 
 152         SecTrustRef                             peerTrust
;                      // RETURNED 
 153         SSLClientCertificateState certState
;            // RETURNED 
 154         char                                    *password
;                      // optional to open clientCerts 
 156         Boolean                                 sessionWasResumed
; 
 157         unsigned char                   sessionID
[MAX_SESSION_ID_LENGTH
]; 
 158         size_t                                  sessionIDLength
; 
 159         CFAbsoluteTime                  handshakeTimeOp
;                // time for this op 
 160         CFAbsoluteTime                  handshakeTimeFirst
;             // time for FIRST op, not averaged 
 161         CFAbsoluteTime                  handshakeTimeTotal
;             // time for all ops except first 
 162         unsigned                                numHandshakes
; 
 164     CFMutableArrayRef       alpnNames
; 
 165     CFMutableArrayRef       policies
; 
 173         printf("***SIGPIPE***\n"); 
 177  * Manually evaluate session's SecTrustRef. 
 180 static OSStatus 
sslEvaluateTrust( 
 183         CFArrayRef 
*peerCerts
)          // fetched and retained 
 185         OSStatus ortn 
= errSecSuccess
; 
 186         SecTrustRef secTrust 
= NULL
; 
 188         ortn 
= SSLGetPeerSecTrust(ctx
, &secTrust
); 
 190                 printf("\n***Error obtaining peer SecTrustRef: %s\n", 
 191                         sslGetSSLErrString(ortn
)); 
 194         if(secTrust 
== NULL
) { 
 195                 /* this is the normal case for resumed sessions, in which 
 196                  * no cert evaluation is performed */ 
 198                         printf("...No SecTrust available - this is a resumed session, right?\n"); 
 200                 return errSecSuccess
; 
 204     if (pargs
->policies
) { 
 205         SecTrustSetPolicies(secTrust
, pargs
->policies
); 
 208         SecTrustResultType      secTrustResult
; 
 209         ortn 
= SecTrustGetTrustResult(secTrust
, &secTrustResult
); // implicitly does trust evaluate 
 211                 printf("\n***Error on SecTrustEvaluate: %d\n", (int)ortn
); 
 215                 const char *res 
= NULL
; 
 216                 switch(secTrustResult
) { 
 217                         case kSecTrustResultInvalid
: 
 218                                 res 
= "kSecTrustResultInvalid"; break; 
 219                         case kSecTrustResultProceed
: 
 220                                 res 
= "kSecTrustResultProceed"; break; 
 221                         case kSecTrustResultDeny
: 
 222                                 res 
= "kSecTrustResultDeny"; break; 
 223                         case kSecTrustResultUnspecified
: 
 224                                 res 
= "kSecTrustResultUnspecified"; break; 
 225                         case kSecTrustResultRecoverableTrustFailure
: 
 226                                 res 
= "kSecTrustResultRecoverableTrustFailure"; break; 
 227                         case kSecTrustResultFatalTrustFailure
: 
 228                                 res 
= "kSecTrustResultFatalTrustFailure"; break; 
 229                         case kSecTrustResultOtherError
: 
 230                                 res 
= "kSecTrustResultOtherError"; break; 
 232                                 res 
= "UNKNOWN"; break; 
 234                 printf("\nSecTrustEvaluate(): secTrustResult %s\n", res
); 
 237         switch(secTrustResult
) { 
 238                 case kSecTrustResultUnspecified
: 
 239                         /* cert chain valid, no special UserTrust assignments */ 
 240                 case kSecTrustResultProceed
: 
 241                         /* cert chain valid AND user explicitly trusts this */ 
 244                         printf("\n***SecTrustEvaluate reported secTrustResult %d\n", 
 245                                 (int)secTrustResult
); 
 246                         ortn 
= errSSLXCertChainInvalid
; 
 252 #ifdef USE_CDSA_CRYPTO 
 253         /* one more thing - get peer certs in the form of an evidence chain */ 
 254         CSSM_TP_APPLE_EVIDENCE_INFO 
*dummyEv
; 
 255         OSStatus thisRtn 
= SecTrustGetResult(secTrust
, &secTrustResult
, 
 256                 peerCerts
, &dummyEv
); 
 258                 printSslErrStr("SecTrustGetResult", thisRtn
); 
 261                 /* workaround for the fact that SSLGetPeerCertificates() 
 262                  * leaves a retain count on each element in the returned array, 
 263                  * requiring us to do a release on each cert. 
 265                 CFIndex numCerts 
= CFArrayGetCount(*peerCerts
); 
 266                 for(CFIndex dex
=0; dex
<numCerts
; dex
++) { 
 267                         CFRetain(CFArrayGetValueAtIndex(*peerCerts
, dex
)); 
 274 /* print reply received from server, safely */ 
 275 static void dumpAscii( 
 279         char *cp 
= (char *)rcvBuf
; 
 283         for(i
=0; i
<len
; i
++) { 
 296                                 if(isprint(c
) && (c 
!= '\n')) { 
 300                                         printf("<%02X>", ((unsigned)c
) & 0xff); 
 310 alpnFunc(SSLContextRef          ctx
, 
 312          const void                         *alpnData
, 
 313          size_t                  alpnDataLength
) 
 315     printf("[selected ALPN]"); 
 318 #pragma clang diagnostic push 
 319 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
 322  * Perform one SSL diagnostic session. Returns nonzero on error. Normally no 
 323  * output to stdout except initial "connecting to" message, unless there 
 324  * is a really screwed up error (i.e., something not directly related 
 325  * to the SSL connection). 
 327 #define RCV_BUF_SIZE            256 
 329 static OSStatus 
sslPing( 
 335     SSLContextRef       ctx 
= NULL
; 
 338     uint8_t             rcvBuf
[RCV_BUF_SIZE
]; 
 339         CFAbsoluteTime          startHandshake
; 
 340         CFAbsoluteTime          endHandshake
; 
 342     pargs
->negVersion 
= kSSLProtocolUnknown
; 
 343     pargs
->negCipher 
= SSL_NULL_WITH_NULL_NULL
; 
 344     pargs
->peerCerts 
= NULL
; 
 346         /* first make sure requested server is there */ 
 347         ortn 
= MakeServerConnection(pargs
->hostName
, pargs
->port
, pargs
->nonBlocking
, 
 350         printf("MakeServerConnection returned %d; aborting\n", (int)ortn
); 
 354                 printf("...connected to server; starting SecureTransport\n"); 
 358          * Set up a SecureTransport session. 
 359          * First the standard calls. 
 361     ctx 
= SSLCreateContext(kCFAllocatorDefault
, kSSLClientSide
, kSSLStreamType
); 
 363                 printf("SSLCreateContext\n"); 
 366         ortn 
= SSLSetIOFuncs(ctx
, SocketRead
, SocketWrite
); 
 368                 printSslErrStr("SSLSetIOFuncs", ortn
); 
 371         ortn 
= SSLSetConnection(ctx
, (SSLConnectionRef
)(intptr_t)sock
); 
 373                 printSslErrStr("SSLSetConnection", ortn
); 
 376         SSLConnectionRef getConn
; 
 377         ortn 
= SSLGetConnection(ctx
, &getConn
); 
 379                 printSslErrStr("SSLGetConnection", ortn
); 
 382         if(getConn 
!= (SSLConnectionRef
)(intptr_t)sock
) { 
 383                 printf("***SSLGetConnection error\n"); 
 387         if(!pargs
->allowHostnameSpoof
) { 
 388                 /* if this isn't set, it isn't checked by AppleX509TP */ 
 389                 const char *vfyHost 
= pargs
->hostName
; 
 390                 if(pargs
->vfyHostName
) { 
 391                         /* generally means we're expecting an error */ 
 392                         vfyHost 
= pargs
->vfyHostName
; 
 394                 ortn 
= SSLSetPeerDomainName(ctx
, vfyHost
, strlen(vfyHost
)); 
 396                         printSslErrStr("SSLSetPeerDomainName", ortn
); 
 402          * SecureTransport options. 
 404         if(pargs
->acceptedProts
) { 
 406                         printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn
); 
 409                 for(const char *cp 
= pargs
->acceptedProts
; *cp
; cp
++) { 
 412                     ortn 
= SSLSetProtocolVersionMax(ctx
, kSSLProtocol2
); 
 415                     ortn 
= SSLSetProtocolVersionMax(ctx
, kSSLProtocol3
); 
 418                     ortn 
= SSLSetProtocolVersionMax(ctx
, kTLSProtocol12
); 
 424                                 printSslErrStr("SSLSetProtocolVersionMax", ortn
); 
 429         ortn 
= SSLSetProtocolVersionMax(ctx
, pargs
->tryVersion
); 
 431             printSslErrStr("SSLSetProtocolVersionMax", ortn
); 
 436         if(pargs
->resumableEnable
) { 
 437                 const void *rtnId 
= NULL
; 
 440                 ortn 
= SSLSetPeerID(ctx
, &peerId
, sizeof(PeerSpec
)); 
 442                         printSslErrStr("SSLSetPeerID", ortn
); 
 445                 /* quick test of the get fcn */ 
 446                 ortn 
= SSLGetPeerID(ctx
, &rtnId
, &rtnIdLen
); 
 448                         printSslErrStr("SSLGetPeerID", ortn
); 
 451                 if((rtnId 
== NULL
) || (rtnIdLen 
!= sizeof(PeerSpec
))) { 
 452                         printf("***SSLGetPeerID screwup\n"); 
 454                 else if(memcmp(&peerId
, rtnId
, rtnIdLen
) != 0) { 
 455                         printf("***SSLGetPeerID data mismatch\n"); 
 458         if(pargs
->allowExpired
) { 
 459                 ortn 
= SSLSetAllowsExpiredCerts(ctx
, true); 
 461                         printSslErrStr("SSLSetAllowExpiredCerts", ortn
); 
 465         if(pargs
->allowExpiredRoot
) { 
 466                 ortn 
= SSLSetAllowsExpiredRoots(ctx
, true); 
 468                         printSslErrStr("SSLSetAllowsExpiredRoots", ortn
); 
 472         if(pargs
->disableCertVerify
) { 
 473                 ortn 
= SSLSetEnableCertVerify(ctx
, false); 
 475                         printSslErrStr("SSLSetEnableCertVerify", ortn
); 
 479         if(pargs
->allowAnyRoot
) { 
 480                 ortn 
= SSLSetAllowsAnyRoot(ctx
, true); 
 482                         printSslErrStr("SSLSetAllowAnyRoot", ortn
); 
 486         if(pargs
->cipherRestrict 
!= '\0') { 
 487                 ortn 
= sslSetCipherRestrictions(ctx
, pargs
->cipherRestrict
); 
 492         if(pargs
->anchorFile
) { 
 493                 ortn 
= sslAddTrustedRoot(ctx
, pargs
->anchorFile
, pargs
->replaceAnchors
); 
 495                         printf("***Error obtaining anchor file %s\n", pargs
->anchorFile
); 
 499         if(pargs
->clientCerts
) { 
 501                 if(pargs
->anchorFile 
== NULL
) { 
 502                         /* assume this is a root we want to implicitly trust */ 
 503                         ortn 
= addIdentityAsTrustedRoot(ctx
, pargs
->clientCerts
); 
 508                 ortn 
= SSLSetCertificate(ctx
, pargs
->clientCerts
); 
 510                         printSslErrStr("SSLSetCertificate", ortn
); 
 513                 /* quickie test for this new function */ 
 514                 ortn 
= SSLGetCertificate(ctx
, &dummy
); 
 516                         printSslErrStr("SSLGetCertificate", ortn
); 
 519                 if(dummy 
!= pargs
->clientCerts
) { 
 520                         printf("***SSLGetCertificate error\n"); 
 525     if (pargs
->alpnNames
) { 
 526         CFMutableDataRef alpn 
= CFDataCreateMutable(NULL
, 0); 
 528         CFArrayForEach(pargs
->alpnNames
, ^(const void *value
) { 
 529             CFDataRef data 
= (CFDataRef
)value
; 
 530             uint8_t len 
= CFDataGetLength(data
); 
 531             CFDataAppendBytes(alpn
, (const UInt8 
*)&len
, sizeof(len
)); 
 532             CFDataAppend(alpn
, data
); 
 535         SSLSetALPNData(ctx
, CFDataGetBytePtr(alpn
), CFDataGetLength(alpn
)); 
 536         SSLSetALPNFunc(ctx
, alpnFunc
, (void *)NULL
); 
 540         /*** end options ***/ 
 543                 printf("...starting SSL handshake\n"); 
 545         startHandshake 
= CFAbsoluteTimeGetCurrent(); 
 548     {   ortn 
= SSLHandshake(ctx
); 
 549             if((ortn 
== errSSLWouldBlock
) && !pargs
->silent
) { 
 550                 /* keep UI responsive */ 
 553     } while (ortn 
== errSSLWouldBlock
); 
 555         endHandshake 
= CFAbsoluteTimeGetCurrent(); 
 556         pargs
->handshakeTimeOp 
= endHandshake 
- startHandshake
; 
 557         if(pargs
->numHandshakes 
== 0) { 
 558                 /* special case, this one is always way longer */ 
 559                 pargs
->handshakeTimeFirst 
= pargs
->handshakeTimeOp
; 
 562                 /* normal running total */ 
 563                 pargs
->handshakeTimeTotal 
+= pargs
->handshakeTimeOp
; 
 565         pargs
->numHandshakes
++; 
 567     ortn 
= SSLCopyPeerTrust(ctx
, &pargs
->peerTrust
); 
 569         printf("***SSLCopyPeerTrust error %" PRIdOSStatus 
"\n", ortn
); 
 570         pargs
->peerTrust 
= NULL
; 
 574         SSLGetClientCertificateState(ctx
, &pargs
->certState
); 
 575         SSLGetNegotiatedCipher(ctx
, &pargs
->negCipher
); 
 576         SSLGetNegotiatedProtocolVersion(ctx
, &pargs
->negVersion
); 
 577         pargs
->sessionIDLength 
= MAX_SESSION_ID_LENGTH
; 
 578         ortn 
= SSLGetResumableSessionInfo(ctx
, &pargs
->sessionWasResumed
, pargs
->sessionID
, &pargs
->sessionIDLength
); 
 580                 OSStatus certRtn 
= sslEvaluateTrust(ctx
, pargs
, &pargs
->peerCerts
); 
 582         if (certRtn 
&& !pargs
->manualCertVerify
) { 
 583             SSLCopyPeerCertificates(ctx
, &pargs
->peerCerts
); 
 587                 if(certRtn 
&& !ortn 
) { 
 600                 printf("...SSL handshake complete\n"); 
 602         length 
= strlen(pargs
->getMsg
); 
 603         (void) SSLWrite(ctx
, pargs
->getMsg
, length
, &actLen
); 
 606          * Try to snag RCV_BUF_SIZE bytes. Exit if (!keepConnected and we get any data 
 607          * at all), or (keepConnected and err != (none, wouldBlock)). 
 611                 if(pargs
->dumpRxData
) { 
 614                         ortn 
= SSLGetBufferedReadSize(ctx
, &avail
); 
 616                                 printf("***SSLGetBufferedReadSize error\n"); 
 620                                 printf("\n%d bytes available: ", (int)avail
); 
 623         ortn 
= SSLRead(ctx
, rcvBuf
, RCV_BUF_SIZE
, &actLen
); 
 624         if((actLen 
== 0) && !pargs
->silent
) { 
 627         if((actLen 
== 0) && (ortn 
== errSecSuccess
)) { 
 628                         printf("***Radar 2984932 confirmed***\n"); 
 630         if (ortn 
== errSSLWouldBlock
) { 
 631                         /* for this loop, these are identical */ 
 632             ortn 
= errSecSuccess
; 
 634                 if((actLen 
> 0) && pargs
->dumpRxData
) { 
 635                         dumpAscii(rcvBuf
, actLen
); 
 637                 if(ortn 
!= errSecSuccess
) { 
 638                         /* connection closed by server or by error */ 
 641                 if(!pargs
->keepConnected 
&& (actLen 
> 0)) { 
 642                 /* good enough, we connected */ 
 650         /* snag these again in case of renegotiate */ 
 651         SSLGetClientCertificateState(ctx
, &pargs
->certState
); 
 652         SSLGetNegotiatedCipher(ctx
, &pargs
->negCipher
); 
 653         SSLGetNegotiatedProtocolVersion(ctx
, &pargs
->negVersion
); 
 655     /* convert normal "shutdown" into zero err rtn */ 
 656         if(ortn 
== errSSLClosedGraceful
) { 
 657                 ortn 
= errSecSuccess
; 
 659         if((ortn 
== errSSLClosedNoNotify
) && !pargs
->requireNotify
) { 
 660                 /* relaxed disconnect rules */ 
 661                 ortn 
= errSecSuccess
; 
 665          * always do close, even on error - to flush outgoing write queue 
 667         OSStatus cerr 
= errSecParam
; 
 669                 cerr 
= SSLClose(ctx
); 
 671         if(ortn 
== errSecSuccess
) { 
 675                 endpointShutdown(sock
); 
 685 static void add_key(const void *key
, const void *value
, void *context
) { 
 686     CFArrayAppendValue((CFMutableArrayRef
)context
, key
); 
 690 static void showInfo(CFDictionaryRef info
) { 
 691     CFIndex dict_count
, key_ix
, key_count
; 
 692     CFMutableArrayRef keys 
= NULL
; 
 693     CFIndex maxWidth 
= 20; /* Maybe precompute this or grab from context? */ 
 695     dict_count 
= CFDictionaryGetCount(info
); 
 696     keys 
= CFArrayCreateMutable(kCFAllocatorDefault
, dict_count
, 
 697         &kCFTypeArrayCallBacks
); 
 698     CFDictionaryApplyFunction(info
, add_key
, keys
); 
 699     key_count 
= CFArrayGetCount(keys
); 
 700     CFArraySortValues(keys
, CFRangeMake(0, key_count
), 
 701         (CFComparatorFunction
)CFStringCompare
, 0); 
 703     for (key_ix 
= 0; key_ix 
< key_count
; ++key_ix
) { 
 704         CFStringRef key 
= (CFStringRef
)CFArrayGetValueAtIndex(keys
, key_ix
); 
 705         CFTypeRef value 
= CFDictionaryGetValue(info
, key
); 
 706         CFMutableStringRef line 
= CFStringCreateMutable(NULL
, 0); 
 708         CFStringAppend(line
, key
); 
 710         for (jx 
= CFStringGetLength(key
); 
 711             jx 
< maxWidth
; ++jx
) { 
 712             CFStringAppend(line
, CFSTR(" ")); 
 714         CFStringAppend(line
, CFSTR(" : ")); 
 715         if (CFStringGetTypeID() == CFGetTypeID(value
)) { 
 716             CFStringAppend(line
, (CFStringRef
)value
); 
 717         } else if (CFDateGetTypeID() == CFGetTypeID(value
)) { 
 718             CFLocaleRef lc 
= CFLocaleCopyCurrent(); 
 719             CFDateFormatterRef df 
= CFDateFormatterCreate(NULL
, lc
, 
 720                 kCFDateFormatterFullStyle
, kCFDateFormatterFullStyle
); 
 721             CFDateRef date 
= (CFDateRef
)value
; 
 722             CFStringRef ds 
= CFDateFormatterCreateStringWithDate(NULL
, df
, 
 724             CFStringAppend(line
, ds
); 
 728         } else if (CFURLGetTypeID() == CFGetTypeID(value
)) { 
 729             CFURLRef url 
= (CFURLRef
)value
; 
 730             CFStringAppend(line
, CFSTR("<")); 
 731             CFStringAppend(line
, CFURLGetString(url
)); 
 732             CFStringAppend(line
, CFSTR(">")); 
 733         } else if (CFDataGetTypeID() == CFGetTypeID(value
)) { 
 734             CFDataRef v_d 
= (CFDataRef
)value
; 
 735             CFStringRef v_s 
= CFStringCreateFromExternalRepresentation( 
 736                 kCFAllocatorDefault
, v_d
, kCFStringEncodingUTF8
); 
 738                 CFStringAppend(line
, CFSTR("/")); 
 739                 CFStringAppend(line
, v_s
); 
 740                 CFStringAppend(line
, CFSTR("/ ")); 
 743             const uint8_t *bytes 
= CFDataGetBytePtr(v_d
); 
 744             CFIndex len 
= CFDataGetLength(v_d
); 
 745             for (jx 
= 0; jx 
< len
; ++jx
) { 
 746                 CFStringAppendFormat(line
, NULL
, CFSTR("%.02X"), bytes
[jx
]); 
 749             CFStringAppendFormat(line
, NULL
, CFSTR("%@"), value
); 
 751         CFStringWriteToFileWithNewline(line
, stdout
); 
 758 #pragma clang diagnostic pop 
 760 static void showPeerTrust(SecTrustRef peerTrust
, bool verbose
) { 
 762         if(peerTrust 
== NULL
) { 
 769     printf("\n=============== Peer Trust Properties ===============\n"); 
 770     CFArrayRef plist 
= SecTrustCopyProperties(peerTrust
); 
 776     printf("\n================== Peer Trust Info ==================\n"); 
 777     CFDictionaryRef info 
= SecTrustCopyInfo(peerTrust
); 
 778     if (info 
&& CFDictionaryGetCount(info
)) { 
 784         numCerts 
= SecTrustGetCertificateCount(peerTrust
); 
 785         for(i
=0; i
<numCerts
; i
++) { 
 786         plist 
= SecTrustCopySummaryPropertiesAtIndex(peerTrust
, i
); 
 787                 printf("\n============= Peer Trust Cert %lu Summary =============\n\n", i
); 
 791                 printf("\n============= Peer Trust Cert %lu Details =============\n\n", i
); 
 792                 plist 
= SecTrustCopyDetailedPropertiesAtIndex(peerTrust
, i
); 
 796                 printf("\n============= End of Peer Trust Cert %lu ==============\n", i
); 
 801 static void showPeerCerts( 
 802         CFArrayRef                      __unused peerCerts
, 
 803         bool                    __unused verbose
) 
 807         SecCertificateRef certRef
; 
 810         if(peerCerts 
== NULL
) { 
 813         numCerts 
= CFArrayGetCount(peerCerts
); 
 814         for(i
=0; i
<numCerts
; i
++) { 
 815                 certRef 
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
); 
 816                 printf("\n==================== Peer Cert %lu ====================\n\n", i
); 
 817         print_cert(certRef
, verbose
); 
 818                 printf("\n================ End of Peer Cert %lu =================\n", i
); 
 823 static void writePeerCerts( 
 824         CFArrayRef                      peerCerts
, 
 825         const char                      *fileBase
) 
 828         SecCertificateRef certRef
; 
 830         char fileName
[_maxFileStringSize
]; 
 832         if(peerCerts 
== NULL
) { 
 835         numCerts 
= CFArrayGetCount(peerCerts
); 
 836         for(i
=0; i
<numCerts
; i
++) { 
 837         snprintf(fileName
, _maxFileStringSize
, "%s%02d.cer", fileBase
, (int)i
); 
 838                 certRef 
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
); 
 839         CFDataRef derCert 
= SecCertificateCopyData(certRef
); 
 841             writeFileSizet(fileName
, CFDataGetBytePtr(derCert
), 
 842                 CFDataGetLength(derCert
)); 
 846         printf("...wrote %lu certs to fileBase %s\n", numCerts
, fileBase
); 
 850  * Show result of an sslPing(). 
 851  * Assumes the following from sslPingArgs: 
 865 static void showSSLResult( 
 866         const sslPingArgs       
*pargs
, 
 868         int                 displayPeerCerts
, 
 869         char                            *fileBase
)              // non-NULL: write certs to file 
 871         CFIndex numPeerCerts
; 
 875         if(pargs
->acceptedProts
) { 
 876                 printf("   Allowed SSL versions   : %s\n", pargs
->acceptedProts
); 
 879                 printf("   Attempted  SSL version : %s\n", 
 880                         sslGetProtocolVersionString(pargs
->tryVersion
)); 
 883         printf("   Result                 : %s\n", sslGetSSLErrString(err
)); 
 884         printf("   Negotiated SSL version : %s\n", 
 885                 sslGetProtocolVersionString(pargs
->negVersion
)); 
 886         printf("   Negotiated CipherSuite : %s\n", 
 887                 sslGetCipherSuiteString(pargs
->negCipher
)); 
 888 #pragma clang diagnostic push 
 889 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
 890         if(pargs
->certState 
!= kSSLClientCertNone
) { 
 891                 printf("   Client Cert State      : %s\n", 
 892                         sslGetClientCertStateString(pargs
->certState
)); 
 894 #pragma clang diagnostic pop 
 896                 printf("   Resumed Session        : "); 
 897                 if(pargs
->sessionWasResumed
) { 
 898                         for(unsigned dex
=0; dex
<pargs
->sessionIDLength
; dex
++) { 
 899                                 printf("%02X ", pargs
->sessionID
[dex
]); 
 900                                 if(((dex 
% 8) == 7) && (dex 
!= (pargs
->sessionIDLength 
- 1))) { 
 907                         printf("NOT RESUMED\n"); 
 909                 printf("   Handshake time         : %f seconds\n", pargs
->handshakeTimeOp
); 
 911         if(pargs
->peerCerts 
== NULL
) { 
 915                 numPeerCerts 
= CFArrayGetCount(pargs
->peerCerts
); 
 917         printf("   Number of server certs : %lu\n", numPeerCerts
); 
 918         if(numPeerCerts 
!= 0) { 
 919                 if (displayPeerCerts 
== 1) { 
 920                         showPeerCerts(pargs
->peerCerts
, false); 
 921                 } else if (displayPeerCerts 
== 2) { 
 922                         showPeerTrust(pargs
->peerTrust
, false); 
 924                 if(fileBase 
!= NULL
) { 
 925                         writePeerCerts(pargs
->peerCerts
, fileBase
); 
 932 static int verifyProtocol( 
 934         SSLProtocol     maxProtocol
, 
 935         SSLProtocol     reqProtocol
, 
 936         SSLProtocol negProtocol
) 
 941         if(reqProtocol 
> maxProtocol
) { 
 942                 /* known not to support this attempt, relax */ 
 943                 reqProtocol 
= maxProtocol
; 
 945         if(reqProtocol 
!= negProtocol
) { 
 946                 printf("***Expected protocol %s; negotiated %s\n", 
 947                         sslGetProtocolVersionString(reqProtocol
), 
 948                         sslGetProtocolVersionString(negProtocol
)); 
 956 static int verifyClientCertState( 
 957         bool                                    verifyCertState
, 
 958         SSLClientCertificateState       expectState
, 
 959         SSLClientCertificateState       gotState
) 
 961         if(!verifyCertState
) { 
 964         if(expectState 
== gotState
) { 
 967         printf("***Expected clientCertState %s; got %s\n", 
 968                 sslGetClientCertStateString(expectState
), 
 969                 sslGetClientCertStateString(gotState
)); 
 973 static SSLProtocol 
charToProt( 
 977 #pragma clang diagnostic push 
 978 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
 981                         return kSSLProtocol2
; 
 983                         return kSSLProtocol3
; 
 985                         return kTLSProtocol12
; 
 989 #pragma clang diagnostic pop 
 992 int main(int argc
, char **argv
) 
 998         char                            fullFileBase
[_maxFileStringSize
]; 
 999         int                                     ourRtn 
= 0;                     // exit status - sum of all errors 
1001         SecKeychainRef          serverKc 
= nil
; 
1004         /* user-spec'd parameters */ 
1005         const char                              *getPath 
= DEFAULT_PATH
; 
1006         char                            *fileBase 
= NULL
; 
1007         int             displayCerts 
= 0; 
1008         bool                    doSslV2 
= false; 
1009         bool                    doSslV3 
= false; 
1010         bool                    doTlsV1 
= true; 
1011     bool                        doTlsV11 
= false; 
1012     bool                        doTlsV12 
= false; 
1013         bool                    protXOnly 
= false;      // kSSLProtocol3Only, kTLSProtocol1Only 
1014         bool                    doProtUnknown 
= false; 
1015         unsigned                        loopCount 
= 1; 
1016         bool                    doPause 
= false; 
1017         bool                    pauseFirstLoop 
= false; 
1018         bool                    verifyProt 
= false; 
1019         char                            *acceptedProts 
= NULL
; 
1020         char                            *keyChainName 
= NULL
; 
1021         char                            *getMsgSpec 
= NULL
; 
1022         bool                    vfyCertState 
= false; 
1023         bool                    displayHandshakeTimes 
= false; 
1024         bool                    completeCertChain 
= false; 
1025 #pragma clang diagnostic push 
1026 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
1027     SSLClientCertificateState expectCertState 
= kSSLClientCertNone
; 
1028     SSLProtocol            maxProtocol 
= kTLSProtocol12
;    // for verifying negotiated protocol 
1029 #pragma clang diagnostic pop 
1031         /* special case - one arg of "h" or "-h" or "hv" */ 
1033             if((strcmp(argv
[1], "h") == 0) || (strcmp(argv
[1], "-h") == 0)) { 
1036                 if(strcmp(argv
[1], "hv") == 0) { 
1041         /* set up defaults */ 
1042         memset(&pargs
, 0, sizeof(sslPingArgs
)); 
1043         pargs
.hostName 
= DEFAULT_HOST
; 
1044         pargs
.port 
= DEFAULT_PORT
; 
1045         pargs
.resumableEnable 
= true; 
1048         for(arg
=1; arg
<argc
; arg
++) { 
1051                         /* first arg, is always hostname; '-' means default */ 
1052                         if(argp
[0] != '-') { 
1053                                 pargs
.hostName 
= argp
; 
1057                 if(argp
[0] == '/') { 
1058                         /* path always starts with leading slash */ 
1066               /* requires another arg */ 
1069           if (pargs
.alpnNames 
== NULL
) { 
1070               pargs
.alpnNames 
= CFArrayCreateMutableForCFTypes(NULL
); 
1073           CFDataRef alpn 
= CFDataCreate(NULL
, (const UInt8 
*)argv
[arg
], strlen(argv
[arg
])); 
1074           CFArrayAppendValue(pargs
.alpnNames
, alpn
); 
1075           CFReleaseNull(alpn
); 
1080           CFDictionaryRef context 
= NULL
; 
1083               /* requires another arg */ 
1087           if (argp
[0] == 'W') { 
1088               context 
= CFDictionaryCreateForCFTypes(NULL
, 
1089                                                      CFSTR("AppleServerAuthenticationAllowUATAPN"), kCFBooleanTrue
, 
1090                                                      CFSTR("AppleServerAuthenticationAllowUATIDS"), kCFBooleanTrue
, 
1091                                                      CFSTR("AppleServerAuthenticationAllowUATGS"), kCFBooleanTrue
, 
1094           const char *verifyName 
= pargs
.hostName
; 
1096           if (pargs
.policies 
== NULL
) { 
1097               pargs
.policies 
= CFArrayCreateMutableForCFTypes(NULL
); 
1100           if (pargs
.vfyHostName
) 
1101               verifyName 
= pargs
.vfyHostName
; 
1103           SecPolicyRef policy 
= NULL
; 
1104           CFStringRef hostname 
= CFStringCreateWithCString(NULL
, verifyName
, kCFStringEncodingUTF8
); 
1106           if (strcasecmp(argv
[arg
], "PushLegacy") == 0) { 
1107               policy 
= SecPolicyCreateApplePushServiceLegacy(hostname
); 
1108           } else if (strcasecmp(argv
[arg
], "Push") == 0) { 
1109               policy 
= SecPolicyCreateApplePushService(hostname
, context
); 
1110           } else if (strcasecmp(argv
[arg
], "IDS") == 0) { 
1111               policy 
= SecPolicyCreateAppleIDSServiceContext(hostname
, context
); 
1112           } else if (strcasecmp(argv
[arg
], "GS") == 0) { 
1113               policy 
= SecPolicyCreateAppleGSService(hostname
, context
); 
1115               printf("unknown policy: %s", argv
[arg
]); 
1116               CFReleaseNull(hostname
); 
1117               CFReleaseNull(context
); 
1122               CFArrayAppendValue(pargs
.policies
, policy
); 
1125           CFReleaseNull(policy
); 
1126           CFReleaseNull(hostname
); 
1127           CFReleaseNull(context
); 
1132                                 pargs
.allowExpired 
= true; 
1135                                 pargs
.allowExpiredRoot 
= true; 
1138                                 pargs
.disableCertVerify 
= true; 
1141                                 pargs
.disableCertVerify 
= true; // implied 
1142                                 pargs
.manualCertVerify 
= true; 
1146                                         /* requires another arg */ 
1149                                 pargs
.anchorFile 
= argv
[arg
]; 
1153                                         /* requires another arg */ 
1156                                 pargs
.anchorFile 
= argv
[arg
]; 
1157                                 pargs
.replaceAnchors 
= true; 
1160                                 pargs
.allowAnyRoot 
= true; 
1163                                 pargs
.dumpRxData 
= true; 
1170                                         /* requires another arg */ 
1173                                 fileBase 
= argv
[arg
]; 
1176                                 pargs
.cipherRestrict 
= argp
[2]; 
1179                                 doSslV3 
= doTlsV1 
= doTlsV11 
= false; 
1183                                 doSslV2 
= doTlsV1 
= doTlsV11 
= doTlsV12 
= false; 
1187                                 doSslV2 
= doSslV3 
= doTlsV11 
= doTlsV12 
= false; 
1191                                 doSslV2 
= doSslV3 
= doTlsV1 
= false; 
1195                                 doSslV2 
= doSslV3 
= doTlsV1 
= doTlsV12 
= false; 
1199                                 doSslV2 
= doSslV3 
= doTlsV1 
= doTlsV11 
= doTlsV12 
= true; 
1205                                 doSslV2 
= doSslV3 
= doTlsV1 
= doTlsV11 
= doTlsV12 
= false; 
1206                                 doProtUnknown 
= true; 
1209                                 pargs
.keepConnected 
= true; 
1212                                 pargs
.requireNotify 
= true; 
1213                                 pargs
.keepConnected 
= true; 
1216                                 pargs
.resumableEnable 
= false; 
1219                                 pargs
.nonBlocking 
= true; 
1225                                 if(argp
[1] != '=') { 
1228                                 verifyProt 
= true;              // implied 
1229                                 maxProtocol 
= charToProt(argp
[2], argv
); 
1232                                 if(argp
[1] != '=') { 
1235                                 acceptedProts 
= argv
[arg
]; 
1236                                 doSslV3 
= doSslV2 
= doTlsV1 
= doTlsV11 
= doTlsV12 
= false; 
1240           /* requires another arg */ 
1243                                 int parsedLoopCount 
= atoi(argv
[arg
]); 
1244                                 if (parsedLoopCount 
<= 0) { 
1245                                         printf("***bad loopCount\n"); 
1248         loopCount 
= (unsigned) parsedLoopCount
; 
1252                     /* requires another arg */ 
1255                                 pargs
.port 
= atoi(argv
[arg
]); 
1258                                 pargs
.allowHostnameSpoof 
= true; 
1262                     /* requires another arg */ 
1265                                 pargs
.vfyHostName 
= argv
[arg
]; 
1269                     /* requires another arg */ 
1272                                 keyChainName 
= &argp
[2]; 
1275                                 getMsgSpec 
= &argp
[2]; 
1278                                 if(argp
[1] != '=') { 
1281                                 vfyCertState 
= true; 
1282 #pragma clang diagnostic push 
1283 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
1286                                                 expectCertState 
= kSSLClientCertNone
; 
1289                                                 expectCertState 
= kSSLClientCertRequested
; 
1292                                                 expectCertState 
= kSSLClientCertSent
; 
1295                                                 expectCertState 
= kSSLClientCertRejected
; 
1300 #pragma clang diagnostic pop 
1303                                 pargs
.password 
= &argp
[2]; 
1309                                 pauseFirstLoop 
= true; 
1315                                 pargs
.verbose 
= true; 
1318                                 pargs
.silent 
= pargs
.quiet 
= true; 
1321                                 displayHandshakeTimes 
= true; 
1324                                 completeCertChain 
= true; 
1327                                 if(pargs
.verbose 
|| (argp
[1] == 'v')) { 
1338                 pargs
.getMsg 
= getMsgSpec
; 
1341                 sprintf(getMsg
, "%s %s %s", 
1342                         DEFAULT_GETMSG
, getPath
, DEFAULT_GET_SUFFIX
); 
1343                 pargs
.getMsg 
= getMsg
; 
1346     /* get client cert and optional encryption cert as CFArrayRef */ 
1348                 pargs
.clientCerts 
= getSslCerts(keyChainName
, false, completeCertChain
, 
1349                         pargs
.anchorFile
, &serverKc
); 
1350                 if(pargs
.clientCerts 
== nil
) { 
1353 #ifdef USE_CDSA_CRYPTO 
1354                 if(pargs
.password
) { 
1355                         OSStatus ortn 
= SecKeychainUnlock(serverKc
, 
1356                                 strlen(pargs
.password
), pargs
.password
, true); 
1358                                 printf("SecKeychainUnlock returned %d\n", (int)ortn
); 
1366         struct sigaction sa
; 
1367         memset(&sa
, 0, sizeof(sa
)); 
1368         sa
.sa_flags 
= SA_RESTART
; 
1369         sa
.sa_handler 
= sigpipe
; 
1370         sigaction(SIGPIPE
, &sa
, NULL
); 
1373 #pragma clang diagnostic push 
1374 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
1375         for(loop
=0; loop
<loopCount
; loop
++) { 
1377                  * One pass for each protocol version, skipping any explicit version if 
1378                  * an attempt at a higher version and succeeded in doing so successfully fell 
1382                         pargs
.tryVersion 
= kTLSProtocol12
; 
1383                         pargs
.acceptedProts 
= NULL
; 
1385                                 printf("Connecting to host %s with TLS V1.2...", pargs
.hostName
); 
1388                         err 
= sslPing(&pargs
); 
1394                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_v3.1", fileBase
); 
1396                                 showSSLResult(&pargs
, 
1399                               fileBase 
? fullFileBase 
: NULL
); 
1401                         CFReleaseNull(pargs
.peerCerts
); 
1403                                 /* deal with fallbacks, skipping redundant tests */ 
1404                                 switch(pargs
.negVersion
) { 
1405                     case kTLSProtocol11
: 
1426                                 ourRtn 
+= verifyProtocol(verifyProt
, maxProtocol
, kTLSProtocol12
, 
1429                         /* note we do this regardless since the client state might be 
1430                          * the cause of a failure */ 
1431                         ourRtn 
+= verifyClientCertState(vfyCertState
, expectCertState
, 
1435                         pargs
.tryVersion 
= kTLSProtocol11
; 
1436                         pargs
.acceptedProts 
= NULL
; 
1438                                 printf("Connecting to host %s with TLS V1.1...", pargs
.hostName
); 
1441                         err 
= sslPing(&pargs
); 
1447                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_v3.1", fileBase
); 
1449                                 showSSLResult(&pargs
, 
1452                               fileBase 
? fullFileBase 
: NULL
); 
1454                         CFReleaseNull(pargs
.peerCerts
); 
1456                                 /* deal with fallbacks, skipping redundant tests */ 
1457                                 switch(pargs
.negVersion
) { 
1473                                 ourRtn 
+= verifyProtocol(verifyProt
, maxProtocol
, kTLSProtocol11
, 
1476                         /* note we do this regardless since the client state might be 
1477                          * the cause of a failure */ 
1478                         ourRtn 
+= verifyClientCertState(vfyCertState
, expectCertState
, 
1483                                 protXOnly 
? kTLSProtocol1Only 
: kTLSProtocol1
; 
1484                         pargs
.acceptedProts 
= NULL
; 
1486                                 printf("Connecting to host %s with TLS V1...", pargs
.hostName
); 
1489                         err 
= sslPing(&pargs
); 
1495                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_v3.1", fileBase
); 
1497                                 showSSLResult(&pargs
, 
1500                                         fileBase 
? fullFileBase 
: NULL
); 
1502                         CFReleaseNull(pargs
.peerCerts
); 
1504                                 /* deal with fallbacks, skipping redundant tests */ 
1505                                 switch(pargs
.negVersion
) { 
1516                                 ourRtn 
+= verifyProtocol(verifyProt
, maxProtocol
, kTLSProtocol1
, 
1519                         /* note we do this regardless since the client state might be 
1520                          * the cause of a failure */ 
1521                         ourRtn 
+= verifyClientCertState(vfyCertState
, expectCertState
, 
1525                         pargs
.tryVersion 
= protXOnly 
? kSSLProtocol3Only 
: kSSLProtocol3
; 
1526                         pargs
.acceptedProts 
= NULL
; 
1528                                 printf("Connecting to host %s with SSL V3...", pargs
.hostName
); 
1531                         err 
= sslPing(&pargs
); 
1537                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_v3.0", fileBase
); 
1539                                 showSSLResult(&pargs
, 
1542                                         fileBase 
? fullFileBase 
: NULL
); 
1544                         CFReleaseNull(pargs
.peerCerts
); 
1546                                 /* deal with fallbacks, skipping redundant tests */ 
1547                                 switch(pargs
.negVersion
) { 
1554                                 ourRtn 
+= verifyProtocol(verifyProt
, maxProtocol
, kSSLProtocol3
, 
1557                         /* note we do this regardless since the client state might be 
1558                          * the cause of a failure */ 
1559                         ourRtn 
+= verifyClientCertState(vfyCertState
, expectCertState
, 
1565                 snprintf(fullFileBase
, _maxFileStringSize
, "%s_v2", fileBase
); 
1568                                 printf("Connecting to host %s with SSL V2...", pargs
.hostName
); 
1571                         pargs
.tryVersion 
= kSSLProtocol2
; 
1572                         pargs
.acceptedProts 
= NULL
; 
1573                         err 
= sslPing(&pargs
); 
1579                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_v2", fileBase
); 
1581                                 showSSLResult(&pargs
, 
1584                                         fileBase 
? fullFileBase 
: NULL
); 
1586                         CFReleaseNull(pargs
.peerCerts
); 
1588                                 ourRtn 
+= verifyProtocol(verifyProt
, maxProtocol
, kSSLProtocol2
, 
1591                         /* note we do this regardless since the client state might be 
1592                          * the cause of a failure */ 
1593                         ourRtn 
+= verifyClientCertState(vfyCertState
, expectCertState
, 
1598                                 printf("Connecting to host %s with kSSLProtocolUnknown...", 
1602                         pargs
.tryVersion 
= kSSLProtocolUnknown
; 
1603                         pargs
.acceptedProts 
= NULL
; 
1604                         err 
= sslPing(&pargs
); 
1610                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_def", fileBase
); 
1612                                 showSSLResult(&pargs
, 
1615                                         fileBase 
? fullFileBase 
: NULL
); 
1617                         CFReleaseNull(pargs
.peerCerts
); 
1619                 if(acceptedProts 
!= NULL
) { 
1620                         pargs
.acceptedProts 
= acceptedProts
; 
1621                         pargs
.tryVersion 
= kSSLProtocolUnknown
; // not used 
1623                                 printf("Connecting to host %s with acceptedProts %s...", 
1624                                         pargs
.hostName
, pargs
.acceptedProts
); 
1627                         err 
= sslPing(&pargs
); 
1633                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_def", fileBase
); 
1635                                 showSSLResult(&pargs
, 
1638                                         fileBase 
? fullFileBase 
: NULL
); 
1640                         CFReleaseNull(pargs
.peerCerts
); 
1644                                  /* pause after first, before last to grab trace */ 
1645                          ((loop 
== 0) || (loop 
== loopCount 
- 1)) 
1650                         printf("a to abort, c to continue: "); 
1651                         resp 
= (char) getchar(); 
1657 #pragma clang diagnostic pop 
1659         if(displayHandshakeTimes
) { 
1660                 CFAbsoluteTime totalTime
; 
1661                 unsigned numHandshakes
; 
1662                 if(pargs
.numHandshakes 
== 1) { 
1663                         /* just display the first one */ 
1664                         totalTime 
= pargs
.handshakeTimeFirst
; 
1668                         /* skip the first one */ 
1669                         totalTime 
= pargs
.handshakeTimeTotal
; 
1670                         numHandshakes 
= pargs
.numHandshakes 
- 1; 
1672                 if(numHandshakes 
!= 0) { 
1673                         printf("   %u handshakes in %f seconds; %f seconds per handshake\n", 
1674                                 numHandshakes
, totalTime
, 
1675                                 (totalTime 
/ numHandshakes
)); 
1680                 printf("===%s exiting with %d %s for host %s\n", argv
[0], ourRtn
, 
1681                         (ourRtn 
> 1) ? "errors" : "error", pargs
.hostName
);