NOEXPORT int load_key_file(SERVICE_OPTIONS *section) { int i, reason; UI_DATA ui_data; s_log(LOG_INFO, "Loading private key from file: %s", section->key); if(file_permissions(section->key)) return 1; /* FAILED */ ui_data.section=section; /* setup current section for callbacks */ SSL_CTX_set_default_passwd_cb(section->ctx, password_cb); for(i=0; i<=3; i++) { if(!i && !cache_initialized) continue; /* there is no cached value */ SSL_CTX_set_default_passwd_cb_userdata(section->ctx, i ? &ui_data : NULL); /* try the cached password first */ if(SSL_CTX_use_PrivateKey_file(section->ctx, section->key, SSL_FILETYPE_PEM)) break; reason=ERR_GET_REASON(ERR_peek_error()); if(i<=2 && reason==EVP_R_BAD_DECRYPT) { sslerror_queue(); /* dump the error queue */ s_log(LOG_ERR, "Wrong pass phrase: retrying"); continue; } sslerror("SSL_CTX_use_PrivateKey_file"); return 1; /* FAILED */ } s_log(LOG_INFO, "Private key loaded from file: %s", section->key); return 0; /* OK */ }
NOEXPORT void sslerror_queue(void) { /* recursive dump of the error queue */ unsigned long err; err=ERR_get_error(); if(err) { sslerror_queue(); sslerror_log(err, "error queue"); } }
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); } }
NOEXPORT int load_key_file(SERVICE_OPTIONS *section) { int i, reason; UI_DATA ui_data; #if !defined(USE_WIN32) && !defined(USE_OS2) struct stat st; /* buffer for stat */ #endif s_log(LOG_INFO, "Loading key from file: %s", section->key); #if !defined(USE_WIN32) && !defined(USE_OS2) /* check permissions of the private key file */ if(stat(section->key, &st)) { ioerror("Private key file not found"); return 1; /* FAILED */ } if(st.st_mode & 7) s_log(LOG_WARNING, "Insecure file permissions on %s", section->key); #endif ui_data.section=section; /* setup current section for callbacks */ #if defined(USE_WIN32) || OPENSSL_VERSION_NUMBER>=0x0090700fL SSL_CTX_set_default_passwd_cb(section->ctx, password_cb); #endif for(i=0; i<=3; i++) { if(!i && !cache_initialized) continue; /* there is no cached value */ SSL_CTX_set_default_passwd_cb_userdata(section->ctx, i ? &ui_data : NULL); /* try the cached password first */ if(SSL_CTX_use_PrivateKey_file(section->ctx, section->key, SSL_FILETYPE_PEM)) break; reason=ERR_GET_REASON(ERR_peek_error()); if(i<=2 && reason==EVP_R_BAD_DECRYPT) { sslerror_queue(); /* dump the error queue */ s_log(LOG_ERR, "Wrong pass phrase: retrying"); continue; } sslerror("SSL_CTX_use_PrivateKey_file"); return 1; /* FAILED */ } return 0; /* OK */ }
NOEXPORT int load_key_engine(SERVICE_OPTIONS *section) { int i, reason; UI_DATA ui_data; EVP_PKEY *pkey; UI_METHOD *ui_method; s_log(LOG_INFO, "Loading key from engine: %s", section->key); ui_data.section=section; /* setup current section for callbacks */ #if defined(USE_WIN32) || OPENSSL_VERSION_NUMBER>=0x0090700fL SSL_CTX_set_default_passwd_cb(section->ctx, password_cb); #endif #ifdef USE_WIN32 ui_method=UI_create_method("stunnel WIN32 UI"); UI_method_set_reader(ui_method, pin_cb); #else /* USE_WIN32 */ ui_method=UI_OpenSSL(); /* workaround for broken engines */ /* ui_data.section=NULL; */ #endif /* USE_WIN32 */ for(i=1; i<=3; i++) { pkey=ENGINE_load_private_key(section->engine, section->key, ui_method, &ui_data); if(!pkey) { reason=ERR_GET_REASON(ERR_peek_error()); if(i<=2 && (reason==7 || reason==160)) { /* wrong PIN */ sslerror_queue(); /* dump the error queue */ s_log(LOG_ERR, "Wrong PIN: retrying"); continue; } sslerror("ENGINE_load_private_key"); return 1; /* FAILED */ } if(SSL_CTX_use_PrivateKey(section->ctx, pkey)) break; /* success */ sslerror("SSL_CTX_use_PrivateKey"); return 1; /* FAILED */ } return 0; /* OK */ }
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); } }