X-Git-Url: https://git.saurik.com/apple/security.git/blobdiff_plain/ce3c8656732c924baf7e88df75eab50891bdc471..fa7225c82381bac4432a6edf16f53b5370238d85:/OSX/libsecurity_ssl/sslViewer/sslViewer.cpp diff --git a/OSX/libsecurity_ssl/sslViewer/sslViewer.cpp b/OSX/libsecurity_ssl/sslViewer/sslViewer.cpp deleted file mode 100644 index eca0ed36..00000000 --- a/OSX/libsecurity_ssl/sslViewer/sslViewer.cpp +++ /dev/null @@ -1,1870 +0,0 @@ -/* - * Copyright (c) 2006-2013 Apple Inc. All Rights Reserved. - * - * SSL viewer tool, Secure Transport. - */ - -#include "SecureTransport.h" - -#include -#include -#include -#include -#include -#include "sslAppUtils.h" -#include "printCert.h" -#include "ioSock.h" -#include "fileIo.h" - -#include -#include -#include -#include -#include -#include -#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 "store.apple.com" -#define DEFAULT_PORT 443 - -#define CFReleaseSafe(CF) { CFTypeRef _cf = (CF); if (_cf) CFRelease(_cf); } -#define CFReleaseNull(CF) { CFTypeRef _cf = (CF); \ - if (_cf) { (CF) = NULL; CFRelease(_cf); } } - -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(" cc Display peer SecTrust\n"); - printf(" d Display received data\n"); - printf(" S Display enabled cipher suites\n"); - printf(" 2 SSLv2 only\n"); - printf(" 3 SSLv3 only\n"); - printf(" tls10 | t TLSv1 only\n"); - printf(" tls11 TLSv1.1 only\n"); - printf(" tls12 TLSv1.2 only\n"); - printf(" L all - TLSv1.2, TLSv1.1, TLSv1, SSLv3, SSLv2 (default = TLSv1.2)\n"); - printf(" g={prot...} Specify legal protocols; prot = any combo of" - " [2|3|t|tls10|tls11|tls12]\n"); - printf(" k=keychain Contains (client|server) 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(" Z fileName fileName is a trusted leaf cert\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., "store.apple.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; - char *trustedLeafFile; - bool replaceAnchors; - bool interactiveAuth; - CFArrayRef clientCerts; // optional - CFArrayRef encryptClientCerts; // optional - uint32 sessionCacheTimeout;// optional - bool disableAnonCiphers; - bool showCipherSuites; - 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 -#if TARGET_OS_MAC && MAC_OS_X_VERSION_MAX_ALLOWED < 1060 - int authType; -#else - SSLClientAuthenticationType authType; // RETURNED -#endif - CFArrayRef dnList; // 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; -} - -/* - * Manually evaluate session's SecTrustRef. - */ - -static OSStatus sslEvaluateTrust( - SSLContext *ctx, - bool verbose, - bool silent, - CFArrayRef *peerCerts) // fetched and retained -{ - OSStatus ortn = errSecSuccess; -#if USE_CDSA_CRYPTO - SecTrustRef secTrust = NULL; - ortn = SSLGetPeerSecTrust(ctx, &secTrust); - 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) { - const 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); - } -#endif - return ortn; -} - -static void sslShowEnabledCipherSuites( - SSLContextRef ctx) -{ - OSStatus status; - SSLCipherSuite *ciphers; - size_t numCiphers, totalCiphers; - unsigned int i; - - status = SSLGetNumberSupportedCiphers(ctx, &totalCiphers); - status = SSLGetNumberEnabledCiphers(ctx, &numCiphers); - ciphers = (SSLCipherSuite *)malloc(sizeof(SSLCipherSuite) * numCiphers); - status = SSLGetEnabledCiphers(ctx, ciphers, &numCiphers); - - printf(" Total enabled ciphers : %ld of %ld\n", numCiphers, totalCiphers); - - for(i=0; i", ((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)sock); - if(ortn) { - printSslErrStr("SSLSetConnection", ortn); - goto cleanup; - } - SSLConnectionRef getConn; - ortn = SSLGetConnection(ctx, &getConn); - if(ortn) { - printSslErrStr("SSLGetConnection", ortn); - goto cleanup; - } - if(getConn != (SSLConnectionRef)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 = kTLSProtocol1; - if (cp[1] == 'l' && cp[2] == 's' && cp[3] == '1') { - cp += 3; - if (cp[1] == '1') { - cp++; - prot = kTLSProtocol11; - } - else if (cp[1] == '2') { - cp++; - 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 && getVers != kSSLProtocolAll) { - 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->trustedLeafFile) { - SecCertificateRef leafCertRef = NULL; - CFMutableArrayRef leafCerts = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - /* sslReadAnchor is a misnomer; it just creates a SecCertificateRef from a file */ - ortn = sslReadAnchor(pargs->trustedLeafFile, &leafCertRef); - if (!ortn) { - CFArrayAppendValue(leafCerts, leafCertRef); - CFRelease(leafCertRef); - ortn = SSLSetTrustedLeafCertificates(ctx, leafCerts); - CFRelease(leafCerts); - } - if(ortn) { - goto cleanup; - } - } - if(pargs->interactiveAuth) { - /* we want to get errSSLServerAuthCompleted from SSLHandshake on server auth completion */ - SSLSetSessionOption(ctx, kSSLSessionOptionBreakOnServerAuth, true); - /* we want to get errSSLClientCertRequested from SSLHandshake on client auth request */ - SSLSetSessionOption(ctx, kSSLSessionOptionBreakOnCertRequested, true); - } - else 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; - } - } - if(pargs->sessionCacheTimeout) { - ortn = SSLSetSessionCacheTimeout(ctx, pargs->sessionCacheTimeout); - if(ortn) { - printSslErrStr("SSLSetSessionCacheTimeout", ortn); - goto cleanup; - } - } - if(!pargs->disableAnonCiphers) { - ortn = SSLSetAllowAnonymousCiphers(ctx, true); - if(ortn) { - printSslErrStr("SSLSetAllowAnonymousCiphers", ortn); - goto cleanup; - } - /* quickie test of the getter */ - Boolean e; - ortn = SSLGetAllowAnonymousCiphers(ctx, &e); - if(ortn) { - printSslErrStr("SSLGetAllowAnonymousCiphers", ortn); - goto cleanup; - } - if(!e) { - printf("***SSLGetAllowAnonymousCiphers() returned false; expected true\n"); - ortn = errSecIO; - goto cleanup; - } - } - if(pargs->showCipherSuites) { - sslShowEnabledCipherSuites(ctx); - } - /*** 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(); - } - else if(ortn == errSSLServerAuthCompleted) { - if(pargs->verbose) { - printf("...server authentication completed\n"); - } - } - else if(ortn == errSSLClientCertRequested) { - if(pargs->verbose) { - printf("...received client cert request\n"); - } - /* %%% could prompt interactively here for client cert to use; - * for now, just use the client cert passed on the command line - */ - 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; - } - } - if(pargs->verbose) { - printf("...setting client certificate\n"); - } - 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; - } - } - else { - printf("***no client certificate specified!\n"); - } - } - } while (ortn == errSSLWouldBlock || - ortn == errSSLServerAuthCompleted || - ortn == errSSLClientCertRequested); - - 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 */ - CFReleaseSafe(pargs->peerCerts); - 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 %d\n", (int)ortn); - pargs->peerTrust = NULL; - } - - /* ditto */ - SSLGetClientCertificateState(ctx, &pargs->certState); -#if TARGET_OS_MAC && MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 - SSLGetNegotiatedClientAuthType(ctx, &pargs->authType); -#endif - SSLGetNegotiatedCipher(ctx, &pargs->negCipher); - SSLGetNegotiatedProtocolVersion(ctx, &pargs->negVersion); - CFReleaseSafe(pargs->dnList); - SSLCopyDistinguishedNames(ctx, &pargs->dnList); - 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"); - } - - /* Write our GET request */ - length = strlen(pargs->getMsg); - ortn = SSLWrite(ctx, pargs->getMsg, length, &actLen); - if(ortn) { - printf("***SSLWrite error: %d\n", (int)ortn); - } else if((actLen > 0) && pargs->dumpRxData) { - dumpAscii((uint8_t*)pargs->getMsg, 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 (ortn == errSecSuccess) { - 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(ortn == errSSLServerAuthCompleted || - ortn == errSSLClientCertRequested) { - /* should never get these once the handshake is complete */ - printf("***SSLRead returned unexpected handshake error!\n"); - } - - 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); - CFReleaseSafe(pargs->dnList); - SSLCopyDistinguishedNames(ctx, &pargs->dnList); - - /* 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); - } - print_line(line); - CFRelease(line); - } - CFRelease(keys); -} - -static void showPeerTrust(SecTrustRef peerTrust, bool verbose) { - CFIndex numCerts; - CFIndex i; - - if(peerTrust == NULL) { - return; - } -#if TARGET_OS_EMBEDDED - 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); - CFRelease(info); - } - - numCerts = SecTrustGetCertificateCount(peerTrust); - for(i=0; i= 1060 - printf(" Client Auth Type : %s\n", - sslGetClientAuthTypeString(pargs.authType)); -#endif - } - if(pargs.verbose) { - printf(" Resumed Session : "); - if(pargs.sessionWasResumed) { - for(unsigned dex=0; dex 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; -} - -/* - * Free everything allocated by sslPing in an sslPingArgs. - * Mainly for looping and malloc debugging. - */ -static void freePingArgs( - sslPingArgs *pargs) -{ - CFReleaseNull(pargs->peerCerts); - CFReleaseNull(pargs->peerTrust); - CFReleaseNull(pargs->dnList); - /* more, later, for client retry/identity fetch */ -} - -static SSLProtocol strToProt( - const char *c, // 2, 3, t, tls10, tls11, tls12 - char **argv) -{ - if (c == NULL) - return kSSLProtocolUnknown; - - switch(c[0]) { - case '2': - return kSSLProtocol2; - case '3': - return kSSLProtocol3; - case 't': - if (c[1] == '\0') - return kTLSProtocol1; - if (c[1] == 'l' && c[2] == 's' && c[3] == '1') { - if (c[4] == '0') - return kTLSProtocol1; - if (c[4] == '1') - return kTLSProtocol11; - if (c[4] == '2') - 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 */ - char *getPath = (char *)DEFAULT_PATH; - char *fileBase = NULL; - bool displayCerts = false; - bool doSslV2 = false; - bool doSslV3 = false; - bool doTlsV1 = true; - bool doTlsV11 = true; - bool doTlsV12 = true; - 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; - char *dnFileBase = NULL; - - /* 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; - -} - -