int tls_verify_certificate_callback(int ok, X509_STORE_CTX *ctx) { char buf[CCERT_BUFSIZ]; X509 *cert; int err; int depth; int max_depth; SSL *con; TLS_SESS_STATE *TLScontext; /* May be NULL as of OpenSSL 1.0, thanks for the API change! */ cert = X509_STORE_CTX_get_current_cert(ctx); err = X509_STORE_CTX_get_error(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); depth = X509_STORE_CTX_get_error_depth(ctx); /* Don't log the internal root CA unless there's an unexpected error. */ if (ok && TLScontext->tadepth > 0 && depth > TLScontext->tadepth) return (1); /* * 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. */ max_depth = SSL_get_verify_depth(con) - 1; /* * 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. */ if (max_depth >= 0 && depth > max_depth) { X509_STORE_CTX_set_error(ctx, err = X509_V_ERR_CERT_CHAIN_TOO_LONG); ok = 0; } if (ok == 0) update_error_state(TLScontext, depth, cert, err); if (TLScontext->log_mask & TLS_LOG_VERBOSE) { if (cert) X509_NAME_oneline(X509_get_subject_name(cert), buf, sizeof(buf)); else strcpy(buf, "<unknown>"); msg_info("%s: depth=%d verify=%d subject=%s", TLScontext->namaddr, depth, ok, printable(buf, '?')); } return (1); }
static int openssl_ssl_get(lua_State*L) { SSL* s = CHECK_OBJECT(1, SSL, "openssl.ssl"); int i; int top = lua_gettop(L); for (i = 2; i <= top; i++) { const char* what = luaL_checklstring(L, i, NULL); if (strcmp(what, "fd") == 0) { lua_pushinteger(L, SSL_get_fd(s)); } else if (strcmp(what, "rfd") == 0) { lua_pushinteger(L, SSL_get_rfd(s)); } else if (strcmp(what, "wfd") == 0) { lua_pushinteger(L, SSL_get_wfd(s)); } else if (strcmp(what, "client_CA_list") == 0) { STACK_OF(X509_NAME)* sn = SSL_get_client_CA_list(s); PUSH_OBJECT(sn, "openssl.sk_x509_name"); } else if (strcmp(what, "read_ahead") == 0) { lua_pushboolean(L, SSL_get_read_ahead(s)); } else if (strcmp(what, "shared_ciphers") == 0) { char buf[LUAL_BUFFERSIZE] = {0}; lua_pushstring(L, SSL_get_shared_ciphers(s, buf, sizeof(buf))); } else if (strcmp(what, "cipher_list") == 0) { //TODO FIX lua_pushstring(L, SSL_get_cipher_list(s, 0)); } else if (strcmp(what, "verify_mode") == 0) { //FIX lua_pushinteger(L, SSL_get_verify_mode(s)); } else if (strcmp(what, "verify_depth") == 0) { lua_pushinteger(L, SSL_get_verify_depth(s)); } else if (strcmp(what, "state_string") == 0) { lua_pushstring(L, SSL_state_string(s)); } else if (strcmp(what, "state_string_long") == 0) { lua_pushstring(L, SSL_state_string_long(s)); } else if (strcmp(what, "rstate_string") == 0) { lua_pushstring(L, SSL_rstate_string(s)); } else if (strcmp(what, "rstate_string_long") == 0) { lua_pushstring(L, SSL_rstate_string_long(s)); } else if (strcmp(what, "version") == 0) { lua_pushstring(L, SSL_get_version(s)); } else if (strcmp(what, "iversion") == 0) { lua_pushinteger(L, SSL_version(s)); } else if (strcmp(what, "default_timeout") == 0) { lua_pushinteger(L, SSL_get_default_timeout(s)); } else if (strcmp(what, "certificate") == 0) { X509* cert = SSL_get_certificate(s); PUSH_OBJECT(cert, "openssl.x509"); } else if (strcmp(what, "verify_result") == 0) { long l = SSL_get_verify_result(s); lua_pushinteger(L, l); } else if (strcmp(what, "version") == 0) { lua_pushstring(L, SSL_get_version(s)); } else if (strcmp(what, "state") == 0) { lua_pushinteger(L, SSL_state(s)); } else if (strcmp(what, "hostname") == 0) { lua_pushstring(L, SSL_get_servername(s, TLSEXT_NAMETYPE_host_name)); } else luaL_argerror(L, i, "can't understant"); } return top - 1; }
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); }