NOEXPORT int servername_cb(SSL *ssl, int *ad, void *arg) { SERVICE_OPTIONS *section=(SERVICE_OPTIONS *)arg; const char *servername=SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); SERVERNAME_LIST *list; CLI *c; #ifdef USE_LIBWRAP char *accepted_address; #endif /* USE_LIBWRAP */ /* leave the alert type at SSL_AD_UNRECOGNIZED_NAME */ (void)ad; /* skip warning about unused parameter */ if(!section->servername_list_head) { s_log(LOG_DEBUG, "SNI: no virtual services defined"); return SSL_TLSEXT_ERR_OK; } if(!servername) { s_log(LOG_NOTICE, "SNI: no servername received"); return SSL_TLSEXT_ERR_NOACK; } s_log(LOG_INFO, "SNI: requested servername: %s", servername); for(list=section->servername_list_head; list; list=list->next) if(matches_wildcard((char *)servername, list->servername)) { s_log(LOG_DEBUG, "SNI: matched pattern: %s", list->servername); c=SSL_get_ex_data(ssl, index_cli); c->opt=list->opt; SSL_set_SSL_CTX(ssl, c->opt->ctx); SSL_set_verify(ssl, SSL_CTX_get_verify_mode(c->opt->ctx), SSL_CTX_get_verify_callback(c->opt->ctx)); s_log(LOG_NOTICE, "SNI: switched to service [%s]", c->opt->servname); #ifdef USE_LIBWRAP accepted_address=s_ntop(&c->peer_addr, c->peer_addr_len); libwrap_auth(c, accepted_address); /* retry on a service switch */ str_free(accepted_address); #endif /* USE_LIBWRAP */ return SSL_TLSEXT_ERR_OK; } s_log(LOG_ERR, "SNI: no pattern matched servername: %s", servername); return SSL_TLSEXT_ERR_ALERT_FATAL; }
void cbtls_info(const SSL *s, int where, int ret) { const char *str, *state; int w; EAP_HANDLER *handler = (EAP_HANDLER *)SSL_get_ex_data(s, 0); REQUEST *request = NULL; if (handler) request = handler->request; w = where & ~SSL_ST_MASK; if (w & SSL_ST_CONNECT) str=" TLS_connect"; else if (w & SSL_ST_ACCEPT) str=" TLS_accept"; else str=" (other)"; state = SSL_state_string_long(s); state = state ? state : "NULL"; if (where & SSL_CB_LOOP) { RDEBUG2("%s: %s\n", str, state); } else if (where & SSL_CB_HANDSHAKE_START) { RDEBUG2("%s: %s\n", str, state); } else if (where & SSL_CB_HANDSHAKE_DONE) { RDEBUG2("%s: %s\n", str, state); } else if (where & SSL_CB_ALERT) { str=(where & SSL_CB_READ)?"read":"write"; radlog(L_ERR,"TLS Alert %s:%s:%s\n", str, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if (where & SSL_CB_EXIT) { if (ret == 0) { radlog(L_ERR, "%s:failed in %s\n", str, state); } else if (ret < 0) { if (SSL_want_read(s)) { RDEBUG2("%s: Need to read more data: %s", str, state); } else { radlog(L_ERR, "%s:error in %s\n", str, state); } } } }
/* DTLS alert callback */ void janus_dtls_callback(const SSL *ssl, int where, int ret) { /* We only care about alerts */ if (!(where & SSL_CB_ALERT)) { return; } janus_dtls_srtp *dtls = SSL_get_ex_data(ssl, 0); if(!dtls) { JANUS_LOG(LOG_ERR, "No DTLS session related to this alert...\n"); return; } janus_ice_component *component = dtls->component; if(component == NULL) { JANUS_LOG(LOG_ERR, "No ICE component related to this alert...\n"); return; } janus_ice_stream *stream = component->stream; if(!stream) { JANUS_LOG(LOG_ERR, "No ICE stream related to this alert...\n"); return; } janus_ice_handle *handle = stream->handle; if(!handle) { JANUS_LOG(LOG_ERR, "No ICE handle related to this alert...\n"); return; } JANUS_LOG(LOG_VERB, "[%"SCNu64"] DTLS alert triggered on stream %"SCNu16" (component %"SCNu16"), closing...\n", handle->handle_id, stream->stream_id, component->component_id); janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_CLEANING); if(!janus_flags_is_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT)) { janus_flags_set(&handle->webrtc_flags, JANUS_ICE_HANDLE_WEBRTC_ALERT); if(handle->iceloop) g_main_loop_quit(handle->iceloop); janus_plugin *plugin = (janus_plugin *)handle->app; if(plugin != NULL) { JANUS_LOG(LOG_VERB, "[%"SCNu64"] Telling the plugin about it (%s)\n", handle->handle_id, plugin->get_name()); if(plugin && plugin->hangup_media) plugin->hangup_media(handle->app_handle); janus_ice_notify_hangup(handle, "DTLS alert"); } } }
//sni lookup server name int httpSSLServerName(SSL *ssl,int *ad,void *arg) { const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (servername==NULL) { return SSL_TLSEXT_ERR_NOACK; } KConnectionSelectable *c = (KConnectionSelectable *)SSL_get_ex_data(ssl,kangle_ssl_conntion_index); if (c==NULL) { return SSL_TLSEXT_ERR_NOACK; } if (c->sni) { return SSL_TLSEXT_ERR_OK; } c->sni = new KSSLSniContext; if (query_vh_success != conf.gvm->queryVirtualHost(c->ls,&c->sni->svh,servername)) { return SSL_TLSEXT_ERR_OK; } if (c->sni->svh->vh && c->sni->svh->vh->ssl_ctx) { SSL_set_SSL_CTX(ssl,c->sni->svh->vh->ssl_ctx); } return SSL_TLSEXT_ERR_OK; }
static int bb_ssl_servername(SSL *ssl,int *ad, void *arg) { const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name); if (!servername) return SSL_TLSEXT_ERR_NOACK; struct bb_connection *bbc = SSL_get_ex_data(ssl, blastbeat.ssl_index); struct bb_acceptor *bba = bbc->acceptor; size_t servername_len = strlen(servername); struct bb_virtualhost *vhost = NULL; struct bb_hostname *bbhn = NULL; if (bba->addr.in4.sin_port != htons(443) && !strchr(servername, ':')) { size_t port_len = strlen(bba->port_str); char *new_sn = bb_alloc(servername_len+port_len); if (!new_sn) return SSL_TLSEXT_ERR_NOACK; memcpy(new_sn, servername, servername_len); memcpy(new_sn + servername_len, bba->port_str, port_len); vhost = bb_vhost_get(new_sn, servername_len+port_len, &bbhn); bb_free(new_sn, servername_len+port_len); } else { vhost = bb_vhost_get((char *)servername, servername_len, &bbhn); } if (!vhost) return SSL_TLSEXT_ERR_NOACK; // per vhost-context is required to decrypt keys sent by dealers if (!vhost->ctx) return SSL_TLSEXT_ERR_NOACK; // prefer dealer-defined context if (bbhn->ctx) { SSL_set_SSL_CTX(ssl, bbhn->ctx); return SSL_TLSEXT_ERR_OK; } SSL_set_SSL_CTX(ssl, vhost->ctx); return SSL_TLSEXT_ERR_OK; }
static int verify_callback(int preverify_ok, X509_STORE_CTX *callback_ctx) { /* our verify callback function */ SSL *ssl; CLI *c; char subject_name[STRLEN]; /* retrieve application specific data */ ssl=X509_STORE_CTX_get_ex_data(callback_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); c=SSL_get_ex_data(ssl, cli_index); /* certificate name for logging */ X509_NAME_oneline(X509_get_subject_name(callback_ctx->current_cert), subject_name, STRLEN); safestring(subject_name); s_log(LOG_DEBUG, "Starting certificate verification: depth=%d, %s", callback_ctx->error_depth, subject_name); if(!cert_check(c, callback_ctx, preverify_ok)) { s_log(LOG_WARNING, "Certificate check failed: depth=%d, %s", callback_ctx->error_depth, subject_name); return 0; /* reject connection */ } if(!crl_check(c, callback_ctx)) { s_log(LOG_WARNING, "CRL check failed: depth=%d, %s", callback_ctx->error_depth, subject_name); return 0; /* reject connection */ } if(c->opt->option.ocsp && !ocsp_check(c, callback_ctx)) { s_log(LOG_WARNING, "OCSP check failed: depth=%d, %s", callback_ctx->error_depth, subject_name); return 0; /* reject connection */ } /* errnum=X509_STORE_CTX_get_error(ctx); */ s_log(LOG_NOTICE, "Certificate accepted: depth=%d, %s", callback_ctx->error_depth, subject_name); return 1; /* accept connection */ }
static int OpenSSL_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { SSL *ssl; int n; struct libwebsocket_context *context; ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); /* * !!! nasty openssl requires the index to come as a library-scope * static */ context = SSL_get_ex_data(ssl, openssl_websocket_private_data_index); n = context->protocols[0].callback(NULL, NULL, LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION, x509_ctx, ssl, preverify_ok); /* convert return code from 0 = OK to 1 = OK */ return !n; }
static int openssl_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) { ErDtlsConnection *self; SSL *ssl; BIO *bio; gchar *pem = NULL; gboolean accepted = FALSE; ssl = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); self = SSL_get_ex_data(ssl, connection_ex_index); g_return_val_if_fail(ER_IS_DTLS_CONNECTION(self), FALSE); pem = _er_dtls_x509_to_pem(x509_ctx->cert); if (!pem) { LOG_WARNING(self, "failed to convert received certificate to pem format"); } else { bio = BIO_new(BIO_s_mem()); if (bio) { gchar buffer[2048]; gint len; len = X509_NAME_print_ex(bio, X509_get_subject_name(x509_ctx->cert), 1, XN_FLAG_MULTILINE); BIO_read(bio, buffer, len); buffer[len] = '\0'; LOG_DEBUG(self, "Peer certificate received:\n%s", buffer); BIO_free(bio); } else { LOG_DEBUG(self, "failed to create certificate print membio"); } g_signal_emit(self, signals[SIGNAL_ON_PEER_CERTIFICATE], 0, pem, &accepted); g_free(pem); } return accepted; }
int SSLContext::advertisedNextProtocolCallback(SSL* ssl, const unsigned char** out, unsigned int* outlen, void* data) { SSLContext* context = (SSLContext*)data; if (context == nullptr || context->advertisedNextProtocols_.empty()) { *out = nullptr; *outlen = 0; } else if (context->advertisedNextProtocols_.size() == 1) { *out = context->advertisedNextProtocols_[0].protocols; *outlen = context->advertisedNextProtocols_[0].length; } else { uintptr_t selected_index = reinterpret_cast<uintptr_t>(SSL_get_ex_data(ssl, sNextProtocolsExDataIndex_)); if (selected_index) { --selected_index; *out = context->advertisedNextProtocols_[selected_index].protocols; *outlen = context->advertisedNextProtocols_[selected_index].length; } else { unsigned char random_byte; RAND_bytes(&random_byte, 1); double random_value = random_byte / 255.0; double sum = 0; for (size_t i = 0; i < context->advertisedNextProtocols_.size(); ++i) { sum += context->advertisedNextProtocols_[i].probability; if (sum < random_value && i + 1 < context->advertisedNextProtocols_.size()) { continue; } uintptr_t selected = i + 1; SSL_set_ex_data(ssl, sNextProtocolsExDataIndex_, (void *)selected); *out = context->advertisedNextProtocols_[i].protocols; *outlen = context->advertisedNextProtocols_[i].length; break; } } } return SSL_TLSEXT_ERR_OK; }
static int openssl_iostream_verify_client_cert(int preverify_ok, X509_STORE_CTX *ctx) { int ssl_extidx = SSL_get_ex_data_X509_STORE_CTX_idx(); SSL *ssl; struct ssl_iostream *ssl_io; char certname[1024]; X509_NAME *subject; ssl = X509_STORE_CTX_get_ex_data(ctx, ssl_extidx); ssl_io = SSL_get_ex_data(ssl, dovecot_ssl_extdata_index); ssl_io->cert_received = TRUE; subject = X509_get_subject_name(X509_STORE_CTX_get_current_cert(ctx)); if (subject == NULL || X509_NAME_oneline(subject, certname, sizeof(certname)) == NULL) certname[0] = '\0'; else certname[sizeof(certname)-1] = '\0'; /* just in case.. */ if (preverify_ok == 0) { openssl_iostream_set_error(ssl_io, t_strdup_printf( "Received invalid SSL certificate: %s: %s", X509_verify_cert_error_string(X509_STORE_CTX_get_error(ctx)), certname)); if (ssl_io->verbose_invalid_cert) i_info("%s", ssl_io->last_error); } else if (ssl_io->verbose) { i_info("Received valid SSL certificate: %s", certname); } if (preverify_ok == 0) { ssl_io->cert_broken = TRUE; if (!ssl_io->allow_invalid_cert) { ssl_io->handshake_failed = TRUE; return 0; } } return 1; }
static int openssl_iostream_verify_client_cert(int preverify_ok, X509_STORE_CTX *ctx) { int ssl_extidx = SSL_get_ex_data_X509_STORE_CTX_idx(); SSL *ssl; struct ssl_iostream *ssl_io; ssl = X509_STORE_CTX_get_ex_data(ctx, ssl_extidx); ssl_io = SSL_get_ex_data(ssl, dovecot_ssl_extdata_index); ssl_io->cert_received = TRUE; if (ssl_io->verbose || (ssl_io->verbose_invalid_cert && !preverify_ok)) { char buf[1024]; X509_NAME *subject; subject = X509_get_subject_name(ctx->current_cert); if (subject == NULL || X509_NAME_oneline(subject, buf, sizeof(buf)) == NULL) buf[0] = '\0'; else buf[sizeof(buf)-1] = '\0'; /* just in case.. */ if (!preverify_ok) { i_info("Invalid certificate: %s: %s", X509_verify_cert_error_string(ctx->error), buf); } else { i_info("Valid certificate: %s", buf); } } if (!preverify_ok) { ssl_io->cert_broken = TRUE; if (ssl_io->require_valid_cert) return 0; } return 1; }
static int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) /* {{{ */ { void *stream; SSL *ssl; X509 *err_cert; int err, depth, ret; ret = preverify_ok; /* determine the status for the current cert */ err_cert = X509_STORE_CTX_get_current_cert(ctx); err = X509_STORE_CTX_get_error(ctx); depth = X509_STORE_CTX_get_error_depth(ctx); /* conjure the stream & context to use */ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); stream = SSL_get_ex_data(ssl, ssl_stream_data_index); /* if allow_self_signed is set, make sure that verification succeeds */ if (err == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT && GET_VER_OPT("allow_self_signed") && zval_is_true(*val)) { ret = 1; } /* check the depth */ if (GET_VER_OPT("verify_depth")) { convert_to_long_ex(val); if (depth > Z_LVAL_PP(val)) { ret = 0; X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG); } } return ret; }
extern "C" int ssl_verify_wrapper(int preverify_ok, X509_STORE_CTX *ctx) { unsigned long binding; X509 *cert; SSL *ssl; BUF_MEM *buf; BIO *out; int result; cert = X509_STORE_CTX_get_current_cert(ctx); ssl = (SSL*) X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); binding = (unsigned long) SSL_get_ex_data(ssl, 0); out = BIO_new(BIO_s_mem()); PEM_write_bio_X509(out, cert); BIO_write(out, "\0", 1); BIO_get_mem_ptr(out, &buf); ConnectionDescriptor *cd = dynamic_cast <ConnectionDescriptor*> (Bindable_t::GetObject(binding)); result = (cd->VerifySslPeer(buf->data) == true ? 1 : 0); BIO_free(out); return result; }
int bud_config_select_sni_context(SSL* s, int* ad, void* arg) { bud_config_t* config; bud_context_t* ctx; const char* servername; config = arg; servername = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name); /* No servername - no context selection */ if (servername == NULL) return SSL_TLSEXT_ERR_OK; /* Async SNI */ ctx = SSL_get_ex_data(s, kBudSSLSNIIndex); /* Normal SNI */ if (ctx == NULL) ctx = bud_config_select_context(config, servername, strlen(servername)); if (ctx != NULL) SSL_set_SSL_CTX(s, ctx->ctx); return SSL_TLSEXT_ERR_OK; }
int _mosquitto_server_certificate_verify(int preverify_ok, X509_STORE_CTX *ctx) { /* Preverify should have already checked expiry, revocation. * We need to verify the hostname. */ struct mosquitto *mosq; SSL *ssl; X509 *cert; /* Always reject if preverify_ok has failed. */ if (!preverify_ok) { return 0; } ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); mosq = SSL_get_ex_data(ssl, tls_ex_index_mosq); if (!mosq) { return 0; } if (mosq->tls_insecure == false) { if (X509_STORE_CTX_get_error_depth(ctx) == 0) { /* FIXME - use X509_check_host() etc. for sufficiently new openssl (>=1.1.x) */ cert = X509_STORE_CTX_get_current_cert(ctx); /* This is the peer certificate, all others are upwards in the chain. */ #if defined(WITH_BROKER) return _mosquitto_verify_certificate_hostname(cert, mosq->bridge->addresses[mosq->bridge->cur_address].address); #else return _mosquitto_verify_certificate_hostname(cert, mosq->host); #endif } else { return preverify_ok; } } else { return preverify_ok; } }
int verify_ssl_cb(int ok, X509_STORE_CTX* store) { SSL* ssl = (SSL *)X509_STORE_CTX_get_app_data(store); void* p = SSL_get_ex_data(ssl, get_ssl_idx()); // get the pointer to the go Ctx object and pass it back into the thunk return verify_ssl_cb_thunk(p, ok, store); }
NOEXPORT void info_callback(const SSL *ssl, int where, int ret) { CLI *c; SSL_CTX *ctx; const char *state_string; c=SSL_get_ex_data((SSL *)ssl, index_cli); if(c) { int state=SSL_get_state((SSL *)ssl); #if 0 s_log(LOG_DEBUG, "state = %x", state); #endif /* log the client certificate request (if received) */ #ifndef SSL3_ST_CR_CERT_REQ_A if(state==TLS_ST_CR_CERT_REQ) #else if(state==SSL3_ST_CR_CERT_REQ_A) #endif print_client_CA_list(SSL_get_client_CA_list(ssl)); #ifndef SSL3_ST_CR_SRVR_DONE_A if(state==TLS_ST_CR_SRVR_DONE) #else if(state==SSL3_ST_CR_SRVR_DONE_A) #endif if(!SSL_get_client_CA_list(ssl)) s_log(LOG_INFO, "Client certificate not requested"); /* prevent renegotiation DoS attack */ if((where&SSL_CB_HANDSHAKE_DONE) && c->reneg_state==RENEG_INIT) { /* first (initial) handshake was completed, remember this, * so that further renegotiation attempts can be detected */ c->reneg_state=RENEG_ESTABLISHED; } else if((where&SSL_CB_ACCEPT_LOOP) && c->reneg_state==RENEG_ESTABLISHED) { #ifndef SSL3_ST_SR_CLNT_HELLO_A if(state==TLS_ST_SR_CLNT_HELLO || state==TLS_ST_SR_CLNT_HELLO) { #else if(state==SSL3_ST_SR_CLNT_HELLO_A || state==SSL23_ST_SR_CLNT_HELLO_A) { #endif /* client hello received after initial handshake, * this means renegotiation -> mark it */ c->reneg_state=RENEG_DETECTED; } } if(c->opt->log_level<LOG_DEBUG) /* performance optimization */ return; } if(where & SSL_CB_LOOP) { state_string=SSL_state_string_long(ssl); if(strcmp(state_string, "unknown state")) s_log(LOG_DEBUG, "SSL state (%s): %s", where & SSL_ST_CONNECT ? "connect" : where & SSL_ST_ACCEPT ? "accept" : "undefined", state_string); } else if(where & SSL_CB_ALERT) { s_log(LOG_DEBUG, "SSL alert (%s): %s: %s", where & SSL_CB_READ ? "read" : "write", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if(where==SSL_CB_HANDSHAKE_DONE) { ctx=SSL_get_SSL_CTX((SSL *)ssl); if(c->opt->option.client) { s_log(LOG_DEBUG, "%6ld client connect(s) requested", SSL_CTX_sess_connect(ctx)); s_log(LOG_DEBUG, "%6ld client connect(s) succeeded", SSL_CTX_sess_connect_good(ctx)); s_log(LOG_DEBUG, "%6ld client renegotiation(s) requested", SSL_CTX_sess_connect_renegotiate(ctx)); } else { s_log(LOG_DEBUG, "%6ld server accept(s) requested", SSL_CTX_sess_accept(ctx)); s_log(LOG_DEBUG, "%6ld server accept(s) succeeded", SSL_CTX_sess_accept_good(ctx)); s_log(LOG_DEBUG, "%6ld server renegotiation(s) requested", SSL_CTX_sess_accept_renegotiate(ctx)); } /* according to the source it not only includes internal and external session caches, but also session tickets */ s_log(LOG_DEBUG, "%6ld session reuse(s)", SSL_CTX_sess_hits(ctx)); if(!c->opt->option.client) { /* server session cache stats */ s_log(LOG_DEBUG, "%6ld internal session cache item(s)", SSL_CTX_sess_number(ctx)); s_log(LOG_DEBUG, "%6ld internal session cache fill-up(s)", SSL_CTX_sess_cache_full(ctx)); s_log(LOG_DEBUG, "%6ld internal session cache miss(es)", SSL_CTX_sess_misses(ctx)); s_log(LOG_DEBUG, "%6ld external session cache hit(s)", SSL_CTX_sess_cb_hits(ctx)); s_log(LOG_DEBUG, "%6ld expired session(s) retrieved", SSL_CTX_sess_timeouts(ctx)); } } } /**************************************** SSL error reporting */ void sslerror(char *txt) { /* OpenSSL error handler */ unsigned long err; err=ERR_get_error(); if(err) { sslerror_queue(); sslerror_log(err, txt); } else { s_log(LOG_ERR, "%s: Peer suddenly disconnected", txt); } }
int dtls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) { //int rc = 0; unsigned int lenHash; const EVP_MD *pEvp = NULL; DTLS_FINGERPRINT_T fingerprint; X509 *pX509 = NULL; SSL *pSSLCtxt = NULL; int sslCbDataIndex; char buf[1024]; char buf2[1024]; DTLS_FINGERPRINT_VERIFY_T *pFingerprintVerify = NULL; pSSLCtxt = X509_STORE_CTX_get_ex_data(x509_ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); for(sslCbDataIndex = 0; sslCbDataIndex <= s_sslCbDataIndex; sslCbDataIndex++) { if((pFingerprintVerify = SSL_get_ex_data(pSSLCtxt, sslCbDataIndex))) { break; } } //LOG(X_DEBUG("DTLS_VERIFY_CB preverify_ok:%d, pFingerprintVerify: 0x%x, name:'%s'"), preverify_ok, pFingerprintVerify, X509_NAME_oneline(X509_get_subject_name(x509_ctx->cert), buf, sizeof(buf))); if(!pFingerprintVerify || pFingerprintVerify->verified) { return 1; } //LOG(X_DEBUG("Verify fingerprint type:%d"), pFingerprintVerify->fingerprint.type); LOGHEX_DEBUG(pFingerprintVerify->fingerprint.buf, pFingerprintVerify->fingerprint.len); if(!(pX509 = x509_ctx->cert)) { return 0; } memset(&fingerprint, 0, sizeof(fingerprint)); fingerprint.type = pFingerprintVerify->fingerprint.type; if(!(pEvp = dtlsFingerprintTypeToEVP(fingerprint.type))) { LOG(X_ERROR("Invalid DTLS fingerprint verification digest type %s (%d)"), sdp_dtls_get_fingerprint_typestr(fingerprint.type), fingerprint.type); return 0; } lenHash = sizeof(fingerprint.buf); if(X509_digest(pX509, pEvp, fingerprint.buf, &lenHash) != 1 || lenHash <= 0) { LOG(X_ERROR("DTLS X509_digest failed for peer certificate: %s"), ERR_reason_error_string(ERR_get_error())); return 0; } else { fingerprint.len = lenHash; } if(fingerprint.len != pFingerprintVerify->fingerprint.len || memcmp(fingerprint.buf, pFingerprintVerify->fingerprint.buf, fingerprint.len)) { LOG(X_ERROR("DTLS fingerprint verification failed for %s fingerprint length %d for remote certificate: %s"), sdp_dtls_get_fingerprint_typestr(fingerprint.type), fingerprint.len, X509_NAME_oneline(X509_get_subject_name(x509_ctx->cert), buf, sizeof(buf))); LOG(X_DEBUG("DTLS remote fingerprint %s does not match %s"), dtls_fingerprint2str(&fingerprint, buf2, sizeof(buf2)), dtls_fingerprint2str(&pFingerprintVerify->fingerprint, buf, sizeof(buf))); return 0; } pFingerprintVerify->verified = 1; LOG(X_DEBUG("DTLS verified %s fingerprint length %d for remote cerficate: %s"), sdp_dtls_get_fingerprint_typestr(fingerprint.type), fingerprint.len, X509_NAME_oneline(X509_get_subject_name(x509_ctx->cert), buf, sizeof(buf))); //LOG(X_DEBUG("DTLS_VERIFY_CB fingerprint type:%d, len: %d"), fingerprint.type, fingerprint.len); LOGHEX_DEBUG(fingerprint.buf, fingerprint.len); return 1; }
/* * Before trusting a certificate, you must make sure that the * certificate is 'valid'. There are several steps that your * application can take in determining if a certificate is * valid. Commonly used steps are: * * 1.Verifying the certificate's signature, and verifying that * the certificate has been issued by a trusted Certificate * Authority. * * 2.Verifying that the certificate is valid for the present date * (i.e. it is being presented within its validity dates). * * 3.Verifying that the certificate has not been revoked by its * issuing Certificate Authority, by checking with respect to a * Certificate Revocation List (CRL). * * 4.Verifying that the credentials presented by the certificate * fulfill additional requirements specific to the application, * such as with respect to access control lists or with respect * to OCSP (Online Certificate Status Processing). * * NOTE: This callback will be called multiple times based on the * depth of the root certificate chain */ static int cbtls_verify(int ok, X509_STORE_CTX *ctx) { char subject[1024]; /* Used for the subject name */ char issuer[1024]; /* Used for the issuer name */ char common_name[1024]; char cn_str[1024]; char buf[64]; EAP_HANDLER *handler = NULL; X509 *client_cert; X509 *issuer_cert; SSL *ssl; int err, depth, lookup; EAP_TLS_CONF *conf; int my_ok = ok; REQUEST *request; ASN1_INTEGER *sn = NULL; ASN1_TIME *asn_time = NULL; #ifdef HAVE_OPENSSL_OCSP_H X509_STORE *ocsp_store = NULL; #endif client_cert = X509_STORE_CTX_get_current_cert(ctx); err = X509_STORE_CTX_get_error(ctx); depth = X509_STORE_CTX_get_error_depth(ctx); lookup = depth; /* * Log client/issuing cert. If there's an error, log * issuing cert. */ if ((lookup > 1) && !my_ok) lookup = 1; /* * Retrieve the pointer to the SSL of the connection currently treated * and the application specific data stored into the SSL object. */ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); handler = (EAP_HANDLER *)SSL_get_ex_data(ssl, 0); request = handler->request; conf = (EAP_TLS_CONF *)SSL_get_ex_data(ssl, 1); #ifdef HAVE_OPENSSL_OCSP_H ocsp_store = (X509_STORE *)SSL_get_ex_data(ssl, 2); #endif /* * Get the Serial Number */ buf[0] = '\0'; sn = X509_get_serialNumber(client_cert); /* * For this next bit, we create the attributes *only* if * we're at the client or issuing certificate. */ if ((lookup <= 1) && sn && (sn->length < (sizeof(buf) / 2))) { char *p = buf; int i; for (i = 0; i < sn->length; i++) { sprintf(p, "%02x", (unsigned int)sn->data[i]); p += 2; } pairadd(&handler->certs, pairmake(cert_attr_names[EAPTLS_SERIAL][lookup], buf, T_OP_SET)); } /* * Get the Expiration Date */ buf[0] = '\0'; asn_time = X509_get_notAfter(client_cert); if ((lookup <= 1) && asn_time && (asn_time->length < MAX_STRING_LEN)) { memcpy(buf, (char*) asn_time->data, asn_time->length); buf[asn_time->length] = '\0'; pairadd(&handler->certs, pairmake(cert_attr_names[EAPTLS_EXPIRATION][lookup], buf, T_OP_SET)); } /* * Get the Subject & Issuer */ subject[0] = issuer[0] = '\0'; X509_NAME_oneline(X509_get_subject_name(client_cert), subject, sizeof(subject)); subject[sizeof(subject) - 1] = '\0'; if ((lookup <= 1) && subject[0] && (strlen(subject) < MAX_STRING_LEN)) { pairadd(&handler->certs, pairmake(cert_attr_names[EAPTLS_SUBJECT][lookup], subject, T_OP_SET)); } X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), issuer, sizeof(issuer)); issuer[sizeof(issuer) - 1] = '\0'; if ((lookup <= 1) && issuer[0] && (strlen(issuer) < MAX_STRING_LEN)) { pairadd(&handler->certs, pairmake(cert_attr_names[EAPTLS_ISSUER][lookup], issuer, T_OP_SET)); } /* * Get the Common Name */ X509_NAME_get_text_by_NID(X509_get_subject_name(client_cert), NID_commonName, common_name, sizeof(common_name)); common_name[sizeof(common_name) - 1] = '\0'; if ((lookup <= 1) && common_name[0] && (strlen(common_name) < MAX_STRING_LEN)) { pairadd(&handler->certs, pairmake(cert_attr_names[EAPTLS_CN][lookup], common_name, T_OP_SET)); } /* * If the CRL has expired, that might still be OK. */ if (!my_ok && (conf->allow_expired_crl) && (err == X509_V_ERR_CRL_HAS_EXPIRED)) { my_ok = 1; X509_STORE_CTX_set_error( ctx, 0 ); } if (!my_ok) { const char *p = X509_verify_cert_error_string(err); radlog(L_ERR,"--> verify error:num=%d:%s\n",err, p); radius_pairmake(request, &request->packet->vps, "Module-Failure-Message", p, T_OP_SET); return my_ok; } switch (ctx->error) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: radlog(L_ERR, "issuer= %s\n", issuer); break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: radlog(L_ERR, "notBefore="); #if 0 ASN1_TIME_print(bio_err, X509_get_notBefore(ctx->current_cert)); #endif break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: radlog(L_ERR, "notAfter="); #if 0 ASN1_TIME_print(bio_err, X509_get_notAfter(ctx->current_cert)); #endif break; } /* * If we're at the actual client cert, apply additional * checks. */ if (depth == 0) { /* * If the conf tells us to, check cert issuer * against the specified value and fail * verification if they don't match. */ if (conf->check_cert_issuer && (strcmp(issuer, conf->check_cert_issuer) != 0)) { radlog(L_AUTH, "rlm_eap_tls: Certificate issuer (%s) does not match specified value (%s)!", issuer, conf->check_cert_issuer); my_ok = 0; } /* * If the conf tells us to, check the CN in the * cert against xlat'ed value, but only if the * previous checks passed. */ if (my_ok && conf->check_cert_cn) { if (!radius_xlat(cn_str, sizeof(cn_str), conf->check_cert_cn, handler->request, NULL)) { radlog(L_ERR, "rlm_eap_tls (%s): xlat failed.", conf->check_cert_cn); /* if this fails, fail the verification */ my_ok = 0; } else { RDEBUG2("checking certificate CN (%s) with xlat'ed value (%s)", common_name, cn_str); if (strcmp(cn_str, common_name) != 0) { radlog(L_AUTH, "rlm_eap_tls: Certificate CN (%s) does not match specified value (%s)!", common_name, cn_str); my_ok = 0; } } } /* check_cert_cn */ #ifdef HAVE_OPENSSL_OCSP_H if (my_ok && conf->ocsp_enable){ RDEBUG2("--> Starting OCSP Request"); if(X509_STORE_CTX_get1_issuer(&issuer_cert, ctx, client_cert)!=1) { radlog(L_ERR, "Error: Couldn't get issuer_cert for %s", common_name); } my_ok = ocsp_check(ocsp_store, issuer_cert, client_cert, conf); } #endif while (conf->verify_client_cert_cmd) { char filename[256]; int fd; FILE *fp; snprintf(filename, sizeof(filename), "%s/%s.client.XXXXXXXX", conf->verify_tmp_dir, progname); fd = mkstemp(filename); if (fd < 0) { RDEBUG("Failed creating file in %s: %s", conf->verify_tmp_dir, strerror(errno)); break; } fp = fdopen(fd, "w"); if (!fp) { RDEBUG("Failed opening file %s: %s", filename, strerror(errno)); break; } if (!PEM_write_X509(fp, client_cert)) { fclose(fp); RDEBUG("Failed writing certificate to file"); goto do_unlink; } fclose(fp); if (!radius_pairmake(request, &request->packet->vps, "TLS-Client-Cert-Filename", filename, T_OP_SET)) { RDEBUG("Failed creating TLS-Client-Cert-Filename"); goto do_unlink; } RDEBUG("Verifying client certificate: %s", conf->verify_client_cert_cmd); if (radius_exec_program(conf->verify_client_cert_cmd, request, 1, NULL, 0, request->packet->vps, NULL, 1) != 0) { radlog(L_AUTH, "rlm_eap_tls: Certificate CN (%s) fails external verification!", common_name); my_ok = 0; } else { RDEBUG("Client certificate CN %s passed external validation", common_name); } do_unlink: unlink(filename); break; } } /* depth == 0 */ if (debug_flag > 0) { RDEBUG2("chain-depth=%d, ", depth); RDEBUG2("error=%d", err); RDEBUG2("--> User-Name = %s", handler->identity); RDEBUG2("--> BUF-Name = %s", common_name); RDEBUG2("--> subject = %s", subject); RDEBUG2("--> issuer = %s", issuer); RDEBUG2("--> verify return:%d", my_ok); } return my_ok; }
// 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 inline void on_ssl_info(const SSL* ssl, int where, int ret) { static_cast<RTC::DtlsTransport*>(SSL_get_ex_data(ssl, 0))->onSSLInfo(where, ret); }
void *modssl_get_app_data2(SSL *ssl) { return (void *)SSL_get_ex_data(ssl, app_data2_idx); }
int tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx) { char buf[CCERT_BUFSIZ]; X509 *cert; int err; int depth; SSL *con; TLS_SESS_STATE *TLScontext; depth = X509_STORE_CTX_get_error_depth(ctx); cert = X509_STORE_CTX_get_current_cert(ctx); con = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); TLScontext = SSL_get_ex_data(con, TLScontext_index); /* * The callback function is called repeatedly, first with the root * certificate, and then with each intermediate certificate ending with * the peer certificate. * * With each call, the validity of the current certificate (usage bits, * attributes, expiration, ... checked by the OpenSSL library) is * available in the "ok" argument. Error details are available via * X509_STORE_CTX API. * * We never terminate the SSL handshake in the verification callback, rather * we allow the TLS handshake to continue, but mark the session as * unverified. The application is responsible for closing any sessions * with unverified credentials. * * Certificate chain depth limit violations are mis-reported by the OpenSSL * library, from SSL_CTX_set_verify(3): * * The certificate verification depth set with SSL[_CTX]_verify_depth() * stops the verification at a certain depth. The error message produced * will be that of an incomplete certificate chain and not * X509_V_ERR_CERT_CHAIN_TOO_LONG as may be expected. * * We set a limit that is one higher than the user requested limit. If this * higher limit is reached, we raise an error even a trusted root CA is * present at this depth. This disambiguates trust chain truncation from * an incomplete trust chain. */ if (depth >= SSL_get_verify_depth(con)) { ok = 0; X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_CHAIN_TOO_LONG); } if (TLScontext->log_level >= 2) { X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); acl_msg_info("%s: certificate verification depth=%d verify=%d subject=%s", TLScontext->namaddr, depth, ok, printable(buf, '?')); } /* * If no errors, or we are not logging verification errors, we are done. */ if (ok || (TLScontext->peer_status & TLS_CERT_FLAG_LOGGED) != 0) return (1); /* * One counter-example is enough. */ TLScontext->peer_status |= TLS_CERT_FLAG_LOGGED; #define PURPOSE ((depth>0) ? "CA": TLScontext->am_server ? "client": "server") /* * Specific causes for verification failure. */ switch (err = X509_STORE_CTX_get_error(ctx)) { case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: acl_msg_info("certificate verification failed for %s: " "self-signed certificate", TLScontext->namaddr); break; case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: /* * There is no difference between issuing cert not provided and * provided, but not found in CAfile/CApath. Either way, we don't * trust it. */ X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, sizeof(buf)); acl_msg_info("certificate verification failed for %s: untrusted issuer %s", TLScontext->namaddr, printable(buf, '?')); break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: acl_msg_info("%s certificate verification failed for %s: certificate not" " yet valid", PURPOSE, TLScontext->namaddr); break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: acl_msg_info("%s certificate verification failed for %s: certificate has" " expired", PURPOSE, TLScontext->namaddr); break; case X509_V_ERR_INVALID_PURPOSE: acl_msg_info("certificate verification failed for %s: not designated for " "use as a %s certificate", TLScontext->namaddr, PURPOSE); break; case X509_V_ERR_CERT_CHAIN_TOO_LONG: acl_msg_info("certificate verification failed for %s: " "certificate chain longer than limit(%d)", TLScontext->namaddr, SSL_get_verify_depth(con) - 1); break; default: acl_msg_info("%s certificate verification failed for %s: num=%d:%s", PURPOSE, TLScontext->namaddr, err, X509_verify_cert_error_string(err)); break; } return (1); }
static int verify_callback(int preverify_ok, X509_STORE_CTX* ctx) { // If the cert has already failed we're done. if (! preverify_ok) { return preverify_ok; } SSL* ssl = X509_STORE_CTX_get_ex_data( ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); // The verify callback is called for each cert in the chain. X509* current_cert = X509_STORE_CTX_get_current_cert(ctx); as_tls_context* asctxt = SSL_get_ex_data(ssl, s_ex_ctxt_index); if (! asctxt) { as_log_warn("Missing as_tls_context in TLS verify callback"); return 0; } pthread_mutex_lock(&asctxt->lock); if (asctxt->cert_blacklist) { // Is this cert blacklisted? char name[256]; X509_NAME* iname = X509_get_issuer_name(current_cert); X509_NAME_oneline(iname, name, sizeof(name)); ASN1_INTEGER* sn = X509_get_serialNumber(current_cert); BIGNUM* snbn = ASN1_INTEGER_to_BN(sn, NULL); char* snhex = BN_bn2hex(snbn); as_log_info("CERT: %s %s", snhex, name); bool blacklisted = cert_blacklist_check(asctxt->cert_blacklist, snhex, name); OPENSSL_free(snhex); BN_free(snbn); if (blacklisted) { as_log_warn("CERT: BLACKLISTED"); pthread_mutex_unlock(&asctxt->lock); return 0; } } pthread_mutex_unlock(&asctxt->lock); // If this is the peer cert, check the name #if OPENSSL_VERSION_NUMBER >= 0x10100000L X509* cert = X509_STORE_CTX_get0_cert(ctx); #else X509* cert = ctx->cert; #endif if (current_cert == cert) { char * hostname = SSL_get_ex_data(ssl, s_ex_name_index); if (! hostname) { as_log_warn("Missing hostname in TLS verify callback"); return 0; } bool allow_wildcard = true; bool matched = as_tls_match_name(cert, hostname, allow_wildcard); if (matched) { as_log_debug("TLS name '%s' matches", hostname); } else { as_log_warn("TLS name '%s' mismatch", hostname); } return matched ? 1 : 0; } // If we make it here we are a root or chain cert and are not // blacklisted. return 1; }
void bud_client_stapling_cache_req_cb(bud_http_request_t* req, bud_error_t err) { bud_client_t* client; bud_config_t* config; bud_context_t* context; const char* id; size_t id_size; const char* url; size_t url_size; char* ocsp; size_t ocsp_size; char* json; size_t json_size; size_t offset; client = req->data; config = client->config; context = SSL_get_ex_data(client->ssl, kBudSSLSNIIndex); client->hello_parse = kBudProgressDone; client->stapling_cache_req = NULL; json = NULL; ocsp = NULL; ASSERT(context != NULL, "Context disappeared"); if (!bud_is_ok(err)) { WARNING(&client->frontend, "OCSP cache cb failed: %d - \"%s\"", err.code, err.str); goto done; } /* Cache hit, success */ if ((req->code >= 200 && req->code < 400) && bud_client_staple_json(client, req->response) == 0) { DBG_LN(&client->frontend, "stapling cache hit"); goto done; } DBG_LN(&client->frontend, "stapling cache miss"); id = bud_context_get_ocsp_id(context, &id_size); url = bud_context_get_ocsp_req(context, &url_size, &ocsp, &ocsp_size); /* Certificate has no OCSP url */ if (url == NULL) goto done; /* Format JSON request */ json_size = 2 + bud_base64_encoded_size(ocsp_size) + 2 + url_size; json_size += /* "ocsp": */ 7 + /* "url": */ 6 + /* {,}\0 */ 4; json = malloc(json_size); if (json == NULL) goto done; offset = snprintf(json, json_size, "{\"url\":\"%.*s\",\"ocsp\":\"", (int) url_size, url); bud_base64_encode(ocsp, ocsp_size, json + offset, json_size - offset); offset += bud_base64_encoded_size(ocsp_size); snprintf(json + offset, json_size - offset, "\"}"); /* Request OCSP response */ client->stapling_req = bud_http_post(config->stapling.pool, config->stapling.query_fmt, id, id_size, json, json_size - 1, bud_client_stapling_req_cb, &err); client->stapling_req->data = client; if (!bud_is_ok(err)) goto done; client->hello_parse = kBudProgressRunning; done: free(ocsp); free(json); json_value_free(req->response); bud_client_cycle(client); }
NOEXPORT void info_callback( #if OPENSSL_VERSION_NUMBER>=0x0090700fL const #endif SSL *ssl, int where, int ret) { CLI *c; c=SSL_get_ex_data(ssl, cli_index); if(c) { if((where&SSL_CB_HANDSHAKE_DONE) && c->reneg_state==RENEG_INIT) { /* first (initial) handshake was completed, remember this, * so that further renegotiation attempts can be detected */ c->reneg_state=RENEG_ESTABLISHED; } else if((where&SSL_CB_ACCEPT_LOOP) && c->reneg_state==RENEG_ESTABLISHED) { int state=SSL_get_state(ssl); if(state==SSL3_ST_SR_CLNT_HELLO_A || state==SSL23_ST_SR_CLNT_HELLO_A) { /* client hello received after initial handshake, * this means renegotiation -> mark it */ c->reneg_state=RENEG_DETECTED; } } } if(global_options.debug_level<LOG_DEBUG) return; /* performance optimization */ if(where & SSL_CB_LOOP) { s_log(LOG_DEBUG, "SSL state (%s): %s", where & SSL_ST_CONNECT ? "connect" : where & SSL_ST_ACCEPT ? "accept" : "undefined", SSL_state_string_long(ssl)); } else if(where & SSL_CB_ALERT) { s_log(LOG_DEBUG, "SSL alert (%s): %s: %s", where & SSL_CB_READ ? "read" : "write", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); } else if(where==SSL_CB_HANDSHAKE_DONE) { s_log(LOG_DEBUG, "%4ld items in the session cache", SSL_CTX_sess_number(ssl->ctx)); s_log(LOG_DEBUG, "%4ld client connects (SSL_connect())", SSL_CTX_sess_connect(ssl->ctx)); s_log(LOG_DEBUG, "%4ld client connects that finished", SSL_CTX_sess_connect_good(ssl->ctx)); s_log(LOG_DEBUG, "%4ld client renegotiations requested", SSL_CTX_sess_connect_renegotiate(ssl->ctx)); s_log(LOG_DEBUG, "%4ld server connects (SSL_accept())", SSL_CTX_sess_accept(ssl->ctx)); s_log(LOG_DEBUG, "%4ld server connects that finished", SSL_CTX_sess_accept_good(ssl->ctx)); s_log(LOG_DEBUG, "%4ld server renegotiations requested", SSL_CTX_sess_accept_renegotiate(ssl->ctx)); s_log(LOG_DEBUG, "%4ld session cache hits", SSL_CTX_sess_hits(ssl->ctx)); s_log(LOG_DEBUG, "%4ld external session cache hits", SSL_CTX_sess_cb_hits(ssl->ctx)); s_log(LOG_DEBUG, "%4ld session cache misses", SSL_CTX_sess_misses(ssl->ctx)); s_log(LOG_DEBUG, "%4ld session cache timeouts", SSL_CTX_sess_timeouts(ssl->ctx)); } }
/* * Before trusting a certificate, you must make sure that the * certificate is 'valid'. There are several steps that your * application can take in determining if a certificate is * valid. Commonly used steps are: * * 1.Verifying the certificate's signature, and verifying that * the certificate has been issued by a trusted Certificate * Authority. * * 2.Verifying that the certificate is valid for the present date * (i.e. it is being presented within its validity dates). * * 3.Verifying that the certificate has not been revoked by its * issuing Certificate Authority, by checking with respect to a * Certificate Revocation List (CRL). * * 4.Verifying that the credentials presented by the certificate * fulfill additional requirements specific to the application, * such as with respect to access control lists or with respect * to OCSP (Online Certificate Status Processing). * * NOTE: This callback will be called multiple times based on the * depth of the root certificate chain */ static int cbtls_verify(int ok, X509_STORE_CTX *ctx) { char subject[1024]; /* Used for the subject name */ char issuer[1024]; /* Used for the issuer name */ char common_name[1024]; char cn_str[1024]; EAP_HANDLER *handler = NULL; X509 *client_cert; SSL *ssl; int err, depth; EAP_TLS_CONF *conf; int my_ok = ok; REQUEST *request; client_cert = X509_STORE_CTX_get_current_cert(ctx); err = X509_STORE_CTX_get_error(ctx); depth = X509_STORE_CTX_get_error_depth(ctx); if (!my_ok) { radlog(L_ERR,"--> verify error:num=%d:%s\n",err, X509_verify_cert_error_string(err)); return my_ok; } /* * Retrieve the pointer to the SSL of the connection currently treated * and the application specific data stored into the SSL object. */ ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); handler = (EAP_HANDLER *)SSL_get_ex_data(ssl, 0); request = handler->request; conf = (EAP_TLS_CONF *)SSL_get_ex_data(ssl, 1); /* * Get the Subject & Issuer */ subject[0] = issuer[0] = '\0'; X509_NAME_oneline(X509_get_subject_name(client_cert), subject, sizeof(subject)); X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), issuer, sizeof(issuer)); subject[sizeof(subject) - 1] = '\0'; issuer[sizeof(issuer) - 1] = '\0'; /* * Get the Common Name */ X509_NAME_get_text_by_NID(X509_get_subject_name(client_cert), NID_commonName, common_name, sizeof(common_name)); common_name[sizeof(common_name) - 1] = '\0'; switch (ctx->error) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: radlog(L_ERR, "issuer= %s\n", issuer); break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: radlog(L_ERR, "notBefore="); #if 0 ASN1_TIME_print(bio_err, X509_get_notBefore(ctx->current_cert)); #endif break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: radlog(L_ERR, "notAfter="); #if 0 ASN1_TIME_print(bio_err, X509_get_notAfter(ctx->current_cert)); #endif break; } /* * If we're at the actual client cert, apply additional * checks. */ if (depth == 0) { /* * If the conf tells us to, check cert issuer * against the specified value and fail * verification if they don't match. */ if (conf->check_cert_issuer && (strcmp(issuer, conf->check_cert_issuer) != 0)) { radlog(L_AUTH, "rlm_eap_tls: Certificate issuer (%s) does not match specified value (%s)!", issuer, conf->check_cert_issuer); my_ok = 0; } /* * If the conf tells us to, check the CN in the * cert against xlat'ed value, but only if the * previous checks passed. */ if (my_ok && conf->check_cert_cn) { if (!radius_xlat(cn_str, sizeof(cn_str), conf->check_cert_cn, handler->request, NULL)) { radlog(L_ERR, "rlm_eap_tls (%s): xlat failed.", conf->check_cert_cn); /* if this fails, fail the verification */ my_ok = 0; } else { RDEBUG2("checking certificate CN (%s) with xlat'ed value (%s)", common_name, cn_str); if (strcmp(cn_str, common_name) != 0) { radlog(L_AUTH, "rlm_eap_tls: Certificate CN (%s) does not match specified value (%s)!", common_name, cn_str); my_ok = 0; } } } /* check_cert_cn */ } /* depth == 0 */ if (debug_flag > 0) { RDEBUG2("chain-depth=%d, ", depth); RDEBUG2("error=%d", err); RDEBUG2("--> User-Name = %s", handler->identity); RDEBUG2("--> BUF-Name = %s", common_name); RDEBUG2("--> subject = %s", subject); RDEBUG2("--> issuer = %s", issuer); RDEBUG2("--> verify return:%d", my_ok); } return my_ok; }
// int VSslServer::ssl_servername_cb_debug(SSL *con, int *ad, void *arg, int* debug) // gilgil temp 2014.03.14 int VSslServer::ssl_servername_cb(SSL *con, int *ad, void *arg) { Q_UNUSED(ad) const char* serverName = SSL_get_servername(con, TLSEXT_NAMETYPE_host_name); // *debug = 1000; // gilgil temp 2014.03.14 if (serverName == NULL) { LOG_DEBUG("serverName is null"); return SSL_TLSEXT_ERR_NOACK; } // *debug = 2500; // gilgil temp 2014.03.14 // LOG_DEBUG("serverName=%p %s", serverName, serverName); // gilgil temp 2014.03.14 // *debug = 3000; // gilgil temp 2014.03.14 VSslServer* server = (VSslServer*)(arg); LOG_ASSERT(server != NULL); VSslServerSession* session = (VSslServerSession*)SSL_get_ex_data(con, VSslSession::VSSL_SESSION_IDENTIFY_INDEX); LOG_ASSERT(session->con == con); // *debug = 500; // gilgil temp 2014.03.14 // LOG_DEBUG("server=%p session=%p", server, session); // gilgil temp 2014.03.14 QString path = server->certificatePath; QFileInfo fi(path); if (!fi.isAbsolute()) { // path = VApp::_filePath() + path; // gilgil temp 2014.12.25 path = QCoreApplication::applicationDirPath() + QDir::separator() + path; } if (!path.endsWith('/') && !path.endsWith('\\')) path += QDir::separator(); QString fileName = path + serverName + ".pem"; // *debug = 4000; // gilgil temp 2014.03.14 { VLock lock(server->certificateCs); // protect file create critical section // *debug = 5000; // gilgil temp 2014.03.14 if (!QFile::exists(fileName)) { QProcess process; process.setWorkingDirectory(path); LOG_DEBUG("working directory=%s", qPrintable(process.workingDirectory())); // gilgil temp 2014.03.01 QString command = QString("\"%1_make_site.bat\" %2 2>&1").arg(path).arg(serverName); LOG_INFO("command=%s", qPrintable(command)); process.start(command); // LOG_DEBUG("pid=%llx", process.pid()); // gilgil temp 2015.01.02 // *debug = 6000; // gilgil temp 2014.03.14 if(!process.waitForStarted()) { LOG_FATAL("process.waitForStarted(%s) return false", qPrintable(command)); } // *debug = 700; // gilgil temp 2014.03.14 while(process.waitForReadyRead()) { QByteArray ba = process.readAll(); LOG_DEBUG("ba.size=%d", ba.size()) LOG_DEBUG("ba.datas=%s", ba.data()); } // *debug = 8000; // gilgil temp 2014.03.14 } // *debug = 9000; // gilgil temp 2014.03.14 // LOG_DEBUG("con=%p", con); // gilgil temp 2014.03.14 // *debug = 9100; // gilgil temp 2014.03.14 if (!session->setup(fileName)) { LOG_ERROR("session->setup(%s) return false", qPrintable(fileName)); } // *debug = 9500; // gilgil temp 2014.03.14 } return SSL_TLSEXT_ERR_NOACK; }
void *SSL_get_app_data2(SSL *ssl) { return (void *)SSL_get_ex_data(ssl, SSL_app_data2_idx); }
int CryptoManager::verify_callback(int preverify_ok, X509_STORE_CTX *ctx) { int err = X509_STORE_CTX_get_error(ctx); SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); SSLVerifyData* verifyData = (SSLVerifyData*)SSL_get_ex_data(ssl, CryptoManager::idxVerifyData); // TODO: we should make sure that the trusted certificate store never overules KeyPrint, if present, because certificate pinning on an individual certificate is a stronger method of verification. // verifyData is unset only when KeyPrint has been pinned and we are not skipping errors due to incomplete chains // we can fail here f.ex. if the certificate has expired but is still pinned with KeyPrint if (!verifyData) return preverify_ok; bool allowUntrusted = verifyData->first; string keyp = verifyData->second; if (!keyp.empty()) { X509* cert = X509_STORE_CTX_get_current_cert(ctx); if (!cert) return 0; string kp2(keyp); if (kp2.compare(0, 12, "trusted_keyp") == 0) { // Possible follow up errors, after verification of a partial chain if (err == X509_V_ERR_CERT_UNTRUSTED || err == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE) { X509_STORE_CTX_set_error(ctx, X509_V_OK); return 1; } } else if (kp2.compare(0, 7, "SHA256/") != 0) return allowUntrusted ? 1 : 0; ByteVector kp = ssl::X509_digest(cert, EVP_sha256()); ByteVector kp2v(kp.size()); Encoder::fromBase32(&kp2[7], &kp2v[0], kp2v.size()); if (std::equal(kp.begin(), kp.end(), kp2v.begin())) { // KeyPrint validated, we can get rid of it (to avoid unnecessary passes) SSL_set_ex_data(ssl, CryptoManager::idxVerifyData, NULL); if (err != X509_V_OK) { // This is the right way to get the certificate store, although it is rather roundabout X509_STORE* store = SSL_CTX_get_cert_store(SSL_get_SSL_CTX(ssl)); dcassert(store == ctx->ctx); // Hide the potential library error about trying to add a dupe ERR_set_mark(); if (X509_STORE_add_cert(store, cert)) { X509_STORE_CTX_set_error(ctx, X509_V_OK); X509_verify_cert(ctx); err = X509_STORE_CTX_get_error(ctx); } else ERR_pop_to_mark(); // KeyPrint was not root certificate or we don't have the issuer certificate, the best we can do is trust the pinned KeyPrint if (err == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN || err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY || err == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT) { X509_STORE_CTX_set_error(ctx, X509_V_OK); // Set this to allow ignoring any follow up errors caused by the incomplete chain SSL_set_ex_data(ssl, CryptoManager::idxVerifyData, &CryptoManager::trustedKeyprint); return 1; } } return (err == X509_V_OK) ? 1 : 0; } else { if (X509_STORE_CTX_get_error_depth(ctx) > 0) return 1; } } if (allowUntrusted) { /* // We let untrusted certificates through unconditionally, when allowed, but we like to complain if (!preverify_ok && err != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) { X509* cert = NULL; if ((cert = X509_STORE_CTX_get_current_cert(ctx)) != NULL) { X509_NAME* subject = X509_get_subject_name(cert); string tmp, line; tmp = getNameEntryByNID(subject, NID_commonName); if (!tmp.empty()) { CID certCID(tmp); if (certCID) tmp = Util::listToString(ClientManager::getInstance()->getNicks(certCID)); line += (!line.empty() ? ", " : "") + tmp; } tmp = getNameEntryByNID(subject, NID_organizationName); if (!tmp.empty()) line += (!line.empty() ? ", " : "") + tmp; ByteVector kp = ssl::X509_digest(cert, EVP_sha256()); string keyp = "SHA256/" + Encoder::toBase32(&kp[0], kp.size()); LogManager::getInstance()->message(STRING_F(VERIFY_CERT_FAILED, line % X509_verify_cert_error_string(err) % keyp), LogManager::LOG_INFO); } }*/ return 1; } return preverify_ok; }