/* * Copyright (c) 2006-2013 Apple Inc. All Rights Reserved. * * SSL viewer tool, SecureTransport / Aspen version. */ #include #include // for SSLGetPeerSecTrust #include #include "sslAppUtils.h" #include "ioSock.h" #include "utilities/fileIo.h" #include "utilities/SecCFWrappers.h" #include #include #include #include #include #include #include #include "SecurityTool/print_cert.h" #include #if NO_SERVER #include #endif #define DEFAULT_GETMSG "GET" #define DEFAULT_PATH "/" #define DEFAULT_GET_SUFFIX "HTTP/1.0\r\n\r\n" #define DEFAULT_HOST "www.amazon.com" #define DEFAULT_PORT 443 #include static void usageNorm(char **argv) { printf("Usage: %s [hostname|-] [path] [option ...]\n", argv[0]); printf(" %s hostname [path] [option ...]\n", argv[0]); printf("Specifying '-' for hostname, or no args, uses default of %s.\n", DEFAULT_HOST); printf("Optional path argument must start with leading '/'.\n"); printf("Options:\n"); printf(" e Allow Expired Certs\n"); printf(" E Allow Expired Roots\n"); printf(" r Allow any root cert\n"); printf(" c Display peer certs\n"); printf(" c c Display peer SecTrust\n"); printf(" d Display received data\n"); printf(" 2 SSLv2 only (default is TLSv1)\n"); printf(" 3 SSLv3 only (default is TLSv1)\n"); printf(" t TLSv1\n"); printf(" %% TLSv1.1 only\n"); printf(" ^ TLSv1.2 only\n"); printf(" L all - TLSv1.2, TLSv1.1, TLSv1.0, SSLv3, SSLv2 (default = TLSv1.2)\n"); printf(" g={prot...} Specify legal protocols; prot = any combo of" " [23t]\n"); printf(" k=keychain Contains cert and keys. Optional.\n"); printf(" l=loopCount Perform loopCount ops (default = 1)\n"); printf(" P=port Default = %d\n", DEFAULT_PORT); printf(" p Pause after each loop\n"); printf(" q Quiet/diagnostic mode (site names and errors" " only)\n"); printf(" a fileName Add fileName to list of trusted roots\n"); printf(" A fileName fileName is ONLY trusted root\n"); printf(" x Disable Cert Verification\n"); printf(" z=password Unlock client keychain with password.\n"); printf(" 8 Complete cert chains (default is out cert is a root)\n"); printf(" s Silent\n"); printf(" V Verbose\n"); printf(" h Help\n"); printf(" hv More, verbose help\n"); } static void usageVerbose(char **argv) __attribute__((noreturn)); static void usageVerbose(char **argv) { usageNorm(argv); printf("Obscure Usage:\n"); printf(" u kSSLProtocolUnknown only (TLSv1)\n"); printf(" M Manual cert verification via " "SecTrustEvaluate\n"); printf(" f fileBase Write Peer Certs to fileBase*\n"); printf(" o TLSv1, SSLv3 use kSSLProtocol__X__Only\n"); printf(" C=cipherSuite (e=40-bit d=DES D=40-bit DES 3=3DES 4=RC4 " "$=40-bit RC4\n" " 2=RC2 a=AES128 A=AES256 h=DH H=Anon DH r=DHE/RSA s=DH/DSS\n"); printf(" y=keychain Encryption-only cert and keys. Optional.\n"); printf(" K Keep connected until server disconnects\n"); printf(" n Require closure notify message in TLSv1, " "SSLv3 mode (implies K)\n"); printf(" R Disable resumable session support\n"); printf(" b Non-blocking I/O\n"); printf(" v Verify negotiated protocol equals attempted\n"); printf(" m=[23t] Max protocol supported as specified; implies " "v\n"); printf(" T=[nrsj] Verify client cert state = " "none/requested/sent/rejected\n"); printf(" H allow hostname spoofing\n"); printf(" F=vfyHost Verify certs with specified host name\n"); printf(" G=getMsg Specify entire GET, POST, etc.\n"); printf(" N Log handshake timing\n"); printf(" 7 Pause only after first loop\n"); exit(1); } static void usage(char **argv) __attribute__((noreturn)); static void usage(char **argv) { usageNorm(argv); exit(1); } /* * Arguments to top-level sslPing() */ typedef struct { SSLProtocol tryVersion; // only used if acceptedProts NULL // uses SSLSetProtocolVersion char *acceptedProts; // optional, any combo of {2,3,t} // uses SSLSetProtocolVersionEnabled const char *hostName; // e.g., "www.amazon.com" const char *vfyHostName; // use this for cert vfy if non-NULL, // else use hostName unsigned short port; const char *getMsg; // e.g., // "GET / HTTP/1.0\r\n\r\n" bool allowExpired; bool allowAnyRoot; bool allowExpiredRoot; bool disableCertVerify; bool manualCertVerify; bool dumpRxData; // display server data char cipherRestrict; // '2', 'd'. etc...; '\0' for // no restriction bool keepConnected; bool requireNotify; // require closure notify // in V3 mode bool resumableEnable; bool allowHostnameSpoof; bool nonBlocking; char *anchorFile; bool replaceAnchors; CFArrayRef clientCerts; // optional CFArrayRef encryptClientCerts; // optional bool quiet; // minimal stdout bool silent; // no stdout bool verbose; SSLProtocol negVersion; // RETURNED SSLCipherSuite negCipher; // RETURNED CFArrayRef peerCerts; // mallocd & RETURNED SecTrustRef peerTrust; // RETURNED SSLClientCertificateState certState; // RETURNED char *password; // optional to open clientCerts char **argv; Boolean sessionWasResumed; unsigned char sessionID[MAX_SESSION_ID_LENGTH]; size_t sessionIDLength; CFAbsoluteTime handshakeTimeOp; // time for this op CFAbsoluteTime handshakeTimeFirst; // time for FIRST op, not averaged CFAbsoluteTime handshakeTimeTotal; // time for all ops except first unsigned numHandshakes; } sslPingArgs; #include static void sigpipe(int sig) { fflush(stdin); printf("***SIGPIPE***\n"); } /* * Snag a copy of current connection's peer certs so we can * examine them later after the connection is closed. * SecureTransport actually does the create and retain for us. */ static OSStatus copyPeerCerts( SSLContext *ctx, CFArrayRef *peerCerts) // mallocd & RETURNED { OSStatus ortn = SSLCopyPeerCertificates(ctx, peerCerts); if(ortn) { printf("***Error obtaining peer certs: %s\n", sslGetSSLErrString(ortn)); } return ortn; } /* free the cert array obtained via SSLGetPeerCertificates() */ static void freePeerCerts( CFArrayRef peerCerts) { if(peerCerts) { CFRelease(peerCerts); } } /* * Manually evaluate session's SecTrustRef. */ #define SSL_SEC_TRUST 1 static OSStatus sslEvaluateTrust( SSLContext *ctx, bool verbose, bool silent, CFArrayRef *peerCerts) // fetched and retained { OSStatus ortn = errSecSuccess; #if USE_CDSA_CRYPTO SecTrustRef secTrust = NULL; #if SSL_SEC_TRUST ortn = SSLGetPeerSecTrust(ctx, &secTrust); #else ortn = errSecUnimplemented; #endif if(ortn) { printf("\n***Error obtaining peer SecTrustRef: %s\n", sslGetSSLErrString(ortn)); return ortn; } if(secTrust == NULL) { /* this is the normal case for resumed sessions, in which * no cert evaluation is performed */ if(!silent) { printf("...No SecTrust available - this is a resumed session, right?\n"); } return errSecSuccess; } SecTrustResultType secTrustResult; ortn = SecTrustEvaluate(secTrust, &secTrustResult); if(ortn) { printf("\n***Error on SecTrustEvaluate: %d\n", (int)ortn); return ortn; } if(verbose) { char *res = NULL; switch(secTrustResult) { case kSecTrustResultInvalid: res = "kSecTrustResultInvalid"; break; case kSecTrustResultProceed: res = "kSecTrustResultProceed"; break; case kSecTrustResultConfirm: res = "kSecTrustResultConfirm"; break; case kSecTrustResultDeny: res = "kSecTrustResultDeny"; break; case kSecTrustResultUnspecified: res = "kSecTrustResultUnspecified"; break; case kSecTrustResultRecoverableTrustFailure: res = "kSecTrustResultRecoverableTrustFailure"; break; case kSecTrustResultFatalTrustFailure: res = "kSecTrustResultFatalTrustFailure"; break; case kSecTrustResultOtherError: res = "kSecTrustResultOtherError"; break; default: res = "UNKNOWN"; break; } printf("\nSecTrustEvaluate(): secTrustResult %s\n", res); } switch(secTrustResult) { case kSecTrustResultUnspecified: /* cert chain valid, no special UserTrust assignments */ case kSecTrustResultProceed: /* cert chain valid AND user explicitly trusts this */ break; default: printf("\n***SecTrustEvaluate reported secTrustResult %d\n", (int)secTrustResult); ortn = errSSLXCertChainInvalid; break; } #endif *peerCerts = NULL; #ifdef USE_CDSA_CRYPTO /* one more thing - get peer certs in the form of an evidence chain */ CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv; OSStatus thisRtn = SecTrustGetResult(secTrust, &secTrustResult, peerCerts, &dummyEv); if(thisRtn) { printSslErrStr("SecTrustGetResult", thisRtn); } else { /* workaround for the fact that SSLGetPeerCertificates() * leaves a retain count on each element in the returned array, * requiring us to do a release on each cert. */ CFIndex numCerts = CFArrayGetCount(*peerCerts); for(CFIndex dex=0; dex", ((unsigned)c) & 0xff); } break; } } printf("\n"); } /* * Perform one SSL diagnostic session. Returns nonzero on error. Normally no * output to stdout except initial "connecting to" message, unless there * is a really screwed up error (i.e., something not directly related * to the SSL connection). */ #define RCV_BUF_SIZE 256 static OSStatus sslPing( sslPingArgs *pargs) { PeerSpec peerId; otSocket sock = 0; OSStatus ortn; SSLContextRef ctx = NULL; size_t length; size_t actLen; uint8_t rcvBuf[RCV_BUF_SIZE]; CFAbsoluteTime startHandshake; CFAbsoluteTime endHandshake; pargs->negVersion = kSSLProtocolUnknown; pargs->negCipher = SSL_NULL_WITH_NULL_NULL; pargs->peerCerts = NULL; /* first make sure requested server is there */ ortn = MakeServerConnection(pargs->hostName, pargs->port, pargs->nonBlocking, &sock, &peerId); if(ortn) { printf("MakeServerConnection returned %d; aborting\n", (int)ortn); return ortn; } if(pargs->verbose) { printf("...connected to server; starting SecureTransport\n"); } /* * Set up a SecureTransport session. * First the standard calls. */ ortn = SSLNewContext(false, &ctx); if(ortn) { printSslErrStr("SSLNewContext", ortn); goto cleanup; } ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite); if(ortn) { printSslErrStr("SSLSetIOFuncs", ortn); goto cleanup; } ortn = SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)sock); if(ortn) { printSslErrStr("SSLSetConnection", ortn); goto cleanup; } SSLConnectionRef getConn; ortn = SSLGetConnection(ctx, &getConn); if(ortn) { printSslErrStr("SSLGetConnection", ortn); goto cleanup; } if(getConn != (SSLConnectionRef)(intptr_t)sock) { printf("***SSLGetConnection error\n"); ortn = errSecParam; goto cleanup; } if(!pargs->allowHostnameSpoof) { /* if this isn't set, it isn't checked by AppleX509TP */ const char *vfyHost = pargs->hostName; if(pargs->vfyHostName) { /* generally means we're expecting an error */ vfyHost = pargs->vfyHostName; } ortn = SSLSetPeerDomainName(ctx, vfyHost, strlen(vfyHost)); if(ortn) { printSslErrStr("SSLSetPeerDomainName", ortn); goto cleanup; } } /* * SecureTransport options. */ if(pargs->acceptedProts) { ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false); if(ortn) { printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn); goto cleanup; } for(const char *cp = pargs->acceptedProts; *cp; cp++) { SSLProtocol prot; switch(*cp) { case '2': prot = kSSLProtocol2; break; case '3': prot = kSSLProtocol3; break; case 't': prot = kTLSProtocol12; break; default: usage(pargs->argv); } ortn = SSLSetProtocolVersionEnabled(ctx, prot, true); if(ortn) { printSslErrStr("SSLSetProtocolVersionEnabled", ortn); goto cleanup; } } } else { ortn = SSLSetProtocolVersion(ctx, pargs->tryVersion); if(ortn) { printSslErrStr("SSLSetProtocolVersion", ortn); goto cleanup; } SSLProtocol getVers; ortn = SSLGetProtocolVersion(ctx, &getVers); if(ortn) { printSslErrStr("SSLGetProtocolVersion", ortn); goto cleanup; } if(getVers != pargs->tryVersion) { printf("***SSLGetProtocolVersion screwup: try %s get %s\n", sslGetProtocolVersionString(pargs->tryVersion), sslGetProtocolVersionString(getVers)); ortn = errSecParam; goto cleanup; } } if(pargs->resumableEnable) { const void *rtnId = NULL; size_t rtnIdLen = 0; ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec)); if(ortn) { printSslErrStr("SSLSetPeerID", ortn); goto cleanup; } /* quick test of the get fcn */ ortn = SSLGetPeerID(ctx, &rtnId, &rtnIdLen); if(ortn) { printSslErrStr("SSLGetPeerID", ortn); goto cleanup; } if((rtnId == NULL) || (rtnIdLen != sizeof(PeerSpec))) { printf("***SSLGetPeerID screwup\n"); } else if(memcmp(&peerId, rtnId, rtnIdLen) != 0) { printf("***SSLGetPeerID data mismatch\n"); } } if(pargs->allowExpired) { ortn = SSLSetAllowsExpiredCerts(ctx, true); if(ortn) { printSslErrStr("SSLSetAllowExpiredCerts", ortn); goto cleanup; } } if(pargs->allowExpiredRoot) { ortn = SSLSetAllowsExpiredRoots(ctx, true); if(ortn) { printSslErrStr("SSLSetAllowsExpiredRoots", ortn); goto cleanup; } } if(pargs->disableCertVerify) { ortn = SSLSetEnableCertVerify(ctx, false); if(ortn) { printSslErrStr("SSLSetEnableCertVerify", ortn); goto cleanup; } } if(pargs->allowAnyRoot) { ortn = SSLSetAllowsAnyRoot(ctx, true); if(ortn) { printSslErrStr("SSLSetAllowAnyRoot", ortn); goto cleanup; } } if(pargs->cipherRestrict != '\0') { ortn = sslSetCipherRestrictions(ctx, pargs->cipherRestrict); if(ortn) { goto cleanup; } } if(pargs->anchorFile) { ortn = sslAddTrustedRoot(ctx, pargs->anchorFile, pargs->replaceAnchors); if(ortn) { printf("***Error obtaining anchor file %s\n", pargs->anchorFile); goto cleanup; } } if(pargs->clientCerts) { CFArrayRef dummy; if(pargs->anchorFile == NULL) { /* assume this is a root we want to implicitly trust */ ortn = addIdentityAsTrustedRoot(ctx, pargs->clientCerts); if(ortn) { goto cleanup; } } ortn = SSLSetCertificate(ctx, pargs->clientCerts); if(ortn) { printSslErrStr("SSLSetCertificate", ortn); goto cleanup; } /* quickie test for this new function */ ortn = SSLGetCertificate(ctx, &dummy); if(ortn) { printSslErrStr("SSLGetCertificate", ortn); goto cleanup; } if(dummy != pargs->clientCerts) { printf("***SSLGetCertificate error\n"); ortn = errSecIO; goto cleanup; } } if(pargs->encryptClientCerts) { if(pargs->anchorFile == NULL) { ortn = addIdentityAsTrustedRoot(ctx, pargs->encryptClientCerts); if(ortn) { goto cleanup; } } ortn = SSLSetEncryptionCertificate(ctx, pargs->encryptClientCerts); if(ortn) { printSslErrStr("SSLSetEncryptionCertificate", ortn); goto cleanup; } } /*** end options ***/ if(pargs->verbose) { printf("...starting SSL handshake\n"); } startHandshake = CFAbsoluteTimeGetCurrent(); do { ortn = SSLHandshake(ctx); if((ortn == errSSLWouldBlock) && !pargs->silent) { /* keep UI responsive */ sslOutputDot(); } } while (ortn == errSSLWouldBlock); endHandshake = CFAbsoluteTimeGetCurrent(); pargs->handshakeTimeOp = endHandshake - startHandshake; if(pargs->numHandshakes == 0) { /* special case, this one is always way longer */ pargs->handshakeTimeFirst = pargs->handshakeTimeOp; } else { /* normal running total */ pargs->handshakeTimeTotal += pargs->handshakeTimeOp; } pargs->numHandshakes++; /* this works even if handshake failed due to cert chain invalid */ if(!pargs->manualCertVerify) { copyPeerCerts(ctx, &pargs->peerCerts); } else { /* else fetched via SecTrust later */ pargs->peerCerts = NULL; } ortn = SSLCopyPeerTrust(ctx, &pargs->peerTrust); if(ortn) { printf("***SSLCopyPeerTrust error %" PRIdOSStatus "\n", ortn); pargs->peerTrust = NULL; } /* ditto */ SSLGetClientCertificateState(ctx, &pargs->certState); SSLGetNegotiatedCipher(ctx, &pargs->negCipher); SSLGetNegotiatedProtocolVersion(ctx, &pargs->negVersion); pargs->sessionIDLength = MAX_SESSION_ID_LENGTH; SSLGetResumableSessionInfo(ctx, &pargs->sessionWasResumed, pargs->sessionID, &pargs->sessionIDLength); if(pargs->manualCertVerify) { OSStatus certRtn = sslEvaluateTrust(ctx, pargs->verbose, pargs->silent, &pargs->peerCerts); if(certRtn && !ortn ) { ortn = certRtn; } } if(ortn) { if(!pargs->silent) { printf("\n"); } goto cleanup; } if(pargs->verbose) { printf("...SSL handshake complete\n"); } length = strlen(pargs->getMsg); (void) SSLWrite(ctx, pargs->getMsg, length, &actLen); /* * Try to snag RCV_BUF_SIZE bytes. Exit if (!keepConnected and we get any data * at all), or (keepConnected and err != (none, wouldBlock)). */ while (1) { actLen = 0; if(pargs->dumpRxData) { size_t avail = 0; ortn = SSLGetBufferedReadSize(ctx, &avail); if(ortn) { printf("***SSLGetBufferedReadSize error\n"); break; } if(avail != 0) { printf("\n%d bytes available: ", (int)avail); } } ortn = SSLRead(ctx, rcvBuf, RCV_BUF_SIZE, &actLen); if((actLen == 0) && !pargs->silent) { sslOutputDot(); } if((actLen == 0) && (ortn == errSecSuccess)) { printf("***Radar 2984932 confirmed***\n"); } if (ortn == errSSLWouldBlock) { /* for this loop, these are identical */ ortn = errSecSuccess; } if((actLen > 0) && pargs->dumpRxData) { dumpAscii(rcvBuf, actLen); } if(ortn != errSecSuccess) { /* connection closed by server or by error */ break; } if(!pargs->keepConnected && (actLen > 0)) { /* good enough, we connected */ break; } } if(!pargs->silent) { printf("\n"); } /* snag these again in case of renegotiate */ SSLGetClientCertificateState(ctx, &pargs->certState); SSLGetNegotiatedCipher(ctx, &pargs->negCipher); SSLGetNegotiatedProtocolVersion(ctx, &pargs->negVersion); /* convert normal "shutdown" into zero err rtn */ if(ortn == errSSLClosedGraceful) { ortn = errSecSuccess; } if((ortn == errSSLClosedNoNotify) && !pargs->requireNotify) { /* relaxed disconnect rules */ ortn = errSecSuccess; } cleanup: /* * always do close, even on error - to flush outgoing write queue */ OSStatus cerr = SSLClose(ctx); if(ortn == errSecSuccess) { ortn = cerr; } if(sock) { endpointShutdown(sock); } if(ctx) { SSLDisposeContext(ctx); } return ortn; } static void add_key(const void *key, const void *value, void *context) { CFArrayAppendValue((CFMutableArrayRef)context, key); } static void showInfo(CFDictionaryRef info) { CFIndex dict_count, key_ix, key_count; CFMutableArrayRef keys = NULL; CFIndex maxWidth = 20; /* Maybe precompute this or grab from context? */ dict_count = CFDictionaryGetCount(info); keys = CFArrayCreateMutable(kCFAllocatorDefault, dict_count, &kCFTypeArrayCallBacks); CFDictionaryApplyFunction(info, add_key, keys); key_count = CFArrayGetCount(keys); CFArraySortValues(keys, CFRangeMake(0, key_count), (CFComparatorFunction)CFStringCompare, 0); for (key_ix = 0; key_ix < key_count; ++key_ix) { CFStringRef key = (CFStringRef)CFArrayGetValueAtIndex(keys, key_ix); CFTypeRef value = CFDictionaryGetValue(info, key); CFMutableStringRef line = CFStringCreateMutable(NULL, 0); CFStringAppend(line, key); CFIndex jx; for (jx = CFStringGetLength(key); jx < maxWidth; ++jx) { CFStringAppend(line, CFSTR(" ")); } CFStringAppend(line, CFSTR(" : ")); if (CFStringGetTypeID() == CFGetTypeID(value)) { CFStringAppend(line, (CFStringRef)value); } else if (CFDateGetTypeID() == CFGetTypeID(value)) { CFLocaleRef lc = CFLocaleCopyCurrent(); CFDateFormatterRef df = CFDateFormatterCreate(NULL, lc, kCFDateFormatterFullStyle, kCFDateFormatterFullStyle); CFDateRef date = (CFDateRef)value; CFStringRef ds = CFDateFormatterCreateStringWithDate(NULL, df, date); CFStringAppend(line, ds); CFRelease(ds); CFRelease(df); CFRelease(lc); } else if (CFURLGetTypeID() == CFGetTypeID(value)) { CFURLRef url = (CFURLRef)value; CFStringAppend(line, CFSTR("<")); CFStringAppend(line, CFURLGetString(url)); CFStringAppend(line, CFSTR(">")); } else if (CFDataGetTypeID() == CFGetTypeID(value)) { CFDataRef v_d = (CFDataRef)value; CFStringRef v_s = CFStringCreateFromExternalRepresentation( kCFAllocatorDefault, v_d, kCFStringEncodingUTF8); if (v_s) { CFStringAppend(line, CFSTR("/")); CFStringAppend(line, v_s); CFStringAppend(line, CFSTR("/ ")); CFRelease(v_s); } const uint8_t *bytes = CFDataGetBytePtr(v_d); CFIndex len = CFDataGetLength(v_d); for (jx = 0; jx < len; ++jx) { CFStringAppendFormat(line, NULL, CFSTR("%.02X"), bytes[jx]); } } else { CFStringAppendFormat(line, NULL, CFSTR("%@"), value); } CFStringWriteToFileWithNewline(line, stdout); CFRelease(line); } CFRelease(keys); } static void showPeerTrust(SecTrustRef peerTrust, bool verbose) { CFIndex numCerts; CFIndex i; if(peerTrust == NULL) { return; } printf("\n=============== Peer Trust Properties ===============\n"); CFArrayRef plist = SecTrustCopyProperties(peerTrust); if (plist) { print_plist(plist); CFRelease(plist); } printf("\n================== Peer Trust Info ==================\n"); CFDictionaryRef info = SecTrustCopyInfo(peerTrust); if (info && CFDictionaryGetCount(info)) { showInfo(info); } if (info) CFRelease(info); numCerts = SecTrustGetCertificateCount(peerTrust); for(i=0; i maxProtocol) { /* known not to support this attempt, relax */ reqProtocol = maxProtocol; } if(reqProtocol != negProtocol) { printf("***Expected protocol %s; negotiated %s\n", sslGetProtocolVersionString(reqProtocol), sslGetProtocolVersionString(negProtocol)); return 1; } else { return 0; } } static int verifyClientCertState( bool verifyCertState, SSLClientCertificateState expectState, SSLClientCertificateState gotState) { if(!verifyCertState) { return 0; } if(expectState == gotState) { return 0; } printf("***Expected clientCertState %s; got %s\n", sslGetClientCertStateString(expectState), sslGetClientCertStateString(gotState)); return 1; } static SSLProtocol charToProt( char c, // 2, 3, t char **argv) { switch(c) { case '2': return kSSLProtocol2; case '3': return kSSLProtocol3; case 't': return kTLSProtocol12; default: usage(argv); } /* NOT REACHED */ return kSSLProtocolUnknown; } int main(int argc, char **argv) { OSStatus err; int arg; char *argp; char getMsg[300]; char fullFileBase[100]; int ourRtn = 0; // exit status - sum of all errors unsigned loop; SecKeychainRef serverKc = nil; SecKeychainRef encryptKc = nil; sslPingArgs pargs; /* user-spec'd parameters */ const char *getPath = DEFAULT_PATH; char *fileBase = NULL; int displayCerts = 0; bool doSslV2 = false; bool doSslV3 = false; bool doTlsV1 = true; bool doTlsV11 = false; bool doTlsV12 = false; bool protXOnly = false; // kSSLProtocol3Only, kTLSProtocol1Only bool doProtUnknown = false; unsigned loopCount = 1; bool doPause = false; bool pauseFirstLoop = false; bool verifyProt = false; SSLProtocol maxProtocol = kTLSProtocol12; // for verifying negotiated // protocol char *acceptedProts = NULL; char *keyChainName = NULL; char *encryptKeyChainName = NULL; char *getMsgSpec = NULL; bool vfyCertState = false; SSLClientCertificateState expectCertState = kSSLClientCertNone; bool displayHandshakeTimes = false; bool completeCertChain = false; /* special case - one arg of "h" or "-h" or "hv" */ if(argc == 2) { if((strcmp(argv[1], "h") == 0) || (strcmp(argv[1], "-h") == 0)) { usage(argv); } if(strcmp(argv[1], "hv") == 0) { usageVerbose(argv); } } /* set up defaults */ memset(&pargs, 0, sizeof(sslPingArgs)); pargs.hostName = DEFAULT_HOST; pargs.port = DEFAULT_PORT; pargs.resumableEnable = true; pargs.argv = argv; for(arg=1; arg 1) ? "errors" : "error", pargs.hostName); } return ourRtn; }