]> git.saurik.com Git - apple/security.git/blob - sslViewer/SSLViewer.cpp
Security-57031.10.10.tar.gz
[apple/security.git] / sslViewer / SSLViewer.cpp
1 /*
2 * Copyright (c) 2006-2013 Apple Inc. All Rights Reserved.
3 *
4 * SSL viewer tool, SecureTransport / Aspen version.
5 */
6
7 #include <Security/SecureTransport.h>
8 #include <Security/SecureTransportPriv.h> // for SSLGetPeerSecTrust
9 #include <Security/SecTrustPriv.h>
10 #include "sslAppUtils.h"
11 #include "ioSock.h"
12 #include "utilities/fileIo.h"
13 #include "utilities/SecCFWrappers.h"
14
15 #include <Security/SecBase.h>
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <time.h>
21 #include <ctype.h>
22 #include <CoreFoundation/CoreFoundation.h>
23 #include "SecurityTool/print_cert.h"
24
25 #include <utilities/SecIOFormat.h>
26
27 #if NO_SERVER
28 #include <securityd/spi.h>
29 #endif
30
31 #define DEFAULT_GETMSG "GET"
32 #define DEFAULT_PATH "/"
33 #define DEFAULT_GET_SUFFIX "HTTP/1.0\r\n\r\n"
34
35 #define DEFAULT_HOST "www.amazon.com"
36 #define DEFAULT_PORT 443
37
38 #include <Security/SecCertificate.h>
39
40 static void usageNorm(char **argv)
41 {
42 printf("Usage: %s [hostname|-] [path] [option ...]\n", argv[0]);
43 printf(" %s hostname [path] [option ...]\n", argv[0]);
44 printf("Specifying '-' for hostname, or no args, uses default of %s.\n",
45 DEFAULT_HOST);
46 printf("Optional path argument must start with leading '/'.\n");
47 printf("Options:\n");
48 printf(" e Allow Expired Certs\n");
49 printf(" E Allow Expired Roots\n");
50 printf(" r Allow any root cert\n");
51 printf(" c Display peer certs\n");
52 printf(" c c Display peer SecTrust\n");
53 printf(" d Display received data\n");
54 printf(" 2 SSLv2 only (default is TLSv1)\n");
55 printf(" 3 SSLv3 only (default is TLSv1)\n");
56 printf(" t TLSv1\n");
57 printf(" %% TLSv1.1 only\n");
58 printf(" ^ TLSv1.2 only\n");
59 printf(" L all - TLSv1.2, TLSv1.1, TLSv1.0, SSLv3, SSLv2 (default = TLSv1.2)\n");
60 printf(" g={prot...} Specify legal protocols; prot = any combo of"
61 " [23t]\n");
62 printf(" k=keychain Contains cert and keys. Optional.\n");
63 printf(" l=loopCount Perform loopCount ops (default = 1)\n");
64 printf(" P=port Default = %d\n", DEFAULT_PORT);
65 printf(" p Pause after each loop\n");
66 printf(" q Quiet/diagnostic mode (site names and errors"
67 " only)\n");
68 printf(" a fileName Add fileName to list of trusted roots\n");
69 printf(" A fileName fileName is ONLY trusted root\n");
70 printf(" x Disable Cert Verification\n");
71 printf(" z=password Unlock client keychain with password.\n");
72 printf(" 8 Complete cert chains (default is out cert is a root)\n");
73 printf(" s Silent\n");
74 printf(" V Verbose\n");
75 printf(" h Help\n");
76 printf(" hv More, verbose help\n");
77 }
78
79 static void usageVerbose(char **argv) __attribute__((noreturn));
80 static void usageVerbose(char **argv)
81 {
82 usageNorm(argv);
83 printf("Obscure Usage:\n");
84 printf(" u kSSLProtocolUnknown only (TLSv1)\n");
85 printf(" M Manual cert verification via "
86 "SecTrustEvaluate\n");
87 printf(" f fileBase Write Peer Certs to fileBase*\n");
88 printf(" o TLSv1, SSLv3 use kSSLProtocol__X__Only\n");
89 printf(" C=cipherSuite (e=40-bit d=DES D=40-bit DES 3=3DES 4=RC4 "
90 "$=40-bit RC4\n"
91 " 2=RC2 a=AES128 A=AES256 h=DH H=Anon DH r=DHE/RSA s=DH/DSS\n");
92 printf(" y=keychain Encryption-only cert and keys. Optional.\n");
93 printf(" K Keep connected until server disconnects\n");
94 printf(" n Require closure notify message in TLSv1, "
95 "SSLv3 mode (implies K)\n");
96 printf(" R Disable resumable session support\n");
97 printf(" b Non-blocking I/O\n");
98 printf(" v Verify negotiated protocol equals attempted\n");
99 printf(" m=[23t] Max protocol supported as specified; implies "
100 "v\n");
101 printf(" T=[nrsj] Verify client cert state = "
102 "none/requested/sent/rejected\n");
103 printf(" H allow hostname spoofing\n");
104 printf(" F=vfyHost Verify certs with specified host name\n");
105 printf(" G=getMsg Specify entire GET, POST, etc.\n");
106 printf(" N Log handshake timing\n");
107 printf(" 7 Pause only after first loop\n");
108 exit(1);
109 }
110
111 static void usage(char **argv) __attribute__((noreturn));
112 static void usage(char **argv)
113 {
114 usageNorm(argv);
115 exit(1);
116 }
117
118 /*
119 * Arguments to top-level sslPing()
120 */
121 typedef struct {
122 SSLProtocol tryVersion; // only used if acceptedProts NULL
123 // uses SSLSetProtocolVersion
124 char *acceptedProts; // optional, any combo of {2,3,t}
125 // uses SSLSetProtocolVersionEnabled
126 const char *hostName; // e.g., "www.amazon.com"
127 const char *vfyHostName; // use this for cert vfy if non-NULL,
128 // else use hostName
129 unsigned short port;
130 const char *getMsg; // e.g.,
131 // "GET / HTTP/1.0\r\n\r\n"
132 bool allowExpired;
133 bool allowAnyRoot;
134 bool allowExpiredRoot;
135 bool disableCertVerify;
136 bool manualCertVerify;
137 bool dumpRxData; // display server data
138 char cipherRestrict; // '2', 'd'. etc...; '\0' for
139 // no restriction
140 bool keepConnected;
141 bool requireNotify; // require closure notify
142 // in V3 mode
143 bool resumableEnable;
144 bool allowHostnameSpoof;
145 bool nonBlocking;
146 char *anchorFile;
147 bool replaceAnchors;
148 CFArrayRef clientCerts; // optional
149 CFArrayRef encryptClientCerts; // optional
150 bool quiet; // minimal stdout
151 bool silent; // no stdout
152 bool verbose;
153 SSLProtocol negVersion; // RETURNED
154 SSLCipherSuite negCipher; // RETURNED
155 CFArrayRef peerCerts; // mallocd & RETURNED
156 SecTrustRef peerTrust; // RETURNED
157 SSLClientCertificateState certState; // RETURNED
158 char *password; // optional to open clientCerts
159 char **argv;
160 Boolean sessionWasResumed;
161 unsigned char sessionID[MAX_SESSION_ID_LENGTH];
162 size_t sessionIDLength;
163 CFAbsoluteTime handshakeTimeOp; // time for this op
164 CFAbsoluteTime handshakeTimeFirst; // time for FIRST op, not averaged
165 CFAbsoluteTime handshakeTimeTotal; // time for all ops except first
166 unsigned numHandshakes;
167
168 } sslPingArgs;
169
170 #include <signal.h>
171 static void sigpipe(int sig)
172 {
173 fflush(stdin);
174 printf("***SIGPIPE***\n");
175 }
176
177 /*
178 * Snag a copy of current connection's peer certs so we can
179 * examine them later after the connection is closed.
180 * SecureTransport actually does the create and retain for us.
181 */
182 static OSStatus copyPeerCerts(
183 SSLContext *ctx,
184 CFArrayRef *peerCerts) // mallocd & RETURNED
185 {
186 OSStatus ortn = SSLCopyPeerCertificates(ctx, peerCerts);
187 if(ortn) {
188 printf("***Error obtaining peer certs: %s\n",
189 sslGetSSLErrString(ortn));
190 }
191 return ortn;
192 }
193
194 /* free the cert array obtained via SSLGetPeerCertificates() */
195 static void freePeerCerts(
196 CFArrayRef peerCerts)
197 {
198 if(peerCerts) {
199 CFRelease(peerCerts);
200 }
201 }
202
203 /*
204 * Manually evaluate session's SecTrustRef.
205 */
206 #define SSL_SEC_TRUST 1
207
208 static OSStatus sslEvaluateTrust(
209 SSLContext *ctx,
210 bool verbose,
211 bool silent,
212 CFArrayRef *peerCerts) // fetched and retained
213 {
214 OSStatus ortn = errSecSuccess;
215 #if USE_CDSA_CRYPTO
216 SecTrustRef secTrust = NULL;
217
218 #if SSL_SEC_TRUST
219 ortn = SSLGetPeerSecTrust(ctx, &secTrust);
220 #else
221 ortn = errSecUnimplemented;
222 #endif
223 if(ortn) {
224 printf("\n***Error obtaining peer SecTrustRef: %s\n",
225 sslGetSSLErrString(ortn));
226 return ortn;
227 }
228 if(secTrust == NULL) {
229 /* this is the normal case for resumed sessions, in which
230 * no cert evaluation is performed */
231 if(!silent) {
232 printf("...No SecTrust available - this is a resumed session, right?\n");
233 }
234 return errSecSuccess;
235 }
236 SecTrustResultType secTrustResult;
237 ortn = SecTrustEvaluate(secTrust, &secTrustResult);
238 if(ortn) {
239 printf("\n***Error on SecTrustEvaluate: %d\n", (int)ortn);
240 return ortn;
241 }
242 if(verbose) {
243 char *res = NULL;
244 switch(secTrustResult) {
245 case kSecTrustResultInvalid:
246 res = "kSecTrustResultInvalid"; break;
247 case kSecTrustResultProceed:
248 res = "kSecTrustResultProceed"; break;
249 case kSecTrustResultConfirm:
250 res = "kSecTrustResultConfirm"; break;
251 case kSecTrustResultDeny:
252 res = "kSecTrustResultDeny"; break;
253 case kSecTrustResultUnspecified:
254 res = "kSecTrustResultUnspecified"; break;
255 case kSecTrustResultRecoverableTrustFailure:
256 res = "kSecTrustResultRecoverableTrustFailure"; break;
257 case kSecTrustResultFatalTrustFailure:
258 res = "kSecTrustResultFatalTrustFailure"; break;
259 case kSecTrustResultOtherError:
260 res = "kSecTrustResultOtherError"; break;
261 default:
262 res = "UNKNOWN"; break;
263 }
264 printf("\nSecTrustEvaluate(): secTrustResult %s\n", res);
265 }
266
267 switch(secTrustResult) {
268 case kSecTrustResultUnspecified:
269 /* cert chain valid, no special UserTrust assignments */
270 case kSecTrustResultProceed:
271 /* cert chain valid AND user explicitly trusts this */
272 break;
273 default:
274 printf("\n***SecTrustEvaluate reported secTrustResult %d\n",
275 (int)secTrustResult);
276 ortn = errSSLXCertChainInvalid;
277 break;
278 }
279 #endif
280
281 *peerCerts = NULL;
282
283 #ifdef USE_CDSA_CRYPTO
284 /* one more thing - get peer certs in the form of an evidence chain */
285 CSSM_TP_APPLE_EVIDENCE_INFO *dummyEv;
286 OSStatus thisRtn = SecTrustGetResult(secTrust, &secTrustResult,
287 peerCerts, &dummyEv);
288 if(thisRtn) {
289 printSslErrStr("SecTrustGetResult", thisRtn);
290 }
291 else {
292 /* workaround for the fact that SSLGetPeerCertificates()
293 * leaves a retain count on each element in the returned array,
294 * requiring us to do a release on each cert.
295 */
296 CFIndex numCerts = CFArrayGetCount(*peerCerts);
297 for(CFIndex dex=0; dex<numCerts; dex++) {
298 CFRetain(CFArrayGetValueAtIndex(*peerCerts, dex));
299 }
300 }
301 #endif
302 return ortn;
303 }
304
305 /* print reply received from server, safely */
306 static void dumpAscii(
307 uint8_t *rcvBuf,
308 size_t len)
309 {
310 char *cp = (char *)rcvBuf;
311 uint32_t i;
312 char c;
313
314 for(i=0; i<len; i++) {
315 c = *cp++;
316 if(c == '\0') {
317 break;
318 }
319 switch(c) {
320 case '\n':
321 printf("\\n");
322 break;
323 case '\r':
324 printf("\\r");
325 break;
326 default:
327 if(isprint(c) && (c != '\n')) {
328 printf("%c", c);
329 }
330 else {
331 printf("<%02X>", ((unsigned)c) & 0xff);
332 }
333 break;
334 }
335
336 }
337 printf("\n");
338 }
339
340 /*
341 * Perform one SSL diagnostic session. Returns nonzero on error. Normally no
342 * output to stdout except initial "connecting to" message, unless there
343 * is a really screwed up error (i.e., something not directly related
344 * to the SSL connection).
345 */
346 #define RCV_BUF_SIZE 256
347
348 static OSStatus sslPing(
349 sslPingArgs *pargs)
350 {
351 PeerSpec peerId;
352 otSocket sock = 0;
353 OSStatus ortn;
354 SSLContextRef ctx = NULL;
355 size_t length;
356 size_t actLen;
357 uint8_t rcvBuf[RCV_BUF_SIZE];
358 CFAbsoluteTime startHandshake;
359 CFAbsoluteTime endHandshake;
360
361 pargs->negVersion = kSSLProtocolUnknown;
362 pargs->negCipher = SSL_NULL_WITH_NULL_NULL;
363 pargs->peerCerts = NULL;
364
365 /* first make sure requested server is there */
366 ortn = MakeServerConnection(pargs->hostName, pargs->port, pargs->nonBlocking,
367 &sock, &peerId);
368 if(ortn) {
369 printf("MakeServerConnection returned %d; aborting\n", (int)ortn);
370 return ortn;
371 }
372 if(pargs->verbose) {
373 printf("...connected to server; starting SecureTransport\n");
374 }
375
376 /*
377 * Set up a SecureTransport session.
378 * First the standard calls.
379 */
380 ortn = SSLNewContext(false, &ctx);
381 if(ortn) {
382 printSslErrStr("SSLNewContext", ortn);
383 goto cleanup;
384 }
385 ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite);
386 if(ortn) {
387 printSslErrStr("SSLSetIOFuncs", ortn);
388 goto cleanup;
389 }
390 ortn = SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)sock);
391 if(ortn) {
392 printSslErrStr("SSLSetConnection", ortn);
393 goto cleanup;
394 }
395 SSLConnectionRef getConn;
396 ortn = SSLGetConnection(ctx, &getConn);
397 if(ortn) {
398 printSslErrStr("SSLGetConnection", ortn);
399 goto cleanup;
400 }
401 if(getConn != (SSLConnectionRef)(intptr_t)sock) {
402 printf("***SSLGetConnection error\n");
403 ortn = errSecParam;
404 goto cleanup;
405 }
406 if(!pargs->allowHostnameSpoof) {
407 /* if this isn't set, it isn't checked by AppleX509TP */
408 const char *vfyHost = pargs->hostName;
409 if(pargs->vfyHostName) {
410 /* generally means we're expecting an error */
411 vfyHost = pargs->vfyHostName;
412 }
413 ortn = SSLSetPeerDomainName(ctx, vfyHost, strlen(vfyHost));
414 if(ortn) {
415 printSslErrStr("SSLSetPeerDomainName", ortn);
416 goto cleanup;
417 }
418 }
419
420 /*
421 * SecureTransport options.
422 */
423 if(pargs->acceptedProts) {
424 ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false);
425 if(ortn) {
426 printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn);
427 goto cleanup;
428 }
429 for(const char *cp = pargs->acceptedProts; *cp; cp++) {
430 SSLProtocol prot;
431 switch(*cp) {
432 case '2':
433 prot = kSSLProtocol2;
434 break;
435 case '3':
436 prot = kSSLProtocol3;
437 break;
438 case 't':
439 prot = kTLSProtocol12;
440 break;
441 default:
442 usage(pargs->argv);
443 }
444 ortn = SSLSetProtocolVersionEnabled(ctx, prot, true);
445 if(ortn) {
446 printSslErrStr("SSLSetProtocolVersionEnabled", ortn);
447 goto cleanup;
448 }
449 }
450 }
451 else {
452 ortn = SSLSetProtocolVersion(ctx, pargs->tryVersion);
453 if(ortn) {
454 printSslErrStr("SSLSetProtocolVersion", ortn);
455 goto cleanup;
456 }
457 SSLProtocol getVers;
458 ortn = SSLGetProtocolVersion(ctx, &getVers);
459 if(ortn) {
460 printSslErrStr("SSLGetProtocolVersion", ortn);
461 goto cleanup;
462 }
463 if(getVers != pargs->tryVersion) {
464 printf("***SSLGetProtocolVersion screwup: try %s get %s\n",
465 sslGetProtocolVersionString(pargs->tryVersion),
466 sslGetProtocolVersionString(getVers));
467 ortn = errSecParam;
468 goto cleanup;
469 }
470 }
471 if(pargs->resumableEnable) {
472 const void *rtnId = NULL;
473 size_t rtnIdLen = 0;
474
475 ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec));
476 if(ortn) {
477 printSslErrStr("SSLSetPeerID", ortn);
478 goto cleanup;
479 }
480 /* quick test of the get fcn */
481 ortn = SSLGetPeerID(ctx, &rtnId, &rtnIdLen);
482 if(ortn) {
483 printSslErrStr("SSLGetPeerID", ortn);
484 goto cleanup;
485 }
486 if((rtnId == NULL) || (rtnIdLen != sizeof(PeerSpec))) {
487 printf("***SSLGetPeerID screwup\n");
488 }
489 else if(memcmp(&peerId, rtnId, rtnIdLen) != 0) {
490 printf("***SSLGetPeerID data mismatch\n");
491 }
492 }
493 if(pargs->allowExpired) {
494 ortn = SSLSetAllowsExpiredCerts(ctx, true);
495 if(ortn) {
496 printSslErrStr("SSLSetAllowExpiredCerts", ortn);
497 goto cleanup;
498 }
499 }
500 if(pargs->allowExpiredRoot) {
501 ortn = SSLSetAllowsExpiredRoots(ctx, true);
502 if(ortn) {
503 printSslErrStr("SSLSetAllowsExpiredRoots", ortn);
504 goto cleanup;
505 }
506 }
507 if(pargs->disableCertVerify) {
508 ortn = SSLSetEnableCertVerify(ctx, false);
509 if(ortn) {
510 printSslErrStr("SSLSetEnableCertVerify", ortn);
511 goto cleanup;
512 }
513 }
514 if(pargs->allowAnyRoot) {
515 ortn = SSLSetAllowsAnyRoot(ctx, true);
516 if(ortn) {
517 printSslErrStr("SSLSetAllowAnyRoot", ortn);
518 goto cleanup;
519 }
520 }
521 if(pargs->cipherRestrict != '\0') {
522 ortn = sslSetCipherRestrictions(ctx, pargs->cipherRestrict);
523 if(ortn) {
524 goto cleanup;
525 }
526 }
527 if(pargs->anchorFile) {
528 ortn = sslAddTrustedRoot(ctx, pargs->anchorFile, pargs->replaceAnchors);
529 if(ortn) {
530 printf("***Error obtaining anchor file %s\n", pargs->anchorFile);
531 goto cleanup;
532 }
533 }
534 if(pargs->clientCerts) {
535 CFArrayRef dummy;
536 if(pargs->anchorFile == NULL) {
537 /* assume this is a root we want to implicitly trust */
538 ortn = addIdentityAsTrustedRoot(ctx, pargs->clientCerts);
539 if(ortn) {
540 goto cleanup;
541 }
542 }
543 ortn = SSLSetCertificate(ctx, pargs->clientCerts);
544 if(ortn) {
545 printSslErrStr("SSLSetCertificate", ortn);
546 goto cleanup;
547 }
548 /* quickie test for this new function */
549 ortn = SSLGetCertificate(ctx, &dummy);
550 if(ortn) {
551 printSslErrStr("SSLGetCertificate", ortn);
552 goto cleanup;
553 }
554 if(dummy != pargs->clientCerts) {
555 printf("***SSLGetCertificate error\n");
556 ortn = errSecIO;
557 goto cleanup;
558 }
559 }
560 if(pargs->encryptClientCerts) {
561 if(pargs->anchorFile == NULL) {
562 ortn = addIdentityAsTrustedRoot(ctx, pargs->encryptClientCerts);
563 if(ortn) {
564 goto cleanup;
565 }
566 }
567 ortn = SSLSetEncryptionCertificate(ctx, pargs->encryptClientCerts);
568 if(ortn) {
569 printSslErrStr("SSLSetEncryptionCertificate", ortn);
570 goto cleanup;
571 }
572 }
573
574 /*** end options ***/
575
576 if(pargs->verbose) {
577 printf("...starting SSL handshake\n");
578 }
579 startHandshake = CFAbsoluteTimeGetCurrent();
580
581 do
582 { ortn = SSLHandshake(ctx);
583 if((ortn == errSSLWouldBlock) && !pargs->silent) {
584 /* keep UI responsive */
585 sslOutputDot();
586 }
587 } while (ortn == errSSLWouldBlock);
588
589 endHandshake = CFAbsoluteTimeGetCurrent();
590 pargs->handshakeTimeOp = endHandshake - startHandshake;
591 if(pargs->numHandshakes == 0) {
592 /* special case, this one is always way longer */
593 pargs->handshakeTimeFirst = pargs->handshakeTimeOp;
594 }
595 else {
596 /* normal running total */
597 pargs->handshakeTimeTotal += pargs->handshakeTimeOp;
598 }
599 pargs->numHandshakes++;
600
601 /* this works even if handshake failed due to cert chain invalid */
602 if(!pargs->manualCertVerify) {
603 copyPeerCerts(ctx, &pargs->peerCerts);
604 }
605 else {
606 /* else fetched via SecTrust later */
607 pargs->peerCerts = NULL;
608 }
609
610 ortn = SSLCopyPeerTrust(ctx, &pargs->peerTrust);
611 if(ortn) {
612 printf("***SSLCopyPeerTrust error %" PRIdOSStatus "\n", ortn);
613 pargs->peerTrust = NULL;
614 }
615
616 /* ditto */
617 SSLGetClientCertificateState(ctx, &pargs->certState);
618 SSLGetNegotiatedCipher(ctx, &pargs->negCipher);
619 SSLGetNegotiatedProtocolVersion(ctx, &pargs->negVersion);
620 pargs->sessionIDLength = MAX_SESSION_ID_LENGTH;
621 SSLGetResumableSessionInfo(ctx, &pargs->sessionWasResumed, pargs->sessionID,
622 &pargs->sessionIDLength);
623 if(pargs->manualCertVerify) {
624 OSStatus certRtn = sslEvaluateTrust(ctx, pargs->verbose, pargs->silent,
625 &pargs->peerCerts);
626 if(certRtn && !ortn ) {
627 ortn = certRtn;
628 }
629 }
630
631 if(ortn) {
632 if(!pargs->silent) {
633 printf("\n");
634 }
635 goto cleanup;
636 }
637
638 if(pargs->verbose) {
639 printf("...SSL handshake complete\n");
640 }
641 length = strlen(pargs->getMsg);
642 (void) SSLWrite(ctx, pargs->getMsg, length, &actLen);
643
644 /*
645 * Try to snag RCV_BUF_SIZE bytes. Exit if (!keepConnected and we get any data
646 * at all), or (keepConnected and err != (none, wouldBlock)).
647 */
648 while (1) {
649 actLen = 0;
650 if(pargs->dumpRxData) {
651 size_t avail = 0;
652
653 ortn = SSLGetBufferedReadSize(ctx, &avail);
654 if(ortn) {
655 printf("***SSLGetBufferedReadSize error\n");
656 break;
657 }
658 if(avail != 0) {
659 printf("\n%d bytes available: ", (int)avail);
660 }
661 }
662 ortn = SSLRead(ctx, rcvBuf, RCV_BUF_SIZE, &actLen);
663 if((actLen == 0) && !pargs->silent) {
664 sslOutputDot();
665 }
666 if((actLen == 0) && (ortn == errSecSuccess)) {
667 printf("***Radar 2984932 confirmed***\n");
668 }
669 if (ortn == errSSLWouldBlock) {
670 /* for this loop, these are identical */
671 ortn = errSecSuccess;
672 }
673 if((actLen > 0) && pargs->dumpRxData) {
674 dumpAscii(rcvBuf, actLen);
675 }
676 if(ortn != errSecSuccess) {
677 /* connection closed by server or by error */
678 break;
679 }
680 if(!pargs->keepConnected && (actLen > 0)) {
681 /* good enough, we connected */
682 break;
683 }
684 }
685 if(!pargs->silent) {
686 printf("\n");
687 }
688
689 /* snag these again in case of renegotiate */
690 SSLGetClientCertificateState(ctx, &pargs->certState);
691 SSLGetNegotiatedCipher(ctx, &pargs->negCipher);
692 SSLGetNegotiatedProtocolVersion(ctx, &pargs->negVersion);
693
694 /* convert normal "shutdown" into zero err rtn */
695 if(ortn == errSSLClosedGraceful) {
696 ortn = errSecSuccess;
697 }
698 if((ortn == errSSLClosedNoNotify) && !pargs->requireNotify) {
699 /* relaxed disconnect rules */
700 ortn = errSecSuccess;
701 }
702 cleanup:
703 /*
704 * always do close, even on error - to flush outgoing write queue
705 */
706 OSStatus cerr = SSLClose(ctx);
707 if(ortn == errSecSuccess) {
708 ortn = cerr;
709 }
710 if(sock) {
711 endpointShutdown(sock);
712 }
713 if(ctx) {
714 SSLDisposeContext(ctx);
715 }
716 return ortn;
717 }
718
719 static void add_key(const void *key, const void *value, void *context) {
720 CFArrayAppendValue((CFMutableArrayRef)context, key);
721 }
722
723 static void showInfo(CFDictionaryRef info) {
724 CFIndex dict_count, key_ix, key_count;
725 CFMutableArrayRef keys = NULL;
726 CFIndex maxWidth = 20; /* Maybe precompute this or grab from context? */
727
728 dict_count = CFDictionaryGetCount(info);
729 keys = CFArrayCreateMutable(kCFAllocatorDefault, dict_count,
730 &kCFTypeArrayCallBacks);
731 CFDictionaryApplyFunction(info, add_key, keys);
732 key_count = CFArrayGetCount(keys);
733 CFArraySortValues(keys, CFRangeMake(0, key_count),
734 (CFComparatorFunction)CFStringCompare, 0);
735
736 for (key_ix = 0; key_ix < key_count; ++key_ix) {
737 CFStringRef key = (CFStringRef)CFArrayGetValueAtIndex(keys, key_ix);
738 CFTypeRef value = CFDictionaryGetValue(info, key);
739 CFMutableStringRef line = CFStringCreateMutable(NULL, 0);
740
741 CFStringAppend(line, key);
742 CFIndex jx;
743 for (jx = CFStringGetLength(key);
744 jx < maxWidth; ++jx) {
745 CFStringAppend(line, CFSTR(" "));
746 }
747 CFStringAppend(line, CFSTR(" : "));
748 if (CFStringGetTypeID() == CFGetTypeID(value)) {
749 CFStringAppend(line, (CFStringRef)value);
750 } else if (CFDateGetTypeID() == CFGetTypeID(value)) {
751 CFLocaleRef lc = CFLocaleCopyCurrent();
752 CFDateFormatterRef df = CFDateFormatterCreate(NULL, lc,
753 kCFDateFormatterFullStyle, kCFDateFormatterFullStyle);
754 CFDateRef date = (CFDateRef)value;
755 CFStringRef ds = CFDateFormatterCreateStringWithDate(NULL, df,
756 date);
757 CFStringAppend(line, ds);
758 CFRelease(ds);
759 CFRelease(df);
760 CFRelease(lc);
761 } else if (CFURLGetTypeID() == CFGetTypeID(value)) {
762 CFURLRef url = (CFURLRef)value;
763 CFStringAppend(line, CFSTR("<"));
764 CFStringAppend(line, CFURLGetString(url));
765 CFStringAppend(line, CFSTR(">"));
766 } else if (CFDataGetTypeID() == CFGetTypeID(value)) {
767 CFDataRef v_d = (CFDataRef)value;
768 CFStringRef v_s = CFStringCreateFromExternalRepresentation(
769 kCFAllocatorDefault, v_d, kCFStringEncodingUTF8);
770 if (v_s) {
771 CFStringAppend(line, CFSTR("/"));
772 CFStringAppend(line, v_s);
773 CFStringAppend(line, CFSTR("/ "));
774 CFRelease(v_s);
775 }
776 const uint8_t *bytes = CFDataGetBytePtr(v_d);
777 CFIndex len = CFDataGetLength(v_d);
778 for (jx = 0; jx < len; ++jx) {
779 CFStringAppendFormat(line, NULL, CFSTR("%.02X"), bytes[jx]);
780 }
781 } else {
782 CFStringAppendFormat(line, NULL, CFSTR("%@"), value);
783 }
784 CFStringWriteToFileWithNewline(line, stdout);
785 CFRelease(line);
786 }
787 CFRelease(keys);
788 }
789
790 static void showPeerTrust(SecTrustRef peerTrust, bool verbose) {
791 CFIndex numCerts;
792 CFIndex i;
793
794 if(peerTrust == NULL) {
795 return;
796 }
797
798 printf("\n=============== Peer Trust Properties ===============\n");
799 CFArrayRef plist = SecTrustCopyProperties(peerTrust);
800 if (plist) {
801 print_plist(plist);
802 CFRelease(plist);
803 }
804
805 printf("\n================== Peer Trust Info ==================\n");
806 CFDictionaryRef info = SecTrustCopyInfo(peerTrust);
807 if (info && CFDictionaryGetCount(info)) {
808 showInfo(info);
809 }
810 if (info)
811 CFRelease(info);
812
813 numCerts = SecTrustGetCertificateCount(peerTrust);
814 for(i=0; i<numCerts; i++) {
815 plist = SecTrustCopySummaryPropertiesAtIndex(peerTrust, i);
816 printf("\n============= Peer Trust Cert %lu Summary =============\n\n", i);
817 print_plist(plist);
818 if (plist)
819 CFRelease(plist);
820 printf("\n============= Peer Trust Cert %lu Details =============\n\n", i);
821 plist = SecTrustCopyDetailedPropertiesAtIndex(peerTrust, i);
822 print_plist(plist);
823 if (plist)
824 CFRelease(plist);
825 printf("\n============= End of Peer Trust Cert %lu ==============\n", i);
826 }
827 }
828
829 static void showPeerCerts(
830 CFArrayRef peerCerts,
831 bool verbose)
832 {
833 CFIndex numCerts;
834 SecCertificateRef certRef;
835 CFIndex i;
836
837 if(peerCerts == NULL) {
838 return;
839 }
840 numCerts = CFArrayGetCount(peerCerts);
841 for(i=0; i<numCerts; i++) {
842 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
843 printf("\n==================== Peer Cert %lu ====================\n\n", i);
844 print_cert(certRef, verbose);
845 printf("\n================ End of Peer Cert %lu =================\n", i);
846 }
847 }
848
849 static void writePeerCerts(
850 CFArrayRef peerCerts,
851 const char *fileBase)
852 {
853 CFIndex numCerts;
854 SecCertificateRef certRef;
855 CFIndex i;
856 char fileName[100];
857
858 if(peerCerts == NULL) {
859 return;
860 }
861 numCerts = CFArrayGetCount(peerCerts);
862 for(i=0; i<numCerts; i++) {
863 sprintf(fileName, "%s%02d.cer", fileBase, (int)i);
864 certRef = (SecCertificateRef)CFArrayGetValueAtIndex(peerCerts, i);
865 CFDataRef derCert = SecCertificateCopyData(certRef);
866 if (derCert) {
867 writeFile(fileName, CFDataGetBytePtr(derCert),
868 CFDataGetLength(derCert));
869 CFRelease(derCert);
870 }
871 }
872 printf("...wrote %lu certs to fileBase %s\n", numCerts, fileBase);
873 }
874
875 /*
876 * Show result of an sslPing().
877 * Assumes the following from sslPingArgs:
878 *
879 * verbose
880 * tryVersion
881 * acceptedProts
882 * negVersion
883 * negCipher
884 * peerCerts
885 * certState
886 * sessionWasResumed
887 * sessionID
888 * sessionIDLength
889 * handshakeTime
890 */
891 static void showSSLResult(
892 const sslPingArgs &pargs,
893 OSStatus err,
894 int displayPeerCerts,
895 char *fileBase) // non-NULL: write certs to file
896 {
897 CFIndex numPeerCerts;
898
899 printf("\n");
900
901 if(pargs.acceptedProts) {
902 printf(" Allowed SSL versions : %s\n", pargs.acceptedProts);
903 }
904 else {
905 printf(" Attempted SSL version : %s\n",
906 sslGetProtocolVersionString(pargs.tryVersion));
907 }
908
909 printf(" Result : %s\n", sslGetSSLErrString(err));
910 printf(" Negotiated SSL version : %s\n",
911 sslGetProtocolVersionString(pargs.negVersion));
912 printf(" Negotiated CipherSuite : %s\n",
913 sslGetCipherSuiteString(pargs.negCipher));
914 if(pargs.certState != kSSLClientCertNone) {
915 printf(" Client Cert State : %s\n",
916 sslGetClientCertStateString(pargs.certState));
917 }
918 if(pargs.verbose) {
919 printf(" Resumed Session : ");
920 if(pargs.sessionWasResumed) {
921 for(unsigned dex=0; dex<pargs.sessionIDLength; dex++) {
922 printf("%02X ", pargs.sessionID[dex]);
923 if(((dex % 8) == 7) && (dex != (pargs.sessionIDLength - 1))) {
924 printf("\n ");
925 }
926 }
927 printf("\n");
928 }
929 else {
930 printf("NOT RESUMED\n");
931 }
932 printf(" Handshake time : %f seconds\n", pargs.handshakeTimeOp);
933 }
934 if(pargs.peerCerts == NULL) {
935 numPeerCerts = 0;
936 }
937 else {
938 numPeerCerts = CFArrayGetCount(pargs.peerCerts);
939 }
940 printf(" Number of server certs : %lu\n", numPeerCerts);
941 if(numPeerCerts != 0) {
942 if (displayPeerCerts == 1) {
943 showPeerCerts(pargs.peerCerts, false);
944 } else if (displayPeerCerts == 2) {
945 showPeerTrust(pargs.peerTrust, false);
946 }
947 if(fileBase != NULL) {
948 writePeerCerts(pargs.peerCerts, fileBase);
949 }
950 }
951
952 printf("\n");
953 }
954
955 static int verifyProtocol(
956 bool verifyProt,
957 SSLProtocol maxProtocol,
958 SSLProtocol reqProtocol,
959 SSLProtocol negProtocol)
960 {
961 if(!verifyProt) {
962 return 0;
963 }
964 if(reqProtocol > maxProtocol) {
965 /* known not to support this attempt, relax */
966 reqProtocol = maxProtocol;
967 }
968 if(reqProtocol != negProtocol) {
969 printf("***Expected protocol %s; negotiated %s\n",
970 sslGetProtocolVersionString(reqProtocol),
971 sslGetProtocolVersionString(negProtocol));
972 return 1;
973 }
974 else {
975 return 0;
976 }
977 }
978
979 static int verifyClientCertState(
980 bool verifyCertState,
981 SSLClientCertificateState expectState,
982 SSLClientCertificateState gotState)
983 {
984 if(!verifyCertState) {
985 return 0;
986 }
987 if(expectState == gotState) {
988 return 0;
989 }
990 printf("***Expected clientCertState %s; got %s\n",
991 sslGetClientCertStateString(expectState),
992 sslGetClientCertStateString(gotState));
993 return 1;
994 }
995
996 static SSLProtocol charToProt(
997 char c, // 2, 3, t
998 char **argv)
999 {
1000 switch(c) {
1001 case '2':
1002 return kSSLProtocol2;
1003 case '3':
1004 return kSSLProtocol3;
1005 case 't':
1006 return kTLSProtocol12;
1007 default:
1008 usage(argv);
1009 }
1010 /* NOT REACHED */
1011 return kSSLProtocolUnknown;
1012 }
1013
1014 int main(int argc, char **argv)
1015 {
1016 OSStatus err;
1017 int arg;
1018 char *argp;
1019 char getMsg[300];
1020 char fullFileBase[100];
1021 int ourRtn = 0; // exit status - sum of all errors
1022 unsigned loop;
1023 SecKeychainRef serverKc = nil;
1024 SecKeychainRef encryptKc = nil;
1025 sslPingArgs pargs;
1026
1027 /* user-spec'd parameters */
1028 const char *getPath = DEFAULT_PATH;
1029 char *fileBase = NULL;
1030 int displayCerts = 0;
1031 bool doSslV2 = false;
1032 bool doSslV3 = false;
1033 bool doTlsV1 = true;
1034 bool doTlsV11 = false;
1035 bool doTlsV12 = false;
1036 bool protXOnly = false; // kSSLProtocol3Only, kTLSProtocol1Only
1037 bool doProtUnknown = false;
1038 unsigned loopCount = 1;
1039 bool doPause = false;
1040 bool pauseFirstLoop = false;
1041 bool verifyProt = false;
1042 SSLProtocol maxProtocol = kTLSProtocol12; // for verifying negotiated
1043 // protocol
1044 char *acceptedProts = NULL;
1045 char *keyChainName = NULL;
1046 char *encryptKeyChainName = NULL;
1047 char *getMsgSpec = NULL;
1048 bool vfyCertState = false;
1049 SSLClientCertificateState expectCertState = kSSLClientCertNone;
1050 bool displayHandshakeTimes = false;
1051 bool completeCertChain = false;
1052
1053 /* special case - one arg of "h" or "-h" or "hv" */
1054 if(argc == 2) {
1055 if((strcmp(argv[1], "h") == 0) || (strcmp(argv[1], "-h") == 0)) {
1056 usage(argv);
1057 }
1058 if(strcmp(argv[1], "hv") == 0) {
1059 usageVerbose(argv);
1060 }
1061 }
1062
1063 /* set up defaults */
1064 memset(&pargs, 0, sizeof(sslPingArgs));
1065 pargs.hostName = DEFAULT_HOST;
1066 pargs.port = DEFAULT_PORT;
1067 pargs.resumableEnable = true;
1068 pargs.argv = argv;
1069
1070 for(arg=1; arg<argc; arg++) {
1071 argp = argv[arg];
1072 if(arg == 1) {
1073 /* first arg, is always hostname; '-' means default */
1074 if(argp[0] != '-') {
1075 pargs.hostName = argp;
1076 }
1077 continue;
1078 }
1079 if(argp[0] == '/') {
1080 /* path always starts with leading slash */
1081 getPath = argp;
1082 continue;
1083 }
1084 /* options */
1085 switch(argp[0]) {
1086 case 'e':
1087 pargs.allowExpired = true;
1088 break;
1089 case 'E':
1090 pargs.allowExpiredRoot = true;
1091 break;
1092 case 'x':
1093 pargs.disableCertVerify = true;
1094 break;
1095 case 'M':
1096 pargs.disableCertVerify = true; // implied
1097 pargs.manualCertVerify = true;
1098 break;
1099 case 'a':
1100 if(++arg == argc) {
1101 /* requires another arg */
1102 usage(argv);
1103 }
1104 pargs.anchorFile = argv[arg];
1105 break;
1106 case 'A':
1107 if(++arg == argc) {
1108 /* requires another arg */
1109 usage(argv);
1110 }
1111 pargs.anchorFile = argv[arg];
1112 pargs.replaceAnchors = true;
1113 break;
1114 case 'r':
1115 pargs.allowAnyRoot = true;
1116 break;
1117 case 'd':
1118 pargs.dumpRxData = true;
1119 break;
1120 case 'c':
1121 displayCerts++;
1122 break;
1123 case 'f':
1124 if(++arg == argc) {
1125 /* requires another arg */
1126 usage(argv);
1127 }
1128 fileBase = argv[arg];
1129 break;
1130 case 'C':
1131 pargs.cipherRestrict = argp[2];
1132 break;
1133 case '2':
1134 doSslV3 = doTlsV1 = doTlsV11 = false;
1135 doSslV2 = true;
1136 break;
1137 case '3':
1138 doSslV2 = doTlsV1 = doTlsV11 = doTlsV12 = false;
1139 doSslV3 = true;
1140 break;
1141 case 't':
1142 doSslV2 = doSslV3 = doTlsV11 = doTlsV12 = false;
1143 doTlsV1 = true;
1144 break;
1145 case '%':
1146 doSslV2 = doSslV3 = doTlsV1 = false;
1147 doTlsV11 = true;
1148 break;
1149 case '^':
1150 doSslV2 = doSslV3 = doTlsV1 = doTlsV12 = false;
1151 doTlsV12 = true;
1152 break;
1153 case 'L':
1154 doSslV2 = doSslV3 = doTlsV1 = doTlsV11 = doTlsV12 = true;
1155 break;
1156 case 'o':
1157 protXOnly = true;
1158 break;
1159 case 'u':
1160 doSslV2 = doSslV3 = doTlsV1 = doTlsV11 = doTlsV12 = false;
1161 doProtUnknown = true;
1162 break;
1163 case 'K':
1164 pargs.keepConnected = true;
1165 break;
1166 case 'n':
1167 pargs.requireNotify = true;
1168 pargs.keepConnected = true;
1169 break;
1170 case 'R':
1171 pargs.resumableEnable = false;
1172 break;
1173 case 'b':
1174 pargs.nonBlocking = true;
1175 break;
1176 case 'v':
1177 verifyProt = true;
1178 break;
1179 case 'm':
1180 if(argp[1] != '=') {
1181 usage(argv);
1182 }
1183 verifyProt = true; // implied
1184 maxProtocol = charToProt(argp[2], argv);
1185 break;
1186 case 'g':
1187 if(argp[1] != '=') {
1188 usage(argv);
1189 }
1190 acceptedProts = &argp[2];
1191 doSslV3 = doSslV2 = doTlsV1 = doTlsV11 = doTlsV12 = false;
1192 break;
1193 case 'l':
1194 loopCount = atoi(&argp[2]);
1195 if(loopCount == 0) {
1196 printf("***bad loopCount\n");
1197 usage(argv);
1198 }
1199 break;
1200 case 'P':
1201 pargs.port = atoi(&argp[2]);
1202 break;
1203 case 'H':
1204 pargs.allowHostnameSpoof = true;
1205 break;
1206 case 'F':
1207 pargs.vfyHostName = &argp[2];
1208 break;
1209 case 'k':
1210 keyChainName = &argp[2];
1211 break;
1212 case 'y':
1213 encryptKeyChainName = &argp[2];
1214 break;
1215 case 'G':
1216 getMsgSpec = &argp[2];
1217 break;
1218 case 'T':
1219 if(argp[1] != '=') {
1220 usage(argv);
1221 }
1222 vfyCertState = true;
1223 switch(argp[2]) {
1224 case 'n':
1225 expectCertState = kSSLClientCertNone;
1226 break;
1227 case 'r':
1228 expectCertState = kSSLClientCertRequested;
1229 break;
1230 case 's':
1231 expectCertState = kSSLClientCertSent;
1232 break;
1233 case 'j':
1234 expectCertState = kSSLClientCertRejected;
1235 break;
1236 default:
1237 usage(argv);
1238 }
1239 break;
1240 case 'z':
1241 pargs.password = &argp[2];
1242 break;
1243 case 'p':
1244 doPause = true;
1245 break;
1246 case '7':
1247 pauseFirstLoop = true;
1248 break;
1249 case 'q':
1250 pargs.quiet = true;
1251 break;
1252 case 'V':
1253 pargs.verbose = true;
1254 break;
1255 case 's':
1256 pargs.silent = pargs.quiet = true;
1257 break;
1258 case 'N':
1259 displayHandshakeTimes = true;
1260 break;
1261 case '8':
1262 completeCertChain = true;
1263 break;
1264 case 'h':
1265 if(pargs.verbose || (argp[1] == 'v')) {
1266 usageVerbose(argv);
1267 }
1268 else {
1269 usage(argv);
1270 }
1271 default:
1272 usage(argv);
1273 }
1274 }
1275 if(getMsgSpec) {
1276 pargs.getMsg = getMsgSpec;
1277 }
1278 else {
1279 sprintf(getMsg, "%s %s %s",
1280 DEFAULT_GETMSG, getPath, DEFAULT_GET_SUFFIX);
1281 pargs.getMsg = getMsg;
1282 }
1283
1284 #if NO_SERVER
1285 # if DEBUG
1286 securityd_init(NULL);
1287 # endif
1288 #endif
1289
1290 /* get client cert and optional encryption cert as CFArrayRef */
1291 if(keyChainName) {
1292 pargs.clientCerts = getSslCerts(keyChainName, false, completeCertChain,
1293 pargs.anchorFile, &serverKc);
1294 if(pargs.clientCerts == nil) {
1295 exit(1);
1296 }
1297 #ifdef USE_CDSA_CRYPTO
1298 if(pargs.password) {
1299 OSStatus ortn = SecKeychainUnlock(serverKc,
1300 strlen(pargs.password), pargs.password, true);
1301 if(ortn) {
1302 printf("SecKeychainUnlock returned %d\n", (int)ortn);
1303 /* oh well */
1304 }
1305 }
1306 #endif
1307 }
1308 if(encryptKeyChainName) {
1309 pargs.encryptClientCerts = getSslCerts(encryptKeyChainName, true,
1310 completeCertChain, pargs.anchorFile, &encryptKc);
1311 if(pargs.encryptClientCerts == nil) {
1312 exit(1);
1313 }
1314 }
1315 signal(SIGPIPE, sigpipe);
1316
1317 for(loop=0; loop<loopCount; loop++) {
1318 /*
1319 * One pass for each protocol version, skipping any explicit version if
1320 * an attempt at a higher version and succeeded in doing so successfully fell
1321 * back.
1322 */
1323 if(doTlsV12) {
1324 pargs.tryVersion = kTLSProtocol12;
1325 pargs.acceptedProts = NULL;
1326 if(!pargs.silent) {
1327 printf("Connecting to host %s with TLS V1.2...", pargs.hostName);
1328 }
1329 fflush(stdout);
1330 err = sslPing(&pargs);
1331 if(err) {
1332 ourRtn++;
1333 }
1334 if(!pargs.quiet) {
1335 if(fileBase) {
1336 sprintf(fullFileBase, "%s_v3.1", fileBase);
1337 }
1338 showSSLResult(pargs,
1339 err,
1340 displayCerts,
1341 fileBase ? fullFileBase : NULL);
1342 }
1343 freePeerCerts(pargs.peerCerts);
1344 if(!err) {
1345 /* deal with fallbacks, skipping redundant tests */
1346 switch(pargs.negVersion) {
1347 case kTLSProtocol11:
1348 doTlsV11 =false;
1349 break;
1350 case kTLSProtocol1:
1351 doTlsV11 =false;
1352 doTlsV1 =false;
1353 break;
1354 case kSSLProtocol3:
1355 doTlsV11 =false;
1356 doTlsV1 =false;
1357 doSslV3 = false;
1358 break;
1359 case kSSLProtocol2:
1360 doTlsV11 =false;
1361 doTlsV1 =false;
1362 doSslV3 = false;
1363 doSslV2 = false;
1364 break;
1365 default:
1366 break;
1367 }
1368 ourRtn += verifyProtocol(verifyProt, maxProtocol, kTLSProtocol12,
1369 pargs.negVersion);
1370 }
1371 /* note we do this regardless since the client state might be
1372 * the cause of a failure */
1373 ourRtn += verifyClientCertState(vfyCertState, expectCertState,
1374 pargs.certState);
1375 }
1376 if(doTlsV11) {
1377 pargs.tryVersion = kTLSProtocol11;
1378 pargs.acceptedProts = NULL;
1379 if(!pargs.silent) {
1380 printf("Connecting to host %s with TLS V1.1...", pargs.hostName);
1381 }
1382 fflush(stdout);
1383 err = sslPing(&pargs);
1384 if(err) {
1385 ourRtn++;
1386 }
1387 if(!pargs.quiet) {
1388 if(fileBase) {
1389 sprintf(fullFileBase, "%s_v3.1", fileBase);
1390 }
1391 showSSLResult(pargs,
1392 err,
1393 displayCerts,
1394 fileBase ? fullFileBase : NULL);
1395 }
1396 freePeerCerts(pargs.peerCerts);
1397 if(!err) {
1398 /* deal with fallbacks, skipping redundant tests */
1399 switch(pargs.negVersion) {
1400 case kTLSProtocol1:
1401 doTlsV1 =false;
1402 break;
1403 case kSSLProtocol3:
1404 doTlsV1 =false;
1405 doSslV3 = false;
1406 break;
1407 case kSSLProtocol2:
1408 doTlsV1 =false;
1409 doSslV3 = false;
1410 doSslV2 = false;
1411 break;
1412 default:
1413 break;
1414 }
1415 ourRtn += verifyProtocol(verifyProt, maxProtocol, kTLSProtocol11,
1416 pargs.negVersion);
1417 }
1418 /* note we do this regardless since the client state might be
1419 * the cause of a failure */
1420 ourRtn += verifyClientCertState(vfyCertState, expectCertState,
1421 pargs.certState);
1422 }
1423 if(doTlsV1) {
1424 pargs.tryVersion =
1425 protXOnly ? kTLSProtocol1Only : kTLSProtocol1;
1426 pargs.acceptedProts = NULL;
1427 if(!pargs.silent) {
1428 printf("Connecting to host %s with TLS V1...", pargs.hostName);
1429 }
1430 fflush(stdout);
1431 err = sslPing(&pargs);
1432 if(err) {
1433 ourRtn++;
1434 }
1435 if(!pargs.quiet) {
1436 if(fileBase) {
1437 sprintf(fullFileBase, "%s_v3.1", fileBase);
1438 }
1439 showSSLResult(pargs,
1440 err,
1441 displayCerts,
1442 fileBase ? fullFileBase : NULL);
1443 }
1444 freePeerCerts(pargs.peerCerts);
1445 if(!err) {
1446 /* deal with fallbacks, skipping redundant tests */
1447 switch(pargs.negVersion) {
1448 case kSSLProtocol3:
1449 doSslV3 = false;
1450 break;
1451 case kSSLProtocol2:
1452 doSslV3 = false;
1453 doSslV2 = false;
1454 break;
1455 default:
1456 break;
1457 }
1458 ourRtn += verifyProtocol(verifyProt, maxProtocol, kTLSProtocol1,
1459 pargs.negVersion);
1460 }
1461 /* note we do this regardless since the client state might be
1462 * the cause of a failure */
1463 ourRtn += verifyClientCertState(vfyCertState, expectCertState,
1464 pargs.certState);
1465 }
1466 if(doSslV3) {
1467 pargs.tryVersion = protXOnly ? kSSLProtocol3Only : kSSLProtocol3;
1468 pargs.acceptedProts = NULL;
1469 if(!pargs.silent) {
1470 printf("Connecting to host %s with SSL V3...", pargs.hostName);
1471 }
1472 fflush(stdout);
1473 err = sslPing(&pargs);
1474 if(err) {
1475 ourRtn++;
1476 }
1477 if(!pargs.quiet) {
1478 if(fileBase) {
1479 sprintf(fullFileBase, "%s_v3.0", fileBase);
1480 }
1481 showSSLResult(pargs,
1482 err,
1483 displayCerts,
1484 fileBase ? fullFileBase : NULL);
1485 }
1486 freePeerCerts(pargs.peerCerts);
1487 if(!err) {
1488 /* deal with fallbacks, skipping redundant tests */
1489 switch(pargs.negVersion) {
1490 case kSSLProtocol2:
1491 doSslV2 = false;
1492 break;
1493 default:
1494 break;
1495 }
1496 ourRtn += verifyProtocol(verifyProt, maxProtocol, kSSLProtocol3,
1497 pargs.negVersion);
1498 }
1499 /* note we do this regardless since the client state might be
1500 * the cause of a failure */
1501 ourRtn += verifyClientCertState(vfyCertState, expectCertState,
1502 pargs.certState);
1503 }
1504
1505 if(doSslV2) {
1506 if(fileBase) {
1507 sprintf(fullFileBase, "%s_v2", fileBase);
1508 }
1509 if(!pargs.silent) {
1510 printf("Connecting to host %s with SSL V2...", pargs.hostName);
1511 }
1512 fflush(stdout);
1513 pargs.tryVersion = kSSLProtocol2;
1514 pargs.acceptedProts = NULL;
1515 err = sslPing(&pargs);
1516 if(err) {
1517 ourRtn++;
1518 }
1519 if(!pargs.quiet) {
1520 if(fileBase) {
1521 sprintf(fullFileBase, "%s_v2", fileBase);
1522 }
1523 showSSLResult(pargs,
1524 err,
1525 displayCerts,
1526 fileBase ? fullFileBase : NULL);
1527 }
1528 freePeerCerts(pargs.peerCerts);
1529 if(!err) {
1530 ourRtn += verifyProtocol(verifyProt, maxProtocol, kSSLProtocol2,
1531 pargs.negVersion);
1532 }
1533 /* note we do this regardless since the client state might be
1534 * the cause of a failure */
1535 ourRtn += verifyClientCertState(vfyCertState, expectCertState,
1536 pargs.certState);
1537 }
1538 if(doProtUnknown) {
1539 if(!pargs.silent) {
1540 printf("Connecting to host %s with kSSLProtocolUnknown...",
1541 pargs.hostName);
1542 }
1543 fflush(stdout);
1544 pargs.tryVersion = kSSLProtocolUnknown;
1545 pargs.acceptedProts = NULL;
1546 err = sslPing(&pargs);
1547 if(err) {
1548 ourRtn++;
1549 }
1550 if(!pargs.quiet) {
1551 if(fileBase) {
1552 sprintf(fullFileBase, "%s_def", fileBase);
1553 }
1554 showSSLResult(pargs,
1555 err,
1556 displayCerts,
1557 fileBase ? fullFileBase : NULL);
1558 }
1559 freePeerCerts(pargs.peerCerts);
1560 }
1561 if(acceptedProts != NULL) {
1562 pargs.acceptedProts = acceptedProts;
1563 pargs.tryVersion = kSSLProtocolUnknown; // not used
1564 if(!pargs.silent) {
1565 printf("Connecting to host %s with acceptedProts %s...",
1566 pargs.hostName, pargs.acceptedProts);
1567 }
1568 fflush(stdout);
1569 err = sslPing(&pargs);
1570 if(err) {
1571 ourRtn++;
1572 }
1573 if(!pargs.quiet) {
1574 if(fileBase) {
1575 sprintf(fullFileBase, "%s_def", fileBase);
1576 }
1577 showSSLResult(pargs,
1578 err,
1579 displayCerts,
1580 fileBase ? fullFileBase : NULL);
1581 }
1582 freePeerCerts(pargs.peerCerts);
1583 }
1584 if(doPause ||
1585 (pauseFirstLoop &&
1586 /* pause after first, before last to grab trace */
1587 ((loop == 0) || (loop == loopCount - 1))
1588 )
1589 ) {
1590 char resp;
1591 fpurge(stdin);
1592 printf("a to abort, c to continue: ");
1593 resp = getchar();
1594 if(resp == 'a') {
1595 break;
1596 }
1597 }
1598 } /* main loop */
1599 if(displayHandshakeTimes) {
1600 CFAbsoluteTime totalTime;
1601 unsigned numHandshakes;
1602 if(pargs.numHandshakes == 1) {
1603 /* just display the first one */
1604 totalTime = pargs.handshakeTimeFirst;
1605 numHandshakes = 1;
1606 }
1607 else {
1608 /* skip the first one */
1609 totalTime = pargs.handshakeTimeTotal;
1610 numHandshakes = pargs.numHandshakes - 1;
1611 }
1612 if(numHandshakes != 0) {
1613 printf(" %u handshakes in %f seconds; %f seconds per handshake\n",
1614 numHandshakes, totalTime,
1615 (totalTime / numHandshakes));
1616 }
1617 }
1618 //printCertShutdown();
1619 if(ourRtn) {
1620 printf("===%s exiting with %d %s for host %s\n", argv[0], ourRtn,
1621 (ourRtn > 1) ? "errors" : "error", pargs.hostName);
1622 }
1623 return ourRtn;
1624
1625 }
1626
1627