static int test_GetEnabledCiphers(SSLContextRef ssl) { size_t max_ciphers = 0; int fail=1; SSLCipherSuite *ciphers = NULL; OSStatus err; err=SSLSetIOFuncs(ssl, &SocketRead, &SocketWrite); err=SSLSetConnection(ssl, NULL); err=SSLHandshake(ssl); require_noerr(SSLGetNumberEnabledCiphers(ssl, &max_ciphers), out); size_t size = max_ciphers * sizeof (SSLCipherSuite); ciphers = (SSLCipherSuite *) malloc(size); require_string(ciphers, out, "out of memory"); memset(ciphers, 0xff, size); size_t num_ciphers = max_ciphers; require_noerr(SSLGetEnabledCiphers(ssl, ciphers, &num_ciphers), out); for (size_t i = 0; i < num_ciphers; i++) { char csname[256]; snprintf(csname, 256, "(%04x) %s", ciphers[i], ciphersuite_name(ciphers[i])); /* Uncomment the next line if you want to list the default enabled ciphers */ //printf("%s\n", csname); require_string(allowed_default_ciphers(ciphers[i]), out, csname); } /* Success! */ fail=0; out: if(ciphers) free(ciphers); return fail; }
static void ssl_cdsa_create_context(gpointer data) { PurpleSslConnection *gsc = (PurpleSslConnection *)data; PurpleAccount *account = gsc->account; PurpleSslCDSAData *cdsa_data; OSStatus err; bool requireFS = purple_account_get_bool(account, "require_forward_secrecy", FALSE); /* * allocate some memory to store variables for the cdsa connection. * the memory comes zero'd from g_new0 so we don't need to null the * pointers held in this struct. */ cdsa_data = g_new0(PurpleSslCDSAData, 1); gsc->private_data = cdsa_data; connections = g_list_append(connections, gsc); /* * allocate a new SSLContextRef object */ err = SSLNewContext(false, &cdsa_data->ssl_ctx); if (err != noErr) { purple_debug_error("cdsa", "SSLNewContext failed\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } /* * Set up our callbacks for reading/writing the file descriptor */ err = SSLSetIOFuncs(cdsa_data->ssl_ctx, SocketRead, SocketWrite); if (err != noErr) { purple_debug_error("cdsa", "SSLSetIOFuncs failed\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } /* * Pass the connection information to the connection to be used by our callbacks */ err = SSLSetConnection(cdsa_data->ssl_ctx, (SSLConnectionRef)(intptr_t)gsc->fd); if (err != noErr) { purple_debug_error("cdsa", "SSLSetConnection failed: %d\n", err); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } size_t numCiphers = 0; err = SSLGetNumberEnabledCiphers(cdsa_data->ssl_ctx, &numCiphers); if (err != noErr) { purple_debug_error("cdsa", "SSLGetNumberEnabledCiphers failed: %d\n", err); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } SSLCipherSuite ciphers[numCiphers]; err = SSLGetEnabledCiphers(cdsa_data->ssl_ctx, ciphers, &numCiphers); if (err != noErr) { purple_debug_error("cdsa", "SSLGetSupportedCiphers failed: %d\n", err); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } SSLCipherSuite enabledCiphers[numCiphers]; size_t numEnabledCiphers = 0; int i; for (i = 0; i < numCiphers; i++) { if (ssl_cdsa_use_cipher(ciphers[i], requireFS)) { enabledCiphers[numEnabledCiphers] = ciphers[i]; numEnabledCiphers++; } } err = SSLSetEnabledCiphers(cdsa_data->ssl_ctx, enabledCiphers, numEnabledCiphers); if (err != noErr) { purple_debug_error("cdsa", "SSLSetEnabledCiphers failed: %d\n", err); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } if (purple_account_get_bool(account, PURPLE_SSL_CDSA_BUGGY_TLS_WORKAROUND, false)) { purple_debug_info("cdsa", "Explicitly disabling TLS 1.1 and above to try and work around buggy TLS stacks\n"); OSStatus protoErr; protoErr = SSLSetProtocolVersionEnabled(cdsa_data->ssl_ctx, kSSLProtocolAll, false); if (protoErr != noErr) { purple_debug_error("cdsa", "SSLSetProtocolVersionEnabled failed to disable protocols\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } protoErr = SSLSetProtocolVersionEnabled(cdsa_data->ssl_ctx, kSSLProtocol3, true); protoErr = SSLSetProtocolVersionEnabled(cdsa_data->ssl_ctx, kTLSProtocol1, true); } if(gsc->host) { /* * Set the peer's domain name so CDSA can check the certificate's CN */ err = SSLSetPeerDomainName(cdsa_data->ssl_ctx, gsc->host, strlen(gsc->host)); if (err != noErr) { purple_debug_error("cdsa", "SSLSetPeerDomainName failed\n"); if (gsc->error_cb != NULL) gsc->error_cb(gsc, PURPLE_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); purple_ssl_close(gsc); return; } } /* * Disable verifying the certificate chain. * We have to do that manually later on! This is the only way to be able to continue with a connection, even though the user * had to manually accept the certificate. */ err = SSLSetEnableCertVerify(cdsa_data->ssl_ctx, false); if (err != noErr) { purple_debug_error("cdsa", "SSLSetEnableCertVerify failed\n"); /* error is not fatal */ } cdsa_data->handshake_handler = purple_input_add(gsc->fd, PURPLE_INPUT_READ, ssl_cdsa_handshake_cb, gsc); }