SECURITY_STATUS schan_imp_get_connection_info(schan_imp_session session, SecPkgContext_ConnectionInfo *info) { struct mac_session* s = (struct mac_session*)session; SSLCipherSuite cipherSuite; const struct cipher_suite* c; int status; TRACE("(%p/%p, %p)\n", s, s->context, info); status = SSLGetNegotiatedCipher(s->context, &cipherSuite); if (status != noErr) { ERR("Failed to get session cipher suite: %d\n", status); return SEC_E_INTERNAL_ERROR; } c = get_cipher_suite(cipherSuite); if (!c) { ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite); return SEC_E_INTERNAL_ERROR; } info->dwProtocol = schan_get_session_protocol(s); info->aiCipher = schan_get_cipher_algid(c); info->dwCipherStrength = schan_get_cipher_key_size(c); info->aiHash = schan_get_mac_algid(c); info->dwHashStrength = schan_get_mac_key_size(c); info->aiExch = schan_get_kx_algid(c); /* FIXME: info->dwExchStrength? */ info->dwExchStrength = 0; return SEC_E_OK; }
const char* Connection::currentCipher() const { SSLCipherSuite cipherSuite; SSLGetNegotiatedCipher(_context, &cipherSuite); const char* name = toCipherName(cipherSuite); return name; }
static CURLcode darwinssl_connect_step2(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; OSStatus err; SSLCipherSuite cipher; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state); /* Here goes nothing: */ err = SSLHandshake(connssl->ssl_ctx); if(err != noErr) { switch (err) { case errSSLWouldBlock: /* they're not done with us yet */ connssl->connecting_state = connssl->ssl_direction ? ssl_connect_2_writing : ssl_connect_2_reading; return CURLE_OK; break; case errSSLServerAuthCompleted: /* the documentation says we need to call SSLHandshake() again */ return darwinssl_connect_step2(conn, sockindex); case errSSLXCertChainInvalid: case errSSLUnknownRootCert: case errSSLNoRootCert: case errSSLCertExpired: failf(data, "SSL certificate problem: OSStatus %d", err); return CURLE_SSL_CACERT; break; default: failf(data, "Unknown SSL protocol error in connection to %s:%d", conn->host.name, err); return CURLE_SSL_CONNECT_ERROR; break; } } else { /* we have been connected fine, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_3; /* Informational message */ (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); infof (data, "SSL connection using %s\n", CipherNameForNumber(cipher)); return CURLE_OK; } }
unsigned int schan_imp_get_session_cipher_block_size(schan_imp_session session) { struct mac_session* s = (struct mac_session*)session; SSLCipherSuite cipherSuite; const struct cipher_suite* c; int status; TRACE("(%p/%p)\n", s, s->context); status = SSLGetNegotiatedCipher(s->context, &cipherSuite); if (status != noErr) { ERR("Failed to get session cipher suite: %d\n", status); return 0; } c = get_cipher_suite(cipherSuite); if (!c) { ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite); return 0; } switch (c->enc_alg) { case schan_enc_3DES_EDE_CBC: return 64; case schan_enc_AES_128_CBC: return 128; case schan_enc_AES_128_GCM: return 128; case schan_enc_AES_256_CBC: return 128; case schan_enc_AES_256_GCM: return 128; case schan_enc_DES_CBC: return 64; case schan_enc_DES40_CBC: return 64; case schan_enc_NULL: return 0; case schan_enc_RC2_CBC_40: return 64; case schan_enc_RC2_CBC: return 64; case schan_enc_RC4_128: return 0; case schan_enc_RC4_40: return 0; case schan_enc_FORTEZZA_CBC: case schan_enc_IDEA_CBC: FIXME("Don't know block size for encryption algorithm %d, returning 0\n", c->enc_alg); return 0; default: FIXME("Unknown encryption algorithm %d for cipher suite %#x, returning 0\n", c->enc_alg, (unsigned int)c->suite); return 0; } }
static void *securetransport_ssl_thread(void *arg) { OSStatus ortn; int sock = (int)arg; int socket = accept(sock, NULL, NULL); CFArrayRef server_certs = server_chain(); ssl_test_handle * ssl = ssl_test_handle_create(socket, server_certs); SSLContextRef ctx = ssl->st; pthread_setname_np("server thread"); //uint64_t start = mach_absolute_time(); do { ortn = SSLHandshake(ctx); } while (ortn == errSSLWouldBlock); require_noerr_action_quiet(ortn, out, fprintf(stderr, "Fell out of SSLHandshake with error: %d\n", (int)ortn)); //uint64_t elapsed = mach_absolute_time() - start; //fprintf(stderr, "setr elapsed: %lld\n", elapsed); /* SSLProtocol proto = kSSLProtocolUnknown; require_noerr_quiet(SSLGetNegotiatedProtocolVersion(ctx, &proto), out); */ SSLCipherSuite cipherSuite; require_noerr_quiet(ortn = SSLGetNegotiatedCipher(ctx, &cipherSuite), out); //fprintf(stderr, "st negotiated %s\n", sslcipher_itoa(cipherSuite)); out: CFRelease(server_certs); SSLClose(ctx); CFRelease(ctx); if(ssl) { close(ssl->comm); free(ssl); } pthread_exit((void *)(intptr_t)ortn); return NULL; }
static gboolean get_cipher_details(PurpleSslConnection *gsc /* IN */, const char **ssl_info /* OUT */, const char **name /* OUT */, const char **mac /* OUT */, const char **key_exchange /* OUT */) { PurpleSslCDSAData *cdsa_data = PURPLE_SSL_CDSA_DATA(gsc); OSStatus err; SSLCipherSuite cipher; SSLProtocol protocol; err = SSLGetNegotiatedCipher(cdsa_data->ssl_ctx, &cipher); if (err != noErr) return FALSE; err = SSLGetNegotiatedProtocolVersion(cdsa_data->ssl_ctx, &protocol); if (err != noErr) return FALSE; *ssl_info = SSLVersionToString(protocol); *name = SSLCipherName(cipher); *mac = SSLMACName(cipher); *key_exchange = SSLKeyExchangeName(cipher); return TRUE; }
ALG_ID schan_imp_get_key_signature_algorithm(schan_imp_session session) { struct mac_session* s = (struct mac_session*)session; SSLCipherSuite cipherSuite; const struct cipher_suite* c; int status; TRACE("(%p/%p)\n", s, s->context); status = SSLGetNegotiatedCipher(s->context, &cipherSuite); if (status != noErr) { ERR("Failed to get session cipher suite: %d\n", status); return 0; } c = get_cipher_suite(cipherSuite); if (!c) { ERR("Unknown session cipher suite: %#x\n", (unsigned int)cipherSuite); return 0; } switch (c->kx_alg) { case schan_kx_DH_DSS_EXPORT: case schan_kx_DH_DSS: case schan_kx_DHE_DSS_EXPORT: case schan_kx_DHE_DSS: return CALG_DSS_SIGN; case schan_kx_DH_RSA_EXPORT: case schan_kx_DH_RSA: case schan_kx_DHE_RSA_EXPORT: case schan_kx_DHE_RSA: case schan_kx_ECDH_RSA: case schan_kx_ECDHE_RSA: case schan_kx_RSA_EXPORT: case schan_kx_RSA: return CALG_RSA_SIGN; case schan_kx_ECDH_ECDSA: case schan_kx_ECDHE_ECDSA: return CALG_ECDSA; case schan_kx_DH_anon_EXPORT: case schan_kx_DH_anon: case schan_kx_DHE_PSK: case schan_kx_ECDH_anon: case schan_kx_FORTEZZA_DMS: case schan_kx_NULL: case schan_kx_PSK: case schan_kx_RSA_PSK: FIXME("Don't know key signature algorithm for key exchange algorithm %d, returning 0\n", c->kx_alg); return 0; default: FIXME("Unknown key exchange algorithm %d for cipher suite %#x, returning 0\n", c->kx_alg, (unsigned int)c->suite); return 0; } }
/* * ssl_cdsa_handshake_cb */ static void ssl_cdsa_handshake_cb(gpointer data, gint source, PurpleInputCondition cond) { PurpleSslConnection *gsc = (PurpleSslConnection *)data; PurpleAccount *account = gsc->account; PurpleSslCDSAData *cdsa_data = PURPLE_SSL_CDSA_DATA(gsc); OSStatus err; purple_debug_info("cdsa", "Connecting\n"); /* * do the negotiation that sets up the SSL connection between * here and there. */ err = SSLHandshake(cdsa_data->ssl_ctx); if (err == errSSLPeerBadRecordMac && !purple_account_get_bool(account, PURPLE_SSL_CDSA_BUGGY_TLS_WORKAROUND, false) && !strcmp(purple_account_get_protocol_id(account),"prpl-jabber")) { /* * Set a flag so we know to explicitly disable TLS 1.1 and 1.2 on our next (immediate) connection attempt for this account. * Some XMPP servers use buggy TLS stacks that incorrectly report their capabilities, which breaks things with 10.8's new support * for TLS 1.1 and 1.2. */ purple_debug_info("cdsa", "SSLHandshake reported that the server rejected our MAC, which most likely means it lied about the TLS versions it supports."); purple_debug_info("cdsa", "Setting a flag in this account to only use TLS 1.0 and below on the next connection attempt."); purple_account_set_bool(account, PURPLE_SSL_CDSA_BUGGY_TLS_WORKAROUND, true); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } else if (err != noErr) { if(err == errSSLWouldBlock) return; fprintf(stderr,"cdsa: SSLHandshake failed with error %d\n",(int)err); purple_debug_error("cdsa", "SSLHandshake failed with error %d\n",(int)err); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } SSLCipherSuite cipher; SSLProtocol protocol; err = SSLGetNegotiatedCipher(cdsa_data->ssl_ctx, &cipher); if (err == noErr) { err = SSLGetNegotiatedProtocolVersion(cdsa_data->ssl_ctx, &protocol); purple_debug_info("cdsa", "Your connection is using %s with %s encryption, using %s for message authentication and %s key exchange (%X).\n", SSLVersionToString(protocol), SSLCipherName(cipher), SSLMACName(cipher), SSLKeyExchangeName(cipher), cipher); } purple_input_remove(cdsa_data->handshake_handler); cdsa_data->handshake_handler = 0; purple_debug_info("cdsa", "SSL_connect: verifying certificate\n"); if(certificate_ui_cb) { // does the application want to verify the certificate? struct query_cert_userdata *userdata = (struct query_cert_userdata*)malloc(sizeof(struct query_cert_userdata)); size_t hostnamelen = 0; SSLGetPeerDomainNameLength(cdsa_data->ssl_ctx, &hostnamelen); userdata->hostname = (char*)malloc(hostnamelen+1); SSLGetPeerDomainName(cdsa_data->ssl_ctx, userdata->hostname, &hostnamelen); userdata->hostname[hostnamelen] = '\0'; // just make sure it's zero-terminated userdata->cond = cond; userdata->gsc = gsc; SSLCopyPeerCertificates(cdsa_data->ssl_ctx, &userdata->certs); certificate_ui_cb(gsc, userdata->hostname, userdata->certs, query_cert_result, userdata); } else { purple_debug_info("cdsa", "SSL_connect complete (did not verify certificate)\n"); /* SSL connected now */ gsc->connect_cb(gsc->connect_cb_data, gsc, cond); } SSLCipherSuite suite; SSLGetNegotiatedCipher(cdsa_data->ssl_ctx, &suite); purple_debug_info("cdsa", "Using cipher %x.\n", suite); }
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 CURLcode darwinssl_connect_step2(struct connectdata *conn, int sockindex) { struct SessionHandle *data = conn->data; struct ssl_connect_data *connssl = &conn->ssl[sockindex]; OSStatus err; SSLCipherSuite cipher; SSLProtocol protocol = 0; DEBUGASSERT(ssl_connect_2 == connssl->connecting_state || ssl_connect_2_reading == connssl->connecting_state || ssl_connect_2_writing == connssl->connecting_state); /* Here goes nothing: */ err = SSLHandshake(connssl->ssl_ctx); if(err != noErr) { switch (err) { case errSSLWouldBlock: /* they're not done with us yet */ connssl->connecting_state = connssl->ssl_direction ? ssl_connect_2_writing : ssl_connect_2_reading; return CURLE_OK; case errSSLServerAuthCompleted: /* the documentation says we need to call SSLHandshake() again */ return darwinssl_connect_step2(conn, sockindex); case errSSLXCertChainInvalid: case errSSLUnknownRootCert: case errSSLNoRootCert: case errSSLCertExpired: failf(data, "SSL certificate problem: OSStatus %d", err); return CURLE_SSL_CACERT; case errSSLHostNameMismatch: failf(data, "SSL certificate peer verification failed, the " "certificate did not match \"%s\"\n", conn->host.dispname); return CURLE_PEER_FAILED_VERIFICATION; default: failf(data, "Unknown SSL protocol error in connection to %s:%d", conn->host.name, err); return CURLE_SSL_CONNECT_ERROR; } } else { /* we have been connected fine, we're not waiting for anything else. */ connssl->connecting_state = ssl_connect_3; /* Informational message */ (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher); (void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol); switch (protocol) { case kSSLProtocol2: infof(data, "SSL 2.0 connection using %s\n", SSLCipherNameForNumber(cipher)); break; case kSSLProtocol3: infof(data, "SSL 3.0 connection using %s\n", SSLCipherNameForNumber(cipher)); break; case kTLSProtocol1: infof(data, "TLS 1.0 connection using %s\n", TLSCipherNameForNumber(cipher)); break; #if defined(__MAC_10_8) || defined(__IPHONE_5_0) case kTLSProtocol11: infof(data, "TLS 1.1 connection using %s\n", TLSCipherNameForNumber(cipher)); break; case kTLSProtocol12: infof(data, "TLS 1.2 connection using %s\n", TLSCipherNameForNumber(cipher)); break; #endif default: infof(data, "Unknown protocol connection\n"); break; } return CURLE_OK; } }
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; }
/* * params->lock is held for us by runSession() - we use it as a semapahore by * unlocking it when we've created a port to listen on. * This is generally run from a thread via sslRunSession() and * sslServerThread() in sslAppUtils.cpp. */ OSStatus sslAppServe( SslAppTestParams *params) { otSocket listenSock = 0; otSocket acceptSock = 0; PeerSpec peerId; OSStatus ortn; SSLContextRef ctx = NULL; SecKeychainRef serverKc = nil; CFArrayRef serverCerts = nil; sslThrDebug("Server", "starting"); params->negVersion = kSSLProtocolUnknown; params->negCipher = SSL_NULL_WITH_NULL_NULL; params->ortn = noHardwareErr; /* set up a socket on which to listen */ for(unsigned retry=0; retry<BIND_RETRIES; retry++) { ortn = ListenForClients(params->port, params->nonBlocking, &listenSock); switch(ortn) { case errSecSuccess: break; case errSecOpWr: /* port already in use - try another */ params->port++; if(params->verbose || THREADING_DEBUG) { printf("...retrying ListenForClients at port %d\n", params->port); } break; default: break; } if(ortn != errSecOpWr) { break; } } /* let main thread know a socket is ready */ if(pthread_mutex_lock(¶ms->pthreadMutex)) { printf("***Error acquiring server lock; aborting.\n"); return -1; } params->serverReady = true; if(pthread_cond_broadcast(¶ms->pthreadCond)) { printf("***Error waking main thread; aborting.\n"); return -1; } if(pthread_mutex_unlock(¶ms->pthreadMutex)) { printf("***Error acquiring server lock; aborting.\n"); return -1; } if(ortn) { printf("ListenForClients returned %d; aborting\n", (int)ortn); return ortn; } /* wait for a connection */ if(params->verbose) { printf("Waiting for client connection..."); fflush(stdout); } ortn = AcceptClientConnection(listenSock, &acceptSock, &peerId); if(ortn) { printf("AcceptClientConnection returned %d; aborting\n", (int)ortn); return ortn; } /* * Set up a SecureTransport session. */ 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)acceptSock); if(ortn) { printSslErrStr("SSLSetConnection", ortn); goto cleanup; } if(params->anchorFile) { ortn = sslAddTrustedRoot(ctx, params->anchorFile, params->replaceAnchors); if(ortn) { goto cleanup; } } if(params->myCertKcName != NULL) { /* if not, better be trying anonymous diff-hellman... :-) */ serverCerts = getSslCerts(params->myCertKcName, false, false, NULL, &serverKc); if(serverCerts == nil) { exit(1); } if(params->password) { ortn = SecKeychainUnlock(serverKc, strlen(params->password), (void *)params->password, true); if(ortn) { printf("SecKeychainUnlock returned %d\n", (int)ortn); /* oh well */ } } if(params->idIsTrustedRoot) { /* assume this is a root we want to implicitly trust */ ortn = addIdentityAsTrustedRoot(ctx, serverCerts); if(ortn) { goto cleanup; } } ortn = SSLSetCertificate(ctx, serverCerts); if(ortn) { printSslErrStr("SSLSetCertificate", ortn); goto cleanup; } } if(params->disableCertVerify) { ortn = SSLSetEnableCertVerify(ctx, false); if(ortn) { printSslErrStr("SSLSetEnableCertVerify", ortn); goto cleanup; } } ortn = sslSetProtocols(ctx, params->acceptedProts, params->tryVersion); if(ortn) { goto cleanup; } if(params->resumeEnable) { ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec)); if(ortn) { printSslErrStr("SSLSetPeerID", ortn); goto cleanup; } } if(params->ciphers != NULL) { ortn = sslSetEnabledCiphers(ctx, params->ciphers); if(ortn) { goto cleanup; } } if(params->authenticate != kNeverAuthenticate) { ortn = SSLSetClientSideAuthenticate(ctx, params->authenticate); if(ortn) { printSslErrStr("SSLSetClientSideAuthenticate", ortn); goto cleanup; } } if(params->dhParams) { #if JAGUAR_BUILD printf("***Diffie-Hellman not supported in this config.\n"); #else ortn = SSLSetDiffieHellmanParams(ctx, params->dhParams, params->dhParamsLen); if(ortn) { printSslErrStr("SSLSetDiffieHellmanParams", ortn); goto cleanup; } #endif } /* Perform SSL/TLS handshake */ do { ortn = SSLHandshake(ctx); if((ortn == errSSLWouldBlock) && !params->silent) { /* keep UI responsive */ sslOutputDot(); } } while (ortn == errSSLWouldBlock); SSLGetClientCertificateState(ctx, ¶ms->certState); SSLGetNegotiatedCipher(ctx, ¶ms->negCipher); SSLGetNegotiatedProtocolVersion(ctx, ¶ms->negVersion); if(params->verbose) { printf("\n"); } if(ortn) { goto cleanup; } /* wait for one complete line */ char readBuf[READBUF_LEN]; size_t length; while(ortn == errSecSuccess) { length = READBUF_LEN; ortn = SSLRead(ctx, readBuf, length, &length); if (ortn == errSSLWouldBlock) { /* keep trying */ ortn = errSecSuccess; continue; } if(length == 0) { /* keep trying */ continue; } /* poor person's line completion scan */ for(unsigned i=0; i<length; i++) { if((readBuf[i] == '\n') || (readBuf[i] == '\r')) { goto serverResp; } } } serverResp: /* send out canned response */ ortn = SSLWrite(ctx, SERVER_MESSAGE, strlen(SERVER_MESSAGE), &length); if(ortn) { printSslErrStr("SSLWrite", ortn); } cleanup: /* * always do close, even on error - to flush outgoing write queue */ if(ctx) { OSStatus cerr = SSLClose(ctx); if(ortn == errSecSuccess) { ortn = cerr; } } if(acceptSock) { while(!params->clientDone && !params->serverAbort) { usleep(100); } endpointShutdown(acceptSock); } if(listenSock) { endpointShutdown(listenSock); } if(ctx) { SSLDisposeContext(ctx); } params->ortn = ortn; sslThrDebug("Server", "done"); return ortn; }
int /* O - Exit status */ main(int argc, /* I - Number of command-line arguments */ char *argv[]) /* I - Command-line arguments */ { int i; /* Looping var */ http_t *http; /* HTTP connection */ const char *server = NULL; /* Hostname from command-line */ int port = 0; /* Port number */ const char *cipherName = "UNKNOWN";/* Cipher suite name */ int dhBits = 0; /* Diffie-Hellman bits */ int tlsVersion = 0; /* TLS version number */ char uri[1024], /* Printer URI */ scheme[32], /* URI scheme */ host[256], /* Hostname */ userpass[256], /* Username/password */ resource[256]; /* Resource path */ int af = AF_UNSPEC, /* Address family */ tls_options = _HTTP_TLS_NONE, /* TLS options */ tls_min_version = _HTTP_TLS_1_0, tls_max_version = _HTTP_TLS_MAX, verbose = 0; /* Verbosity */ ipp_t *request, /* IPP Get-Printer-Attributes request */ *response; /* IPP Get-Printer-Attributes response */ ipp_attribute_t *attr; /* Current attribute */ const char *name; /* Attribute name */ char value[1024]; /* Attribute (string) value */ static const char * const pattrs[] = /* Requested attributes */ { "color-supported", "compression-supported", "document-format-supported", "pages-per-minute", "printer-location", "printer-make-and-model", "printer-state", "printer-state-reasons", "sides-supported", "uri-authentication-supported", "uri-security-supported" }; for (i = 1; i < argc; i ++) { if (!strcmp(argv[i], "--dh")) { tls_options |= _HTTP_TLS_ALLOW_DH; } else if (!strcmp(argv[i], "--no-cbc")) { tls_options |= _HTTP_TLS_DENY_CBC; } else if (!strcmp(argv[i], "--no-tls10")) { tls_min_version = _HTTP_TLS_1_1; } else if (!strcmp(argv[i], "--tls10")) { tls_min_version = _HTTP_TLS_1_0; tls_max_version = _HTTP_TLS_1_0; } else if (!strcmp(argv[i], "--rc4")) { tls_options |= _HTTP_TLS_ALLOW_RC4; } else if (!strcmp(argv[i], "--verbose") || !strcmp(argv[i], "-v")) { verbose = 1; } else if (!strcmp(argv[i], "-4")) { af = AF_INET; } else if (!strcmp(argv[i], "-6")) { af = AF_INET6; } else if (argv[i][0] == '-') { printf("tlscheck: Unknown option '%s'.\n", argv[i]); usage(); } else if (!server) { if (!strncmp(argv[i], "ipps://", 7)) { httpSeparateURI(HTTP_URI_CODING_ALL, argv[i], scheme, sizeof(scheme), userpass, sizeof(userpass), host, sizeof(host), &port, resource, sizeof(resource)); server = host; } else { server = argv[i]; strlcpy(resource, "/ipp/print", sizeof(resource)); } } else if (!port && (argv[i][0] == '=' || isdigit(argv[i][0] & 255))) { if (argv[i][0] == '=') port = atoi(argv[i] + 1); else port = atoi(argv[i]); } else { printf("tlscheck: Unexpected argument '%s'.\n", argv[i]); usage(); } } if (!server) usage(); if (!port) port = 631; _httpTLSSetOptions(tls_options, tls_min_version, tls_max_version); http = httpConnect2(server, port, NULL, af, HTTP_ENCRYPTION_ALWAYS, 1, 30000, NULL); if (!http) { printf("%s: ERROR (%s)\n", server, cupsLastErrorString()); return (1); } #ifdef __APPLE__ SSLProtocol protocol; SSLCipherSuite cipher; char unknownCipherName[256]; int paramsNeeded = 0; const void *params; size_t paramsLen; OSStatus err; if ((err = SSLGetNegotiatedProtocolVersion(http->tls, &protocol)) != noErr) { printf("%s: ERROR (No protocol version - %d)\n", server, (int)err); httpClose(http); return (1); } switch (protocol) { default : tlsVersion = 0; break; case kSSLProtocol3 : tlsVersion = 30; break; case kTLSProtocol1 : tlsVersion = 10; break; case kTLSProtocol11 : tlsVersion = 11; break; case kTLSProtocol12 : tlsVersion = 12; break; } if ((err = SSLGetNegotiatedCipher(http->tls, &cipher)) != noErr) { printf("%s: ERROR (No cipher suite - %d)\n", server, (int)err); httpClose(http); return (1); } switch (cipher) { case TLS_NULL_WITH_NULL_NULL: cipherName = "TLS_NULL_WITH_NULL_NULL"; break; case TLS_RSA_WITH_NULL_MD5: cipherName = "TLS_RSA_WITH_NULL_MD5"; break; case TLS_RSA_WITH_NULL_SHA: cipherName = "TLS_RSA_WITH_NULL_SHA"; break; case TLS_RSA_WITH_RC4_128_MD5: cipherName = "TLS_RSA_WITH_RC4_128_MD5"; break; case TLS_RSA_WITH_RC4_128_SHA: cipherName = "TLS_RSA_WITH_RC4_128_SHA"; break; case TLS_RSA_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_RSA_WITH_3DES_EDE_CBC_SHA"; break; case TLS_RSA_WITH_NULL_SHA256: cipherName = "TLS_RSA_WITH_NULL_SHA256"; break; case TLS_RSA_WITH_AES_128_CBC_SHA256: cipherName = "TLS_RSA_WITH_AES_128_CBC_SHA256"; break; case TLS_RSA_WITH_AES_256_CBC_SHA256: cipherName = "TLS_RSA_WITH_AES_256_CBC_SHA256"; break; case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"; paramsNeeded = 1; break; case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"; paramsNeeded = 1; break; case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"; paramsNeeded = 1; break; case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"; paramsNeeded = 1; break; case TLS_DH_DSS_WITH_AES_128_CBC_SHA256: cipherName = "TLS_DH_DSS_WITH_AES_128_CBC_SHA256"; paramsNeeded = 1; break; case TLS_DH_RSA_WITH_AES_128_CBC_SHA256: cipherName = "TLS_DH_RSA_WITH_AES_128_CBC_SHA256"; paramsNeeded = 1; break; case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256: cipherName = "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256"; paramsNeeded = 1; break; case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256: cipherName = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256"; paramsNeeded = 1; break; case TLS_DH_DSS_WITH_AES_256_CBC_SHA256: cipherName = "TLS_DH_DSS_WITH_AES_256_CBC_SHA256"; paramsNeeded = 1; break; case TLS_DH_RSA_WITH_AES_256_CBC_SHA256: cipherName = "TLS_DH_RSA_WITH_AES_256_CBC_SHA256"; paramsNeeded = 1; break; case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256: cipherName = "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256"; paramsNeeded = 1; break; case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256: cipherName = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256"; paramsNeeded = 1; break; case TLS_DH_anon_WITH_RC4_128_MD5: cipherName = "TLS_DH_anon_WITH_RC4_128_MD5"; paramsNeeded = 1; break; case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"; paramsNeeded = 1; break; case TLS_DH_anon_WITH_AES_128_CBC_SHA256: cipherName = "TLS_DH_anon_WITH_AES_128_CBC_SHA256"; paramsNeeded = 1; break; case TLS_DH_anon_WITH_AES_256_CBC_SHA256: cipherName = "TLS_DH_anon_WITH_AES_256_CBC_SHA256"; paramsNeeded = 1; break; case TLS_PSK_WITH_RC4_128_SHA: cipherName = "TLS_PSK_WITH_RC4_128_SHA"; break; case TLS_PSK_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_PSK_WITH_3DES_EDE_CBC_SHA"; break; case TLS_PSK_WITH_AES_128_CBC_SHA: cipherName = "TLS_PSK_WITH_AES_128_CBC_SHA"; break; case TLS_PSK_WITH_AES_256_CBC_SHA: cipherName = "TLS_PSK_WITH_AES_256_CBC_SHA"; break; case TLS_DHE_PSK_WITH_RC4_128_SHA: cipherName = "TLS_DHE_PSK_WITH_RC4_128_SHA"; paramsNeeded = 1; break; case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"; paramsNeeded = 1; break; case TLS_DHE_PSK_WITH_AES_128_CBC_SHA: cipherName = "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"; paramsNeeded = 1; break; case TLS_DHE_PSK_WITH_AES_256_CBC_SHA: cipherName = "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"; paramsNeeded = 1; break; case TLS_RSA_PSK_WITH_RC4_128_SHA: cipherName = "TLS_RSA_PSK_WITH_RC4_128_SHA"; break; case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"; break; case TLS_RSA_PSK_WITH_AES_128_CBC_SHA: cipherName = "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"; break; case TLS_RSA_PSK_WITH_AES_256_CBC_SHA: cipherName = "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"; break; case TLS_PSK_WITH_NULL_SHA: cipherName = "TLS_PSK_WITH_NULL_SHA"; break; case TLS_DHE_PSK_WITH_NULL_SHA: cipherName = "TLS_DHE_PSK_WITH_NULL_SHA"; paramsNeeded = 1; break; case TLS_RSA_PSK_WITH_NULL_SHA: cipherName = "TLS_RSA_PSK_WITH_NULL_SHA"; break; case TLS_RSA_WITH_AES_128_GCM_SHA256: cipherName = "TLS_RSA_WITH_AES_128_GCM_SHA256"; break; case TLS_RSA_WITH_AES_256_GCM_SHA384: cipherName = "TLS_RSA_WITH_AES_256_GCM_SHA384"; break; case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256: cipherName = "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"; paramsNeeded = 1; break; case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384: cipherName = "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384"; paramsNeeded = 1; break; case TLS_DH_RSA_WITH_AES_128_GCM_SHA256: cipherName = "TLS_DH_RSA_WITH_AES_128_GCM_SHA256"; paramsNeeded = 1; break; case TLS_DH_RSA_WITH_AES_256_GCM_SHA384: cipherName = "TLS_DH_RSA_WITH_AES_256_GCM_SHA384"; paramsNeeded = 1; break; case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256: cipherName = "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256"; paramsNeeded = 1; break; case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384: cipherName = "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384"; paramsNeeded = 1; break; case TLS_DH_DSS_WITH_AES_128_GCM_SHA256: cipherName = "TLS_DH_DSS_WITH_AES_128_GCM_SHA256"; paramsNeeded = 1; break; case TLS_DH_DSS_WITH_AES_256_GCM_SHA384: cipherName = "TLS_DH_DSS_WITH_AES_256_GCM_SHA384"; paramsNeeded = 1; break; case TLS_DH_anon_WITH_AES_128_GCM_SHA256: cipherName = "TLS_DH_anon_WITH_AES_128_GCM_SHA256"; paramsNeeded = 1; break; case TLS_DH_anon_WITH_AES_256_GCM_SHA384: cipherName = "TLS_DH_anon_WITH_AES_256_GCM_SHA384"; paramsNeeded = 1; break; case TLS_PSK_WITH_AES_128_GCM_SHA256: cipherName = "TLS_PSK_WITH_AES_128_GCM_SHA256"; break; case TLS_PSK_WITH_AES_256_GCM_SHA384: cipherName = "TLS_PSK_WITH_AES_256_GCM_SHA384"; break; case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256: cipherName = "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256"; paramsNeeded = 1; break; case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384: cipherName = "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384"; paramsNeeded = 1; break; case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256: cipherName = "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256"; break; case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384: cipherName = "TLS_RSA_PSK_WITH_AES_256_GCM_SHA384"; break; case TLS_PSK_WITH_AES_128_CBC_SHA256: cipherName = "TLS_PSK_WITH_AES_128_CBC_SHA256"; break; case TLS_PSK_WITH_AES_256_CBC_SHA384: cipherName = "TLS_PSK_WITH_AES_256_CBC_SHA384"; break; case TLS_PSK_WITH_NULL_SHA256: cipherName = "TLS_PSK_WITH_NULL_SHA256"; break; case TLS_PSK_WITH_NULL_SHA384: cipherName = "TLS_PSK_WITH_NULL_SHA384"; break; case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256: cipherName = "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256"; paramsNeeded = 1; break; case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384: cipherName = "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384"; paramsNeeded = 1; break; case TLS_DHE_PSK_WITH_NULL_SHA256: cipherName = "TLS_DHE_PSK_WITH_NULL_SHA256"; paramsNeeded = 1; break; case TLS_DHE_PSK_WITH_NULL_SHA384: cipherName = "TLS_DHE_PSK_WITH_NULL_SHA384"; paramsNeeded = 1; break; case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256: cipherName = "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256"; break; case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384: cipherName = "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384"; break; case TLS_RSA_PSK_WITH_NULL_SHA256: cipherName = "TLS_RSA_PSK_WITH_NULL_SHA256"; break; case TLS_RSA_PSK_WITH_NULL_SHA384: cipherName = "TLS_RSA_PSK_WITH_NULL_SHA384"; break; case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256: cipherName = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256"; paramsNeeded = 1; break; case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384: cipherName = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384"; paramsNeeded = 1; break; case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256: cipherName = "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256"; paramsNeeded = 1; break; case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384: cipherName = "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384"; paramsNeeded = 1; break; case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256: cipherName = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256"; paramsNeeded = 1; break; case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384: cipherName = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384"; paramsNeeded = 1; break; case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256: cipherName = "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256"; paramsNeeded = 1; break; case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384: cipherName = "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384"; paramsNeeded = 1; break; case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: cipherName = "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"; paramsNeeded = 1; break; case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: cipherName = "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"; paramsNeeded = 1; break; case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256: cipherName = "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256"; paramsNeeded = 1; break; case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384: cipherName = "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384"; paramsNeeded = 1; break; case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: cipherName = "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"; paramsNeeded = 1; break; case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: cipherName = "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"; paramsNeeded = 1; break; case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256: cipherName = "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256"; paramsNeeded = 1; break; case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384: cipherName = "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384"; paramsNeeded = 1; break; case TLS_RSA_WITH_AES_128_CBC_SHA: cipherName = "TLS_RSA_WITH_AES_128_CBC_SHA"; break; case TLS_DH_DSS_WITH_AES_128_CBC_SHA: cipherName = "TLS_DH_DSS_WITH_AES_128_CBC_SHA"; paramsNeeded = 1; break; case TLS_DH_RSA_WITH_AES_128_CBC_SHA: cipherName = "TLS_DH_RSA_WITH_AES_128_CBC_SHA"; paramsNeeded = 1; break; case TLS_DHE_DSS_WITH_AES_128_CBC_SHA: cipherName = "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"; paramsNeeded = 1; break; case TLS_DHE_RSA_WITH_AES_128_CBC_SHA: cipherName = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"; paramsNeeded = 1; break; case TLS_DH_anon_WITH_AES_128_CBC_SHA: cipherName = "TLS_DH_anon_WITH_AES_128_CBC_SHA"; paramsNeeded = 1; break; case TLS_RSA_WITH_AES_256_CBC_SHA: cipherName = "TLS_RSA_WITH_AES_256_CBC_SHA"; break; case TLS_DH_DSS_WITH_AES_256_CBC_SHA: cipherName = "TLS_DH_DSS_WITH_AES_256_CBC_SHA"; paramsNeeded = 1; break; case TLS_DH_RSA_WITH_AES_256_CBC_SHA: cipherName = "TLS_DH_RSA_WITH_AES_256_CBC_SHA"; paramsNeeded = 1; break; case TLS_DHE_DSS_WITH_AES_256_CBC_SHA: cipherName = "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"; paramsNeeded = 1; break; case TLS_DHE_RSA_WITH_AES_256_CBC_SHA: cipherName = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"; paramsNeeded = 1; break; case TLS_DH_anon_WITH_AES_256_CBC_SHA: cipherName = "TLS_DH_anon_WITH_AES_256_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDH_ECDSA_WITH_NULL_SHA: cipherName = "TLS_ECDH_ECDSA_WITH_NULL_SHA"; paramsNeeded = 1; break; case TLS_ECDH_ECDSA_WITH_RC4_128_SHA: cipherName = "TLS_ECDH_ECDSA_WITH_RC4_128_SHA"; paramsNeeded = 1; break; case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA: cipherName = "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA: cipherName = "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDHE_ECDSA_WITH_NULL_SHA: cipherName = "TLS_ECDHE_ECDSA_WITH_NULL_SHA"; paramsNeeded = 1; break; case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA: cipherName = "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"; paramsNeeded = 1; break; case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA: cipherName = "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA: cipherName = "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDH_RSA_WITH_NULL_SHA: cipherName = "TLS_ECDH_RSA_WITH_NULL_SHA"; paramsNeeded = 1; break; case TLS_ECDH_RSA_WITH_RC4_128_SHA: cipherName = "TLS_ECDH_RSA_WITH_RC4_128_SHA"; paramsNeeded = 1; break; case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA: cipherName = "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA: cipherName = "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDHE_RSA_WITH_NULL_SHA: cipherName = "TLS_ECDHE_RSA_WITH_NULL_SHA"; paramsNeeded = 1; break; case TLS_ECDHE_RSA_WITH_RC4_128_SHA: cipherName = "TLS_ECDHE_RSA_WITH_RC4_128_SHA"; paramsNeeded = 1; break; case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: cipherName = "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA: cipherName = "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDH_anon_WITH_NULL_SHA: cipherName = "TLS_ECDH_anon_WITH_NULL_SHA"; paramsNeeded = 1; break; case TLS_ECDH_anon_WITH_RC4_128_SHA: cipherName = "TLS_ECDH_anon_WITH_RC4_128_SHA"; paramsNeeded = 1; break; case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA: cipherName = "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDH_anon_WITH_AES_128_CBC_SHA: cipherName = "TLS_ECDH_anon_WITH_AES_128_CBC_SHA"; paramsNeeded = 1; break; case TLS_ECDH_anon_WITH_AES_256_CBC_SHA: cipherName = "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"; paramsNeeded = 1; break; default : snprintf(unknownCipherName, sizeof(unknownCipherName), "UNKNOWN_%04X", cipher); cipherName = unknownCipherName; break; } if (cipher == TLS_RSA_WITH_RC4_128_MD5 || cipher == TLS_RSA_WITH_RC4_128_SHA) { printf("%s: ERROR (Printers MUST NOT negotiate RC4 cipher suites.)\n", server); httpClose(http); return (1); } if ((err = SSLGetDiffieHellmanParams(http->tls, ¶ms, ¶msLen)) != noErr && paramsNeeded) { printf("%s: ERROR (Unable to get Diffie-Hellman parameters - %d)\n", server, (int)err); httpClose(http); return (1); } if (paramsLen < 128 && paramsLen != 0) { printf("%s: ERROR (Diffie-Hellman parameters MUST be at least 2048 bits, but Printer uses only %d bits/%d bytes)\n", server, (int)paramsLen * 8, (int)paramsLen); httpClose(http); return (1); } dhBits = (int)paramsLen * 8; #endif /* __APPLE__ */ if (dhBits > 0) printf("%s: OK (TLS: %d.%d, %s, %d DH bits)\n", server, tlsVersion / 10, tlsVersion % 10, cipherName, dhBits); else printf("%s: OK (TLS: %d.%d, %s)\n", server, tlsVersion / 10, tlsVersion % 10, cipherName); if (verbose) { httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), "ipps", NULL, host, port, resource); request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, uri); ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser()); ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(pattrs) / sizeof(pattrs[0])), NULL, pattrs); response = cupsDoRequest(http, request, resource); for (attr = ippFirstAttribute(response); attr; attr = ippNextAttribute(response)) { if (ippGetGroupTag(attr) != IPP_TAG_PRINTER) continue; if ((name = ippGetName(attr)) == NULL) continue; ippAttributeString(attr, value, sizeof(value)); printf(" %s=%s\n", name, value); } ippDelete(response); } httpClose(http); return (0); }
int dtls_client(const char *hostname, int bypass) { int fd; int tlsfd; struct sockaddr_in sa; printf("Running dtls_client test with hostname=%s, bypass=%d\n", hostname, bypass); if ((fd=socket(AF_INET, SOCK_DGRAM, 0))==-1) { perror("socket"); exit(-1); } memset((char *) &sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_port = htons(PORT); if (inet_aton(hostname, &sa.sin_addr)==0) { fprintf(stderr, "inet_aton() failed\n"); exit(1); } if(connect(fd, (struct sockaddr *)&sa, sizeof(sa))==-1) { perror("connect"); return errno; } /* Change to non blocking io */ fcntl(fd, F_SETFL, O_NONBLOCK); SSLRecordContextRef c=(intptr_t)fd; OSStatus ortn; SSLContextRef ctx = NULL; SSLClientCertificateState certState; SSLCipherSuite negCipher; SSLProtocol negVersion; /* * Set up a SecureTransport session. */ ctx = SSLCreateContextWithRecordFuncs(kCFAllocatorDefault, kSSLClientSide, kSSLDatagramType, &TLSSocket_Funcs); if(!ctx) { printSslErrStr("SSLCreateContextWithRecordFuncs", -1); return -1; } printf("Attaching filter\n"); ortn = TLSSocket_Attach(fd); if(ortn) { printSslErrStr("TLSSocket_Attach", ortn); return ortn; } if(bypass) { tlsfd = open("/dev/tlsnke", O_RDWR); if(tlsfd<0) { perror("opening tlsnke dev"); exit(-1); } } ortn = SSLSetRecordContext(ctx, c); if(ortn) { printSslErrStr("SSLSetRecordContext", ortn); return ortn; } ortn = SSLSetMaxDatagramRecordSize(ctx, 600); if(ortn) { printSslErrStr("SSLSetMaxDatagramRecordSize", ortn); return ortn; } /* Lets not verify the cert, which is a random test cert */ ortn = SSLSetEnableCertVerify(ctx, false); if(ortn) { printSslErrStr("SSLSetEnableCertVerify", ortn); return ortn; } ortn = SSLSetCertificate(ctx, server_chain()); if(ortn) { printSslErrStr("SSLSetCertificate", ortn); return ortn; } printf("Handshake...\n"); do { ortn = SSLHandshake(ctx); if(ortn == errSSLWouldBlock) { /* keep UI responsive */ sslOutputDot(); } } while (ortn == errSSLWouldBlock); SSLGetClientCertificateState(ctx, &certState); SSLGetNegotiatedCipher(ctx, &negCipher); SSLGetNegotiatedProtocolVersion(ctx, &negVersion); int count; size_t len; ssize_t sreadLen, swriteLen; size_t readLen, writeLen; char buffer[BUFLEN]; count = 0; while(count<COUNT) { int timeout = 10000; snprintf(buffer, BUFLEN, "Message %d", count); len = strlen(buffer); if(bypass) { /* Send data through the side channel, kind of like utun would */ swriteLen=write(tlsfd, buffer, len); if(swriteLen<0) { perror("write to tlsfd"); break; } writeLen=swriteLen; } else { ortn=SSLWrite(ctx, buffer, len, &writeLen); if(ortn) { printSslErrStr("SSLWrite", ortn); break; } } printf("Wrote %lu bytes\n", writeLen); count++; if(bypass) { do { sreadLen=read(tlsfd, buffer, BUFLEN); } while((sreadLen==-1) && (errno==EAGAIN) && (timeout--)); if((sreadLen==-1) && (errno==EAGAIN)) { printf("Read timeout...\n"); continue; } if(sreadLen<0) { perror("read from tlsfd"); break; } readLen=sreadLen; } else { do { ortn=SSLRead(ctx, buffer, BUFLEN, &readLen); } while((ortn==errSSLWouldBlock) && (timeout--)); if(ortn==errSSLWouldBlock) { printf("SSLRead timeout...\n"); continue; } if(ortn) { printSslErrStr("SSLRead", ortn); break; } } buffer[readLen]=0; printf("Received %lu bytes: %s\n", readLen, buffer); } SSLClose(ctx); SSLDisposeContext(ctx); 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; }
/* relies on SSLSetProtocolVersionEnabled */ OSStatus sslAppClient( SslAppTestParams *params) { PeerSpec peerId; otSocket sock = 0; OSStatus ortn; SSLContextRef ctx = NULL; SecKeychainRef clientKc = nil; CFArrayRef clientCerts = nil; sslThrDebug("Client", "starting"); params->negVersion = kSSLProtocolUnknown; params->negCipher = SSL_NULL_WITH_NULL_NULL; params->ortn = noHardwareErr; /* first make sure requested server is there */ ortn = MakeServerConnection(params->hostName, params->port, params->nonBlocking, &sock, &peerId); if(ortn) { printf("MakeServerConnection returned %d; aborting\n", (int)ortn); return ortn; } /* * Set up a SecureTransport session. */ ortn = SSLNewContext(false, &ctx); if(ortn) { printSslErrStr("SSLNewContext", ortn); goto cleanup; } ortn = SSLSetIOFuncs(ctx, SocketRead, SocketWrite); if(ortn) { printSslErrStr("SSLSetIOFuncs", ortn); goto cleanup; } ortn = SSLSetConnection(ctx, (SSLConnectionRef)sock); if(ortn) { printSslErrStr("SSLSetConnection", ortn); goto cleanup; } if(!params->skipHostNameCheck) { ortn = SSLSetPeerDomainName(ctx, params->hostName, strlen(params->hostName)); if(ortn) { printSslErrStr("SSLSetPeerDomainName", ortn); goto cleanup; } } /* remainder of setup is optional */ if(params->anchorFile) { ortn = sslAddTrustedRoot(ctx, params->anchorFile, params->replaceAnchors); if(ortn) { goto cleanup; } } ortn = sslSetProtocols(ctx, params->acceptedProts, params->tryVersion); if(ortn) { goto cleanup; } if(params->resumeEnable) { ortn = SSLSetPeerID(ctx, &peerId, sizeof(PeerSpec)); if(ortn) { printSslErrStr("SSLSetPeerID", ortn); goto cleanup; } } if(params->disableCertVerify) { ortn = SSLSetEnableCertVerify(ctx, false); if(ortn) { printSslErrStr("SSLSetEnableCertVerify", ortn); goto cleanup; } } if(params->ciphers != NULL) { ortn = sslSetEnabledCiphers(ctx, params->ciphers); if(ortn) { goto cleanup; } } if(params->myCertKcName) { clientCerts = getSslCerts(params->myCertKcName, false, false, NULL, &clientKc); if(clientCerts == nil) { exit(1); } if(params->password) { ortn = SecKeychainUnlock(clientKc, strlen(params->password), (void *)params->password, true); if(ortn) { printf("SecKeychainUnlock returned %d\n", (int)ortn); /* oh well */ } } if(params->idIsTrustedRoot) { /* assume this is a root we want to implicitly trust */ ortn = addIdentityAsTrustedRoot(ctx, clientCerts); if(ortn) { goto cleanup; } } ortn = SSLSetCertificate(ctx, clientCerts); if(ortn) { printSslErrStr("SSLSetCertificate", ortn); goto cleanup; } } do { ortn = SSLHandshake(ctx); if((ortn == errSSLWouldBlock) && !params->silent) { /* keep UI responsive */ sslOutputDot(); } } while (ortn == errSSLWouldBlock); SSLGetClientCertificateState(ctx, ¶ms->certState); SSLGetNegotiatedCipher(ctx, ¶ms->negCipher); SSLGetNegotiatedProtocolVersion(ctx, ¶ms->negVersion); if(ortn != errSecSuccess) { goto cleanup; } /* send a GET msg */ size_t actLen; ortn = SSLWrite(ctx, CLIENT_GETMSG, strlen(CLIENT_GETMSG), &actLen); if(ortn) { printSslErrStr("SSLWrite", ortn); goto cleanup; } #if KEEP_CONNECTED /* * Consume any server data and wait for server to disconnect */ char readBuf[READBUF_LEN]; do { ortn = SSLRead(ctx, readBuf, READBUF_LEN, &actLen); } while (ortn == errSSLWouldBlock); /* convert normal "shutdown" into zero err rtn */ if(ortn == errSSLClosedGraceful) { ortn = errSecSuccess; } #endif /* KEEP_CONNECTED */ cleanup: if(ctx) { OSStatus cerr = SSLClose(ctx); if(ortn == errSecSuccess) { ortn = cerr; } } if(sock) { endpointShutdown(sock); } if(ctx) { SSLDisposeContext(ctx); } params->ortn = ortn; sslThrDebug("Client", "done"); return ortn; }