+++ /dev/null
-/* sslPing.c - simple version sslPing test */
-
-#include "testParams.h"
-#include <stdlib.h>
-#include <stdio.h>
-#include <Security/SecureTransport.h>
-#include "ioSockThr.h"
-#include "testutil.h"
-#include <security_utilities/threading.h>
-#include <utilLib/common.h>
-
-#define DEFAULT_GETMSG "GET / HTTP/1.0\r\n\r\n"
-#define DEFAULT_PORT 443
-
-#define LOCALHOST_RANGE 0
-
-#define ALLOW_ANY_ROOT 0
-
-/*
- * List of hosts. All support all three protocols and access to "/".
- */
-typedef struct {
- const char *hostName;
- unsigned short port;
-} sslHostDef;
-
-#if LOCALHOST_RANGE
-static const sslHostDef knownSslHosts[] =
-{
- { "localhost", 1300 },
- { "localhost", 1301 },
- { "localhost", 1302 },
- { "localhost", 1303 },
- { "localhost", 1304 },
- { "localhost", 1305 },
- { "localhost", 1306 },
- { "localhost", 1307 }
-};
-#else /* LOCALHOST_RANGE */
-static const sslHostDef knownSslHosts[] =
-{
- {"www.amazon.com", DEFAULT_PORT },
- {"store.apple.com", DEFAULT_PORT },
- {"www.thawte.com", DEFAULT_PORT },
- {"account.authorize.net", DEFAULT_PORT },
- {"gmail.google.com", DEFAULT_PORT },
- {"digitalid.verisign.com", DEFAULT_PORT},
- {"www.firstamlink.com", DEFAULT_PORT},
- {"remote.harpercollins.com", DEFAULT_PORT},
- {"mbanxonlinebanking.harrisbank.com", DEFAULT_PORT},
-};
-#endif /* LOCALHOST_RANGE */
-#define NUM_KNOWN_HOSTS (sizeof(knownSslHosts) / sizeof(sslHostDef))
-
-/* for memory leak debug only, with only one thread running */
-#define DO_PAUSE 0
-
-/*
- * Snag test-specific opts.
- *
- * -- [23t] for SSL2, SSL3, TLS1 only operation. Default is all, randomly.
- * -- m - multi sites; default is just one
- * -- r - enable resumable sessions.
- */
-static int initFlag;
-static SSLProtocol globalTryProt = kSSLProtocolUnknown;
-static const char *globalProtStr = NULL;
-static bool justOneHost = 1;
-
-/*
- * Enable resumable sessions. Setting this true exercises the session cache
- * logic in ST but significantly decreases the testing of most of the
- * rest of the handshaking (including cert chain verification).
- * Also, when this is true, once a given site has negotiated a given
- * protocol version, ST disallows negotiation of a higher version with
- * that site.
- */
-static bool resumeEnable = 0;
-
-
-int sslPingInit(TestParams *testParams)
-{
- if(initFlag) {
- return 0;
- }
- if(testParams->testOpts == NULL) {
- initFlag = 1;
- return 0;
- }
- char *testOpts;
- for(testOpts=testParams->testOpts; *testOpts; testOpts++) {
- switch(*testOpts) {
- case '2':
- globalTryProt = kSSLProtocol2;
- globalProtStr = "SSL2";
- break;
- case '3':
- globalTryProt = kSSLProtocol3Only;
- globalProtStr = "SSL3";
- break;
- case 't':
- globalTryProt = kTLSProtocol1Only;
- globalProtStr = "TLS1";
- break;
- case 'm':
- justOneHost = 0;
- break;
- case 'r':
- resumeEnable = 1;
- break;
- default:
- /* for other tests */
- break;
- }
- }
- if(!testParams->quiet) {
- printf("...sslPing using %s only\n", globalProtStr);
- }
- initFlag = 1;
- return 0;
-}
-
-
-/* gethostbyname, called by MakeServerConnection, is not thread-safe. */
-static Mutex connectLock;
-
-#define ENABLE_SSL2 0
-
-/*
- * Roll the dice and select a random host and SSL protocol
- */
-static const char *selectHostAndProt(
- unsigned short &port,
- SSLProtocol &tryProt,
- const char *&protStr)
-{
- unsigned char r[2];
-
- appGetRandomBytes(r, 2);
- if(globalTryProt != kSSLProtocolUnknown) {
- /* user spec'd at cmd line */
- tryProt = globalTryProt;
- protStr = globalProtStr;
- }
- else {
- unsigned modulo = ENABLE_SSL2 ? 5 : 4;
- switch(r[0] % modulo) {
- case 0:
- tryProt = kSSLProtocol3;
- protStr = "SSL3";
- break;
- case 1:
- tryProt = kSSLProtocol3Only;
- protStr = "SSL3Only";
- break;
- case 2:
- tryProt = kTLSProtocol1;
- protStr = "TLS1";
- break;
- case 3:
- tryProt = kTLSProtocol1Only;
- protStr = "TLS1Only";
- break;
- case 4:
- tryProt = kSSLProtocol2;
- protStr = "SSL2";
- break;
- default:
- printf("Huh?\n");
- exit(1);
- }
- }
- const sslHostDef *hostDef;
- if(justOneHost) {
- hostDef = &knownSslHosts[0];
- }
- else {
- hostDef = &(knownSslHosts[r[1] % NUM_KNOWN_HOSTS]);
- }
- port = hostDef->port;
- return hostDef->hostName;
-}
-
-/*
- * 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 conection).
- */
-#define RCV_BUF_SIZE 256
-
-static OSStatus doSslPing(
- SSLProtocol tryVersion,
- const char *hostName, // e.g., "www.amazon.com"
- unsigned short port,
- const char *getMsg, // e.g., "GET / HTTP/1.0\r\n\r\n"
- CSSM_BOOL allowExpired,
- CSSM_BOOL keepConnected,
- CSSM_BOOL requireNotify, // require closure notify in V3 mode
- SSLProtocol *negVersion, // RETURNED
- SSLCipherSuite *negCipher) // RETURNED
-{
- PeerSpec peerId;
- otSocket sock = 0;
- OSStatus ortn;
- SSLContextRef ctx = NULL;
- size_t length;
- size_t actLen;
- uint8 rcvBuf[RCV_BUF_SIZE];
-
- *negVersion = kSSLProtocolUnknown;
- *negCipher = SSL_NULL_WITH_NULL_NULL;
-
- /* first make sure requested server is there */
- connectLock.lock();
- ortn = MakeServerConnection(hostName, port, &sock, &peerId);
- connectLock.unlock();
- if(ortn) {
- printf("MakeServerConnection(%s) returned %d; aborting\n",
- hostName, (int)ortn);
- return ortn;
- }
-
- /*
- * 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 = SSLSetProtocolVersion(ctx, tryVersion);
- if(ortn) {
- printSslErrStr("SSLSetProtocolVersion", ortn);
- goto cleanup;
- }
- ortn = SSLSetConnection(ctx, (SSLConnectionRef)sock);
- if(ortn) {
- printSslErrStr("SSLSetConnection", ortn);
- goto cleanup;
- }
- if(resumeEnable) {
- ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
- if(ortn) {
- printSslErrStr("SSLSetPeerID", ortn);
- goto cleanup;
- }
- }
-
- /*
- * SecureTransport options.
- */
- if(allowExpired) {
- ortn = SSLSetAllowsExpiredCerts(ctx, true);
- if(ortn) {
- printSslErrStr("SSLSetAllowExpiredCerts", ortn);
- goto cleanup;
- }
- }
-
- #if ALLOW_ANY_ROOT
- ortn = SSLSetAllowsAnyRoot(ctx, true);
- if(ortn) {
- printSslErrStr("SSLSetAllowAnyRoot", ortn);
- goto cleanup;
- }
- #endif
-
- do
- { ortn = SSLHandshake(ctx);
- if(ortn == errSSLWouldBlock) {
- /* keep UI responsive */
- // outputDot();
- }
- } while (ortn == errSSLWouldBlock);
-
- /* this works even if handshake failed due to cert chain invalid */
- // not for this version... copyPeerCerts(ctx, peerCerts);
-
- SSLGetNegotiatedCipher(ctx, negCipher);
- SSLGetNegotiatedProtocolVersion(ctx, negVersion);
-
- if(ortn) {
- printf("\n");
- goto cleanup;
- }
-
- length = strlen(getMsg);
- ortn = SSLWrite(ctx, 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;
- ortn = SSLRead(ctx, rcvBuf, RCV_BUF_SIZE, &actLen);
- if(actLen == 0) {
- // outputDot();
- }
- if (ortn == errSSLWouldBlock) {
- /* for this loop, these are identical */
- ortn = noErr;
- }
- // if((actLen > 0) && dumpRxData) {
- // not here... dumpAscii(rcvBuf, actLen);
- // }
- if(keepConnected) {
- if(ortn != noErr) {
- /* connection closed by server or by error */
- break;
- }
- }
- else if(actLen > 0) {
- /* good enough, we connected */
- break;
- }
- }
- //printf("\n");
-
- /* convert normal "shutdown" into zero err rtn */
- if(ortn == errSSLClosedGraceful) {
- ortn = noErr;
- }
- if((ortn == errSSLClosedNoNotify) && !requireNotify) {
- /* relaxed disconnect rules */
- ortn = noErr;
- }
- if (ortn == noErr) {
- ortn = SSLClose(ctx);
- }
-cleanup:
- if(sock) {
- endpointShutdown(sock);
- }
- if(ctx) {
- SSLDisposeContext(ctx);
- }
- return ortn;
-}
-
-int sslPing(TestParams *testParams)
-{
- unsigned loopNum;
- SSLProtocol negVersion;
- SSLProtocol tryVersion;
- const char *hostName;
- unsigned short port;
- SSLCipherSuite negCipher;
- OSStatus err;
- const char *protStr;
-
- for(loopNum=0; loopNum<testParams->numLoops; loopNum++) {
- if(!testParams->quiet) {
- printChar(testParams->progressChar);
- }
- hostName = selectHostAndProt(port, tryVersion, protStr);
- if(testParams->verbose) {
- printf("\nConnecting to host %s with %s...",
- hostName, protStr);
- fflush(stdout);
- }
- err = doSslPing(tryVersion,
- hostName,
- port,
- DEFAULT_GETMSG,
- CSSM_FALSE, // allowExpired
- CSSM_FALSE, // keepConnected
- CSSM_FALSE, // requireNotify
- &negVersion,
- &negCipher);
- if(err) {
- printf("sslPing error (%d)\n", (int)err);
- break;
- }
- if(testParams->verbose) {
- switch(negVersion) {
- case kSSLProtocol2:
- printf("negVersion = SSL2\n");
- break;
- case kSSLProtocol3:
- printf("negVersion = SSL3\n");
- break;
- case kTLSProtocol1:
- printf("negVersion = TLS1\n");
- break;
- default:
- printf("unknown negVersion! (%d)\n",
- (int)negVersion);
- break;
- }
- }
- #if DO_PAUSE
- fpurge(stdin);
- printf("Hit CR to proceed: ");
- getchar();
- #endif
- }
- return (int)err;
-}
-