]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/threadTest/sslPing.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / threadTest / sslPing.cpp
1 /* sslPing.c - simple version sslPing test */
2
3 #include "testParams.h"
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <Security/SecureTransport.h>
7 #include "ioSockThr.h"
8 #include "testutil.h"
9 #include <security_utilities/threading.h>
10 #include <utilLib/common.h>
11
12 #define DEFAULT_GETMSG "GET / HTTP/1.0\r\n\r\n"
13 #define DEFAULT_PORT 443
14
15 #define LOCALHOST_RANGE 0
16
17 #define ALLOW_ANY_ROOT 0
18
19 /*
20 * List of hosts. All support all three protocols and access to "/".
21 */
22 typedef struct {
23 const char *hostName;
24 unsigned short port;
25 } sslHostDef;
26
27 #if LOCALHOST_RANGE
28 static const sslHostDef knownSslHosts[] =
29 {
30 { "localhost", 1300 },
31 { "localhost", 1301 },
32 { "localhost", 1302 },
33 { "localhost", 1303 },
34 { "localhost", 1304 },
35 { "localhost", 1305 },
36 { "localhost", 1306 },
37 { "localhost", 1307 }
38 };
39 #else /* LOCALHOST_RANGE */
40 static const sslHostDef knownSslHosts[] =
41 {
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},
51 };
52 #endif /* LOCALHOST_RANGE */
53 #define NUM_KNOWN_HOSTS (sizeof(knownSslHosts) / sizeof(sslHostDef))
54
55 /* for memory leak debug only, with only one thread running */
56 #define DO_PAUSE 0
57
58 /*
59 * Snag test-specific opts.
60 *
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.
64 */
65 static int initFlag;
66 static SSLProtocol globalTryProt = kSSLProtocolUnknown;
67 static const char *globalProtStr = NULL;
68 static bool justOneHost = 1;
69
70 /*
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
76 * that site.
77 */
78 static bool resumeEnable = 0;
79
80
81 int sslPingInit(TestParams *testParams)
82 {
83 if(initFlag) {
84 return 0;
85 }
86 if(testParams->testOpts == NULL) {
87 initFlag = 1;
88 return 0;
89 }
90 char *testOpts;
91 for(testOpts=testParams->testOpts; *testOpts; testOpts++) {
92 switch(*testOpts) {
93 case '2':
94 globalTryProt = kSSLProtocol2;
95 globalProtStr = "SSL2";
96 break;
97 case '3':
98 globalTryProt = kSSLProtocol3Only;
99 globalProtStr = "SSL3";
100 break;
101 case 't':
102 globalTryProt = kTLSProtocol1Only;
103 globalProtStr = "TLS1";
104 break;
105 case 'm':
106 justOneHost = 0;
107 break;
108 case 'r':
109 resumeEnable = 1;
110 break;
111 default:
112 /* for other tests */
113 break;
114 }
115 }
116 if(!testParams->quiet) {
117 printf("...sslPing using %s only\n", globalProtStr);
118 }
119 initFlag = 1;
120 return 0;
121 }
122
123
124 /* gethostbyname, called by MakeServerConnection, is not thread-safe. */
125 static Mutex connectLock;
126
127 #define ENABLE_SSL2 0
128
129 /*
130 * Roll the dice and select a random host and SSL protocol
131 */
132 static const char *selectHostAndProt(
133 unsigned short &port,
134 SSLProtocol &tryProt,
135 const char *&protStr)
136 {
137 unsigned char r[2];
138
139 appGetRandomBytes(r, 2);
140 if(globalTryProt != kSSLProtocolUnknown) {
141 /* user spec'd at cmd line */
142 tryProt = globalTryProt;
143 protStr = globalProtStr;
144 }
145 else {
146 unsigned modulo = ENABLE_SSL2 ? 5 : 4;
147 switch(r[0] % modulo) {
148 case 0:
149 tryProt = kSSLProtocol3;
150 protStr = "SSL3";
151 break;
152 case 1:
153 tryProt = kSSLProtocol3Only;
154 protStr = "SSL3Only";
155 break;
156 case 2:
157 tryProt = kTLSProtocol1;
158 protStr = "TLS1";
159 break;
160 case 3:
161 tryProt = kTLSProtocol1Only;
162 protStr = "TLS1Only";
163 break;
164 case 4:
165 tryProt = kSSLProtocol2;
166 protStr = "SSL2";
167 break;
168 default:
169 printf("Huh?\n");
170 exit(1);
171 }
172 }
173 const sslHostDef *hostDef;
174 if(justOneHost) {
175 hostDef = &knownSslHosts[0];
176 }
177 else {
178 hostDef = &(knownSslHosts[r[1] % NUM_KNOWN_HOSTS]);
179 }
180 port = hostDef->port;
181 return hostDef->hostName;
182 }
183
184 /*
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).
189 */
190 #define RCV_BUF_SIZE 256
191
192 static OSStatus doSslPing(
193 SSLProtocol tryVersion,
194 const char *hostName, // e.g., "www.amazon.com"
195 unsigned short port,
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
202 {
203 PeerSpec peerId;
204 otSocket sock = 0;
205 OSStatus ortn;
206 SSLContextRef ctx = NULL;
207 size_t length;
208 size_t actLen;
209 uint8 rcvBuf[RCV_BUF_SIZE];
210
211 *negVersion = kSSLProtocolUnknown;
212 *negCipher = SSL_NULL_WITH_NULL_NULL;
213
214 /* first make sure requested server is there */
215 connectLock.lock();
216 ortn = MakeServerConnection(hostName, port, &sock, &peerId);
217 connectLock.unlock();
218 if(ortn) {
219 printf("MakeServerConnection(%s) returned %d; aborting\n",
220 hostName, (int)ortn);
221 return ortn;
222 }
223
224 /*
225 * Set up a SecureTransport session.
226 * First the standard calls.
227 */
228 ortn = SSLNewContext(false, &ctx);
229 if(ortn) {
230 printSslErrStr("SSLNewContext", ortn);
231 goto cleanup;
232 }
233 ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
234 if(ortn) {
235 printSslErrStr("SSLSetIOFuncs", ortn);
236 goto cleanup;
237 }
238 ortn = SSLSetProtocolVersion(ctx, tryVersion);
239 if(ortn) {
240 printSslErrStr("SSLSetProtocolVersion", ortn);
241 goto cleanup;
242 }
243 ortn = SSLSetConnection(ctx, (SSLConnectionRef)sock);
244 if(ortn) {
245 printSslErrStr("SSLSetConnection", ortn);
246 goto cleanup;
247 }
248 if(resumeEnable) {
249 ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
250 if(ortn) {
251 printSslErrStr("SSLSetPeerID", ortn);
252 goto cleanup;
253 }
254 }
255
256 /*
257 * SecureTransport options.
258 */
259 if(allowExpired) {
260 ortn = SSLSetAllowsExpiredCerts(ctx, true);
261 if(ortn) {
262 printSslErrStr("SSLSetAllowExpiredCerts", ortn);
263 goto cleanup;
264 }
265 }
266
267 #if ALLOW_ANY_ROOT
268 ortn = SSLSetAllowsAnyRoot(ctx, true);
269 if(ortn) {
270 printSslErrStr("SSLSetAllowAnyRoot", ortn);
271 goto cleanup;
272 }
273 #endif
274
275 do
276 { ortn = SSLHandshake(ctx);
277 if(ortn == errSSLWouldBlock) {
278 /* keep UI responsive */
279 // outputDot();
280 }
281 } while (ortn == errSSLWouldBlock);
282
283 /* this works even if handshake failed due to cert chain invalid */
284 // not for this version... copyPeerCerts(ctx, peerCerts);
285
286 SSLGetNegotiatedCipher(ctx, negCipher);
287 SSLGetNegotiatedProtocolVersion(ctx, negVersion);
288
289 if(ortn) {
290 printf("\n");
291 goto cleanup;
292 }
293
294 length = strlen(getMsg);
295 ortn = SSLWrite(ctx, getMsg, length, &actLen);
296
297 /*
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)).
300 */
301 while (1) {
302 actLen = 0;
303 ortn = SSLRead(ctx, rcvBuf, RCV_BUF_SIZE, &actLen);
304 if(actLen == 0) {
305 // outputDot();
306 }
307 if (ortn == errSSLWouldBlock) {
308 /* for this loop, these are identical */
309 ortn = noErr;
310 }
311 // if((actLen > 0) && dumpRxData) {
312 // not here... dumpAscii(rcvBuf, actLen);
313 // }
314 if(keepConnected) {
315 if(ortn != noErr) {
316 /* connection closed by server or by error */
317 break;
318 }
319 }
320 else if(actLen > 0) {
321 /* good enough, we connected */
322 break;
323 }
324 }
325 //printf("\n");
326
327 /* convert normal "shutdown" into zero err rtn */
328 if(ortn == errSSLClosedGraceful) {
329 ortn = noErr;
330 }
331 if((ortn == errSSLClosedNoNotify) && !requireNotify) {
332 /* relaxed disconnect rules */
333 ortn = noErr;
334 }
335 if (ortn == noErr) {
336 ortn = SSLClose(ctx);
337 }
338 cleanup:
339 if(sock) {
340 endpointShutdown(sock);
341 }
342 if(ctx) {
343 SSLDisposeContext(ctx);
344 }
345 return ortn;
346 }
347
348 int sslPing(TestParams *testParams)
349 {
350 unsigned loopNum;
351 SSLProtocol negVersion;
352 SSLProtocol tryVersion;
353 const char *hostName;
354 unsigned short port;
355 SSLCipherSuite negCipher;
356 OSStatus err;
357 const char *protStr;
358
359 for(loopNum=0; loopNum<testParams->numLoops; loopNum++) {
360 if(!testParams->quiet) {
361 printChar(testParams->progressChar);
362 }
363 hostName = selectHostAndProt(port, tryVersion, protStr);
364 if(testParams->verbose) {
365 printf("\nConnecting to host %s with %s...",
366 hostName, protStr);
367 fflush(stdout);
368 }
369 err = doSslPing(tryVersion,
370 hostName,
371 port,
372 DEFAULT_GETMSG,
373 CSSM_FALSE, // allowExpired
374 CSSM_FALSE, // keepConnected
375 CSSM_FALSE, // requireNotify
376 &negVersion,
377 &negCipher);
378 if(err) {
379 printf("sslPing error (%d)\n", (int)err);
380 break;
381 }
382 if(testParams->verbose) {
383 switch(negVersion) {
384 case kSSLProtocol2:
385 printf("negVersion = SSL2\n");
386 break;
387 case kSSLProtocol3:
388 printf("negVersion = SSL3\n");
389 break;
390 case kTLSProtocol1:
391 printf("negVersion = TLS1\n");
392 break;
393 default:
394 printf("unknown negVersion! (%d)\n",
395 (int)negVersion);
396 break;
397 }
398 }
399 #if DO_PAUSE
400 fpurge(stdin);
401 printf("Hit CR to proceed: ");
402 getchar();
403 #endif
404 }
405 return (int)err;
406 }
407