2 * Copyright (c) 2008-2013 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Trivial SSL server example, using SecureTransport / OS X version.
27 * Written by Doug Mitchell.
29 #include <Security/SecureTransport.h>
30 #include <Security/SecureTransportPriv.h>
31 #include "sslAppUtils.h"
33 #include "utilities/fileIo.h"
35 #include <Security/SecBase.h>
42 #include <sys/param.h>
44 #include <Security/Security.h>
45 #include <Security/SecCertificatePriv.h>
47 #include <CoreFoundation/CoreFoundation.h>
48 #include "SecurityTool/print_cert.h"
51 #include <securityd/spi.h>
54 /* Set true when PR-3074739 is merged to TOT */
55 #define SET_DH_PARAMS_ENABLE 1
57 /* true when using SSLCopyPeerCertificates() per Radar 3311892 */
58 #define USE_COPY_PEER_CERTS 1
61 * Defaults, overridable by user.
63 #define SERVER_MESSAGE "HTTP/1.0 200 OK\015\012Content-Type: text/html\015\012\015\012" \
64 "<HTML><HEAD><TITLE>SecureTransport Test Server</TITLE></HEAD>" \
65 "<BODY><H2>Secure connection established.</H2>" \
66 "Message from the 'sslServer' sample application.\015\012</BODY>" \
69 /* For ease of debugging, pick a non-privileged port */
70 #define DEFAULT_PORT 1200
71 // #define DEFAULT_PORT 443
73 #define DEFAULT_HOST "localhost"
75 #define DEFAULT_KC "certkc"
77 static void usage(char **argv
)
79 printf("Usage: %s [option ...]\n", argv
[0]);
81 printf(" P=port Port to listen on; default is %d\n", DEFAULT_PORT
);
82 printf(" k=keychain Contains server cert and keys.\n");
83 printf(" y=keychain Encryption-only cert and keys.\n");
84 printf(" e Allow Expired Certs\n");
85 printf(" r Allow any root cert\n");
86 printf(" E Allow Expired Roots\n");
87 printf(" x Disable Cert Verification\n");
88 printf(" f=fileBase Write Peer Certs to fileBase*\n");
89 printf(" c Display peer certs\n");
90 printf(" d Display received data\n");
91 printf(" C=cipherSuite (e=40-bit d=DES D=40-bit DES 3=3DES 4=RC4 $=40-bit RC4\n"
92 " 2=RC2 a=AES128 A=AES256 h=DH H=Anon DH r=DHE/RSA s=DH/DSS\n"
94 printf(" 2 SSLv2 only (default is best fit)\n");
95 printf(" 3 SSLv3 only (default is best fit)\n");
96 printf(" t TLSv1 only (default is best fit)\n");
97 printf(" o TLSv1, SSLv3 use kSSLProtocol__X__Only\n");
98 printf(" g={prot...} Specify legal protocols; prot = any combo of [23t]\n");
99 printf(" T=[nrsj] Verify client cert state = "
100 "none/requested/sent/rejected\n");
101 printf(" R Disable resumable session support\n");
102 printf(" i=timeout Session cache timeout\n");
103 printf(" u=[nat] Authentication: n=never; a=always; t=try\n");
104 printf(" b Non-blocking I/O\n");
105 printf(" a fileNmae Add fileName to list of trusted roots\n");
106 printf(" A fileName fileName is ONLY trusted root\n");
107 printf(" U filename Add filename to acceptable DNList (multiple times OK)\n");
108 printf(" D filename Diffie-Hellman parameters from filename\n");
109 printf(" z=password Unlock server keychain with password.\n");
110 printf(" H Do SecIndentityRef search instead of specific keychain\n");
111 printf(" M Complete cert chain (default assumes that our identity is root)\n");
112 printf(" 4 Disable anonymous ciphers\n");
113 printf(" p Pause after each phase\n");
114 printf(" l[=loops] Loop, performing multiple transactions\n");
115 printf(" q Quiet/diagnostic mode (site names and errors only)\n");
120 /* snag a copy of current connection's peer certs so we can
121 * examine them later after the connection is closed */
122 static OSStatus
copyPeerCerts(
124 CFArrayRef
*peerCerts
) // mallocd & RETURNED
126 #if USE_COPY_PEER_CERTS
127 OSStatus ortn
= SSLCopyPeerCertificates(ctx
, peerCerts
);
129 OSStatus ortn
= SSLGetPeerCertificates(ctx
, peerCerts
);
132 printf("***Error obtaining peer certs: %s\n",
133 sslGetSSLErrString(ortn
));
138 /* free the cert array obtained via SSLGetPeerCertificates() */
139 static void freePeerCerts(
140 CFArrayRef peerCerts
)
142 if(peerCerts
== NULL
) {
146 #if USE_COPY_PEER_CERTS
148 /* Voila! Problem fixed. */
149 CFRelease(peerCerts
);
155 SecCertificateRef certData
;
158 numCerts
= CFArrayGetCount(peerCerts
);
159 for(i
=0; i
<numCerts
; i
++) {
160 certData
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
);
163 CFRelease(peerCerts
);
167 /* print reply received from server */
168 static void dumpAscii(
172 char *cp
= (char *)rcvBuf
;
176 for(i
=0; i
<len
; i
++) {
189 if(isprint(c
) && (c
!= '\n')) {
193 printf("<%02X>", ((unsigned)c
) & 0xff);
202 static void doPause(const char *prompt
) {
204 printf("%s. ", prompt
);
207 printf("Continue (n/anything)? ");
215 * Perform one SSL diagnostic server-side session. Returns nonzero on error.
216 * Normally no output to stdout except initial "waiting for connection" message,
217 * unless there is a really screwed up error (i.e., something not directly related
218 * to the SSL connection).
220 #define RCV_BUF_SIZE 256
222 static OSStatus
sslServe(
224 unsigned short portNum
,
225 SSLProtocol tryVersion
, // only used if acceptedProts NULL
226 const char *acceptedProts
,
227 CFArrayRef serverCerts
, // required
228 char *password
, // optional
229 CFArrayRef encryptServerCerts
, // optional
232 bool allowExpiredRoot
,
233 bool disableCertVerify
,
236 char cipherRestrict
, // '2', 'd'. etc...'\0' for no
238 SSLAuthenticate authenticate
,
239 unsigned char *dhParams
, // optional D-H parameters
240 unsigned dhParamsLen
,
241 CFArrayRef acceptableDNList
, // optional
242 bool resumableEnable
,
243 uint32_t sessionCacheTimeout
,// optional
244 bool disableAnonCiphers
,
245 bool silent
, // no stdout
247 SSLProtocol
*negVersion
, // RETURNED
248 SSLCipherSuite
*negCipher
, // RETURNED
249 SSLClientCertificateState
*certState
, // RETURNED
250 Boolean
*sessionWasResumed
, // RETURNED
251 unsigned char *sessionID
, // mallocd by caller, RETURNED
252 size_t *sessionIDLength
, // RETURNED
253 CFArrayRef
*peerCerts
, // mallocd & RETURNED
259 SSLContextRef ctx
= NULL
;
261 uint8_t rcvBuf
[RCV_BUF_SIZE
];
262 const char *outMsg
= SERVER_MESSAGE
;
264 *negVersion
= kSSLProtocolUnknown
;
265 *negCipher
= SSL_NULL_WITH_NULL_NULL
;
269 signal(SIGPIPE
, sigpipe
);
272 /* first wait for a connection */
274 printf("Waiting for client connection on port %u...", portNum
);
277 ortn
= AcceptClientConnection(listenSock
, &acceptSock
, &peerId
);
279 printf("AcceptClientConnection returned %d; aborting\n", (int)ortn
);
284 * Set up a SecureTransport session.
285 * First the standard calls.
287 ortn
= SSLNewContext(true, &ctx
);
289 printSslErrStr("SSLNewContext", ortn
);
292 ortn
= SSLSetIOFuncs(ctx
, SocketRead
, SocketWrite
);
294 printSslErrStr("SSLSetIOFuncs", ortn
);
297 ortn
= SSLSetConnection(ctx
, (SSLConnectionRef
)(intptr_t)acceptSock
);
299 printSslErrStr("SSLSetConnection", ortn
);
303 /* have to do these options befor setting server certs */
305 ortn
= SSLSetAllowsExpiredCerts(ctx
, true);
307 printSslErrStr("SSLSetAllowExpiredCerts", ortn
);
312 ortn
= SSLSetAllowsAnyRoot(ctx
, true);
314 printSslErrStr("SSLSetAllowAnyRoot", ortn
);
320 ortn
= sslAddTrustedRoot(ctx
, anchorFile
, replaceAnchors
);
322 printf("***Error obtaining anchor file %s\n", anchorFile
);
326 if(serverCerts
!= NULL
) {
327 if(anchorFile
== NULL
) {
328 /* no specific anchors, so assume we want to trust this one */
329 ortn
= addIdentityAsTrustedRoot(ctx
, serverCerts
);
334 ortn
= SSLSetCertificate(ctx
, serverCerts
);
336 printSslErrStr("SSLSetCertificate", ortn
);
340 if(encryptServerCerts
) {
341 ortn
= SSLSetEncryptionCertificate(ctx
, encryptServerCerts
);
343 printSslErrStr("SSLSetEncryptionCertificate", ortn
);
347 if(allowExpiredRoot
) {
348 ortn
= SSLSetAllowsExpiredRoots(ctx
, true);
350 printSslErrStr("SSLSetAllowsExpiredRoots", ortn
);
354 if(disableCertVerify
) {
355 ortn
= SSLSetEnableCertVerify(ctx
, false);
357 printSslErrStr("SSLSetEnableCertVerify", ortn
);
363 * SecureTransport options.
366 ortn
= SSLSetProtocolVersionEnabled(ctx
, kSSLProtocolAll
, false);
368 printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn
);
371 for(const char *cp
= acceptedProts
; *cp
; cp
++) {
372 SSLProtocol prot
= kSSLProtocolUnknown
;
375 prot
= kSSLProtocol2
;
378 prot
= kSSLProtocol3
;
381 prot
= kTLSProtocol1
;
386 ortn
= SSLSetProtocolVersionEnabled(ctx
, prot
, true);
388 printSslErrStr("SSLSetProtocolVersionEnabled", ortn
);
394 ortn
= SSLSetProtocolVersion(ctx
, tryVersion
);
396 printSslErrStr("SSLSetProtocolVersion", ortn
);
400 if(resumableEnable
) {
401 ortn
= SSLSetPeerID(ctx
, &peerId
, sizeof(PeerSpec
));
403 printSslErrStr("SSLSetPeerID", ortn
);
407 if(cipherRestrict
!= '\0') {
408 ortn
= sslSetCipherRestrictions(ctx
, cipherRestrict
);
413 if(authenticate
!= kNeverAuthenticate
) {
414 ortn
= SSLSetClientSideAuthenticate(ctx
, authenticate
);
416 printSslErrStr("SSLSetClientSideAuthenticate", ortn
);
421 ortn
= SSLSetDiffieHellmanParams(ctx
, dhParams
, dhParamsLen
);
423 printSslErrStr("SSLSetDiffieHellmanParams", ortn
);
427 if(sessionCacheTimeout
) {
428 ortn
= SSLSetSessionCacheTimeout(ctx
, sessionCacheTimeout
);
430 printSslErrStr("SSLSetSessionCacheTimeout", ortn
);
434 if(disableAnonCiphers
) {
435 ortn
= SSLSetAllowAnonymousCiphers(ctx
, false);
437 printSslErrStr("SSLSetAllowAnonymousCiphers", ortn
);
440 /* quickie test of the getter */
442 ortn
= SSLGetAllowAnonymousCiphers(ctx
, &e
);
444 printSslErrStr("SSLGetAllowAnonymousCiphers", ortn
);
448 printf("***SSLGetAllowAnonymousCiphers() returned true; expected false\n");
454 if(acceptableDNList) {
455 ortn = SSLSetCertificateAuthorities(ctx, acceptableDNList, TRUE);
457 printSslErrStr("SSLSetCertificateAuthorities", ortn);
465 doPause("SSLContext initialized");
468 /* Perform SSL/TLS handshake */
470 { ortn
= SSLHandshake(ctx
);
471 if((ortn
== errSSLWouldBlock
) && !silent
) {
472 /* keep UI responsive */
475 } while (ortn
== errSSLWouldBlock
);
477 /* this works even if handshake failed due to cert chain invalid */
478 copyPeerCerts(ctx
, peerCerts
);
480 SSLGetClientCertificateState(ctx
, certState
);
481 SSLGetNegotiatedCipher(ctx
, negCipher
);
482 SSLGetNegotiatedProtocolVersion(ctx
, negVersion
);
483 *sessionIDLength
= MAX_SESSION_ID_LENGTH
;
484 SSLGetResumableSessionInfo(ctx
, sessionWasResumed
, sessionID
,
494 doPause("SSLContext handshake complete");
497 /* wait for one complete line or user says they've had enough */
498 while(ortn
== errSecSuccess
) {
499 length
= sizeof(rcvBuf
);
500 ortn
= SSLRead(ctx
, rcvBuf
, length
, &length
);
502 /* keep UI responsive */
506 /* print what we have */
507 printf("client request: ");
508 dumpAscii(rcvBuf
, length
);
511 /* allow user to bail */
515 printf("\nMore client request (y/anything): ");
522 /* poor person's line completion scan */
523 for(unsigned i
=0; i
<length
; i
++) {
524 if((rcvBuf
[i
] == '\n') || (rcvBuf
[i
] == '\r')) {
525 /* a labelled break would be nice here.... */
529 if (ortn
== errSSLWouldBlock
) {
530 ortn
= errSecSuccess
;
536 doPause("Client GET msg received");
539 /* send out canned response */
540 length
= strlen(outMsg
);
541 ortn
= SSLWrite(ctx
, outMsg
, length
, &length
);
543 printSslErrStr("SSLWrite", ortn
);
546 doPause("Server response sent");
550 * always do close, even on error - to flush outgoing write queue
552 OSStatus cerr
= SSLClose(ctx
);
553 if(ortn
== errSecSuccess
) {
557 endpointShutdown(acceptSock
);
560 SSLDisposeContext(ctx
);
562 /* FIXME - dispose of serverCerts */
566 static void showPeerCerts(
567 CFArrayRef peerCerts
,
571 SecCertificateRef certRef
;
574 if(peerCerts
== NULL
) {
577 numCerts
= CFArrayGetCount(peerCerts
);
578 for(i
=0; i
<numCerts
; i
++) {
579 certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
);
580 printf("\n================== Server Cert %lu ===================\n\n", i
);
581 print_cert(certRef
, verbose
);
582 printf("\n=============== End of Server Cert %lu ===============\n", i
);
586 static void writePeerCerts(
587 CFArrayRef peerCerts
,
588 const char *fileBase
)
591 SecCertificateRef certRef
;
595 if(peerCerts
== NULL
) {
598 numCerts
= CFArrayGetCount(peerCerts
);
599 for(i
=0; i
<numCerts
; i
++) {
600 sprintf(fileName
, "%s%02d.cer", fileBase
, (int)i
);
601 certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(peerCerts
, i
);
602 writeFile(fileName
, SecCertificateGetBytePtr(certRef
),
603 SecCertificateGetLength(certRef
));
605 printf("...wrote %lu certs to fileBase %s\n", numCerts
, fileBase
);
608 static void showSSLResult(
609 SSLProtocol tryVersion
,
612 SSLProtocol negVersion
,
613 SSLCipherSuite negCipher
,
614 Boolean sessionWasResumed
,
615 unsigned char *sessionID
,
616 size_t sessionIDLength
,
617 CFArrayRef peerCerts
,
618 bool displayPeerCerts
,
619 SSLClientCertificateState certState
,
620 char *fileBase
) // non-NULL: write certs to file
622 CFIndex numPeerCerts
;
626 printf(" Allowed SSL versions : %s\n", acceptedProts
);
629 printf(" Attempted SSL version : %s\n",
630 sslGetProtocolVersionString(tryVersion
));
632 printf(" Result : %s\n", sslGetSSLErrString(err
));
633 printf(" Negotiated SSL version : %s\n",
634 sslGetProtocolVersionString(negVersion
));
635 printf(" Negotiated CipherSuite : %s\n",
636 sslGetCipherSuiteString(negCipher
));
637 if(certState
!= kSSLClientCertNone
) {
638 printf(" Client Cert State : %s\n",
639 sslGetClientCertStateString(certState
));
641 printf(" Resumed Session : ");
642 if(sessionWasResumed
) {
643 for(unsigned dex
=0; dex
<sessionIDLength
; dex
++) {
644 printf("%02X ", sessionID
[dex
]);
645 if(((dex
% 8) == 7) && (dex
!= (sessionIDLength
- 1))) {
652 printf("NOT RESUMED\n");
654 if(peerCerts
== NULL
) {
658 numPeerCerts
= CFArrayGetCount(peerCerts
);
660 printf(" Number of peer certs : %lu\n", numPeerCerts
);
661 if(numPeerCerts
!= 0) {
662 if(displayPeerCerts
) {
663 showPeerCerts(peerCerts
, false);
665 if(fileBase
!= NULL
) {
666 writePeerCerts(peerCerts
, fileBase
);
672 static int verifyClientCertState(
673 bool verifyCertState
,
674 SSLClientCertificateState expectState
,
675 SSLClientCertificateState gotState
)
677 if(!verifyCertState
) {
680 if(expectState
== gotState
) {
683 printf("***Expected clientCertState %s; got %s\n",
684 sslGetClientCertStateString(expectState
),
685 sslGetClientCertStateString(gotState
));
689 int main(int argc
, char **argv
)
693 char fullFileBase
[100];
694 SSLProtocol negVersion
;
695 SSLCipherSuite negCipher
;
696 Boolean sessionWasResumed
;
697 unsigned char sessionID
[MAX_SESSION_ID_LENGTH
];
698 size_t sessionIDLength
;
699 CFArrayRef peerCerts
= NULL
;
702 CFArrayRef serverCerts
= nil
; // required
703 CFArrayRef encryptCerts
= nil
; // optional
704 SecKeychainRef serverKc
= nil
;
705 SecKeychainRef encryptKc
= nil
;
708 SSLClientCertificateState certState
; // obtained from sslServe
710 /* user-spec'd parameters */
711 unsigned short portNum
= DEFAULT_PORT
;
712 bool allowExpired
= false;
713 bool allowAnyRoot
= false;
714 char *fileBase
= NULL
;
715 bool displayCerts
= false;
716 char cipherRestrict
= '\0';
717 SSLProtocol attemptProt
= kTLSProtocol1
;
718 bool protXOnly
= false; // kSSLProtocol3Only,
720 char *acceptedProts
= NULL
; // "23t" ==> SSLSetProtocolVersionEnabled
722 bool resumableEnable
= true;
724 char *keyChainName
= NULL
;
725 char *encryptKeyChainName
= NULL
;
727 SSLAuthenticate authenticate
= kNeverAuthenticate
;
728 bool nonBlocking
= false;
729 bool allowExpiredRoot
= false;
730 bool disableCertVerify
= false;
731 char *anchorFile
= NULL
;
732 bool replaceAnchors
= false;
733 bool vfyCertState
= false;
734 SSLClientCertificateState expectCertState
= kSSLClientCertNone
;
735 char *password
= NULL
;
736 char *dhParamsFile
= NULL
;
737 unsigned char *dhParams
= NULL
;
738 unsigned dhParamsLen
= 0;
739 bool doIdSearch
= false;
740 bool completeCertChain
= false;
741 uint32_t sessionCacheTimeout
= 0;
742 bool disableAnonCiphers
= false;
743 CFMutableArrayRef acceptableDNList
= NULL
;
745 for(arg
=1; arg
<argc
; arg
++) {
749 portNum
= atoi(&argp
[2]);
752 keyChainName
= &argp
[2];
755 encryptKeyChainName
= &argp
[2];
761 allowExpiredRoot
= true;
764 disableCertVerify
= true;
768 /* requires another arg */
771 anchorFile
= argv
[arg
];
775 /* requires another arg */
778 anchorFile
= argv
[arg
];
779 replaceAnchors
= true;
788 expectCertState
= kSSLClientCertNone
;
791 expectCertState
= kSSLClientCertRequested
;
794 expectCertState
= kSSLClientCertSent
;
797 expectCertState
= kSSLClientCertRejected
;
815 cipherRestrict
= argp
[2];
818 attemptProt
= kSSLProtocol2
;
821 attemptProt
= kSSLProtocol3
;
824 attemptProt
= kTLSProtocol1
;
833 acceptedProts
= &argp
[2];
836 resumableEnable
= false;
846 case 'a': authenticate
= kAlwaysAuthenticate
; break;
847 case 'n': authenticate
= kNeverAuthenticate
; break;
848 case 't': authenticate
= kTryAuthenticate
; break;
849 default: usage(argv
);
854 /* requires another arg */
857 dhParamsFile
= argv
[arg
];
866 completeCertChain
= true;
869 sessionCacheTimeout
= atoi(&argp
[2]);
872 disableAnonCiphers
= true;
883 /* requires another arg */
886 if(cspReadFile(argv
[arg
], &caCert
, &caCertLen
)) {
887 printf("***Error reading file %s. Aborting.\n", argv
[arg
]);
890 if(acceptableDNList
== NULL
) {
891 acceptableDNList
= CFArrayCreateMutable(NULL
, 0, &kCFTypeArrayCallBacks
);
893 certData
.Data
= caCert
;
894 certData
.Length
= caCertLen
;
895 ortn
= SecCertificateCreateFromData(&certData
,
897 CSSM_CERT_ENCODING_DER
,
900 cssmPerror("SecCertificateCreateFromData", ortn
);
903 CFArrayAppendValue(acceptableDNList
, secCert
);
908 if(argp
[1] == '\0') {
909 /* no loop count --> loop forever */
913 else if(argp
[1] != '=') {
916 loops
= atoi(&argp
[2]);
925 securityd_init(NULL
);
929 /* get server cert and optional encryption cert as CFArrayRef */
931 serverCerts
= getSslCerts(keyChainName
, false, completeCertChain
,
932 anchorFile
, &serverKc
);
933 if(serverCerts
== nil
) {
940 OSStatus ortn
= sslIdentityPicker(NULL
, anchorFile
, true, NULL
, &serverCerts
);
942 printf("***IdentitySearch failure; aborting.\n");
947 OSStatus ortn
= SecKeychainUnlock(serverKc
, strlen(password
), password
, true);
949 printf("SecKeychainUnlock returned %d\n", (int)ortn
);
953 if(encryptKeyChainName
) {
954 encryptCerts
= getSslCerts(encryptKeyChainName
, true, completeCertChain
,
955 anchorFile
, &encryptKc
);
956 if(encryptCerts
== nil
) {
962 (void) encryptKeyChainName
;
965 switch(attemptProt
) {
967 attemptProt
= kTLSProtocol1Only
;
970 attemptProt
= kSSLProtocol3Only
;
978 int r
= cspReadFile(dhParamsFile
, &dhParams
, &dhParamsLen
);
980 printf("***Error reading diffie-hellman params from %s; aborting\n",
988 /* one-time only server port setup */
989 err
= ListenForClients(portNum
, nonBlocking
, &listenSock
);
991 printf("ListenForClients returned %d; aborting\n", (int)err
);
995 for(loopNum
=1; ; loopNum
++) {
996 err
= sslServe(listenSock
,
1015 sessionCacheTimeout
,
1031 SSLProtocol tryProt
= attemptProt
;
1032 showSSLResult(tryProt
,
1043 fileBase
? fullFileBase
: NULL
);
1045 errCount
+= verifyClientCertState(vfyCertState
, expectCertState
,
1047 freePeerCerts(peerCerts
);
1048 if(loops
&& (loopNum
== loops
)) {
1053 endpointShutdown(listenSock
);
1056 CFRelease(serverKc
);
1059 CFRelease(encryptKc
);