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/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 
= SecTrustEvaluate(secTrust
, &secTrustResult
); 
 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 #pragma clang diagnostic push 
 222 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
 223             case kSecTrustResultConfirm
: 
 224 #pragma clang diagnostic pop 
 225                                 res 
= "kSecTrustResultConfirm"; break; 
 226                         case kSecTrustResultDeny
: 
 227                                 res 
= "kSecTrustResultDeny"; break; 
 228                         case kSecTrustResultUnspecified
: 
 229                                 res 
= "kSecTrustResultUnspecified"; break; 
 230                         case kSecTrustResultRecoverableTrustFailure
: 
 231                                 res 
= "kSecTrustResultRecoverableTrustFailure"; break; 
 232                         case kSecTrustResultFatalTrustFailure
: 
 233                                 res 
= "kSecTrustResultFatalTrustFailure"; break; 
 234                         case kSecTrustResultOtherError
: 
 235                                 res 
= "kSecTrustResultOtherError"; break; 
 237                                 res 
= "UNKNOWN"; break; 
 239                 printf("\nSecTrustEvaluate(): secTrustResult %s\n", res
); 
 242         switch(secTrustResult
) { 
 243                 case kSecTrustResultUnspecified
: 
 244                         /* cert chain valid, no special UserTrust assignments */ 
 245                 case kSecTrustResultProceed
: 
 246                         /* cert chain valid AND user explicitly trusts this */ 
 249                         printf("\n***SecTrustEvaluate reported secTrustResult %d\n", 
 250                                 (int)secTrustResult
); 
 251                         ortn 
= errSSLXCertChainInvalid
; 
 260 /* print reply received from server, safely */ 
 261 static void dumpAscii( 
 265         char *cp 
= (char *)rcvBuf
; 
 269         for(i
=0; i
<len
; i
++) { 
 282                                 if(isprint(c
) && (c 
!= '\n')) { 
 286                                         printf("<%02X>", ((unsigned)c
) & 0xff); 
 296 alpnFunc(SSLContextRef          ctx
, 
 298          const void                         *alpnData
, 
 299          size_t                  alpnDataLength
) 
 301     printf("[selected ALPN]"); 
 304 #pragma clang diagnostic push 
 305 #pragma clang diagnostic ignored "-Wdeprecated-declarations" 
 308  * Perform one SSL diagnostic session. Returns nonzero on error. Normally no 
 309  * output to stdout except initial "connecting to" message, unless there 
 310  * is a really screwed up error (i.e., something not directly related 
 311  * to the SSL connection). 
 313 #define RCV_BUF_SIZE            256 
 315 static OSStatus 
sslPing( 
 321     SSLContextRef       ctx 
= NULL
; 
 324     uint8_t             rcvBuf
[RCV_BUF_SIZE
]; 
 325         CFAbsoluteTime          startHandshake
; 
 326         CFAbsoluteTime          endHandshake
; 
 328     pargs
->negVersion 
= kSSLProtocolUnknown
; 
 329     pargs
->negCipher 
= SSL_NULL_WITH_NULL_NULL
; 
 330     pargs
->peerCerts 
= NULL
; 
 332         /* first make sure requested server is there */ 
 333         ortn 
= MakeServerConnection(pargs
->hostName
, pargs
->port
, pargs
->nonBlocking
, 
 336         printf("MakeServerConnection returned %d; aborting\n", (int)ortn
); 
 340                 printf("...connected to server; starting SecureTransport\n"); 
 344          * Set up a SecureTransport session. 
 345          * First the standard calls. 
 347     ctx 
= SSLCreateContext(kCFAllocatorDefault
, kSSLClientSide
, kSSLStreamType
); 
 349                 printf("SSLCreateContext\n"); 
 352         ortn 
= SSLSetIOFuncs(ctx
, SocketRead
, SocketWrite
); 
 354                 printSslErrStr("SSLSetIOFuncs", ortn
); 
 357         ortn 
= SSLSetConnection(ctx
, (SSLConnectionRef
)(intptr_t)sock
); 
 359                 printSslErrStr("SSLSetConnection", ortn
); 
 362         SSLConnectionRef getConn
; 
 363         ortn 
= SSLGetConnection(ctx
, &getConn
); 
 365                 printSslErrStr("SSLGetConnection", ortn
); 
 368         if(getConn 
!= (SSLConnectionRef
)(intptr_t)sock
) { 
 369                 printf("***SSLGetConnection error\n"); 
 373         if(!pargs
->allowHostnameSpoof
) { 
 374                 /* if this isn't set, it isn't checked by AppleX509TP */ 
 375                 const char *vfyHost 
= pargs
->hostName
; 
 376                 if(pargs
->vfyHostName
) { 
 377                         /* generally means we're expecting an error */ 
 378                         vfyHost 
= pargs
->vfyHostName
; 
 380                 ortn 
= SSLSetPeerDomainName(ctx
, vfyHost
, strlen(vfyHost
)); 
 382                         printSslErrStr("SSLSetPeerDomainName", ortn
); 
 388          * SecureTransport options. 
 390         if(pargs
->acceptedProts
) { 
 391                 ortn 
= SSLSetProtocolVersionEnabled(ctx
, kSSLProtocolAll
, false); 
 393                         printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn
); 
 396                 for(const char *cp 
= pargs
->acceptedProts
; *cp
; cp
++) { 
 400                                         prot 
= kSSLProtocol2
; 
 403                                         prot 
= kSSLProtocol3
; 
 406                                         prot 
= kTLSProtocol12
; 
 411                         ortn 
= SSLSetProtocolVersionEnabled(ctx
, prot
, true); 
 413                                 printSslErrStr("SSLSetProtocolVersionEnabled", ortn
); 
 419                 ortn 
= SSLSetProtocolVersion(ctx
, pargs
->tryVersion
); 
 421                         printSslErrStr("SSLSetProtocolVersion", ortn
); 
 425                 ortn 
= SSLGetProtocolVersion(ctx
, &getVers
); 
 427                         printSslErrStr("SSLGetProtocolVersion", ortn
); 
 430                 if(getVers 
!= pargs
->tryVersion
) { 
 431                         printf("***SSLGetProtocolVersion screwup: try %s  get %s\n", 
 432                                 sslGetProtocolVersionString(pargs
->tryVersion
), 
 433                                 sslGetProtocolVersionString(getVers
)); 
 438         if(pargs
->resumableEnable
) { 
 439                 const void *rtnId 
= NULL
; 
 442                 ortn 
= SSLSetPeerID(ctx
, &peerId
, sizeof(PeerSpec
)); 
 444                         printSslErrStr("SSLSetPeerID", ortn
); 
 447                 /* quick test of the get fcn */ 
 448                 ortn 
= SSLGetPeerID(ctx
, &rtnId
, &rtnIdLen
); 
 450                         printSslErrStr("SSLGetPeerID", ortn
); 
 453                 if((rtnId 
== NULL
) || (rtnIdLen 
!= sizeof(PeerSpec
))) { 
 454                         printf("***SSLGetPeerID screwup\n"); 
 456                 else if(memcmp(&peerId
, rtnId
, rtnIdLen
) != 0) { 
 457                         printf("***SSLGetPeerID data mismatch\n"); 
 460         if(pargs
->allowExpired
) { 
 461                 ortn 
= SSLSetAllowsExpiredCerts(ctx
, true); 
 463                         printSslErrStr("SSLSetAllowExpiredCerts", ortn
); 
 467         if(pargs
->allowExpiredRoot
) { 
 468                 ortn 
= SSLSetAllowsExpiredRoots(ctx
, true); 
 470                         printSslErrStr("SSLSetAllowsExpiredRoots", ortn
); 
 474         if(pargs
->disableCertVerify
) { 
 475                 ortn 
= SSLSetEnableCertVerify(ctx
, false); 
 477                         printSslErrStr("SSLSetEnableCertVerify", ortn
); 
 481         if(pargs
->allowAnyRoot
) { 
 482                 ortn 
= SSLSetAllowsAnyRoot(ctx
, true); 
 484                         printSslErrStr("SSLSetAllowAnyRoot", ortn
); 
 488         if(pargs
->cipherRestrict 
!= '\0') { 
 489                 ortn 
= sslSetCipherRestrictions(ctx
, pargs
->cipherRestrict
); 
 494         if(pargs
->anchorFile
) { 
 495                 ortn 
= sslAddTrustedRoot(ctx
, pargs
->anchorFile
, pargs
->replaceAnchors
); 
 497                         printf("***Error obtaining anchor file %s\n", pargs
->anchorFile
); 
 501         if(pargs
->clientCerts
) { 
 503                 if(pargs
->anchorFile 
== NULL
) { 
 504                         /* assume this is a root we want to implicitly trust */ 
 505                         ortn 
= addIdentityAsTrustedRoot(ctx
, pargs
->clientCerts
); 
 510                 ortn 
= SSLSetCertificate(ctx
, pargs
->clientCerts
); 
 512                         printSslErrStr("SSLSetCertificate", ortn
); 
 515                 /* quickie test for this new function */ 
 516                 ortn 
= SSLGetCertificate(ctx
, &dummy
); 
 518                         printSslErrStr("SSLGetCertificate", ortn
); 
 521                 if(dummy 
!= pargs
->clientCerts
) { 
 522                         printf("***SSLGetCertificate error\n"); 
 527     if (pargs
->alpnNames
) { 
 528         CFMutableDataRef alpn 
= CFDataCreateMutable(NULL
, 0); 
 530         CFArrayForEach(pargs
->alpnNames
, ^(const void *value
) { 
 531             CFDataRef data 
= (CFDataRef
)value
; 
 532             uint8_t len 
= CFDataGetLength(data
); 
 533             CFDataAppendBytes(alpn
, (const UInt8 
*)&len
, sizeof(len
)); 
 534             CFDataAppend(alpn
, data
); 
 537         SSLSetALPNData(ctx
, CFDataGetBytePtr(alpn
), CFDataGetLength(alpn
)); 
 538         SSLSetALPNFunc(ctx
, alpnFunc
, (void *)NULL
); 
 542         /*** end options ***/ 
 545                 printf("...starting SSL handshake\n"); 
 547         startHandshake 
= CFAbsoluteTimeGetCurrent(); 
 550     {   ortn 
= SSLHandshake(ctx
); 
 551             if((ortn 
== errSSLWouldBlock
) && !pargs
->silent
) { 
 552                 /* keep UI responsive */ 
 555     } while (ortn 
== errSSLWouldBlock
); 
 557         endHandshake 
= CFAbsoluteTimeGetCurrent(); 
 558         pargs
->handshakeTimeOp 
= endHandshake 
- startHandshake
; 
 559         if(pargs
->numHandshakes 
== 0) { 
 560                 /* special case, this one is always way longer */ 
 561                 pargs
->handshakeTimeFirst 
= pargs
->handshakeTimeOp
; 
 564                 /* normal running total */ 
 565                 pargs
->handshakeTimeTotal 
+= pargs
->handshakeTimeOp
; 
 567         pargs
->numHandshakes
++; 
 569     ortn 
= SSLCopyPeerTrust(ctx
, &pargs
->peerTrust
); 
 571         printf("***SSLCopyPeerTrust error %" PRIdOSStatus 
"\n", ortn
); 
 572         pargs
->peerTrust 
= NULL
; 
 576         SSLGetClientCertificateState(ctx
, &pargs
->certState
); 
 577         SSLGetNegotiatedCipher(ctx
, &pargs
->negCipher
); 
 578         SSLGetNegotiatedProtocolVersion(ctx
, &pargs
->negVersion
); 
 579         pargs
->sessionIDLength 
= MAX_SESSION_ID_LENGTH
; 
 580         ortn 
= SSLGetResumableSessionInfo(ctx
, &pargs
->sessionWasResumed
, pargs
->sessionID
, &pargs
->sessionIDLength
); 
 582                 OSStatus certRtn 
= sslEvaluateTrust(ctx
, pargs
, &pargs
->peerCerts
); 
 584         if (certRtn 
&& !pargs
->manualCertVerify
) { 
 585             SSLCopyPeerCertificates(ctx
, &pargs
->peerCerts
); 
 589                 if(certRtn 
&& !ortn 
) { 
 602                 printf("...SSL handshake complete\n"); 
 604         length 
= strlen(pargs
->getMsg
); 
 605         (void) SSLWrite(ctx
, pargs
->getMsg
, length
, &actLen
); 
 608          * Try to snag RCV_BUF_SIZE bytes. Exit if (!keepConnected and we get any data 
 609          * at all), or (keepConnected and err != (none, wouldBlock)). 
 613                 if(pargs
->dumpRxData
) { 
 616                         ortn 
= SSLGetBufferedReadSize(ctx
, &avail
); 
 618                                 printf("***SSLGetBufferedReadSize error\n"); 
 622                                 printf("\n%d bytes available: ", (int)avail
); 
 625         ortn 
= SSLRead(ctx
, rcvBuf
, RCV_BUF_SIZE
, &actLen
); 
 626         if((actLen 
== 0) && !pargs
->silent
) { 
 629         if((actLen 
== 0) && (ortn 
== errSecSuccess
)) { 
 630                         printf("***Radar 2984932 confirmed***\n"); 
 632         if (ortn 
== errSSLWouldBlock
) { 
 633                         /* for this loop, these are identical */ 
 634             ortn 
= errSecSuccess
; 
 636                 if((actLen 
> 0) && pargs
->dumpRxData
) { 
 637                         dumpAscii(rcvBuf
, actLen
); 
 639                 if(ortn 
!= errSecSuccess
) { 
 640                         /* connection closed by server or by error */ 
 643                 if(!pargs
->keepConnected 
&& (actLen 
> 0)) { 
 644                 /* good enough, we connected */ 
 652         /* snag these again in case of renegotiate */ 
 653         SSLGetClientCertificateState(ctx
, &pargs
->certState
); 
 654         SSLGetNegotiatedCipher(ctx
, &pargs
->negCipher
); 
 655         SSLGetNegotiatedProtocolVersion(ctx
, &pargs
->negVersion
); 
 657     /* convert normal "shutdown" into zero err rtn */ 
 658         if(ortn 
== errSSLClosedGraceful
) { 
 659                 ortn 
= errSecSuccess
; 
 661         if((ortn 
== errSSLClosedNoNotify
) && !pargs
->requireNotify
) { 
 662                 /* relaxed disconnect rules */ 
 663                 ortn 
= errSecSuccess
; 
 667          * always do close, even on error - to flush outgoing write queue 
 669         OSStatus cerr 
= SSLClose(ctx
); 
 670         if(ortn 
== errSecSuccess
) { 
 674                 endpointShutdown(sock
); 
 684 static void add_key(const void *key
, const void *value
, void *context
) { 
 685     CFArrayAppendValue((CFMutableArrayRef
)context
, key
); 
 689 static void showInfo(CFDictionaryRef info
) { 
 690     CFIndex dict_count
, key_ix
, key_count
; 
 691     CFMutableArrayRef keys 
= NULL
; 
 692     CFIndex maxWidth 
= 20; /* Maybe precompute this or grab from context? */ 
 694     dict_count 
= CFDictionaryGetCount(info
); 
 695     keys 
= CFArrayCreateMutable(kCFAllocatorDefault
, dict_count
, 
 696         &kCFTypeArrayCallBacks
); 
 697     CFDictionaryApplyFunction(info
, add_key
, keys
); 
 698     key_count 
= CFArrayGetCount(keys
); 
 699     CFArraySortValues(keys
, CFRangeMake(0, key_count
), 
 700         (CFComparatorFunction
)CFStringCompare
, 0); 
 702     for (key_ix 
= 0; key_ix 
< key_count
; ++key_ix
) { 
 703         CFStringRef key 
= (CFStringRef
)CFArrayGetValueAtIndex(keys
, key_ix
); 
 704         CFTypeRef value 
= CFDictionaryGetValue(info
, key
); 
 705         CFMutableStringRef line 
= CFStringCreateMutable(NULL
, 0); 
 707         CFStringAppend(line
, key
); 
 709         for (jx 
= CFStringGetLength(key
); 
 710             jx 
< maxWidth
; ++jx
) { 
 711             CFStringAppend(line
, CFSTR(" ")); 
 713         CFStringAppend(line
, CFSTR(" : ")); 
 714         if (CFStringGetTypeID() == CFGetTypeID(value
)) { 
 715             CFStringAppend(line
, (CFStringRef
)value
); 
 716         } else if (CFDateGetTypeID() == CFGetTypeID(value
)) { 
 717             CFLocaleRef lc 
= CFLocaleCopyCurrent(); 
 718             CFDateFormatterRef df 
= CFDateFormatterCreate(NULL
, lc
, 
 719                 kCFDateFormatterFullStyle
, kCFDateFormatterFullStyle
); 
 720             CFDateRef date 
= (CFDateRef
)value
; 
 721             CFStringRef ds 
= CFDateFormatterCreateStringWithDate(NULL
, df
, 
 723             CFStringAppend(line
, ds
); 
 727         } else if (CFURLGetTypeID() == CFGetTypeID(value
)) { 
 728             CFURLRef url 
= (CFURLRef
)value
; 
 729             CFStringAppend(line
, CFSTR("<")); 
 730             CFStringAppend(line
, CFURLGetString(url
)); 
 731             CFStringAppend(line
, CFSTR(">")); 
 732         } else if (CFDataGetTypeID() == CFGetTypeID(value
)) { 
 733             CFDataRef v_d 
= (CFDataRef
)value
; 
 734             CFStringRef v_s 
= CFStringCreateFromExternalRepresentation( 
 735                 kCFAllocatorDefault
, v_d
, kCFStringEncodingUTF8
); 
 737                 CFStringAppend(line
, CFSTR("/")); 
 738                 CFStringAppend(line
, v_s
); 
 739                 CFStringAppend(line
, CFSTR("/ ")); 
 742             const uint8_t *bytes 
= CFDataGetBytePtr(v_d
); 
 743             CFIndex len 
= CFDataGetLength(v_d
); 
 744             for (jx 
= 0; jx 
< len
; ++jx
) { 
 745                 CFStringAppendFormat(line
, NULL
, CFSTR("%.02X"), bytes
[jx
]); 
 748             CFStringAppendFormat(line
, NULL
, CFSTR("%@"), value
); 
 750         CFStringWriteToFileWithNewline(line
, stdout
); 
 757 #pragma clang diagnostic pop 
 759 static void showPeerTrust(SecTrustRef peerTrust
, bool verbose
) { 
 761         if(peerTrust 
== NULL
) { 
 768     printf("\n=============== Peer Trust Properties ===============\n"); 
 769     CFArrayRef plist 
= SecTrustCopyProperties(peerTrust
); 
 775     printf("\n================== Peer Trust Info ==================\n"); 
 776     CFDictionaryRef info 
= SecTrustCopyInfo(peerTrust
); 
 777     if (info 
&& CFDictionaryGetCount(info
)) { 
 783         numCerts 
= SecTrustGetCertificateCount(peerTrust
); 
 784         for(i
=0; i
<numCerts
; i
++) { 
 785         plist 
= SecTrustCopySummaryPropertiesAtIndex(peerTrust
, i
); 
 786                 printf("\n============= Peer Trust Cert %lu Summary =============\n\n", i
); 
 790                 printf("\n============= Peer Trust Cert %lu Details =============\n\n", i
); 
 791                 plist 
= SecTrustCopyDetailedPropertiesAtIndex(peerTrust
, i
); 
 795                 printf("\n============= End of Peer Trust Cert %lu ==============\n", i
); 
 800 static void showPeerCerts( 
 801         CFArrayRef                      __unused peerCerts
, 
 802         bool                    __unused verbose
) 
 806         SecCertificateRef certRef
; 
 809         if(peerCerts 
== NULL
) { 
 812         numCerts 
= CFArrayGetCount(peerCerts
); 
 813         for(i
=0; i
<numCerts
; i
++) { 
 814                 certRef 
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
); 
 815                 printf("\n==================== Peer Cert %lu ====================\n\n", i
); 
 816         print_cert(certRef
, verbose
); 
 817                 printf("\n================ End of Peer Cert %lu =================\n", i
); 
 822 static void writePeerCerts( 
 823         CFArrayRef                      peerCerts
, 
 824         const char                      *fileBase
) 
 827         SecCertificateRef certRef
; 
 829         char fileName
[_maxFileStringSize
]; 
 831         if(peerCerts 
== NULL
) { 
 834         numCerts 
= CFArrayGetCount(peerCerts
); 
 835         for(i
=0; i
<numCerts
; i
++) { 
 836         snprintf(fileName
, _maxFileStringSize
, "%s%02d.cer", fileBase
, (int)i
); 
 837                 certRef 
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
); 
 838         CFDataRef derCert 
= SecCertificateCopyData(certRef
); 
 840             writeFileSizet(fileName
, CFDataGetBytePtr(derCert
), 
 841                 CFDataGetLength(derCert
)); 
 845         printf("...wrote %lu certs to fileBase %s\n", numCerts
, fileBase
); 
 849  * Show result of an sslPing(). 
 850  * Assumes the following from sslPingArgs: 
 864 static void showSSLResult( 
 865         const sslPingArgs       
*pargs
, 
 867         int                 displayPeerCerts
, 
 868         char                            *fileBase
)              // non-NULL: write certs to file 
 870         CFIndex numPeerCerts
; 
 874         if(pargs
->acceptedProts
) { 
 875                 printf("   Allowed SSL versions   : %s\n", pargs
->acceptedProts
); 
 878                 printf("   Attempted  SSL version : %s\n", 
 879                         sslGetProtocolVersionString(pargs
->tryVersion
)); 
 882         printf("   Result                 : %s\n", sslGetSSLErrString(err
)); 
 883         printf("   Negotiated SSL version : %s\n", 
 884                 sslGetProtocolVersionString(pargs
->negVersion
)); 
 885         printf("   Negotiated CipherSuite : %s\n", 
 886                 sslGetCipherSuiteString(pargs
->negCipher
)); 
 887         if(pargs
->certState 
!= kSSLClientCertNone
) { 
 888                 printf("   Client Cert State      : %s\n", 
 889                         sslGetClientCertStateString(pargs
->certState
)); 
 892                 printf("   Resumed Session        : "); 
 893                 if(pargs
->sessionWasResumed
) { 
 894                         for(unsigned dex
=0; dex
<pargs
->sessionIDLength
; dex
++) { 
 895                                 printf("%02X ", pargs
->sessionID
[dex
]); 
 896                                 if(((dex 
% 8) == 7) && (dex 
!= (pargs
->sessionIDLength 
- 1))) { 
 903                         printf("NOT RESUMED\n"); 
 905                 printf("   Handshake time         : %f seconds\n", pargs
->handshakeTimeOp
); 
 907         if(pargs
->peerCerts 
== NULL
) { 
 911                 numPeerCerts 
= CFArrayGetCount(pargs
->peerCerts
); 
 913         printf("   Number of server certs : %lu\n", numPeerCerts
); 
 914         if(numPeerCerts 
!= 0) { 
 915                 if (displayPeerCerts 
== 1) { 
 916                         showPeerCerts(pargs
->peerCerts
, false); 
 917                 } else if (displayPeerCerts 
== 2) { 
 918                         showPeerTrust(pargs
->peerTrust
, false); 
 920                 if(fileBase 
!= NULL
) { 
 921                         writePeerCerts(pargs
->peerCerts
, fileBase
); 
 928 static int verifyProtocol( 
 930         SSLProtocol     maxProtocol
, 
 931         SSLProtocol     reqProtocol
, 
 932         SSLProtocol negProtocol
) 
 937         if(reqProtocol 
> maxProtocol
) { 
 938                 /* known not to support this attempt, relax */ 
 939                 reqProtocol 
= maxProtocol
; 
 941         if(reqProtocol 
!= negProtocol
) { 
 942                 printf("***Expected protocol %s; negotiated %s\n", 
 943                         sslGetProtocolVersionString(reqProtocol
), 
 944                         sslGetProtocolVersionString(negProtocol
)); 
 952 static int verifyClientCertState( 
 953         bool                                    verifyCertState
, 
 954         SSLClientCertificateState       expectState
, 
 955         SSLClientCertificateState       gotState
) 
 957         if(!verifyCertState
) { 
 960         if(expectState 
== gotState
) { 
 963         printf("***Expected clientCertState %s; got %s\n", 
 964                 sslGetClientCertStateString(expectState
), 
 965                 sslGetClientCertStateString(gotState
)); 
 969 static SSLProtocol 
charToProt( 
 975                         return kSSLProtocol2
; 
 977                         return kSSLProtocol3
; 
 979                         return kTLSProtocol12
; 
 985 int main(int argc
, char **argv
) 
 991         char                            fullFileBase
[_maxFileStringSize
]; 
 992         int                                     ourRtn 
= 0;                     // exit status - sum of all errors 
 994         SecKeychainRef          serverKc 
= nil
; 
 997         /* user-spec'd parameters */ 
 998         const char                              *getPath 
= DEFAULT_PATH
; 
 999         char                            *fileBase 
= NULL
; 
1000         int             displayCerts 
= 0; 
1001         bool                    doSslV2 
= false; 
1002         bool                    doSslV3 
= false; 
1003         bool                    doTlsV1 
= true; 
1004     bool                        doTlsV11 
= false; 
1005     bool                        doTlsV12 
= false; 
1006         bool                    protXOnly 
= false;      // kSSLProtocol3Only, kTLSProtocol1Only 
1007         bool                    doProtUnknown 
= false; 
1008         unsigned                        loopCount 
= 1; 
1009         bool                    doPause 
= false; 
1010         bool                    pauseFirstLoop 
= false; 
1011         bool                    verifyProt 
= false; 
1012         SSLProtocol                     maxProtocol 
= kTLSProtocol12
;   // for verifying negotiated 
1014         char                            *acceptedProts 
= NULL
; 
1015         char                            *keyChainName 
= NULL
; 
1016         char                            *getMsgSpec 
= NULL
; 
1017         bool                    vfyCertState 
= false; 
1018         SSLClientCertificateState expectCertState 
= kSSLClientCertNone
; 
1019         bool                    displayHandshakeTimes 
= false; 
1020         bool                    completeCertChain 
= false; 
1022         /* special case - one arg of "h" or "-h" or "hv" */ 
1024             if((strcmp(argv
[1], "h") == 0) || (strcmp(argv
[1], "-h") == 0)) { 
1027                 if(strcmp(argv
[1], "hv") == 0) { 
1032         /* set up defaults */ 
1033         memset(&pargs
, 0, sizeof(sslPingArgs
)); 
1034         pargs
.hostName 
= DEFAULT_HOST
; 
1035         pargs
.port 
= DEFAULT_PORT
; 
1036         pargs
.resumableEnable 
= true; 
1039         for(arg
=1; arg
<argc
; arg
++) { 
1042                         /* first arg, is always hostname; '-' means default */ 
1043                         if(argp
[0] != '-') { 
1044                                 pargs
.hostName 
= argp
; 
1048                 if(argp
[0] == '/') { 
1049                         /* path always starts with leading slash */ 
1057               /* requires another arg */ 
1060           if (pargs
.alpnNames 
== NULL
) { 
1061               pargs
.alpnNames 
= CFArrayCreateMutableForCFTypes(NULL
); 
1064           CFDataRef alpn 
= CFDataCreate(NULL
, (const UInt8 
*)argv
[arg
], strlen(argv
[arg
])); 
1065           CFArrayAppendValue(pargs
.alpnNames
, alpn
); 
1066           CFReleaseNull(alpn
); 
1071           CFDictionaryRef context 
= NULL
; 
1074               /* requires another arg */ 
1078           if (argp
[0] == 'W') { 
1079               context 
= CFDictionaryCreateForCFTypes(NULL
, 
1080                                                      CFSTR("AppleServerAuthenticationAllowUATAPN"), kCFBooleanTrue
, 
1081                                                      CFSTR("AppleServerAuthenticationAllowUATIDS"), kCFBooleanTrue
, 
1082                                                      CFSTR("AppleServerAuthenticationAllowUATGS"), kCFBooleanTrue
, 
1085           const char *verifyName 
= pargs
.hostName
; 
1087           if (pargs
.policies 
== NULL
) { 
1088               pargs
.policies 
= CFArrayCreateMutableForCFTypes(NULL
); 
1091           if (pargs
.vfyHostName
) 
1092               verifyName 
= pargs
.vfyHostName
; 
1094           SecPolicyRef policy 
= NULL
; 
1095           CFStringRef hostname 
= CFStringCreateWithCString(NULL
, verifyName
, kCFStringEncodingUTF8
); 
1097           if (strcasecmp(argv
[arg
], "PushLegacy") == 0) { 
1098               policy 
= SecPolicyCreateApplePushServiceLegacy(hostname
); 
1099           } else if (strcasecmp(argv
[arg
], "Push") == 0) { 
1100               policy 
= SecPolicyCreateApplePushService(hostname
, context
); 
1101           } else if (strcasecmp(argv
[arg
], "IDS") == 0) { 
1102               policy 
= SecPolicyCreateAppleIDSServiceContext(hostname
, context
); 
1103           } else if (strcasecmp(argv
[arg
], "GS") == 0) { 
1104               policy 
= SecPolicyCreateAppleGSService(hostname
, context
); 
1106               printf("unknown policy: %s", argv
[arg
]); 
1107               CFReleaseNull(hostname
); 
1108               CFReleaseNull(context
); 
1113               CFArrayAppendValue(pargs
.policies
, policy
); 
1116           CFReleaseNull(policy
); 
1117           CFReleaseNull(hostname
); 
1118           CFReleaseNull(context
); 
1123                                 pargs
.allowExpired 
= true; 
1126                                 pargs
.allowExpiredRoot 
= true; 
1129                                 pargs
.disableCertVerify 
= true; 
1132                                 pargs
.disableCertVerify 
= true; // implied 
1133                                 pargs
.manualCertVerify 
= true; 
1137                                         /* requires another arg */ 
1140                                 pargs
.anchorFile 
= argv
[arg
]; 
1144                                         /* requires another arg */ 
1147                                 pargs
.anchorFile 
= argv
[arg
]; 
1148                                 pargs
.replaceAnchors 
= true; 
1151                                 pargs
.allowAnyRoot 
= true; 
1154                                 pargs
.dumpRxData 
= true; 
1161                                         /* requires another arg */ 
1164                                 fileBase 
= argv
[arg
]; 
1167                                 pargs
.cipherRestrict 
= argp
[2]; 
1170                                 doSslV3 
= doTlsV1 
= doTlsV11 
= false; 
1174                                 doSslV2 
= doTlsV1 
= doTlsV11 
= doTlsV12 
= false; 
1178                                 doSslV2 
= doSslV3 
= doTlsV11 
= doTlsV12 
= false; 
1182                                 doSslV2 
= doSslV3 
= doTlsV1 
= false; 
1186                                 doSslV2 
= doSslV3 
= doTlsV1 
= doTlsV12 
= false; 
1190                                 doSslV2 
= doSslV3 
= doTlsV1 
= doTlsV11 
= doTlsV12 
= true; 
1196                                 doSslV2 
= doSslV3 
= doTlsV1 
= doTlsV11 
= doTlsV12 
= false; 
1197                                 doProtUnknown 
= true; 
1200                                 pargs
.keepConnected 
= true; 
1203                                 pargs
.requireNotify 
= true; 
1204                                 pargs
.keepConnected 
= true; 
1207                                 pargs
.resumableEnable 
= false; 
1210                                 pargs
.nonBlocking 
= true; 
1216                                 if(argp
[1] != '=') { 
1219                                 verifyProt 
= true;              // implied 
1220                                 maxProtocol 
= charToProt(argp
[2], argv
); 
1223                                 if(argp
[1] != '=') { 
1226                                 acceptedProts 
= argv
[arg
]; 
1227                                 doSslV3 
= doSslV2 
= doTlsV1 
= doTlsV11 
= doTlsV12 
= false; 
1231           /* requires another arg */ 
1234                                 int parsedLoopCount 
= atoi(argv
[arg
]); 
1235                                 if (parsedLoopCount 
<= 0) { 
1236                                         printf("***bad loopCount\n"); 
1239         loopCount 
= (unsigned) parsedLoopCount
; 
1243                     /* requires another arg */ 
1246                                 pargs
.port 
= atoi(argv
[arg
]); 
1249                                 pargs
.allowHostnameSpoof 
= true; 
1253                     /* requires another arg */ 
1256                                 pargs
.vfyHostName 
= argv
[arg
]; 
1260                     /* requires another arg */ 
1263                                 keyChainName 
= &argp
[2]; 
1266                                 getMsgSpec 
= &argp
[2]; 
1269                                 if(argp
[1] != '=') { 
1272                                 vfyCertState 
= true; 
1275                                                 expectCertState 
= kSSLClientCertNone
; 
1278                                                 expectCertState 
= kSSLClientCertRequested
; 
1281                                                 expectCertState 
= kSSLClientCertSent
; 
1284                                                 expectCertState 
= kSSLClientCertRejected
; 
1291                                 pargs
.password 
= &argp
[2]; 
1297                                 pauseFirstLoop 
= true; 
1303                                 pargs
.verbose 
= true; 
1306                                 pargs
.silent 
= pargs
.quiet 
= true; 
1309                                 displayHandshakeTimes 
= true; 
1312                                 completeCertChain 
= true; 
1315                                 if(pargs
.verbose 
|| (argp
[1] == 'v')) { 
1326                 pargs
.getMsg 
= getMsgSpec
; 
1329                 sprintf(getMsg
, "%s %s %s", 
1330                         DEFAULT_GETMSG
, getPath
, DEFAULT_GET_SUFFIX
); 
1331                 pargs
.getMsg 
= getMsg
; 
1334     /* get client cert and optional encryption cert as CFArrayRef */ 
1336                 pargs
.clientCerts 
= getSslCerts(keyChainName
, false, completeCertChain
, 
1337                         pargs
.anchorFile
, &serverKc
); 
1338                 if(pargs
.clientCerts 
== nil
) { 
1344         struct sigaction sa
; 
1345         memset(&sa
, 0, sizeof(sa
)); 
1346         sa
.sa_flags 
= SA_RESTART
; 
1347         sa
.sa_handler 
= sigpipe
; 
1348         sigaction(SIGPIPE
, &sa
, NULL
); 
1351         for(loop
=0; loop
<loopCount
; loop
++) { 
1353                  * One pass for each protocol version, skipping any explicit version if 
1354                  * an attempt at a higher version and succeeded in doing so successfully fell 
1358                         pargs
.tryVersion 
= kTLSProtocol12
; 
1359                         pargs
.acceptedProts 
= NULL
; 
1361                                 printf("Connecting to host %s with TLS V1.2...", pargs
.hostName
); 
1364                         err 
= sslPing(&pargs
); 
1370                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_v3.1", fileBase
); 
1372                                 showSSLResult(&pargs
, 
1375                               fileBase 
? fullFileBase 
: NULL
); 
1377                         CFReleaseNull(pargs
.peerCerts
); 
1379                                 /* deal with fallbacks, skipping redundant tests */ 
1380                                 switch(pargs
.negVersion
) { 
1381                     case kTLSProtocol11
: 
1402                                 ourRtn 
+= verifyProtocol(verifyProt
, maxProtocol
, kTLSProtocol12
, 
1405                         /* note we do this regardless since the client state might be 
1406                          * the cause of a failure */ 
1407                         ourRtn 
+= verifyClientCertState(vfyCertState
, expectCertState
, 
1411                         pargs
.tryVersion 
= kTLSProtocol11
; 
1412                         pargs
.acceptedProts 
= NULL
; 
1414                                 printf("Connecting to host %s with TLS V1.1...", pargs
.hostName
); 
1417                         err 
= sslPing(&pargs
); 
1423                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_v3.1", fileBase
); 
1425                                 showSSLResult(&pargs
, 
1428                               fileBase 
? fullFileBase 
: NULL
); 
1430                         CFReleaseNull(pargs
.peerCerts
); 
1432                                 /* deal with fallbacks, skipping redundant tests */ 
1433                                 switch(pargs
.negVersion
) { 
1449                                 ourRtn 
+= verifyProtocol(verifyProt
, maxProtocol
, kTLSProtocol11
, 
1452                         /* note we do this regardless since the client state might be 
1453                          * the cause of a failure */ 
1454                         ourRtn 
+= verifyClientCertState(vfyCertState
, expectCertState
, 
1459                                 protXOnly 
? kTLSProtocol1Only 
: kTLSProtocol1
; 
1460                         pargs
.acceptedProts 
= NULL
; 
1462                                 printf("Connecting to host %s with TLS V1...", pargs
.hostName
); 
1465                         err 
= sslPing(&pargs
); 
1471                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_v3.1", fileBase
); 
1473                                 showSSLResult(&pargs
, 
1476                                         fileBase 
? fullFileBase 
: NULL
); 
1478                         CFReleaseNull(pargs
.peerCerts
); 
1480                                 /* deal with fallbacks, skipping redundant tests */ 
1481                                 switch(pargs
.negVersion
) { 
1492                                 ourRtn 
+= verifyProtocol(verifyProt
, maxProtocol
, kTLSProtocol1
, 
1495                         /* note we do this regardless since the client state might be 
1496                          * the cause of a failure */ 
1497                         ourRtn 
+= verifyClientCertState(vfyCertState
, expectCertState
, 
1501                         pargs
.tryVersion 
= protXOnly 
? kSSLProtocol3Only 
: kSSLProtocol3
; 
1502                         pargs
.acceptedProts 
= NULL
; 
1504                                 printf("Connecting to host %s with SSL V3...", pargs
.hostName
); 
1507                         err 
= sslPing(&pargs
); 
1513                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_v3.0", fileBase
); 
1515                                 showSSLResult(&pargs
, 
1518                                         fileBase 
? fullFileBase 
: NULL
); 
1520                         CFReleaseNull(pargs
.peerCerts
); 
1522                                 /* deal with fallbacks, skipping redundant tests */ 
1523                                 switch(pargs
.negVersion
) { 
1530                                 ourRtn 
+= verifyProtocol(verifyProt
, maxProtocol
, kSSLProtocol3
, 
1533                         /* note we do this regardless since the client state might be 
1534                          * the cause of a failure */ 
1535                         ourRtn 
+= verifyClientCertState(vfyCertState
, expectCertState
, 
1541                 snprintf(fullFileBase
, _maxFileStringSize
, "%s_v2", fileBase
); 
1544                                 printf("Connecting to host %s with SSL V2...", pargs
.hostName
); 
1547                         pargs
.tryVersion 
= kSSLProtocol2
; 
1548                         pargs
.acceptedProts 
= NULL
; 
1549                         err 
= sslPing(&pargs
); 
1555                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_v2", fileBase
); 
1557                                 showSSLResult(&pargs
, 
1560                                         fileBase 
? fullFileBase 
: NULL
); 
1562                         CFReleaseNull(pargs
.peerCerts
); 
1564                                 ourRtn 
+= verifyProtocol(verifyProt
, maxProtocol
, kSSLProtocol2
, 
1567                         /* note we do this regardless since the client state might be 
1568                          * the cause of a failure */ 
1569                         ourRtn 
+= verifyClientCertState(vfyCertState
, expectCertState
, 
1574                                 printf("Connecting to host %s with kSSLProtocolUnknown...", 
1578                         pargs
.tryVersion 
= kSSLProtocolUnknown
; 
1579                         pargs
.acceptedProts 
= NULL
; 
1580                         err 
= sslPing(&pargs
); 
1586                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_def", fileBase
); 
1588                                 showSSLResult(&pargs
, 
1591                                         fileBase 
? fullFileBase 
: NULL
); 
1593                         CFReleaseNull(pargs
.peerCerts
); 
1595                 if(acceptedProts 
!= NULL
) { 
1596                         pargs
.acceptedProts 
= acceptedProts
; 
1597                         pargs
.tryVersion 
= kSSLProtocolUnknown
; // not used 
1599                                 printf("Connecting to host %s with acceptedProts %s...", 
1600                                         pargs
.hostName
, pargs
.acceptedProts
); 
1603                         err 
= sslPing(&pargs
); 
1609                     snprintf(fullFileBase
, _maxFileStringSize
, "%s_def", fileBase
); 
1611                                 showSSLResult(&pargs
, 
1614                                         fileBase 
? fullFileBase 
: NULL
); 
1616                         CFReleaseNull(pargs
.peerCerts
); 
1620                                  /* pause after first, before last to grab trace */ 
1621                          ((loop 
== 0) || (loop 
== loopCount 
- 1)) 
1626                         printf("a to abort, c to continue: "); 
1627                         resp 
= (char) getchar(); 
1633         if(displayHandshakeTimes
) { 
1634                 CFAbsoluteTime totalTime
; 
1635                 unsigned numHandshakes
; 
1636                 if(pargs
.numHandshakes 
== 1) { 
1637                         /* just display the first one */ 
1638                         totalTime 
= pargs
.handshakeTimeFirst
; 
1642                         /* skip the first one */ 
1643                         totalTime 
= pargs
.handshakeTimeTotal
; 
1644                         numHandshakes 
= pargs
.numHandshakes 
- 1; 
1646                 if(numHandshakes 
!= 0) { 
1647                         printf("   %u handshakes in %f seconds; %f seconds per handshake\n", 
1648                                 numHandshakes
, totalTime
, 
1649                                 (totalTime 
/ numHandshakes
)); 
1654                 printf("===%s exiting with %d %s for host %s\n", argv
[0], ourRtn
, 
1655                         (ourRtn 
> 1) ? "errors" : "error", pargs
.hostName
);