/** * ssl_set_verify_partial - Allow verification using partial chains (with no root) * @param ctx SSL context * @retval 0 Success * @retval -1 Error */ static int ssl_set_verify_partial(SSL_CTX *ctx) { int rc = 0; #ifdef HAVE_SSL_PARTIAL_CHAIN X509_VERIFY_PARAM *param = NULL; if (C_SslVerifyPartialChains) { param = X509_VERIFY_PARAM_new(); if (param) { X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_PARTIAL_CHAIN); if (SSL_CTX_set1_param(ctx, param) == 0) { mutt_debug(LL_DEBUG2, "SSL_CTX_set1_param() failed.\n"); rc = -1; } X509_VERIFY_PARAM_free(param); } else { mutt_debug(LL_DEBUG2, "X509_VERIFY_PARAM_new() failed.\n"); rc = -1; } } #endif return rc; }
int mono_btls_x509_verify_param_set_flags (MonoBtlsX509VerifyParam *param, unsigned long flags) { if (!param->owns) return -1; return X509_VERIFY_PARAM_set_flags (param->param, flags); }
/** * Loads a CRL and appends its certificates to the specified SSL context. * * @param context The SSL context. * @param crlPath The path to the CRL file. */ void AddCRLToSSLContext(const shared_ptr<SSL_CTX>& context, const String& crlPath) { X509_STORE *x509_store = SSL_CTX_get_cert_store(context.get()); X509_LOOKUP *lookup; lookup = X509_STORE_add_lookup(x509_store, X509_LOOKUP_file()); if (!lookup) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("X509_STORE_add_lookup") << errinfo_openssl_error(ERR_get_error())); } if (X509_LOOKUP_load_file(lookup, crlPath.CStr(), X509_FILETYPE_PEM) != 0) { BOOST_THROW_EXCEPTION(openssl_error() << boost::errinfo_api_function("X509_LOOKUP_load_file") << errinfo_openssl_error(ERR_get_error()) << boost::errinfo_file_name(crlPath)); } X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); X509_STORE_set1_param(x509_store, param); X509_VERIFY_PARAM_free(param); }
int tls_configure_ssl(struct tls *ctx, SSL_CTX *ssl_ctx) { SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); SSL_CTX_set_mode(ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_SSLv3); SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1); SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_1); SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TLSv1_2); if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_0) == 0) SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1); if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_1) == 0) SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_1); if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0) SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TLSv1_2); if (ctx->config->alpn != NULL) { if (SSL_CTX_set_alpn_protos(ssl_ctx, ctx->config->alpn, ctx->config->alpn_len) != 0) { tls_set_errorx(ctx, "failed to set alpn"); goto err; } } if (ctx->config->ciphers != NULL) { if (SSL_CTX_set_cipher_list(ssl_ctx, ctx->config->ciphers) != 1) { tls_set_errorx(ctx, "failed to set ciphers"); goto err; } } if (ctx->config->verify_time == 0) { X509_VERIFY_PARAM_set_flags(ssl_ctx->param, X509_V_FLAG_NO_CHECK_TIME); } /* Disable any form of session caching by default */ SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET); return (0); err: return (-1); }
int mono_btls_x509_verify_param_set_mono_flags (MonoBtlsX509VerifyParam *param, MonoBtlsX509VerifyFlags flags) { unsigned long current; if (!param->owns) return -1; current = X509_VERIFY_PARAM_get_flags (param->param); if (flags & MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK) current |= X509_V_FLAG_CRL_CHECK; if (flags & MONO_BTLS_X509_VERIFY_FLAGS_CRL_CHECK_ALL) current |= X509_V_FLAG_CRL_CHECK_ALL; if (flags & MONO_BTLS_X509_VERIFY_FLAGS_X509_STRICT) current |= X509_V_FLAG_X509_STRICT; return X509_VERIFY_PARAM_set_flags (param->param, current); }
int tls_configure_ssl(struct tls *ctx) { SSL_CTX_set_mode(ctx->ssl_ctx, SSL_MODE_ENABLE_PARTIAL_WRITE); SSL_CTX_set_mode(ctx->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); SSL_CTX_set_mode(ctx->ssl_ctx, SSL_MODE_RELEASE_BUFFERS); SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3); SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1); SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1); SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2); if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_0) == 0) SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1); if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_1) == 0) SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1); if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0) SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2); if (ctx->config->ciphers != NULL) { if (SSL_CTX_set_cipher_list(ctx->ssl_ctx, ctx->config->ciphers) != 1) { tls_set_errorx(ctx, "failed to set ciphers"); goto err; } } SSL_CTX_set_info_callback(ctx->ssl_ctx, tls_info_callback); #ifdef X509_V_FLAG_NO_CHECK_TIME if (ctx->config->verify_time == 0) { X509_VERIFY_PARAM *vfp = SSL_CTX_get0_param(ctx->ssl_ctx); X509_VERIFY_PARAM_set_flags(vfp, X509_V_FLAG_NO_CHECK_TIME); } #endif return (0); err: return (-1); }
static X509_VERIFY_PARAM *createverifyparams(char **poids) { X509_VERIFY_PARAM *pm; ASN1_OBJECT *pobject; int i; pm = X509_VERIFY_PARAM_new(); if (!pm) return NULL; for (i = 0; poids[i]; i++) { pobject = OBJ_txt2obj(poids[i], 0); if (!pobject) { X509_VERIFY_PARAM_free(pm); return NULL; } X509_VERIFY_PARAM_add0_policy(pm, pobject); } X509_VERIFY_PARAM_set_flags(pm, X509_V_FLAG_POLICY_CHECK | X509_V_FLAG_EXPLICIT_POLICY); return pm; }
/* static */ void BSecureSocket::Private::_CreateContext() { sContext = SSL_CTX_new(SSLv23_method()); // Disable legacy protocols. They have known vulnerabilities. SSL_CTX_set_options(sContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); // Don't bother us with ERROR_WANT_READ. SSL_CTX_set_mode(sContext, SSL_MODE_AUTO_RETRY); // Setup certificate verification BPath certificateStore; find_directory(B_SYSTEM_DATA_DIRECTORY, &certificateStore); certificateStore.Append("ssl/CARootCertificates.pem"); // TODO we may want to add a non-packaged certificate directory? // (would make it possible to store user-added certificate exceptions // there) SSL_CTX_load_verify_locations(sContext, certificateStore.Path(), NULL); SSL_CTX_set_verify(sContext, SSL_VERIFY_PEER, VerifyCallback); // OpenSSL 1.0.2 and later: use the alternate "trusted first" algorithm to validate certificate // chains. This makes the validation stop as soon as a recognized certificate is found in the // chain, instead of validating the whole chain, then seeing if the root certificate is known. #ifdef X509_V_FLAG_TRUSTED_FIRST X509_VERIFY_PARAM* verifyParam = X509_VERIFY_PARAM_new(); X509_VERIFY_PARAM_set_flags(verifyParam, X509_V_FLAG_TRUSTED_FIRST); SSL_CTX_set1_param(sContext, verifyParam); // TODO we need to free this after freeing the SSL context (which we currently never do) // X509_VERIFY_PARAM_free(verifyParam); #endif // Get an unique index number for storing application data in SSL // structs. We will store a pointer to the BSecureSocket class there. sDataIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); }
/* static */ void BSecureSocket::Private::_CreateContext() { // We want SSL to report errors in human readable format. SSL_load_error_strings(); // "SSLv23" means "any SSL or TLS version". We disable SSL v2 and v3 below // to keep only TLS 1.0 and above. sContext = SSL_CTX_new(SSLv23_method()); #if TRACE_SSL // For debugging purposes: get all SSL messages to the standard error. SSL_CTX_set_info_callback(sContext, apps_ssl_info_callback); #endif // Disable legacy protocols. They have known vulnerabilities. SSL_CTX_set_options(sContext, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); // Disable SSL/TLS compression to prevent the CRIME attack. SSL_CTX_set_options(sContext, SSL_OP_NO_COMPRESSION); // Don't bother us with ERROR_WANT_READ. SSL_CTX_set_mode(sContext, SSL_MODE_AUTO_RETRY); // Setup cipher suites. // Only accept reasonably secure ones ("HIGH") and disable some known // broken stuff (https://wiki.openssl.org/index.php/SSL/TLS_Client) SSL_CTX_set_cipher_list(sContext, "HIGH:!aNULL:!PSK:!SRP:!MD5:!RC4"); SSL_CTX_set_ecdh_auto(sContext, 1); // Setup certificate verification BPath certificateStore; find_directory(B_SYSTEM_DATA_DIRECTORY, &certificateStore); certificateStore.Append("ssl/CARootCertificates.pem"); // TODO we may want to add a non-packaged certificate directory? // (would make it possible to store user-added certificate exceptions // there) SSL_CTX_load_verify_locations(sContext, certificateStore.Path(), NULL); SSL_CTX_set_verify(sContext, SSL_VERIFY_PEER, VerifyCallback); // OpenSSL 1.0.2 and later: use the alternate "trusted first" algorithm to // validate certificate chains. This makes the validation stop as soon as a // recognized certificate is found in the chain, instead of validating the // whole chain, then seeing if the root certificate is known. #ifdef X509_V_FLAG_TRUSTED_FIRST X509_VERIFY_PARAM* verifyParam = X509_VERIFY_PARAM_new(); X509_VERIFY_PARAM_set_flags(verifyParam, X509_V_FLAG_TRUSTED_FIRST); SSL_CTX_set1_param(sContext, verifyParam); // TODO we need to free this after freeing the SSL context (which we // currently never do) // X509_VERIFY_PARAM_free(verifyParam); #endif // Get an unique index number for storing application data in SSL // structs. We will store a pointer to the BSecureSocket class there. sDataIndex = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL); #ifdef TRACE_SESSION_KEY FILE *keylog = NULL; const char *logpath = getenv("SSLKEYLOGFILE"); if (logpath) keylog = fopen(logpath, "w+"); if (keylog) { fprintf(keylog, "# Key Log File generated by Haiku Network Kit\n"); sKeyLogBIO = BIO_new_fp(keylog, BIO_NOCLOSE); } #endif }
TLSSession * tls_context_setup_session(TLSContext *self) { SSL *ssl; TLSSession *session; gint ssl_error; if (!self->ssl_ctx) { gint verify_mode = 0; gint verify_flags = X509_V_FLAG_POLICY_CHECK; if (self->mode == TM_CLIENT) self->ssl_ctx = SSL_CTX_new(SSLv23_client_method()); else self->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); if (!self->ssl_ctx) goto error; if (file_exists(self->key_file) && !SSL_CTX_use_PrivateKey_file(self->ssl_ctx, self->key_file, SSL_FILETYPE_PEM)) goto error; if (file_exists(self->cert_file) && !SSL_CTX_use_certificate_chain_file(self->ssl_ctx, self->cert_file)) goto error; if (self->key_file && self->cert_file && !SSL_CTX_check_private_key(self->ssl_ctx)) goto error; if (file_exists(self->ca_dir) && !SSL_CTX_load_verify_locations(self->ssl_ctx, NULL, self->ca_dir)) goto error; if (file_exists(self->crl_dir) && !SSL_CTX_load_verify_locations(self->ssl_ctx, NULL, self->crl_dir)) goto error; if (self->crl_dir) verify_flags |= X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL; X509_VERIFY_PARAM_set_flags(self->ssl_ctx->param, verify_flags); switch (self->verify_mode) { case TVM_NONE: verify_mode = SSL_VERIFY_NONE; break; case TVM_OPTIONAL | TVM_UNTRUSTED: verify_mode = SSL_VERIFY_NONE; break; case TVM_OPTIONAL | TVM_TRUSTED: verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; break; case TVM_REQUIRED | TVM_UNTRUSTED: verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; break; case TVM_REQUIRED | TVM_TRUSTED: verify_mode = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT; break; default: g_assert_not_reached(); } SSL_CTX_set_verify(self->ssl_ctx, verify_mode, tls_session_verify_callback); SSL_CTX_set_options(self->ssl_ctx, SSL_OP_NO_SSLv2); if (self->cipher_suite) { if (!SSL_CTX_set_cipher_list(self->ssl_ctx, self->cipher_suite)) goto error; } } ssl = SSL_new(self->ssl_ctx); if (self->mode == TM_CLIENT) SSL_set_connect_state(ssl); else SSL_set_accept_state(ssl); session = tls_session_new(ssl, self); SSL_set_app_data(ssl, session); return session; error: ssl_error = ERR_get_error(); msg_error("Error setting up TLS session context", evt_tag_printf("tls_error", "%s:%s:%s", ERR_lib_error_string(ssl_error), ERR_func_error_string(ssl_error), ERR_reason_error_string(ssl_error)), NULL); ERR_clear_error(); if (self->ssl_ctx) { SSL_CTX_free(self->ssl_ctx); self->ssl_ctx = NULL; } return NULL; }
int opt_verify(int opt, X509_VERIFY_PARAM *vpm) { int i; ossl_intmax_t t = 0; ASN1_OBJECT *otmp; X509_PURPOSE *xptmp; const X509_VERIFY_PARAM *vtmp; assert(vpm != NULL); assert(opt > OPT_V__FIRST); assert(opt < OPT_V__LAST); switch ((enum range)opt) { case OPT_V__FIRST: case OPT_V__LAST: return 0; case OPT_V_POLICY: otmp = OBJ_txt2obj(opt_arg(), 0); if (otmp == NULL) { BIO_printf(bio_err, "%s: Invalid Policy %s\n", prog, opt_arg()); return 0; } X509_VERIFY_PARAM_add0_policy(vpm, otmp); break; case OPT_V_PURPOSE: /* purpose name -> purpose index */ i = X509_PURPOSE_get_by_sname(opt_arg()); if (i < 0) { BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg()); return 0; } /* purpose index -> purpose object */ xptmp = X509_PURPOSE_get0(i); /* purpose object -> purpose value */ i = X509_PURPOSE_get_id(xptmp); if (!X509_VERIFY_PARAM_set_purpose(vpm, i)) { BIO_printf(bio_err, "%s: Internal error setting purpose %s\n", prog, opt_arg()); return 0; } break; case OPT_V_VERIFY_NAME: vtmp = X509_VERIFY_PARAM_lookup(opt_arg()); if (vtmp == NULL) { BIO_printf(bio_err, "%s: Invalid verify name %s\n", prog, opt_arg()); return 0; } X509_VERIFY_PARAM_set1(vpm, vtmp); break; case OPT_V_VERIFY_DEPTH: i = atoi(opt_arg()); if (i >= 0) X509_VERIFY_PARAM_set_depth(vpm, i); break; case OPT_V_VERIFY_AUTH_LEVEL: i = atoi(opt_arg()); if (i >= 0) X509_VERIFY_PARAM_set_auth_level(vpm, i); break; case OPT_V_ATTIME: if (!opt_imax(opt_arg(), &t)) return 0; if (t != (time_t)t) { BIO_printf(bio_err, "%s: epoch time out of range %s\n", prog, opt_arg()); return 0; } X509_VERIFY_PARAM_set_time(vpm, (time_t)t); break; case OPT_V_VERIFY_HOSTNAME: if (!X509_VERIFY_PARAM_set1_host(vpm, opt_arg(), 0)) return 0; break; case OPT_V_VERIFY_EMAIL: if (!X509_VERIFY_PARAM_set1_email(vpm, opt_arg(), 0)) return 0; break; case OPT_V_VERIFY_IP: if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, opt_arg())) return 0; break; case OPT_V_IGNORE_CRITICAL: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL); break; case OPT_V_ISSUER_CHECKS: /* NOP, deprecated */ break; case OPT_V_CRL_CHECK: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK); break; case OPT_V_CRL_CHECK_ALL: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); break; case OPT_V_POLICY_CHECK: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_POLICY_CHECK); break; case OPT_V_EXPLICIT_POLICY: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXPLICIT_POLICY); break; case OPT_V_INHIBIT_ANY: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_ANY); break; case OPT_V_INHIBIT_MAP: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_MAP); break; case OPT_V_X509_STRICT: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_X509_STRICT); break; case OPT_V_EXTENDED_CRL: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXTENDED_CRL_SUPPORT); break; case OPT_V_USE_DELTAS: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_USE_DELTAS); break; case OPT_V_POLICY_PRINT: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NOTIFY_POLICY); break; case OPT_V_CHECK_SS_SIG: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CHECK_SS_SIGNATURE); break; case OPT_V_TRUSTED_FIRST: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_TRUSTED_FIRST); break; case OPT_V_SUITEB_128_ONLY: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS_ONLY); break; case OPT_V_SUITEB_128: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS); break; case OPT_V_SUITEB_192: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_192_LOS); break; case OPT_V_PARTIAL_CHAIN: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN); break; case OPT_V_NO_ALT_CHAINS: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_ALT_CHAINS); break; case OPT_V_NO_CHECK_TIME: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_CHECK_TIME); break; } return 1; }
int opt_verify(int opt, X509_VERIFY_PARAM *vpm) { unsigned long ul; int i; ASN1_OBJECT *otmp; X509_PURPOSE *xptmp; const X509_VERIFY_PARAM *vtmp; assert(vpm != NULL); assert(opt > OPT_V__FIRST); assert(opt < OPT_V__LAST); switch ((enum range)opt) { case OPT_V__FIRST: case OPT_V__LAST: return 0; case OPT_V_POLICY: otmp = OBJ_txt2obj(opt_arg(), 0); if (otmp == NULL) { BIO_printf(bio_err, "%s: Invalid Policy %s\n", prog, opt_arg()); return 0; } X509_VERIFY_PARAM_add0_policy(vpm, otmp); break; case OPT_V_PURPOSE: i = X509_PURPOSE_get_by_sname(opt_arg()); if (i < 0) { BIO_printf(bio_err, "%s: Invalid purpose %s\n", prog, opt_arg()); return 0; } xptmp = X509_PURPOSE_get0(i); i = X509_PURPOSE_get_id(xptmp); X509_VERIFY_PARAM_set_purpose(vpm, i); break; case OPT_V_VERIFY_NAME: vtmp = X509_VERIFY_PARAM_lookup(opt_arg()); if (vtmp == NULL) { BIO_printf(bio_err, "%s: Invalid verify name %s\n", prog, opt_arg()); return 0; } X509_VERIFY_PARAM_set1(vpm, vtmp); break; case OPT_V_VERIFY_DEPTH: i = atoi(opt_arg()); if (i >= 0) X509_VERIFY_PARAM_set_depth(vpm, i); break; case OPT_V_ATTIME: opt_ulong(opt_arg(), &ul); if (ul) X509_VERIFY_PARAM_set_time(vpm, (time_t)ul); break; case OPT_V_VERIFY_HOSTNAME: if (!X509_VERIFY_PARAM_set1_host(vpm, opt_arg(), 0)) return 0; break; case OPT_V_VERIFY_EMAIL: if (!X509_VERIFY_PARAM_set1_email(vpm, opt_arg(), 0)) return 0; break; case OPT_V_VERIFY_IP: if (!X509_VERIFY_PARAM_set1_ip_asc(vpm, opt_arg())) return 0; break; case OPT_V_IGNORE_CRITICAL: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_IGNORE_CRITICAL); break; case OPT_V_ISSUER_CHECKS: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CB_ISSUER_CHECK); break; case OPT_V_CRL_CHECK: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK); break; case OPT_V_CRL_CHECK_ALL: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); break; case OPT_V_POLICY_CHECK: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_POLICY_CHECK); break; case OPT_V_EXPLICIT_POLICY: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXPLICIT_POLICY); break; case OPT_V_INHIBIT_ANY: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_ANY); break; case OPT_V_INHIBIT_MAP: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_INHIBIT_MAP); break; case OPT_V_X509_STRICT: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_X509_STRICT); break; case OPT_V_EXTENDED_CRL: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_EXTENDED_CRL_SUPPORT); break; case OPT_V_USE_DELTAS: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_USE_DELTAS); break; case OPT_V_POLICY_PRINT: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NOTIFY_POLICY); break; case OPT_V_CHECK_SS_SIG: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_CHECK_SS_SIGNATURE); break; case OPT_V_TRUSTED_FIRST: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_TRUSTED_FIRST); break; case OPT_V_SUITEB_128_ONLY: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS_ONLY); break; case OPT_V_SUITEB_128: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_128_LOS); break; case OPT_V_SUITEB_192: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_SUITEB_192_LOS); break; case OPT_V_PARTIAL_CHAIN: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN); break; case OPT_V_NO_ALT_CHAINS: X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_NO_ALT_CHAINS); } return 1; }
int tls_configure_ssl_verify(struct tls *ctx, SSL_CTX *ssl_ctx, int verify) { size_t ca_len = ctx->config->ca_len; char *ca_mem = ctx->config->ca_mem; char *crl_mem = ctx->config->crl_mem; size_t crl_len = ctx->config->crl_len; char *ca_free = NULL; STACK_OF(X509_INFO) *xis = NULL; X509_STORE *store; X509_INFO *xi; BIO *bio = NULL; int rv = -1; int i; SSL_CTX_set_verify(ssl_ctx, verify, NULL); SSL_CTX_set_cert_verify_callback(ssl_ctx, tls_ssl_cert_verify_cb, ctx); if (ctx->config->verify_depth >= 0) SSL_CTX_set_verify_depth(ssl_ctx, ctx->config->verify_depth); if (ctx->config->verify_cert == 0) goto done; /* If no CA has been specified, attempt to load the default. */ if (ctx->config->ca_mem == NULL && ctx->config->ca_path == NULL) { if (tls_config_load_file(&ctx->error, "CA", _PATH_SSL_CA_FILE, &ca_mem, &ca_len) != 0) goto err; ca_free = ca_mem; } if (ca_mem != NULL) { if (ca_len > INT_MAX) { tls_set_errorx(ctx, "ca too long"); goto err; } if (SSL_CTX_load_verify_mem(ssl_ctx, ca_mem, ca_len) != 1) { tls_set_errorx(ctx, "ssl verify memory setup failure"); goto err; } } else if (SSL_CTX_load_verify_locations(ssl_ctx, NULL, ctx->config->ca_path) != 1) { tls_set_errorx(ctx, "ssl verify locations failure"); goto err; } if (crl_mem != NULL) { if (crl_len > INT_MAX) { tls_set_errorx(ctx, "crl too long"); goto err; } if ((bio = BIO_new_mem_buf(crl_mem, crl_len)) == NULL) { tls_set_errorx(ctx, "failed to create buffer"); goto err; } if ((xis = PEM_X509_INFO_read_bio(bio, NULL, tls_password_cb, NULL)) == NULL) { tls_set_errorx(ctx, "failed to parse crl"); goto err; } store = SSL_CTX_get_cert_store(ssl_ctx); for (i = 0; i < sk_X509_INFO_num(xis); i++) { xi = sk_X509_INFO_value(xis, i); if (xi->crl == NULL) continue; if (!X509_STORE_add_crl(store, xi->crl)) { tls_set_error(ctx, "failed to add crl"); goto err; } xi->crl = NULL; } X509_VERIFY_PARAM_set_flags(store->param, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL); } done: rv = 0; err: sk_X509_INFO_pop_free(xis, X509_INFO_free); BIO_free(bio); free(ca_free); return (rv); }
int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { struct per_session_data__http *pss = (struct per_session_data__http *)user; unsigned char buffer[4096 + LWS_PRE]; unsigned long amount, file_len, sent; char leaf_path[1024]; const char *mimetype; char *other_headers; unsigned char *end, *start; struct timeval tv; unsigned char *p; #ifndef LWS_NO_CLIENT struct per_session_data__http *pss1; struct lws *wsi1; #endif char buf[256]; char b64[64]; int n, m; #ifdef EXTERNAL_POLL struct lws_pollargs *pa = (struct lws_pollargs *)in; #endif switch (reason) { case LWS_CALLBACK_HTTP: lwsl_info("lws_http_serve: %s\n",in); if (debug_level & LLL_INFO) { dump_handshake_info(wsi); /* dump the individual URI Arg parameters */ n = 0; while (lws_hdr_copy_fragment(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_URI_ARGS, n) > 0) { lwsl_notice("URI Arg %d: %s\n", ++n, buf); } } { lws_get_peer_simple(wsi, buf, sizeof(buf)); lwsl_info("HTTP connect from %s\n", buf); } if (len < 1) { lws_return_http_status(wsi, HTTP_STATUS_BAD_REQUEST, NULL); goto try_to_reuse; } #ifndef LWS_NO_CLIENT if (!strncmp(in, "/proxytest", 10)) { struct lws_client_connect_info i; char *rootpath = "/"; const char *p = (const char *)in; if (lws_get_child(wsi)) break; pss->client_finished = 0; memset(&i,0, sizeof(i)); i.context = lws_get_context(wsi); i.address = "git.libwebsockets.org"; i.port = 80; i.ssl_connection = 0; if (p[10]) i.path = (char *)in + 10; else i.path = rootpath; i.host = "git.libwebsockets.org"; i.origin = NULL; i.method = "GET"; i.parent_wsi = wsi; i.uri_replace_from = "git.libwebsockets.org/"; i.uri_replace_to = "/proxytest/"; if (!lws_client_connect_via_info(&i)) { lwsl_err("proxy connect fail\n"); break; } break; } #endif #if 1 /* this example server has no concept of directories */ if (strchr((const char *)in + 1, '/')) { lws_return_http_status(wsi, HTTP_STATUS_NOT_ACCEPTABLE, NULL); goto try_to_reuse; } #endif /* if a legal POST URL, let it continue and accept data */ if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) return 0; /* check for the "send a big file by hand" example case */ if (!strcmp((const char *)in, "/leaf.jpg")) { if (strlen(resource_path) > sizeof(leaf_path) - 10) return -1; sprintf(leaf_path, "%s/leaf.jpg", resource_path); /* well, let's demonstrate how to send the hard way */ p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; pss->fd = lws_plat_file_open(wsi, leaf_path, &file_len, LWS_O_RDONLY); if (pss->fd == LWS_INVALID_FILE) { lwsl_err("failed to open file %s\n", leaf_path); return -1; } /* * we will send a big jpeg file, but it could be * anything. Set the Content-Type: appropriately * so the browser knows what to do with it. * * Notice we use the APIs to build the header, which * will do the right thing for HTTP 1/1.1 and HTTP2 * depending on what connection it happens to be working * on */ if (lws_add_http_header_status(wsi, 200, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"image/jpeg", 10, &p, end)) return 1; if (lws_add_http_header_content_length(wsi, file_len, &p, end)) return 1; if (lws_finalize_http_header(wsi, &p, end)) return 1; /* * send the http headers... * this won't block since it's the first payload sent * on the connection since it was established * (too small for partial) * * Notice they are sent using LWS_WRITE_HTTP_HEADERS * which also means you can't send body too in one step, * this is mandated by changes in HTTP2 */ *p = '\0'; lwsl_info("%s\n", buffer + LWS_PRE); n = lws_write(wsi, buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS); if (n < 0) { lws_plat_file_close(wsi, pss->fd); return -1; } /* * book us a LWS_CALLBACK_HTTP_WRITEABLE callback */ lws_callback_on_writable(wsi); break; } /* if not, send a file the easy way */ if (!strncmp(in, "/cgit-data/", 11)) { in = (char *)in + 11; strcpy(buf, "/usr/share/cgit"); } else strcpy(buf, resource_path); if (strcmp(in, "/")) { if (*((const char *)in) != '/') strcat(buf, "/"); strncat(buf, in, sizeof(buf) - strlen(buf) - 1); } else /* default file to serve */ strcat(buf, "/test.html"); buf[sizeof(buf) - 1] = '\0'; /* refuse to serve files we don't understand */ mimetype = get_mimetype(buf); if (!mimetype) { lwsl_err("Unknown mimetype for %s\n", buf); lws_return_http_status(wsi, HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, NULL); return -1; } /* demonstrates how to set a cookie on / */ other_headers = leaf_path; p = (unsigned char *)leaf_path; if (!strcmp((const char *)in, "/") && !lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_COOKIE)) { /* this isn't very unguessable but it'll do for us */ gettimeofday(&tv, NULL); n = sprintf(b64, "test=LWS_%u_%u_COOKIE;Max-Age=360000", (unsigned int)tv.tv_sec, (unsigned int)tv.tv_usec); if (lws_add_http_header_by_name(wsi, (unsigned char *)"set-cookie:", (unsigned char *)b64, n, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) return 1; } if (lws_is_ssl(wsi) && lws_add_http_header_by_name(wsi, (unsigned char *) "Strict-Transport-Security:", (unsigned char *) "max-age=15768000 ; " "includeSubDomains", 36, &p, (unsigned char *)leaf_path + sizeof(leaf_path))) return 1; n = (char *)p - leaf_path; n = lws_serve_http_file(wsi, buf, mimetype, other_headers, n); if (n < 0 || ((n > 0) && lws_http_transaction_completed(wsi))) return -1; /* error or can't reuse connection: close the socket */ /* * notice that the sending of the file completes asynchronously, * we'll get a LWS_CALLBACK_HTTP_FILE_COMPLETION callback when * it's done */ break; case LWS_CALLBACK_HTTP_BODY: /* create the POST argument parser if not already existing */ if (!pss->spa) { pss->spa = lws_spa_create(wsi, param_names, ARRAY_SIZE(param_names), 1024, file_upload_cb, pss); if (!pss->spa) return -1; pss->filename[0] = '\0'; pss->file_length = 0; } /* let it parse the POST data */ if (lws_spa_process(pss->spa, in, len)) return -1; break; case LWS_CALLBACK_HTTP_BODY_COMPLETION: lwsl_debug("LWS_CALLBACK_HTTP_BODY_COMPLETION\n"); /* * the whole of the sent body arrived, * respond to the client with a redirect to show the * results */ /* call to inform no more payload data coming */ lws_spa_finalize(pss->spa); p = (unsigned char *)pss->result + LWS_PRE; end = p + sizeof(pss->result) - LWS_PRE - 1; p += sprintf((char *)p, "<html><body><h1>Form results (after urldecoding)</h1>" "<table><tr><td>Name</td><td>Length</td><td>Value</td></tr>"); for (n = 0; n < ARRAY_SIZE(param_names); n++) p += lws_snprintf((char *)p, end - p, "<tr><td><b>%s</b></td><td>%d</td><td>%s</td></tr>", param_names[n], lws_spa_get_length(pss->spa, n), lws_spa_get_string(pss->spa, n)); p += lws_snprintf((char *)p, end - p, "</table><br><b>filename:</b> %s, <b>length</b> %ld", pss->filename, pss->file_length); p += lws_snprintf((char *)p, end - p, "</body></html>"); pss->result_len = p - (unsigned char *)(pss->result + LWS_PRE); p = buffer + LWS_PRE; start = p; end = p + sizeof(buffer) - LWS_PRE; if (lws_add_http_header_status(wsi, 200, &p, end)) return 1; if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/html", 9, &p, end)) return 1; if (lws_add_http_header_content_length(wsi, pss->result_len, &p, end)) return 1; if (lws_finalize_http_header(wsi, &p, end)) return 1; n = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS); if (n < 0) return 1; n = lws_write(wsi, (unsigned char *)pss->result + LWS_PRE, pss->result_len, LWS_WRITE_HTTP); if (n < 0) return 1; goto try_to_reuse; case LWS_CALLBACK_HTTP_DROP_PROTOCOL: lwsl_debug("LWS_CALLBACK_HTTP_DROP_PROTOCOL\n"); /* called when our wsi user_space is going to be destroyed */ if (pss->spa) { lws_spa_destroy(pss->spa); pss->spa = NULL; } break; case LWS_CALLBACK_HTTP_FILE_COMPLETION: goto try_to_reuse; case LWS_CALLBACK_HTTP_WRITEABLE: lwsl_info("LWS_CALLBACK_HTTP_WRITEABLE\n"); if (pss->client_finished) return -1; if (pss->fd == LWS_INVALID_FILE) goto try_to_reuse; #ifndef LWS_NO_CLIENT if (pss->reason_bf & 2) { char *px = buf + LWS_PRE; int lenx = sizeof(buf) - LWS_PRE; /* * our sink is writeable and our source has something * to read. So read a lump of source material of * suitable size to send or what's available, whichever * is the smaller. */ pss->reason_bf &= ~2; wsi1 = lws_get_child(wsi); if (!wsi1) break; if (lws_http_client_read(wsi1, &px, &lenx) < 0) goto bail; if (pss->client_finished) return -1; break; } #endif /* * we can send more of whatever it is we were sending */ sent = 0; do { /* we'd like the send this much */ n = sizeof(buffer) - LWS_PRE; /* but if the peer told us he wants less, we can adapt */ m = lws_get_peer_write_allowance(wsi); /* -1 means not using a protocol that has this info */ if (m == 0) /* right now, peer can't handle anything */ goto later; if (m != -1 && m < n) /* he couldn't handle that much */ n = m; n = lws_plat_file_read(wsi, pss->fd, &amount, buffer + LWS_PRE, n); /* problem reading, close conn */ if (n < 0) { lwsl_err("problem reading file\n"); goto bail; } n = (int)amount; /* sent it all, close conn */ if (n == 0) goto penultimate; /* * To support HTTP2, must take care about preamble space * * identification of when we send the last payload frame * is handled by the library itself if you sent a * content-length header */ m = lws_write(wsi, buffer + LWS_PRE, n, LWS_WRITE_HTTP); if (m < 0) { lwsl_err("write failed\n"); /* write failed, close conn */ goto bail; } if (m) /* while still active, extend timeout */ lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT, 5); sent += m; } while (!lws_send_pipe_choked(wsi) && (sent < 1024 * 1024)); later: lws_callback_on_writable(wsi); break; penultimate: lws_plat_file_close(wsi, pss->fd); pss->fd = LWS_INVALID_FILE; goto try_to_reuse; bail: lws_plat_file_close(wsi, pss->fd); return -1; /* * callback for confirming to continue with client IP appear in * protocol 0 callback since no websocket protocol has been agreed * yet. You can just ignore this if you won't filter on client IP * since the default unhandled callback return is 0 meaning let the * connection continue. */ case LWS_CALLBACK_FILTER_NETWORK_CONNECTION: /* if we returned non-zero from here, we kill the connection */ break; #ifndef LWS_NO_CLIENT case LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP: { char ctype[64], ctlen = 0; lwsl_err("LWS_CALLBACK_ESTABLISHED_CLIENT_HTTP\n"); p = buffer + LWS_PRE; end = p + sizeof(buffer) - LWS_PRE; if (lws_add_http_header_status(lws_get_parent(wsi), 200, &p, end)) return 1; if (lws_add_http_header_by_token(lws_get_parent(wsi), WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end)) return 1; ctlen = lws_hdr_copy(wsi, ctype, sizeof(ctype), WSI_TOKEN_HTTP_CONTENT_TYPE); if (ctlen > 0) { if (lws_add_http_header_by_token(lws_get_parent(wsi), WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)ctype, ctlen, &p, end)) return 1; } #if 0 if (lws_add_http_header_content_length(lws_get_parent(wsi), file_len, &p, end)) return 1; #endif if (lws_finalize_http_header(lws_get_parent(wsi), &p, end)) return 1; *p = '\0'; lwsl_info("%s\n", buffer + LWS_PRE); n = lws_write(lws_get_parent(wsi), buffer + LWS_PRE, p - (buffer + LWS_PRE), LWS_WRITE_HTTP_HEADERS); if (n < 0) return -1; break; } case LWS_CALLBACK_CLOSED_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_CLOSED_CLIENT_HTTP\n"); return -1; break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p\n", wsi); assert(lws_get_parent(wsi)); if (!lws_get_parent(wsi)) break; // lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP: wsi %p: sock: %d, parent_wsi: %p, parent_sock:%d, len %d\n", // wsi, lws_get_socket_fd(wsi), // lws_get_parent(wsi), // lws_get_socket_fd(lws_get_parent(wsi)), len); pss1 = lws_wsi_user(lws_get_parent(wsi)); pss1->reason_bf |= 2; lws_callback_on_writable(lws_get_parent(wsi)); break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ: //lwsl_err("LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ len %d\n", len); assert(lws_get_parent(wsi)); m = lws_write(lws_get_parent(wsi), (unsigned char *)in, len, LWS_WRITE_HTTP); if (m < 0) return -1; break; case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: //lwsl_err("LWS_CALLBACK_COMPLETED_CLIENT_HTTP\n"); assert(lws_get_parent(wsi)); if (!lws_get_parent(wsi)) break; pss1 = lws_wsi_user(lws_get_parent(wsi)); pss1->client_finished = 1; break; #endif /* * callbacks for managing the external poll() array appear in * protocol 0 callback */ case LWS_CALLBACK_LOCK_POLL: /* * lock mutex to protect pollfd state * called before any other POLL related callback * if protecting wsi lifecycle change, len == 1 */ test_server_lock(len); break; case LWS_CALLBACK_UNLOCK_POLL: /* * unlock mutex to protect pollfd state when * called after any other POLL related callback * if protecting wsi lifecycle change, len == 1 */ test_server_unlock(len); break; #ifdef EXTERNAL_POLL case LWS_CALLBACK_ADD_POLL_FD: if (count_pollfds >= max_poll_elements) { lwsl_err("LWS_CALLBACK_ADD_POLL_FD: too many sockets to track\n"); return 1; } fd_lookup[pa->fd] = count_pollfds; pollfds[count_pollfds].fd = pa->fd; pollfds[count_pollfds].events = pa->events; pollfds[count_pollfds++].revents = 0; break; case LWS_CALLBACK_DEL_POLL_FD: if (!--count_pollfds) break; m = fd_lookup[pa->fd]; /* have the last guy take up the vacant slot */ pollfds[m] = pollfds[count_pollfds]; fd_lookup[pollfds[count_pollfds].fd] = m; break; case LWS_CALLBACK_CHANGE_MODE_POLL_FD: pollfds[fd_lookup[pa->fd]].events = pa->events; break; #endif case LWS_CALLBACK_GET_THREAD_ID: /* * if you will call "lws_callback_on_writable" * from a different thread, return the caller thread ID * here so lws can use this information to work out if it * should signal the poll() loop to exit and restart early */ /* return pthread_getthreadid_np(); */ break; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) case LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: /* Verify the client certificate */ if (!len || (SSL_get_verify_result((SSL*)in) != X509_V_OK)) { int err = X509_STORE_CTX_get_error((X509_STORE_CTX*)user); int depth = X509_STORE_CTX_get_error_depth((X509_STORE_CTX*)user); const char* msg = X509_verify_cert_error_string(err); lwsl_err("LWS_CALLBACK_OPENSSL_PERFORM_CLIENT_CERT_VERIFICATION: SSL error: %s (%d), depth: %d\n", msg, err, depth); return 1; } break; #if defined(LWS_HAVE_SSL_CTX_set1_param) case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: if (crl_path[0]) { /* Enable CRL checking */ X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); SSL_CTX_set1_param((SSL_CTX*)user, param); X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX*)user); X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); n = X509_load_cert_crl_file(lookup, crl_path, X509_FILETYPE_PEM); X509_VERIFY_PARAM_free(param); if (n != 1) { char errbuf[256]; n = ERR_get_error(); lwsl_err("LWS_CALLBACK_OPENSSL_LOAD_EXTRA_SERVER_VERIFY_CERTS: SSL error: %s (%d)\n", ERR_error_string(n, errbuf), n); return 1; } } break; #endif #endif #endif #endif default: break; } return 0; /* if we're on HTTP1.1 or 2.0, will keep the idle connection alive */ try_to_reuse: if (lws_http_transaction_completed(wsi)) return -1; return 0; }
static int callback_dumb_increment(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { const char *which = "http"; switch (reason) { case LWS_CALLBACK_CLIENT_ESTABLISHED: lwsl_info("dumb: LWS_CALLBACK_CLIENT_ESTABLISHED\n"); break; case LWS_CALLBACK_CLOSED: lwsl_notice("dumb: LWS_CALLBACK_CLOSED\n"); wsi_dumb = NULL; break; case LWS_CALLBACK_CLIENT_RECEIVE: ((char *)in)[len] = '\0'; lwsl_info("rx %d '%s'\n", (int)len, (char *)in); break; /* because we are protocols[0] ... */ case LWS_CALLBACK_CLIENT_CONNECTION_ERROR: if (wsi == wsi_dumb) { which = "dumb"; wsi_dumb = NULL; } if (wsi == wsi_mirror) { which = "mirror"; wsi_mirror = NULL; } lwsl_err("CLIENT_CONNECTION_ERROR: %s: %s %p\n", which, in); break; case LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED: if ((strcmp(in, "deflate-stream") == 0) && deny_deflate) { lwsl_notice("denied deflate-stream extension\n"); return 1; } if ((strcmp(in, "x-webkit-deflate-frame") == 0)) return 1; if ((strcmp(in, "deflate-frame") == 0)) return 1; break; case LWS_CALLBACK_RECEIVE_CLIENT_HTTP: { char buffer[1024 + LWS_PRE]; char *px = buffer + LWS_PRE; int lenx = sizeof(buffer) - LWS_PRE; lwsl_notice("LWS_CALLBACK_RECEIVE_CLIENT_HTTP\n"); /* * Often you need to flow control this by something * else being writable. In that case call the api * to get a callback when writable here, and do the * pending client read in the writeable callback of * the output. */ if (lws_http_client_read(wsi, &px, &lenx) < 0) return -1; while (lenx--) putchar(*px++); } break; case LWS_CALLBACK_COMPLETED_CLIENT_HTTP: wsi_dumb = NULL; force_exit = 1; break; #if defined(LWS_USE_POLARSSL) #else #if defined(LWS_USE_MBEDTLS) #else #if defined(LWS_OPENSSL_SUPPORT) && defined(LWS_HAVE_SSL_CTX_set1_param) case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: if (crl_path[0]) { /* Enable CRL checking of the server certificate */ X509_VERIFY_PARAM *param = X509_VERIFY_PARAM_new(); X509_VERIFY_PARAM_set_flags(param, X509_V_FLAG_CRL_CHECK); SSL_CTX_set1_param((SSL_CTX*)user, param); X509_STORE *store = SSL_CTX_get_cert_store((SSL_CTX*)user); X509_LOOKUP *lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file()); int n = X509_load_cert_crl_file(lookup, crl_path, X509_FILETYPE_PEM); X509_VERIFY_PARAM_free(param); if (n != 1) { char errbuf[256]; n = ERR_get_error(); lwsl_err("LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS: SSL error: %s (%d)\n", ERR_error_string(n, errbuf), n); return 1; } } break; #endif #endif #endif default: break; } return 0; }
static int pk7_verify(X509_STORE *cert_store, PKCS7 *p7, BIO *detached, char *ebuf, int ebufsize) { PKCS7_SIGNER_INFO *si; verify_context vctx; BIO *p7bio=NULL; char readbuf[1024*4]; int res = 1; int i; STACK_OF(PKCS7_SIGNER_INFO) *sk; vctx.err = X509_V_OK; ebuf[0] = 0; OpenSSL_add_all_algorithms(); EVP_add_digest(EVP_md5()); EVP_add_digest(EVP_sha1()); ERR_load_crypto_strings(); ERR_clear_error(); X509_VERIFY_PARAM_set_flags(cert_store->param, X509_V_FLAG_CB_ISSUER_CHECK); X509_STORE_set_verify_cb_func(cert_store, verify_callback); p7bio = PKCS7_dataInit(p7, detached); /* We now have to 'read' from p7bio to calculate digests etc. */ while (BIO_read(p7bio, readbuf, sizeof(readbuf)) > 0) ; /* We can now verify signatures */ sk = PKCS7_get_signer_info(p7); if (sk == NULL) { /* there are no signatures on this data */ res = 0; fz_strlcpy(ebuf, "No signatures", ebufsize); goto exit; } for (i=0; i<sk_PKCS7_SIGNER_INFO_num(sk); i++) { int rc; si = sk_PKCS7_SIGNER_INFO_value(sk, i); rc = PKCS7_dataVerify(cert_store, &vctx.x509_ctx, p7bio,p7, si); if (rc <= 0 || vctx.err != X509_V_OK) { char tbuf[120]; if (rc <= 0) { fz_strlcpy(ebuf, ERR_error_string(ERR_get_error(), tbuf), ebufsize); } else { /* Error while checking the certificate chain */ snprintf(ebuf, ebufsize, "%s(%d): %s", X509_verify_cert_error_string(vctx.err), vctx.err, vctx.certdesc); } res = 0; goto exit; } } exit: X509_STORE_CTX_cleanup(&vctx.x509_ctx); ERR_free_strings(); return res; }
static int load_crl(SSL_CTX * ctx, char *crl_directory, int crl_check_all) { #if OPENSSL_VERSION_NUMBER >= 0x10000000L DIR *d; struct dirent *dir; int crl_added = 0; LM_DBG("Loading CRL from directory\n"); /*Get X509 store from SSL context*/ X509_STORE *store = SSL_CTX_get_cert_store(ctx); if(!store) { LM_ERR("Unable to get X509 store from ssl context\n"); return -1; } /*Parse directory*/ d = opendir(crl_directory); if(!d) { LM_ERR("Unable to open crl directory '%s'\n", crl_directory); return -1; } while ((dir = readdir(d)) != NULL) { /*Skip if not regular file*/ if (dir->d_type != DT_REG) continue; /*Create filename*/ char* filename = (char*) pkg_malloc(sizeof(char)*(strlen(crl_directory)+strlen(dir->d_name)+2)); if (!filename) { LM_ERR("Unable to allocate crl filename\n"); closedir(d); return -1; } strcpy(filename,crl_directory); if(filename[strlen(filename)-1] != '/') strcat(filename,"/"); strcat(filename,dir->d_name); /*Get CRL content*/ FILE *fp = fopen(filename,"r"); pkg_free(filename); if(!fp) continue; X509_CRL *crl = PEM_read_X509_CRL(fp, NULL, NULL, NULL); fclose(fp); if(!crl) continue; /*Add CRL to X509 store*/ if (X509_STORE_add_crl(store, crl) == 1) crl_added++; else LM_ERR("Unable to add crl to ssl context\n"); X509_CRL_free(crl); } closedir(d); if (!crl_added) { LM_ERR("No suitable CRL files found in directory %s\n", crl_directory); return -1; } /*Enable CRL checking*/ X509_VERIFY_PARAM *param; param = X509_VERIFY_PARAM_new(); int flags = X509_V_FLAG_CRL_CHECK; if(crl_check_all) flags |= X509_V_FLAG_CRL_CHECK_ALL; X509_VERIFY_PARAM_set_flags(param, flags); SSL_CTX_set1_param(ctx, param); X509_VERIFY_PARAM_free(param); return 0; #else static int already_warned = 0; if (!already_warned) { LM_WARN("CRL not supported in %s\n", OPENSSL_VERSION_TEXT); already_warned = 1; } return 0; #endif }
as_status as_tls_context_setup(as_config_tls* tlscfg, as_tls_context* ctx, as_error* errp) { // Clear the destination, in case we don't make it. ctx->ssl_ctx = NULL; ctx->pkey = NULL; ctx->cert_blacklist = NULL; ctx->log_session_info = tlscfg->log_session_info; ctx->for_login_only = tlscfg->for_login_only; as_tls_check_init(); pthread_mutex_init(&ctx->lock, NULL); if (tlscfg->cert_blacklist) { ctx->cert_blacklist = cert_blacklist_read(tlscfg->cert_blacklist); if (! ctx->cert_blacklist) { as_tls_context_destroy(ctx); return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR, "Failed to read certificate blacklist: %s", tlscfg->cert_blacklist); } } uint16_t protocols = AS_TLS_PROTOCOL_NONE; as_status status = protocols_parse(tlscfg, &protocols, errp); if (status != AEROSPIKE_OK) { as_tls_context_destroy(ctx); return status; } const SSL_METHOD* method = NULL; // If the selected protocol set is a single protocol we can use a specific method. if (protocols == AS_TLS_PROTOCOL_TLSV1) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L method = TLS_client_method(); #else method = TLSv1_client_method(); #endif } else if (protocols == AS_TLS_PROTOCOL_TLSV1_1) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L method = TLS_client_method(); #else method = TLSv1_1_client_method(); #endif } else if (protocols == AS_TLS_PROTOCOL_TLSV1_2) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L method = TLS_client_method(); #else method = TLSv1_2_client_method(); #endif } else { // Multiple protocols are enabled, use a flexible method. #if OPENSSL_VERSION_NUMBER >= 0x10100000L method = TLS_client_method(); #else method = SSLv23_client_method(); #endif } ctx->ssl_ctx = SSL_CTX_new(method); if (ctx->ssl_ctx == NULL) { as_tls_context_destroy(ctx); unsigned long errcode = ERR_get_error(); char errbuf[1024]; ERR_error_string_n(errcode, errbuf, sizeof(errbuf)); return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR, "Failed to create new TLS context: %s", errbuf); } /* always disable SSLv2, as per RFC 6176 */ SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2); SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3); // Turn off non-enabled protocols. if (! (protocols & AS_TLS_PROTOCOL_TLSV1)) { SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1); } if (! (protocols & AS_TLS_PROTOCOL_TLSV1_1)) { SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1); } if (! (protocols & AS_TLS_PROTOCOL_TLSV1_2)) { SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2); } if (tlscfg->cafile || tlscfg->capath) { int rv = SSL_CTX_load_verify_locations(ctx->ssl_ctx, tlscfg->cafile, tlscfg->capath); if (rv != 1) { as_tls_context_destroy(ctx); char errbuf[1024]; unsigned long errcode = ERR_get_error(); if (errcode != 0) { ERR_error_string_n(errcode, errbuf, sizeof(errbuf)); return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR, "Failed to load CAFile: %s", errbuf); } return as_error_set_message(errp, AEROSPIKE_ERR_TLS_ERROR, "Unknown failure loading CAFile"); } } if (tlscfg->certfile) { int rv = SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, tlscfg->certfile); if (rv != 1) { // We seem to be seeing this bug: // https://groups.google.com/ // forum/#!topic/mailing.openssl.users/nRvRzmKnEQA // If the rv is not 1 check the error stack; if it doesn't have an // error assume we are OK. // unsigned long errcode = ERR_peek_error(); if (errcode != SSL_ERROR_NONE) { // There *was* an error after all. as_tls_context_destroy(ctx); unsigned long errcode = ERR_get_error(); char errbuf[1024]; ERR_error_string_n(errcode, errbuf, sizeof(errbuf)); return as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR, "SSL_CTX_use_certificate_chain_file failed: %s", errbuf); } } } if (tlscfg->keyfile) { bool ok = false; FILE *fh = fopen(tlscfg->keyfile, "r"); if (fh == NULL) { as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR, "failed to open key file %s: %s", tlscfg->keyfile, strerror(errno)); } else { EVP_PKEY *pkey = PEM_read_PrivateKey(fh, NULL, password_cb, tlscfg->keyfile_pw); if (pkey == NULL) { unsigned long errcode = ERR_get_error(); if (ERR_GET_REASON(errcode) == PEM_R_BAD_PASSWORD_READ) { if (tlscfg->keyfile_pw == NULL) { as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR, "key file %s requires a password", tlscfg->keyfile); } else { as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR, "password for key file %s too long", tlscfg->keyfile); } } else if (ERR_GET_REASON(errcode) == EVP_R_BAD_DECRYPT) { as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR, "invalid password for key file %s", tlscfg->keyfile); } else { char errbuf[1024]; ERR_error_string_n(errcode, errbuf, sizeof(errbuf)); as_error_update(errp, AEROSPIKE_ERR_TLS_ERROR, "PEM_read_PrivateKey failed: %s", errbuf); } } else { ctx->pkey = pkey; SSL_CTX_use_PrivateKey(ctx->ssl_ctx, pkey); ok = true; } fclose(fh); } if (!ok) { as_tls_context_destroy(ctx); return AEROSPIKE_ERR_TLS_ERROR; } } if (tlscfg->cipher_suite) { int rv = SSL_CTX_set_cipher_list(ctx->ssl_ctx, tlscfg->cipher_suite); if (rv != 1) { as_tls_context_destroy(ctx); return as_error_set_message(errp, AEROSPIKE_ERR_TLS_ERROR, "no compatible cipher found"); } // It's bogus that we have to create an SSL just to get the // cipher list, but SSL_CTX_get_ciphers doesn't appear to // exist ... SSL* ssl = SSL_new(ctx->ssl_ctx); for (int prio = 0; true; ++prio) { char const * cipherstr = SSL_get_cipher_list(ssl, prio); if (!cipherstr) { break; } as_log_info("cipher %d: %s", prio+1, cipherstr); } SSL_free(ssl); } if (tlscfg->crl_check || tlscfg->crl_check_all) { X509_VERIFY_PARAM* param = X509_VERIFY_PARAM_new(); unsigned long flags = X509_V_FLAG_CRL_CHECK; if (tlscfg->crl_check_all) { flags |= X509_V_FLAG_CRL_CHECK_ALL; } X509_VERIFY_PARAM_set_flags(param, flags); SSL_CTX_set1_param(ctx->ssl_ctx, param); X509_VERIFY_PARAM_free(param); } SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, verify_callback); manage_sigpipe(); return AEROSPIKE_OK; }
/** * xmlSecOpenSSLX509StoreVerify: * @store: the pointer to X509 key data store klass. * @certs: the untrusted certificates stack. * @crls: the crls stack. * @keyInfoCtx: the pointer to <dsig:KeyInfo/> element processing context. * * Verifies @certs list. * * Returns: pointer to the first verified certificate from @certs. */ X509* xmlSecOpenSSLX509StoreVerify(xmlSecKeyDataStorePtr store, XMLSEC_STACK_OF_X509* certs, XMLSEC_STACK_OF_X509_CRL* crls, xmlSecKeyInfoCtx* keyInfoCtx) { xmlSecOpenSSLX509StoreCtxPtr ctx; STACK_OF(X509)* certs2 = NULL; STACK_OF(X509_CRL)* crls2 = NULL; X509 * res = NULL; X509 * cert; X509 * err_cert = NULL; X509_STORE_CTX *xsc; char buf[256]; int err = 0; int i; int ret; xmlSecAssert2(xmlSecKeyDataStoreCheckId(store, xmlSecOpenSSLX509StoreId), NULL); xmlSecAssert2(certs != NULL, NULL); xmlSecAssert2(keyInfoCtx != NULL, NULL); xsc = X509_STORE_CTX_new(); if(xsc == NULL) { xmlSecOpenSSLError(xmlSecKeyDataStoreGetName(store), "X509_STORE_CTX_new"); goto done; } ctx = xmlSecOpenSSLX509StoreGetCtx(store); xmlSecAssert2(ctx != NULL, NULL); xmlSecAssert2(ctx->xst != NULL, NULL); /* dup certs */ certs2 = sk_X509_dup(certs); if(certs2 == NULL) { xmlSecOpenSSLError(xmlSecKeyDataStoreGetName(store), "sk_X509_dup"); goto done; } /* add untrusted certs from the store */ if(ctx->untrusted != NULL) { for(i = 0; i < sk_X509_num(ctx->untrusted); ++i) { ret = sk_X509_push(certs2, sk_X509_value(ctx->untrusted, i)); if(ret < 1) { xmlSecOpenSSLError(xmlSecKeyDataStoreGetName(store), "sk_X509_push"); goto done; } } } /* dup crls but remove all non-verified */ if(crls != NULL) { crls2 = sk_X509_CRL_dup(crls); if(crls2 == NULL) { xmlSecOpenSSLError(xmlSecKeyDataStoreGetName(store), "sk_X509_CRL_dup"); goto done; } for(i = 0; i < sk_X509_CRL_num(crls2); ) { ret = xmlSecOpenSSLX509VerifyCRL(ctx->xst, sk_X509_CRL_value(crls2, i)); if(ret == 1) { ++i; } else if(ret == 0) { (void)sk_X509_CRL_delete(crls2, i); } else { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "xmlSecOpenSSLX509VerifyCRL", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } } } /* remove all revoked certs */ for(i = 0; i < sk_X509_num(certs2);) { cert = sk_X509_value(certs2, i); if(crls2 != NULL) { ret = xmlSecOpenSSLX509VerifyCertAgainstCrls(crls2, cert); if(ret == 0) { (void)sk_X509_delete(certs2, i); continue; } else if(ret != 1) { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "xmlSecOpenSSLX509VerifyCertAgainstCrls", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } } if(ctx->crls != NULL) { ret = xmlSecOpenSSLX509VerifyCertAgainstCrls(ctx->crls, cert); if(ret == 0) { (void)sk_X509_delete(certs2, i); continue; } else if(ret != 1) { xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "xmlSecOpenSSLX509VerifyCertAgainstCrls", XMLSEC_ERRORS_R_XMLSEC_FAILED, XMLSEC_ERRORS_NO_MESSAGE); goto done; } } ++i; } /* get one cert after another and try to verify */ for(i = 0; i < sk_X509_num(certs2); ++i) { cert = sk_X509_value(certs2, i); if(xmlSecOpenSSLX509FindNextChainCert(certs2, cert) == NULL) { ret = X509_STORE_CTX_init(xsc, ctx->xst, cert, certs2); if(ret != 1) { xmlSecOpenSSLError(xmlSecKeyDataStoreGetName(store), "X509_STORE_CTX_init"); goto done; } if(keyInfoCtx->certsVerificationTime > 0) { X509_STORE_CTX_set_time(xsc, 0, keyInfoCtx->certsVerificationTime); } { X509_VERIFY_PARAM * vpm = NULL; unsigned long vpm_flags = 0; vpm = X509_VERIFY_PARAM_new(); if(vpm == NULL) { xmlSecOpenSSLError(xmlSecKeyDataStoreGetName(store), "X509_VERIFY_PARAM_new"); goto done; } vpm_flags = X509_VERIFY_PARAM_get_flags(vpm); vpm_flags &= (~X509_V_FLAG_CRL_CHECK); if(keyInfoCtx->certsVerificationTime > 0) { vpm_flags |= X509_V_FLAG_USE_CHECK_TIME; X509_VERIFY_PARAM_set_time(vpm, keyInfoCtx->certsVerificationTime); } X509_VERIFY_PARAM_set_depth(vpm, keyInfoCtx->certsVerificationDepth); X509_VERIFY_PARAM_set_flags(vpm, vpm_flags); X509_STORE_CTX_set0_param(xsc, vpm); } ret = X509_verify_cert(xsc); err_cert = X509_STORE_CTX_get_current_cert(xsc); err = X509_STORE_CTX_get_error(xsc); X509_STORE_CTX_cleanup (xsc); if(ret == 1) { res = cert; goto done; } else if(ret < 0) { const char* err_msg; buf[0] = '\0'; X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof buf); err_msg = X509_verify_cert_error_string(err); xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "X509_verify_cert", XMLSEC_ERRORS_R_CRYPTO_FAILED, "subj=%s;err=%d;msg=%s", xmlSecErrorsSafeString(buf), err, xmlSecErrorsSafeString(err_msg)); goto done; } else if(ret == 0) { const char* err_msg; buf[0] = '\0'; X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof buf); err_msg = X509_verify_cert_error_string(err); xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), "X509_verify_cert", XMLSEC_ERRORS_R_CRYPTO_FAILED, "subj=%s;err=%d;msg=%s", xmlSecErrorsSafeString(buf), err, xmlSecErrorsSafeString(err_msg)); } } } /* if we came here then we found nothing. do we have any error? */ if((err != 0) && (err_cert != NULL)) { const char* err_msg; err_msg = X509_verify_cert_error_string(err); switch (err) { case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: X509_NAME_oneline(X509_get_issuer_name(err_cert), buf, sizeof buf); xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), NULL, XMLSEC_ERRORS_R_CERT_ISSUER_FAILED, "err=%d;msg=%s;issuer=%s", err, xmlSecErrorsSafeString(err_msg), xmlSecErrorsSafeString(buf)); break; case X509_V_ERR_CERT_NOT_YET_VALID: case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), NULL, XMLSEC_ERRORS_R_CERT_NOT_YET_VALID, "err=%d;msg=%s", err, xmlSecErrorsSafeString(err_msg)); break; case X509_V_ERR_CERT_HAS_EXPIRED: case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), NULL, XMLSEC_ERRORS_R_CERT_HAS_EXPIRED, "err=%d;msg=%s", err, xmlSecErrorsSafeString(err_msg)); break; default: xmlSecError(XMLSEC_ERRORS_HERE, xmlSecErrorsSafeString(xmlSecKeyDataStoreGetName(store)), NULL, XMLSEC_ERRORS_R_CERT_VERIFY_FAILED, "err=%d;msg=%s", err, xmlSecErrorsSafeString(err_msg)); } } done: if(certs2 != NULL) { sk_X509_free(certs2); } if(crls2 != NULL) { sk_X509_CRL_free(crls2); } if(xsc != NULL) { X509_STORE_CTX_free(xsc); } return(res); }