OSStatus sslSetProtocols( SSLContextRef ctx, const char *acceptedProts, SSLProtocol tryVersion) // only used if acceptedProts NULL { OSStatus ortn; if(acceptedProts) { #if JAGUAR_BUILD printf("***SSLSetProtocolVersionEnabled not supported in this config.\n"); exit(1); #endif ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false); if(ortn) { printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn); return ortn; } for(const char *cp = acceptedProts; *cp; cp++) { SSLProtocol prot; switch(*cp) { case '2': prot = kSSLProtocol2; break; case '3': prot = kSSLProtocol3; break; case 't': prot = kTLSProtocol1; break; default: printf("***BRRZAP! Bad acceptedProts string %s. Aborting.\n", acceptedProts); exit(1); } ortn = SSLSetProtocolVersionEnabled(ctx, prot, true); if(ortn) { printSslErrStr("SSLSetProtocolVersionEnabled", ortn); return ortn; } } } else { ortn = SSLSetProtocolVersion(ctx, tryVersion); if(ortn) { printSslErrStr("SSLSetProtocolVersion", ortn); return ortn; } } return errSecSuccess; }
static OSStatus sslServe( otSocket listenSock, SSLProtocol tryVersion, const char *hostName, // e.g., "www.amazon.com" CFArrayRef serverCerts, // required CFArrayRef encryptServerCerts, // optional CSSM_BOOL allowExpired, CSSM_BOOL allowAnyRoot, char cipherRestrict, // '2', 'd'. etc...'\0' for no // restriction SSLAuthenticate authenticate, CSSM_BOOL resumableEnable, CSSM_BOOL silent, // no stdout CSSM_BOOL pause, SSLProtocol *negVersion, // RETURNED SSLCipherSuite *negCipher, // RETURNED CFArrayRef *peerCerts) // mallocd & RETURNED { otSocket acceptSock; PeerSpec peerId; OSStatus ortn; SSLContextRef ctx = NULL; UInt32 length; uint8 rcvBuf[RCV_BUF_SIZE]; char *outMsg = SERVER_MESSAGE; *negVersion = kSSLProtocolUnknown; *negCipher = SSL_NULL_WITH_NULL_NULL; *peerCerts = NULL; #if IGNORE_SIGPIPE signal(SIGPIPE, sigpipe); #endif /* first wait for a connection */ if(!silent) { printf("Waiting for client connection..."); fflush(stdout); } ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId); if(ortn) { printf("AcceptClientConnection returned %d; aborting\n", ortn); return ortn; } /* * Set up a SecureTransport session. * First the standard calls. */ ortn = SSLNewContext(true, &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, acceptSock); if(ortn) { printSslErrStr("SSLSetConnection", ortn); goto cleanup; } ortn = SSLSetPeerDomainName(ctx, hostName, strlen(hostName) + 1); if(ortn) { printSslErrStr("SSLSetPeerDomainName", ortn); goto cleanup; } /* have to do these options befor setting server certs */ if(allowExpired) { ortn = SSLSetAllowsExpiredCerts(ctx, true); if(ortn) { printSslErrStr("SSLSetAllowExpiredCerts", ortn); goto cleanup; } } if(allowAnyRoot) { ortn = SSLSetAllowsAnyRoot(ctx, true); if(ortn) { printSslErrStr("SSLSetAllowAnyRoot", ortn); goto cleanup; } } ortn = SSLSetCertificate(ctx, serverCerts); if(ortn) { printSslErrStr("SSLSetCertificate", ortn); goto cleanup; } if(encryptServerCerts) { ortn = SSLSetEncryptionCertificate(ctx, encryptServerCerts); if(ortn) { printSslErrStr("SSLSetEncryptionCertificate", ortn); goto cleanup; } } /* * SecureTransport options. */ if(resumableEnable) { ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec)); if(ortn) { printSslErrStr("SSLSetPeerID", ortn); goto cleanup; } } if(cipherRestrict != '\0') { ortn = setCipherRestrictions(ctx, cipherRestrict); if(ortn) { goto cleanup; } } #if AUTHENTICATE_ENABLE if(authenticate != kNeverAuthenticate) { ortn = SSLSetClientSideAuthenticate(ctx, authenticate); if(ortn) { printSslErrStr("SSLSetClientSideAuthenticate", ortn); goto cleanup; } } #endif if(pause) { doPause("SSLContext initialized"); } /* Perform SSL/TLS handshake */ do { ortn = SSLHandshake(ctx); if((ortn == errSSLWouldBlock) && !silent) { /* keep UI responsive */ outputDot(); } } while (ortn == errSSLWouldBlock); /* this works even if handshake failed due to cert chain invalid */ copyPeerCerts(ctx, peerCerts); SSLGetNegotiatedCipher(ctx, negCipher); SSLGetNegotiatedProtocolVersion(ctx, negVersion); if(!silent) { printf("\n"); } if(ortn) { goto cleanup; } if(pause) { doPause("SSLContext handshake complete"); } /* wait for one complete line or user says they've had enough */ while(ortn == noErr) { length = sizeof(rcvBuf); ortn = SSLRead(ctx, rcvBuf, length, &length); if(length == 0) { /* keep UI responsive */ outputDot(); } else { /* print what we have */ printf("client request: "); dumpAscii(rcvBuf, length); } if(pause) { /* allow user to bail */ char resp; fpurge(stdin); printf("\nMore client request (y/anything): "); resp = getchar(); if(resp != 'y') { break; } } /* poor person's line completion scan */ for(unsigned i=0; i<length; i++) { if((rcvBuf[i] == '\n') || (rcvBuf[i] == '\r')) { /* a labelled break would be nice here.... */ goto serverResp; } } if (ortn == errSSLWouldBlock) { ortn = noErr; } } serverResp: if(pause) { doPause("Client GET msg received"); } /* send out canned response */ length = strlen(outMsg); ortn = SSLWrite(ctx, outMsg, length, &length); if(ortn) { printSslErrStr("SSLWrite", ortn); } if(pause) { doPause("Server response sent"); } if (ortn == noErr) { ortn = SSLClose(ctx); } cleanup: if(acceptSock) { endpointShutdown(acceptSock); } if(ctx) { SSLDisposeContext(ctx); } /* FIXME - dispose of serverCerts */ return ortn; }
static OSStatus sslServe( otSocket listenSock, unsigned short portNum, SSLProtocol tryVersion, // only used if acceptedProts NULL const char *acceptedProts, CFArrayRef serverCerts, // required char *password, // optional CFArrayRef encryptServerCerts, // optional bool allowExpired, bool allowAnyRoot, bool allowExpiredRoot, bool disableCertVerify, char *anchorFile, bool replaceAnchors, char cipherRestrict, // '2', 'd'. etc...'\0' for no // restriction SSLAuthenticate authenticate, unsigned char *dhParams, // optional D-H parameters unsigned dhParamsLen, CFArrayRef acceptableDNList, // optional bool resumableEnable, uint32_t sessionCacheTimeout,// optional bool disableAnonCiphers, bool silent, // no stdout bool pause, SSLProtocol *negVersion, // RETURNED SSLCipherSuite *negCipher, // RETURNED SSLClientCertificateState *certState, // RETURNED Boolean *sessionWasResumed, // RETURNED unsigned char *sessionID, // mallocd by caller, RETURNED size_t *sessionIDLength, // RETURNED CFArrayRef *peerCerts, // mallocd & RETURNED char **argv) { otSocket acceptSock; PeerSpec peerId; OSStatus ortn; SSLContextRef ctx = NULL; size_t length; uint8_t rcvBuf[RCV_BUF_SIZE]; const char *outMsg = SERVER_MESSAGE; *negVersion = kSSLProtocolUnknown; *negCipher = SSL_NULL_WITH_NULL_NULL; *peerCerts = NULL; #if IGNORE_SIGPIPE signal(SIGPIPE, sigpipe); #endif /* first wait for a connection */ if(!silent) { printf("Waiting for client connection on port %u...", portNum); fflush(stdout); } ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId); if(ortn) { printf("AcceptClientConnection returned %d; aborting\n", (int)ortn); return ortn; } /* * Set up a SecureTransport session. * First the standard calls. */ ortn = SSLNewContext(true, &ctx); if(ortn) { printSslErrStr("SSLNewContext", ortn); goto cleanup; } ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite); if(ortn) { printSslErrStr("SSLSetIOFuncs", ortn); goto cleanup; } ortn = SSLSetConnection(ctx, (SSLConnectionRef)(intptr_t)acceptSock); if(ortn) { printSslErrStr("SSLSetConnection", ortn); goto cleanup; } /* have to do these options befor setting server certs */ if(allowExpired) { ortn = SSLSetAllowsExpiredCerts(ctx, true); if(ortn) { printSslErrStr("SSLSetAllowExpiredCerts", ortn); goto cleanup; } } if(allowAnyRoot) { ortn = SSLSetAllowsAnyRoot(ctx, true); if(ortn) { printSslErrStr("SSLSetAllowAnyRoot", ortn); goto cleanup; } } if(anchorFile) { ortn = sslAddTrustedRoot(ctx, anchorFile, replaceAnchors); if(ortn) { printf("***Error obtaining anchor file %s\n", anchorFile); goto cleanup; } } if(serverCerts != NULL) { if(anchorFile == NULL) { /* no specific anchors, so assume we want to trust this one */ ortn = addIdentityAsTrustedRoot(ctx, serverCerts); if(ortn) { goto cleanup; } } ortn = SSLSetCertificate(ctx, serverCerts); if(ortn) { printSslErrStr("SSLSetCertificate", ortn); goto cleanup; } } if(encryptServerCerts) { ortn = SSLSetEncryptionCertificate(ctx, encryptServerCerts); if(ortn) { printSslErrStr("SSLSetEncryptionCertificate", ortn); goto cleanup; } } if(allowExpiredRoot) { ortn = SSLSetAllowsExpiredRoots(ctx, true); if(ortn) { printSslErrStr("SSLSetAllowsExpiredRoots", ortn); goto cleanup; } } if(disableCertVerify) { ortn = SSLSetEnableCertVerify(ctx, false); if(ortn) { printSslErrStr("SSLSetEnableCertVerify", ortn); goto cleanup; } } /* * SecureTransport options. */ if(acceptedProts) { ortn = SSLSetProtocolVersionEnabled(ctx, kSSLProtocolAll, false); if(ortn) { printSslErrStr("SSLSetProtocolVersionEnabled(all off)", ortn); goto cleanup; } for(const char *cp = acceptedProts; *cp; cp++) { SSLProtocol prot = kSSLProtocolUnknown; switch(*cp) { case '2': prot = kSSLProtocol2; break; case '3': prot = kSSLProtocol3; break; case 't': prot = kTLSProtocol1; break; default: usage(argv); } ortn = SSLSetProtocolVersionEnabled(ctx, prot, true); if(ortn) { printSslErrStr("SSLSetProtocolVersionEnabled", ortn); goto cleanup; } } } else { ortn = SSLSetProtocolVersion(ctx, tryVersion); if(ortn) { printSslErrStr("SSLSetProtocolVersion", ortn); goto cleanup; } } if(resumableEnable) { ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec)); if(ortn) { printSslErrStr("SSLSetPeerID", ortn); goto cleanup; } } if(cipherRestrict != '\0') { ortn = sslSetCipherRestrictions(ctx, cipherRestrict); if(ortn) { goto cleanup; } } if(authenticate != kNeverAuthenticate) { ortn = SSLSetClientSideAuthenticate(ctx, authenticate); if(ortn) { printSslErrStr("SSLSetClientSideAuthenticate", ortn); goto cleanup; } } if(dhParams) { ortn = SSLSetDiffieHellmanParams(ctx, dhParams, dhParamsLen); if(ortn) { printSslErrStr("SSLSetDiffieHellmanParams", ortn); goto cleanup; } } if(sessionCacheTimeout) { ortn = SSLSetSessionCacheTimeout(ctx, sessionCacheTimeout); if(ortn) { printSslErrStr("SSLSetSessionCacheTimeout", ortn); goto cleanup; } } if(disableAnonCiphers) { ortn = SSLSetAllowAnonymousCiphers(ctx, false); if(ortn) { printSslErrStr("SSLSetAllowAnonymousCiphers", ortn); goto cleanup; } /* quickie test of the getter */ Boolean e; ortn = SSLGetAllowAnonymousCiphers(ctx, &e); if(ortn) { printSslErrStr("SSLGetAllowAnonymousCiphers", ortn); goto cleanup; } if(e) { printf("***SSLGetAllowAnonymousCiphers() returned true; expected false\n"); ortn = errSecIO; goto cleanup; } } /* XXX/cs if(acceptableDNList) { ortn = SSLSetCertificateAuthorities(ctx, acceptableDNList, TRUE); if(ortn) { printSslErrStr("SSLSetCertificateAuthorities", ortn); goto cleanup; } } */ /* end options */ if(pause) { doPause("SSLContext initialized"); } /* Perform SSL/TLS handshake */ do { ortn = SSLHandshake(ctx); if((ortn == errSSLWouldBlock) && !silent) { /* keep UI responsive */ sslOutputDot(); } } while (ortn == errSSLWouldBlock); /* this works even if handshake failed due to cert chain invalid */ copyPeerCerts(ctx, peerCerts); SSLGetClientCertificateState(ctx, certState); SSLGetNegotiatedCipher(ctx, negCipher); SSLGetNegotiatedProtocolVersion(ctx, negVersion); *sessionIDLength = MAX_SESSION_ID_LENGTH; SSLGetResumableSessionInfo(ctx, sessionWasResumed, sessionID, sessionIDLength); if(!silent) { printf("\n"); } if(ortn) { goto cleanup; } if(pause) { doPause("SSLContext handshake complete"); } /* wait for one complete line or user says they've had enough */ while(ortn == errSecSuccess) { length = sizeof(rcvBuf); ortn = SSLRead(ctx, rcvBuf, length, &length); if(length == 0) { /* keep UI responsive */ sslOutputDot(); } else { /* print what we have */ printf("client request: "); dumpAscii(rcvBuf, length); } if(pause) { /* allow user to bail */ char resp; fpurge(stdin); printf("\nMore client request (y/anything): "); resp = getchar(); if(resp != 'y') { break; } } /* poor person's line completion scan */ for(unsigned i=0; i<length; i++) { if((rcvBuf[i] == '\n') || (rcvBuf[i] == '\r')) { /* a labelled break would be nice here.... */ goto serverResp; } } if (ortn == errSSLWouldBlock) { ortn = errSecSuccess; } } serverResp: if(pause) { doPause("Client GET msg received"); } /* send out canned response */ length = strlen(outMsg); ortn = SSLWrite(ctx, outMsg, length, &length); if(ortn) { printSslErrStr("SSLWrite", ortn); } if(pause) { doPause("Server response sent"); } cleanup: /* * always do close, even on error - to flush outgoing write queue */ OSStatus cerr = SSLClose(ctx); if(ortn == errSecSuccess) { ortn = cerr; } if(acceptSock) { endpointShutdown(acceptSock); } if(ctx) { SSLDisposeContext(ctx); } /* FIXME - dispose of serverCerts */ return ortn; }
int main(int argc, char **argv) { /* user-spec'd variables */ const char *kcName = DEFAULT_KC; unsigned xferSize = XFERSIZE_DEF; int port = PORT_DEF; const char *hostName = HOST_DEF; SSLCipherSuite cipherSuite = TLS_RSA_WITH_AES_128_CBC_SHA; SSLProtocol prot = kTLSProtocol1Only; char password[200]; bool clientAuthEnable = false; bool isServer = false; unsigned bufSize = BUFSIZE; bool diffieHellman = false; int nonBlocking = 0; if(argc < 2) { usage(argv); } password[0] = 0; switch(argv[1][0]) { case 's': isServer = true; break; case 'c': isServer = false; break; default: usage(argv); } extern int optind; extern char *optarg; int arg; optind = 2; while ((arg = getopt(argc, argv, "h:p:k:x:c:v:w:b:aB")) != -1) { switch (arg) { case 'h': hostName = optarg; break; case 'p': port = atoi(optarg); break; case 'k': kcName = optarg; break; case 'x': xferSize = atoi(optarg); break; case 'c': if(!isServer) { printf("***Specify cipherSuite on server side.\n"); exit(1); } switch(optarg[0]) { case 'r': cipherSuite = SSL_RSA_WITH_RC4_128_SHA; break; case 'd': cipherSuite = SSL_RSA_WITH_DES_CBC_SHA; break; case 'D': cipherSuite = SSL_RSA_WITH_3DES_EDE_CBC_SHA; break; case 'h': cipherSuite = SSL_DH_anon_WITH_RC4_128_MD5; diffieHellman = true; break; case 'H': cipherSuite = SSL_DHE_DSS_WITH_DES_CBC_SHA; diffieHellman = true; break; case 'A': cipherSuite = TLS_RSA_WITH_AES_256_CBC_SHA; break; default: usage(argv); } break; case 'v': if(!isServer) { printf("***Specify protocol on server side.\n"); exit(1); } switch(optarg[0]) { case 't': prot = kTLSProtocol1Only; break; case '2': prot = kSSLProtocol2; break; case '3': prot = kSSLProtocol3Only; break; default: usage(argv); } break; case 'w': strcpy(password, optarg); break; case 'b': bufSize = atoi(optarg); break; case 'a': clientAuthEnable = true; break; case 'B': nonBlocking = 1; break; default: usage(argv); } } /* per-transfer buffer - make it random for server */ char *buf = (char *)malloc(bufSize); if(isServer) { Security::DevRandomGenerator rng; rng.random(buf, bufSize); } /* gather Diffie-Hellman params from cwd */ unsigned char *dhParams = NULL; unsigned dhParamsLen = 0; if(diffieHellman && isServer) { if(readFile(DH_PARAM_FILE, &dhParams, &dhParamsLen)) { printf("***Error reading Diffie-Hellman Params. Prepare to " "wait for a minute during SSL handshake.\n"); } } /* * Open keychain; both sides use the same one. */ OSStatus ortn; SecKeychainRef certKc = NULL; CFAbsoluteTime kcOpenStart = CFAbsoluteTimeGetCurrent(); ortn = SecKeychainOpen(kcName, &certKc); if(ortn) { printf("Error opening keychain %s (%d); aborting.\n", kcName, (int)ortn); exit(1); } if(password[0]) { ortn = SecKeychainUnlock(certKc, strlen(password), password, true); if(ortn) { printf("SecKeychainUnlock returned %d\n", (int)ortn); /* oh well */ } } CFAbsoluteTime kcOpenEnd = CFAbsoluteTimeGetCurrent(); otSocket peerSock = 0; otSocket listenSock = 0; // for server only PeerSpec peerId; if(isServer) { printf("...listening for client connection on port %d\n", port); ortn = ListenForClients(port, nonBlocking, &listenSock); if(ortn) { printf("...error establishing a listen socket. Aborting.\n"); exit(1); } ortn = AcceptClientConnection(listenSock, &peerSock, &peerId); if(ortn) { printf("...error listening for connection. Aborting.\n"); exit(1); } } else { printf("...connecting to host %s at port %d\n", hostName, port); ortn = MakeServerConnection(hostName, port, nonBlocking, &peerSock, &peerId); if(ortn) { printf("...error connecting to server %s. Aborting.\n", hostName); exit(1); } } /* start timing SSL setup */ CFAbsoluteTime setupStart = CFAbsoluteTimeGetCurrent(); SSLContextRef ctx; ortn = SSLNewContext(isServer, &ctx); if(ortn) { printSslErrStr("SSLNewContext", ortn); exit(1); } ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite); if(ortn) { printSslErrStr("SSLSetIOFuncs", ortn); exit(1); } ortn = SSLSetConnection(ctx, (SSLConnectionRef)peerSock); if(ortn) { printSslErrStr("SSLSetConnection", ortn); exit(1); } ortn = SSLSetPeerDomainName(ctx, hostName, strlen(hostName) + 1); if(ortn) { printSslErrStr("SSLSetPeerDomainName", ortn); exit(1); } /* * Server/client specific setup. * * Client uses the same keychain as server, but it uses it for * sslAddTrustedRoots() instead of getSslCerts() and * SSLSetCertificate(). */ CFArrayRef myCerts = NULL; if(clientAuthEnable || isServer) { myCerts = sslKcRefToCertArray(certKc, CSSM_FALSE, CSSM_FALSE, NULL, NULL); if(myCerts == NULL) { exit(1); } ortn = addIdentityAsTrustedRoot(ctx, myCerts); if(ortn) { exit(1); } ortn = SSLSetCertificate(ctx, myCerts); if(ortn) { printSslErrStr("SSLSetCertificate", ortn); exit(1); } } if(isServer) { SSLAuthenticate auth; if(clientAuthEnable) { auth = kAlwaysAuthenticate; } else { auth = kNeverAuthenticate; } ortn = SSLSetClientSideAuthenticate(ctx, auth); if(ortn) { printSslErrStr("SSLSetClientSideAuthenticate", ortn); exit(1); } ortn = SSLSetEnabledCiphers(ctx, &cipherSuite, 1); if(ortn) { printSslErrStr("SSLSetEnabledCiphers", ortn); exit(1); } ortn = SSLSetProtocolVersion(ctx, prot); if(ortn) { printSslErrStr("SSLSetProtocolVersion", ortn); exit(1); } if(dhParams != NULL) { ortn = SSLSetDiffieHellmanParams(ctx, dhParams, dhParamsLen); if(ortn) { printSslErrStr("SSLSetDiffieHellmanParams", ortn); exit(1); } } } else { /* client setup */ if(!clientAuthEnable) { /* We're not presenting a cert; trust the server certs */ bool foundOne; ortn = sslAddTrustedRoots(ctx, certKc, &foundOne); if(ortn) { printSslErrStr("sslAddTrustedRoots", ortn); exit(1); } } } /* * Context setup complete. Start timing handshake. */ CFAbsoluteTime hshakeStart = CFAbsoluteTimeGetCurrent(); do { ortn = SSLHandshake(ctx); } while (ortn == errSSLWouldBlock); if(ortn) { printSslErrStr("SSLHandshake", ortn); exit(1); } CFAbsoluteTime hshakeEnd = CFAbsoluteTimeGetCurrent(); /* snag these before data xfer possibly shuts down connection */ SSLProtocol negVersion; SSLCipherSuite negCipher; SSLClientCertificateState certState; // RETURNED SSLGetNegotiatedCipher(ctx, &negCipher); SSLGetNegotiatedProtocolVersion(ctx, &negVersion); SSLGetClientCertificateState(ctx, &certState); /* server sends xferSize bytes to client and shuts down */ size_t bytesMoved; CFAbsoluteTime dataStart = CFAbsoluteTimeGetCurrent(); size_t totalMoved = 0; if(isServer) { size_t bytesToGo = xferSize; bool done = false; do { size_t thisMove = bufSize; if(thisMove > bytesToGo) { thisMove = bytesToGo; } ortn = SSLWrite(ctx, buf, thisMove, &bytesMoved); switch(ortn) { case noErr: case errSSLWouldBlock: break; default: done = true; break; } bytesToGo -= bytesMoved; totalMoved += bytesMoved; if(bytesToGo == 0) { done = true; } } while(!done); if(ortn != noErr) { printSslErrStr("SSLWrite", ortn); exit(1); } } else { /* client reads until error or errSSLClosedGraceful */ bool done = false; do { ortn = SSLRead(ctx, buf, bufSize, &bytesMoved); switch(ortn) { case errSSLClosedGraceful: done = true; break; case noErr: case errSSLWouldBlock: break; default: done = true; break; } totalMoved += bytesMoved; } while(!done); if(ortn != errSSLClosedGraceful) { printSslErrStr("SSLRead", ortn); exit(1); } } /* shut down channel */ ortn = SSLClose(ctx); if(ortn) { printSslErrStr("SSLCLose", ortn); exit(1); } CFAbsoluteTime dataEnd = CFAbsoluteTimeGetCurrent(); /* how'd we do? */ printf("SSL version : %s\n", sslGetProtocolVersionString(negVersion)); printf("CipherSuite : %s\n", sslGetCipherSuiteString(negCipher)); printf("Client Cert State : %s\n", sslGetClientCertStateString(certState)); if(password[0]) { printf("keychain open/unlock : "); } else { printf("keychain open : "); } printf("%f s\n", kcOpenEnd - kcOpenStart); printf("SSLContext setup : %f s\n", hshakeStart - setupStart); printf("SSL Handshake : %f s\n", hshakeEnd - hshakeStart); printf("Data Transfer : %u bytes in %f s\n", (unsigned)totalMoved, dataEnd - dataStart); printf(" : %.1f Kbytes/s\n", totalMoved / (dataEnd - dataStart) / 1024.0); return 0; }