void pni_sasl_set_desired_state(pn_transport_t *transport, enum pni_sasl_state desired_state) { pni_sasl_t *sasl = transport->sasl; if (sasl->last_state > desired_state) { if (transport->trace & PN_TRACE_DRV) pn_transport_logf(transport, "Trying to send SASL frame (%d), but illegal: already in later state (%d)", desired_state, sasl->last_state); } else if (sasl->client && !pni_sasl_is_client_state(desired_state)) { if (transport->trace & PN_TRACE_DRV) pn_transport_logf(transport, "Trying to send server SASL frame (%d) on a client", desired_state); } else if (!sasl->client && !pni_sasl_is_server_state(desired_state)) { if (transport->trace & PN_TRACE_DRV) pn_transport_logf(transport, "Trying to send client SASL frame (%d) on a server", desired_state); } else { // If we need to repeat CHALLENGE or RESPONSE frames adjust current state to seem // like they haven't been sent yet if (sasl->last_state==desired_state && desired_state==SASL_POSTED_RESPONSE) { sasl->last_state = SASL_POSTED_INIT; } if (sasl->last_state==desired_state && desired_state==SASL_POSTED_CHALLENGE) { sasl->last_state = SASL_POSTED_MECHANISMS; } // If we already pretended to receive outcome and we actually received outcome // we must set last_state here as we've already stoped outputting from this layer if (sasl->last_state==SASL_PRETEND_OUTCOME && (desired_state==SASL_RECVED_OUTCOME_SUCCEED || desired_state==SASL_RECVED_OUTCOME_FAIL) ) { sasl->last_state = desired_state; } sasl->desired_state = desired_state; // Don't emit transport event on error as there will be a TRANSPORT_ERROR event if (desired_state != SASL_ERROR) pni_emit(transport); } }
int pn_ssl_domain_set_peer_authentication(pn_ssl_domain_t *domain, const pn_ssl_verify_mode_t mode, const char *trusted_CAs) { if (!domain) return -1; switch (mode) { case PN_SSL_VERIFY_PEER: case PN_SSL_VERIFY_PEER_NAME: if (!domain->has_ca_db) { pn_transport_logf(NULL, "Error: cannot verify peer without a trusted CA configured.\n" " Use pn_ssl_domain_set_trusted_ca_db()"); return -1; } if (domain->mode == PN_SSL_MODE_SERVER) { // openssl requires that server connections supply a list of trusted CAs which is // sent to the client if (!trusted_CAs) { pn_transport_logf(NULL, "Error: a list of trusted CAs must be provided."); return -1; } if (!domain->has_certificate) { pn_transport_logf(NULL, "Error: Server cannot verify peer without configuring a certificate.\n" " Use pn_ssl_domain_set_credentials()"); } if (domain->trusted_CAs) free(domain->trusted_CAs); domain->trusted_CAs = pn_strdup( trusted_CAs ); STACK_OF(X509_NAME) *cert_names; cert_names = SSL_load_client_CA_file( domain->trusted_CAs ); if (cert_names != NULL) SSL_CTX_set_client_CA_list(domain->ctx, cert_names); else { pn_transport_logf(NULL, "Error: Unable to process file of trusted CAs: %s", trusted_CAs); return -1; } } SSL_CTX_set_verify( domain->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback); #if (OPENSSL_VERSION_NUMBER < 0x00905100L) SSL_CTX_set_verify_depth(domain->ctx, 1); #endif break; case PN_SSL_ANONYMOUS_PEER: // hippie free love mode... :) SSL_CTX_set_verify( domain->ctx, SSL_VERIFY_NONE, NULL ); break; default: pn_transport_logf(NULL, "Invalid peer authentication mode given." ); return -1; } domain->verify_mode = mode; return 0; }
int pn_post_frame(pn_dispatcher_t *disp, uint16_t ch, const char *fmt, ...) { va_list ap; va_start(ap, fmt); pn_data_clear(disp->output_args); int err = pn_data_vfill(disp->output_args, fmt, ap); va_end(ap); if (err) { pn_transport_logf(disp->transport, "error posting frame: %s, %s: %s", fmt, pn_code(err), pn_error_text(pn_data_error(disp->output_args))); return PN_ERR; } pn_do_trace(disp, ch, OUT, disp->output_args, disp->output_payload, disp->output_size); encode_performatives: pn_buffer_clear( disp->frame ); pn_bytes_t buf = pn_buffer_bytes( disp->frame ); buf.size = pn_buffer_available( disp->frame ); ssize_t wr = pn_data_encode( disp->output_args, buf.start, buf.size ); if (wr < 0) { if (wr == PN_OVERFLOW) { pn_buffer_ensure( disp->frame, pn_buffer_available( disp->frame ) * 2 ); goto encode_performatives; } pn_transport_logf(disp->transport, "error posting frame: %s", pn_code(wr)); return PN_ERR; } pn_frame_t frame = {disp->frame_type}; frame.channel = ch; frame.payload = buf.start; frame.size = wr; size_t n; while (!(n = pn_write_frame(disp->output + disp->available, disp->capacity - disp->available, frame))) { disp->capacity *= 2; disp->output = (char *) realloc(disp->output, disp->capacity); } disp->output_frames_ct += 1; if (disp->trace & PN_TRACE_RAW) { pn_string_set(disp->scratch, "RAW: \""); pn_quote(disp->scratch, disp->output + disp->available, n); pn_string_addf(disp->scratch, "\""); pn_transport_log(disp->transport, pn_string_get(disp->scratch)); } disp->available += n; return 0; }
static void pni_process_server_result(pn_transport_t *transport, int result) { pni_sasl_t *sasl = transport->sasl; sasl_conn_t *cyrus_conn = (sasl_conn_t*)sasl->impl_context; switch (result) { case SASL_OK: // Authenticated sasl->outcome = PN_SASL_OK; transport->authenticated = true; // Get username from SASL const void* value; sasl_getprop(cyrus_conn, SASL_USERNAME, &value); sasl->username = (const char*) value; if (transport->trace & PN_TRACE_DRV) pn_transport_logf(transport, "Authenticated user: %s with mechanism %s", sasl->username, sasl->selected_mechanism); pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME); break; case SASL_CONTINUE: // Need to send a challenge pni_sasl_set_desired_state(transport, SASL_POSTED_CHALLENGE); break; default: pni_check_sasl_result(cyrus_conn, result, transport); // Failed to authenticate sasl->outcome = PN_SASL_AUTH; pni_sasl_set_desired_state(transport, SASL_POSTED_OUTCOME); break; } }
static ssize_t pn_input_read_sasl(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available) { pni_sasl_t *sasl = transport->sasl; bool eos = pn_transport_capacity(transport)==PN_EOS; if (eos) { pn_do_error(transport, "amqp:connection:framing-error", "connection aborted"); pn_set_error_layer(transport); return PN_EOS; } pni_sasl_start_server_if_needed(transport); if (!pni_sasl_is_final_input_state(sasl)) { return pn_dispatcher_input(transport, bytes, available, false, &transport->halt); } if (pni_sasl_impl_can_encrypt(transport)) { sasl->max_encrypt_size = pni_sasl_impl_max_encrypt_size(transport); if (transport->trace & PN_TRACE_DRV) pn_transport_logf(transport, "SASL Encryption enabled: buffer=%d", sasl->max_encrypt_size); transport->io_layers[layer] = &sasl_encrypt_layer; } else if (sasl->client) { transport->io_layers[layer] = &pni_passthru_layer; } else { return pni_passthru_layer.process_input(transport, layer, bytes, available); } return transport->io_layers[layer]->process_input(transport, layer, bytes, available); }
static ssize_t pn_input_read_sasl_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available) { bool eos = pn_transport_capacity(transport)==PN_EOS; pni_protocol_type_t protocol = pni_sniff_header(bytes, available); switch (protocol) { case PNI_PROTOCOL_AMQP_SASL: if (transport->io_layers[layer] == &sasl_read_header_layer) { transport->io_layers[layer] = &sasl_layer; } else { transport->io_layers[layer] = &sasl_write_header_layer; } if (transport->trace & PN_TRACE_FRM) pn_transport_logf(transport, " <- %s", "SASL"); pni_sasl_set_external_security(transport, pn_ssl_get_ssf((pn_ssl_t*)transport), pn_ssl_get_remote_subject((pn_ssl_t*)transport)); return SASL_HEADER_LEN; case PNI_PROTOCOL_INSUFFICIENT: if (!eos) return 0; /* Fallthru */ default: break; } char quoted[1024]; pn_quote_data(quoted, 1024, bytes, available); pn_do_error(transport, "amqp:connection:framing-error", "%s header mismatch: %s ['%s']%s", "SASL", pni_protocol_name(protocol), quoted, !eos ? "" : " (connection aborted)"); pn_set_error_layer(transport); return PN_EOS; }
int pn_ssl_domain_set_trusted_ca_db(pn_ssl_domain_t *domain, const char *certificate_db) { if (!domain) return -1; // certificates can be either a file or a directory, which determines how it is passed // to SSL_CTX_load_verify_locations() struct stat sbuf; if (stat( certificate_db, &sbuf ) != 0) { pn_transport_logf(NULL, "stat(%s) failed: %s", certificate_db, strerror(errno)); return -1; } const char *file; const char *dir; if (S_ISDIR(sbuf.st_mode)) { dir = certificate_db; file = NULL; } else { dir = NULL; file = certificate_db; } if (SSL_CTX_load_verify_locations( domain->ctx, file, dir ) != 1) { ssl_log_error("SSL_CTX_load_verify_locations( %s ) failed", certificate_db); return -1; } domain->has_ca_db = true; return 0; }
static ssize_t pn_output_write_sasl(pn_transport_t* transport, unsigned int layer, char* bytes, size_t available) { pni_sasl_t *sasl = transport->sasl; // this accounts for when pn_do_error is invoked, e.g. by idle timeout if (transport->close_sent) return PN_EOS; pni_sasl_start_server_if_needed(transport); pni_post_sasl_frame(transport); if (transport->available != 0 || !pni_sasl_is_final_output_state(sasl)) { return pn_dispatcher_output(transport, bytes, available); } // We only get here if there is nothing to output and we're a final output state if (sasl->outcome != PN_SASL_OK && pni_sasl_is_final_input_state(sasl)) { return PN_EOS; } // We know that auth succeeded or we're not in final input state if (pni_sasl_impl_can_encrypt(transport)) { sasl->max_encrypt_size = pni_sasl_impl_max_encrypt_size(transport); if (transport->trace & PN_TRACE_DRV) pn_transport_logf(transport, "SASL Encryption enabled: buffer=%d", sasl->max_encrypt_size); transport->io_layers[layer] = &sasl_encrypt_layer; } else if (sasl->client) { return pni_passthru_layer.process_output(transport, layer, bytes, available ); } else { transport->io_layers[layer] = &pni_passthru_layer; } return transport->io_layers[layer]->process_output(transport, layer, bytes, available); }
static bool pni_check_sasl_result(sasl_conn_t *conn, int r, pn_transport_t *logger) { if (r!=SASL_OK) { if (logger->trace & PN_TRACE_DRV) pn_transport_logf(logger, "sasl error: %s", conn ? sasl_errdetail(conn) : sasl_errstring(r, NULL, NULL)); return false; } return true; }
int pn_ssl_domain_allow_unsecured_client(pn_ssl_domain_t *domain) { if (!domain) return -1; if (domain->mode != PN_SSL_MODE_SERVER) { pn_transport_logf(NULL, "Cannot permit unsecured clients - not a server."); return -1; } domain->allow_unsecured = true; return 0; }
static ssize_t pn_output_write_sasl_header(pn_transport_t *transport, unsigned int layer, char *bytes, size_t size) { if (transport->trace & PN_TRACE_FRM) pn_transport_logf(transport, " -> %s", "SASL"); assert(size >= SASL_HEADER_LEN); memmove(bytes, SASL_HEADER, SASL_HEADER_LEN); if (transport->io_layers[layer]==&sasl_write_header_layer) { transport->io_layers[layer] = &sasl_layer; } else { transport->io_layers[layer] = &sasl_read_header_layer; } return SASL_HEADER_LEN; }
int pn_dispatch_frame(pn_dispatcher_t *disp, pn_frame_t frame) { if (frame.size == 0) { // ignore null frames if (disp->trace & PN_TRACE_FRM) pn_transport_logf(disp->transport, "%u <- (EMPTY FRAME)\n", frame.channel); return 0; } ssize_t dsize = pn_data_decode(disp->args, frame.payload, frame.size); if (dsize < 0) { pn_string_format(disp->scratch, "Error decoding frame: %s %s\n", pn_code(dsize), pn_error_text(pn_data_error(disp->args))); pn_quote(disp->scratch, frame.payload, frame.size); pn_transport_log(disp->transport, pn_string_get(disp->scratch)); return dsize; } disp->channel = frame.channel; // XXX: assuming numeric uint64_t lcode; bool scanned; int e = pn_data_scan(disp->args, "D?L.", &scanned, &lcode); if (e) { pn_transport_log(disp->transport, "Scan error"); return e; } if (!scanned) { pn_transport_log(disp->transport, "Error dispatching frame"); return PN_ERR; } uint8_t code = lcode; disp->code = code; disp->size = frame.size - dsize; if (disp->size) disp->payload = frame.payload + dsize; pn_do_trace(disp, disp->channel, IN, disp->args, disp->payload, disp->size); pn_action_t *action = disp->actions[code]; int err = action(disp); disp->channel = 0; disp->code = 0; pn_data_clear(disp->args); disp->size = 0; disp->payload = NULL; return err; }
ssize_t pni_sasl_impl_decode(pn_transport_t *transport, pn_bytes_t in, pn_bytes_t *out) { if ( in.size==0 ) return 0; sasl_conn_t *cyrus_conn = (sasl_conn_t*)transport->sasl->impl_context; const char *output; unsigned int outlen; int r = sasl_decode(cyrus_conn, in.start, in.size, &output, &outlen); if (outlen==0) return 0; if ( r==SASL_OK ) { *out = pn_bytes(outlen, output); return outlen; } if (transport->trace & PN_TRACE_DRV) pn_transport_logf(transport, "SASL decode error: %s", sasl_errdetail(cyrus_conn)); return PN_ERR; }
int pn_post_transfer_frame(pn_dispatcher_t *disp, uint16_t ch, uint32_t handle, pn_sequence_t id, const pn_bytes_t *tag, uint32_t message_format, bool settled, bool more, pn_sequence_t frame_limit) { bool more_flag = more; int framecount = 0; // create preformatives, assuming 'more' flag need not change compute_performatives: pn_data_clear(disp->output_args); int err = pn_data_fill(disp->output_args, "DL[IIzIoo]", TRANSFER, handle, id, tag->size, tag->start, message_format, settled, more_flag); if (err) { pn_transport_logf(disp->transport, "error posting transfer frame: %s: %s", pn_code(err), pn_error_text(pn_data_error(disp->output_args))); return PN_ERR; } do { // send as many frames as possible without changing the 'more' flag... encode_performatives: pn_buffer_clear( disp->frame ); pn_bytes_t buf = pn_buffer_bytes( disp->frame ); buf.size = pn_buffer_available( disp->frame ); ssize_t wr = pn_data_encode(disp->output_args, buf.start, buf.size); if (wr < 0) { if (wr == PN_OVERFLOW) { pn_buffer_ensure( disp->frame, pn_buffer_available( disp->frame ) * 2 ); goto encode_performatives; } pn_transport_logf(disp->transport, "error posting frame: %s", pn_code(wr)); return PN_ERR; } buf.size = wr; // check if we need to break up the outbound frame size_t available = disp->output_size; if (disp->remote_max_frame) { if ((available + buf.size) > disp->remote_max_frame - 8) { available = disp->remote_max_frame - 8 - buf.size; if (more_flag == false) { more_flag = true; goto compute_performatives; // deal with flag change } } else if (more_flag == true && more == false) { // caller has no more, and this is the last frame more_flag = false; goto compute_performatives; } } if (pn_buffer_available( disp->frame ) < (available + buf.size)) { // not enough room for payload - try again... pn_buffer_ensure( disp->frame, available + buf.size ); goto encode_performatives; } pn_do_trace(disp, ch, OUT, disp->output_args, disp->output_payload, available); memmove( buf.start + buf.size, disp->output_payload, available); disp->output_payload += available; disp->output_size -= available; buf.size += available; pn_frame_t frame = {disp->frame_type}; frame.channel = ch; frame.payload = buf.start; frame.size = buf.size; size_t n; while (!(n = pn_write_frame(disp->output + disp->available, disp->capacity - disp->available, frame))) { disp->capacity *= 2; disp->output = (char *) realloc(disp->output, disp->capacity); } disp->output_frames_ct += 1; framecount++; if (disp->trace & PN_TRACE_RAW) { pn_string_set(disp->scratch, "RAW: \""); pn_quote(disp->scratch, disp->output + disp->available, n); pn_string_addf(disp->scratch, "\""); pn_transport_log(disp->transport, pn_string_get(disp->scratch)); } disp->available += n; } while (disp->output_size > 0 && framecount < frame_limit); disp->output_payload = NULL; return framecount; }
// Certificate chain verification callback: return 1 if verified, // 0 if remote cannot be verified (fail handshake). // static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { if (!preverify_ok || X509_STORE_CTX_get_error_depth(ctx) != 0) // already failed, or not at peer cert in chain return preverify_ok; X509 *cert = X509_STORE_CTX_get_current_cert(ctx); SSL *ssn = (SSL *) X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); if (!ssn) { pn_transport_logf(NULL, "Error: unexpected error - SSL session info not available for peer verify!"); return 0; // fail connection } pn_transport_t *transport = (pn_transport_t *)SSL_get_ex_data(ssn, ssl_ex_data_index); if (!transport) { pn_transport_logf(NULL, "Error: unexpected error - SSL context info not available for peer verify!"); return 0; // fail connection } pni_ssl_t *ssl = transport->ssl; if (ssl->domain->verify_mode != PN_SSL_VERIFY_PEER_NAME) return preverify_ok; if (!ssl->peer_hostname) { pn_transport_logf(transport, "Error: configuration error: PN_SSL_VERIFY_PEER_NAME configured, but no peer hostname set!"); return 0; // fail connection } ssl_log(transport, "Checking identifying name in peer cert against '%s'", ssl->peer_hostname); bool matched = false; /* first check any SubjectAltName entries, as per RFC2818 */ GENERAL_NAMES *sans = (GENERAL_NAMES *) X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (sans) { int name_ct = sk_GENERAL_NAME_num( sans ); int i; for (i = 0; !matched && i < name_ct; ++i) { GENERAL_NAME *name = sk_GENERAL_NAME_value( sans, i ); if (name->type == GEN_DNS) { ASN1_STRING *asn1 = name->d.dNSName; if (asn1 && asn1->data && asn1->length) { unsigned char *str; int len = ASN1_STRING_to_UTF8( &str, asn1 ); if (len >= 0) { ssl_log(transport, "SubjectAltName (dns) from peer cert = '%.*s'", len, str ); matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len ); OPENSSL_free( str ); } } } } GENERAL_NAMES_free( sans ); } /* if no general names match, try the CommonName from the subject */ X509_NAME *name = X509_get_subject_name(cert); int i = -1; while (!matched && (i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0) { X509_NAME_ENTRY *ne = X509_NAME_get_entry(name, i); ASN1_STRING *name_asn1 = X509_NAME_ENTRY_get_data(ne); if (name_asn1) { unsigned char *str; int len = ASN1_STRING_to_UTF8( &str, name_asn1); if (len >= 0) { ssl_log(transport, "commonName from peer cert = '%.*s'", len, str); matched = match_dns_pattern( ssl->peer_hostname, (const char *)str, len ); OPENSSL_free(str); } } } if (!matched) { ssl_log(transport, "Error: no name matching %s found in peer cert - rejecting handshake.", ssl->peer_hostname); preverify_ok = 0; #ifdef X509_V_ERR_APPLICATION_VERIFICATION X509_STORE_CTX_set_error( ctx, X509_V_ERR_APPLICATION_VERIFICATION ); #endif } else { ssl_log(transport, "Name from peer cert matched - peer is valid."); } return preverify_ok; }
static int init_ssl_socket(pn_transport_t* transport, pni_ssl_t *ssl) { if (ssl->ssl) return 0; if (!ssl->domain) return -1; ssl->ssl = SSL_new(ssl->domain->ctx); if (!ssl->ssl) { pn_transport_logf(transport, "SSL socket setup failure." ); return -1; } // store backpointer to pn_transport_t in SSL object: SSL_set_ex_data(ssl->ssl, ssl_ex_data_index, transport); #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if (ssl->peer_hostname && ssl->domain->mode == PN_SSL_MODE_CLIENT) { SSL_set_tlsext_host_name(ssl->ssl, ssl->peer_hostname); } #endif // restore session, if available if (ssl->session_id) { pn_ssl_session_t *ssn = ssn_cache_find( ssl->domain, ssl->session_id ); if (ssn) { ssl_log( transport, "Restoring previous session id=%s", ssn->id ); int rc = SSL_set_session( ssl->ssl, ssn->session ); if (rc != 1) { ssl_log( transport, "Session restore failed, id=%s", ssn->id ); } LL_REMOVE( ssl->domain, ssn_cache, ssn ); ssl_session_free( ssn ); } } // now layer a BIO over the SSL socket ssl->bio_ssl = BIO_new(BIO_f_ssl()); if (!ssl->bio_ssl) { pn_transport_log(transport, "BIO setup failure." ); return -1; } (void)BIO_set_ssl(ssl->bio_ssl, ssl->ssl, BIO_NOCLOSE); // create the "lower" BIO "pipe", and attach it below the SSL layer if (!BIO_new_bio_pair(&ssl->bio_ssl_io, 0, &ssl->bio_net_io, 0)) { pn_transport_log(transport, "BIO setup failure." ); return -1; } SSL_set_bio(ssl->ssl, ssl->bio_ssl_io, ssl->bio_ssl_io); if (ssl->domain->mode == PN_SSL_MODE_SERVER) { SSL_set_accept_state(ssl->ssl); BIO_set_ssl_mode(ssl->bio_ssl, 0); // server mode ssl_log( transport, "Server SSL socket created." ); } else { // client mode SSL_set_connect_state(ssl->ssl); BIO_set_ssl_mode(ssl->bio_ssl, 1); // client mode ssl_log( transport, "Client SSL socket created." ); } ssl->subject = NULL; return 0; }
pn_ssl_domain_t *pn_ssl_domain( pn_ssl_mode_t mode ) { if (!ssl_initialized) { ssl_initialized = 1; SSL_library_init(); SSL_load_error_strings(); OpenSSL_add_all_algorithms(); ssl_ex_data_index = SSL_get_ex_new_index( 0, (void *) "org.apache.qpid.proton.ssl", NULL, NULL, NULL); } pn_ssl_domain_t *domain = (pn_ssl_domain_t *) calloc(1, sizeof(pn_ssl_domain_t)); if (!domain) return NULL; domain->ref_count = 1; domain->mode = mode; // enable all supported protocol versions, then explicitly disable the // known vulnerable ones. This should allow us to use the latest version // of the TLS standard that the installed library supports. switch(mode) { case PN_SSL_MODE_CLIENT: domain->ctx = SSL_CTX_new(SSLv23_client_method()); // and TLSv1+ if (!domain->ctx) { ssl_log_error("Unable to initialize OpenSSL context."); free(domain); return NULL; } break; case PN_SSL_MODE_SERVER: domain->ctx = SSL_CTX_new(SSLv23_server_method()); // and TLSv1+ if (!domain->ctx) { ssl_log_error("Unable to initialize OpenSSL context."); free(domain); return NULL; } break; default: pn_transport_logf(NULL, "Invalid value for pn_ssl_mode_t: %d", mode); free(domain); return NULL; } const long reject_insecure = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3; SSL_CTX_set_options(domain->ctx, reject_insecure); #ifdef SSL_OP_NO_COMPRESSION // Mitigate the CRIME vulnerability SSL_CTX_set_options(domain->ctx, SSL_OP_NO_COMPRESSION); #endif // by default, allow anonymous ciphers so certificates are not required 'out of the box' if (!SSL_CTX_set_cipher_list( domain->ctx, CIPHERS_ANONYMOUS )) { ssl_log_error("Failed to set cipher list to %s", CIPHERS_ANONYMOUS); pn_ssl_domain_free(domain); return NULL; } // ditto: by default do not authenticate the peer (can be done by SASL). if (pn_ssl_domain_set_peer_authentication( domain, PN_SSL_ANONYMOUS_PEER, NULL )) { pn_ssl_domain_free(domain); return NULL; } DH *dh = get_dh2048(); if (dh) { SSL_CTX_set_tmp_dh(domain->ctx, dh); DH_free(dh); SSL_CTX_set_options(domain->ctx, SSL_OP_SINGLE_DH_USE); } return domain; }