1 /* sslPing.c - simple version sslPing test */
3 #include "testParams.h"
6 #include <Security/SecureTransport.h>
9 #include <security_utilities/threading.h>
10 #include <utilLib/common.h>
12 #define DEFAULT_GETMSG "GET / HTTP/1.0\r\n\r\n"
13 #define DEFAULT_PORT 443
15 #define LOCALHOST_RANGE 0
17 #define ALLOW_ANY_ROOT 0
20 * List of hosts. All support all three protocols and access to "/".
28 static const sslHostDef knownSslHosts
[] =
30 { "localhost", 1300 },
31 { "localhost", 1301 },
32 { "localhost", 1302 },
33 { "localhost", 1303 },
34 { "localhost", 1304 },
35 { "localhost", 1305 },
36 { "localhost", 1306 },
39 #else /* LOCALHOST_RANGE */
40 static const sslHostDef knownSslHosts
[] =
42 {"www.amazon.com", DEFAULT_PORT
},
43 {"store.apple.com", DEFAULT_PORT
},
44 {"www.thawte.com", DEFAULT_PORT
},
45 {"account.authorize.net", DEFAULT_PORT
},
46 {"gmail.google.com", DEFAULT_PORT
},
47 {"digitalid.verisign.com", DEFAULT_PORT
},
48 {"www.firstamlink.com", DEFAULT_PORT
},
49 {"remote.harpercollins.com", DEFAULT_PORT
},
50 {"mbanxonlinebanking.harrisbank.com", DEFAULT_PORT
},
52 #endif /* LOCALHOST_RANGE */
53 #define NUM_KNOWN_HOSTS (sizeof(knownSslHosts) / sizeof(sslHostDef))
55 /* for memory leak debug only, with only one thread running */
59 * Snag test-specific opts.
61 * -- [23t] for SSL2, SSL3, TLS1 only operation. Default is all, randomly.
62 * -- m - multi sites; default is just one
63 * -- r - enable resumable sessions.
66 static SSLProtocol globalTryProt
= kSSLProtocolUnknown
;
67 static const char *globalProtStr
= NULL
;
68 static bool justOneHost
= 1;
71 * Enable resumable sessions. Setting this true exercises the session cache
72 * logic in ST but significantly decreases the testing of most of the
73 * rest of the handshaking (including cert chain verification).
74 * Also, when this is true, once a given site has negotiated a given
75 * protocol version, ST disallows negotiation of a higher version with
78 static bool resumeEnable
= 0;
81 int sslPingInit(TestParams
*testParams
)
86 if(testParams
->testOpts
== NULL
) {
91 for(testOpts
=testParams
->testOpts
; *testOpts
; testOpts
++) {
94 globalTryProt
= kSSLProtocol2
;
95 globalProtStr
= "SSL2";
98 globalTryProt
= kSSLProtocol3Only
;
99 globalProtStr
= "SSL3";
102 globalTryProt
= kTLSProtocol1Only
;
103 globalProtStr
= "TLS1";
112 /* for other tests */
116 if(!testParams
->quiet
) {
117 printf("...sslPing using %s only\n", globalProtStr
);
124 /* gethostbyname, called by MakeServerConnection, is not thread-safe. */
125 static Mutex connectLock
;
127 #define ENABLE_SSL2 0
130 * Roll the dice and select a random host and SSL protocol
132 static const char *selectHostAndProt(
133 unsigned short &port
,
134 SSLProtocol
&tryProt
,
135 const char *&protStr
)
139 appGetRandomBytes(r
, 2);
140 if(globalTryProt
!= kSSLProtocolUnknown
) {
141 /* user spec'd at cmd line */
142 tryProt
= globalTryProt
;
143 protStr
= globalProtStr
;
146 unsigned modulo
= ENABLE_SSL2
? 5 : 4;
147 switch(r
[0] % modulo
) {
149 tryProt
= kSSLProtocol3
;
153 tryProt
= kSSLProtocol3Only
;
154 protStr
= "SSL3Only";
157 tryProt
= kTLSProtocol1
;
161 tryProt
= kTLSProtocol1Only
;
162 protStr
= "TLS1Only";
165 tryProt
= kSSLProtocol2
;
173 const sslHostDef
*hostDef
;
175 hostDef
= &knownSslHosts
[0];
178 hostDef
= &(knownSslHosts
[r
[1] % NUM_KNOWN_HOSTS
]);
180 port
= hostDef
->port
;
181 return hostDef
->hostName
;
185 * Perform one SSL diagnostic session. Returns nonzero on error. Normally no
186 * output to stdout except initial "connecting to" message, unless there
187 * is a really screwed up error (i.e., something not directly related
188 * to the SSL conection).
190 #define RCV_BUF_SIZE 256
192 static OSStatus
doSslPing(
193 SSLProtocol tryVersion
,
194 const char *hostName
, // e.g., "www.amazon.com"
196 const char *getMsg
, // e.g., "GET / HTTP/1.0\r\n\r\n"
197 CSSM_BOOL allowExpired
,
198 CSSM_BOOL keepConnected
,
199 CSSM_BOOL requireNotify
, // require closure notify in V3 mode
200 SSLProtocol
*negVersion
, // RETURNED
201 SSLCipherSuite
*negCipher
) // RETURNED
206 SSLContextRef ctx
= NULL
;
209 uint8 rcvBuf
[RCV_BUF_SIZE
];
211 *negVersion
= kSSLProtocolUnknown
;
212 *negCipher
= SSL_NULL_WITH_NULL_NULL
;
214 /* first make sure requested server is there */
216 ortn
= MakeServerConnection(hostName
, port
, &sock
, &peerId
);
217 connectLock
.unlock();
219 printf("MakeServerConnection(%s) returned %d; aborting\n",
220 hostName
, (int)ortn
);
225 * Set up a SecureTransport session.
226 * First the standard calls.
228 ortn
= SSLNewContext(false, &ctx
);
230 printSslErrStr("SSLNewContext", ortn
);
233 ortn
= SSLSetIOFuncs(ctx
, SocketRead
, SocketWrite
);
235 printSslErrStr("SSLSetIOFuncs", ortn
);
238 ortn
= SSLSetProtocolVersion(ctx
, tryVersion
);
240 printSslErrStr("SSLSetProtocolVersion", ortn
);
243 ortn
= SSLSetConnection(ctx
, (SSLConnectionRef
)sock
);
245 printSslErrStr("SSLSetConnection", ortn
);
249 ortn
= SSLSetPeerID(ctx
, &peerId
, sizeof(PeerSpec
));
251 printSslErrStr("SSLSetPeerID", ortn
);
257 * SecureTransport options.
260 ortn
= SSLSetAllowsExpiredCerts(ctx
, true);
262 printSslErrStr("SSLSetAllowExpiredCerts", ortn
);
268 ortn
= SSLSetAllowsAnyRoot(ctx
, true);
270 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
276 { ortn
= SSLHandshake(ctx
);
277 if(ortn
== errSSLWouldBlock
) {
278 /* keep UI responsive */
281 } while (ortn
== errSSLWouldBlock
);
283 /* this works even if handshake failed due to cert chain invalid */
284 // not for this version... copyPeerCerts(ctx, peerCerts);
286 SSLGetNegotiatedCipher(ctx
, negCipher
);
287 SSLGetNegotiatedProtocolVersion(ctx
, negVersion
);
294 length
= strlen(getMsg
);
295 ortn
= SSLWrite(ctx
, getMsg
, length
, &actLen
);
298 * Try to snag RCV_BUF_SIZE bytes. Exit if (!keepConnected and we get any data
299 * at all), or (keepConnected and err != (none, wouldBlock)).
303 ortn
= SSLRead(ctx
, rcvBuf
, RCV_BUF_SIZE
, &actLen
);
307 if (ortn
== errSSLWouldBlock
) {
308 /* for this loop, these are identical */
311 // if((actLen > 0) && dumpRxData) {
312 // not here... dumpAscii(rcvBuf, actLen);
316 /* connection closed by server or by error */
320 else if(actLen
> 0) {
321 /* good enough, we connected */
327 /* convert normal "shutdown" into zero err rtn */
328 if(ortn
== errSSLClosedGraceful
) {
331 if((ortn
== errSSLClosedNoNotify
) && !requireNotify
) {
332 /* relaxed disconnect rules */
336 ortn
= SSLClose(ctx
);
340 endpointShutdown(sock
);
343 SSLDisposeContext(ctx
);
348 int sslPing(TestParams
*testParams
)
351 SSLProtocol negVersion
;
352 SSLProtocol tryVersion
;
353 const char *hostName
;
355 SSLCipherSuite negCipher
;
359 for(loopNum
=0; loopNum
<testParams
->numLoops
; loopNum
++) {
360 if(!testParams
->quiet
) {
361 printChar(testParams
->progressChar
);
363 hostName
= selectHostAndProt(port
, tryVersion
, protStr
);
364 if(testParams
->verbose
) {
365 printf("\nConnecting to host %s with %s...",
369 err
= doSslPing(tryVersion
,
373 CSSM_FALSE
, // allowExpired
374 CSSM_FALSE
, // keepConnected
375 CSSM_FALSE
, // requireNotify
379 printf("sslPing error (%d)\n", (int)err
);
382 if(testParams
->verbose
) {
385 printf("negVersion = SSL2\n");
388 printf("negVersion = SSL3\n");
391 printf("negVersion = TLS1\n");
394 printf("unknown negVersion! (%d)\n",
401 printf("Hit CR to proceed: ");