/** * 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; }
void SSLContext::setX509VerifyParam( const ssl::X509VerifyParam& x509VerifyParam) { if (!x509VerifyParam) { return; } if (SSL_CTX_set1_param(ctx_, x509VerifyParam.get()) != 1) { throw std::runtime_error("SSL_CTX_set1_param " + getErrors()); } }
/* 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 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 */ 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 }
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; }
int s_client_main(int argc, char **argv) { unsigned int off = 0, clr = 0; SSL *con = NULL; int s, k, width, state = 0, af = AF_UNSPEC; char *cbuf = NULL, *sbuf = NULL, *mbuf = NULL; int cbuf_len, cbuf_off; int sbuf_len, sbuf_off; fd_set readfds, writefds; char *port = PORT_STR; int full_log = 1; char *host = SSL_HOST_NAME; char *cert_file = NULL, *key_file = NULL; int cert_format = FORMAT_PEM, key_format = FORMAT_PEM; char *passarg = NULL, *pass = NULL; X509 *cert = NULL; EVP_PKEY *key = NULL; char *CApath = NULL, *CAfile = NULL, *cipher = NULL; int reconnect = 0, badop = 0, verify = SSL_VERIFY_NONE, bugs = 0; int crlf = 0; int write_tty, read_tty, write_ssl, read_ssl, tty_on, ssl_pending; SSL_CTX *ctx = NULL; int ret = 1, in_init = 1, i, nbio_test = 0; int starttls_proto = PROTO_OFF; int prexit = 0; X509_VERIFY_PARAM *vpm = NULL; int badarg = 0; const SSL_METHOD *meth = NULL; int socket_type = SOCK_STREAM; BIO *sbio; int mbuf_len = 0; struct timeval timeout, *timeoutp; const char *errstr = NULL; #ifndef OPENSSL_NO_ENGINE char *engine_id = NULL; char *ssl_client_engine_id = NULL; ENGINE *ssl_client_engine = NULL; #endif ENGINE *e = NULL; #ifndef OPENSSL_NO_TLSEXT char *servername = NULL; tlsextctx tlsextcbp = {NULL, 0}; #ifndef OPENSSL_NO_NEXTPROTONEG const char *next_proto_neg_in = NULL; #endif #endif char *sess_in = NULL; char *sess_out = NULL; struct sockaddr peer; int peerlen = sizeof(peer); int enable_timeouts = 0; long socket_mtu = 0; meth = SSLv23_client_method(); c_Pause = 0; c_quiet = 0; c_ign_eof = 0; c_debug = 0; c_msg = 0; c_showcerts = 0; if (((cbuf = malloc(BUFSIZZ)) == NULL) || ((sbuf = malloc(BUFSIZZ)) == NULL) || ((mbuf = malloc(BUFSIZZ + 1)) == NULL)) { /* NUL byte */ BIO_printf(bio_err, "out of memory\n"); goto end; } verify_depth = 0; verify_error = X509_V_OK; c_nbio = 0; argc--; argv++; while (argc >= 1) { if (strcmp(*argv, "-host") == 0) { if (--argc < 1) goto bad; host = *(++argv); } else if (strcmp(*argv, "-port") == 0) { if (--argc < 1) goto bad; port = *(++argv); if (port == NULL || *port == '\0') goto bad; } else if (strcmp(*argv, "-connect") == 0) { if (--argc < 1) goto bad; if (!extract_host_port(*(++argv), &host, NULL, &port)) goto bad; } else if (strcmp(*argv, "-verify") == 0) { verify = SSL_VERIFY_PEER; if (--argc < 1) goto bad; verify_depth = strtonum(*(++argv), 0, INT_MAX, &errstr); if (errstr) goto bad; BIO_printf(bio_err, "verify depth is %d\n", verify_depth); } else if (strcmp(*argv, "-cert") == 0) { if (--argc < 1) goto bad; cert_file = *(++argv); } else if (strcmp(*argv, "-sess_out") == 0) { if (--argc < 1) goto bad; sess_out = *(++argv); } else if (strcmp(*argv, "-sess_in") == 0) { if (--argc < 1) goto bad; sess_in = *(++argv); } else if (strcmp(*argv, "-certform") == 0) { if (--argc < 1) goto bad; cert_format = str2fmt(*(++argv)); } else if (args_verify(&argv, &argc, &badarg, bio_err, &vpm)) { if (badarg) goto bad; continue; } else if (strcmp(*argv, "-verify_return_error") == 0) verify_return_error = 1; else if (strcmp(*argv, "-prexit") == 0) prexit = 1; else if (strcmp(*argv, "-crlf") == 0) crlf = 1; else if (strcmp(*argv, "-quiet") == 0) { c_quiet = 1; c_ign_eof = 1; } else if (strcmp(*argv, "-ign_eof") == 0) c_ign_eof = 1; else if (strcmp(*argv, "-no_ign_eof") == 0) c_ign_eof = 0; else if (strcmp(*argv, "-pause") == 0) c_Pause = 1; else if (strcmp(*argv, "-debug") == 0) c_debug = 1; #ifndef OPENSSL_NO_TLSEXT else if (strcmp(*argv, "-tlsextdebug") == 0) c_tlsextdebug = 1; else if (strcmp(*argv, "-status") == 0) c_status_req = 1; #endif else if (strcmp(*argv, "-msg") == 0) c_msg = 1; else if (strcmp(*argv, "-showcerts") == 0) c_showcerts = 1; else if (strcmp(*argv, "-nbio_test") == 0) nbio_test = 1; else if (strcmp(*argv, "-state") == 0) state = 1; else if (strcmp(*argv, "-ssl3") == 0) meth = SSLv3_client_method(); else if (strcmp(*argv, "-tls1_2") == 0) meth = TLSv1_2_client_method(); else if (strcmp(*argv, "-tls1_1") == 0) meth = TLSv1_1_client_method(); else if (strcmp(*argv, "-tls1") == 0) meth = TLSv1_client_method(); #ifndef OPENSSL_NO_DTLS1 else if (strcmp(*argv, "-dtls1") == 0) { meth = DTLSv1_client_method(); socket_type = SOCK_DGRAM; } else if (strcmp(*argv, "-timeout") == 0) enable_timeouts = 1; else if (strcmp(*argv, "-mtu") == 0) { if (--argc < 1) goto bad; socket_mtu = strtonum(*(++argv), 0, LONG_MAX, &errstr); if (errstr) goto bad; } #endif else if (strcmp(*argv, "-bugs") == 0) bugs = 1; else if (strcmp(*argv, "-keyform") == 0) { if (--argc < 1) goto bad; key_format = str2fmt(*(++argv)); } else if (strcmp(*argv, "-pass") == 0) { if (--argc < 1) goto bad; passarg = *(++argv); } else if (strcmp(*argv, "-key") == 0) { if (--argc < 1) goto bad; key_file = *(++argv); } else if (strcmp(*argv, "-reconnect") == 0) { reconnect = 5; } else if (strcmp(*argv, "-CApath") == 0) { if (--argc < 1) goto bad; CApath = *(++argv); } else if (strcmp(*argv, "-CAfile") == 0) { if (--argc < 1) goto bad; CAfile = *(++argv); } else if (strcmp(*argv, "-no_tls1_2") == 0) off |= SSL_OP_NO_TLSv1_2; else if (strcmp(*argv, "-no_tls1_1") == 0) off |= SSL_OP_NO_TLSv1_1; else if (strcmp(*argv, "-no_tls1") == 0) off |= SSL_OP_NO_TLSv1; else if (strcmp(*argv, "-no_ssl3") == 0) off |= SSL_OP_NO_SSLv3; else if (strcmp(*argv, "-no_ssl2") == 0) off |= SSL_OP_NO_SSLv2; else if (strcmp(*argv, "-no_comp") == 0) { off |= SSL_OP_NO_COMPRESSION; } #ifndef OPENSSL_NO_TLSEXT else if (strcmp(*argv, "-no_ticket") == 0) { off |= SSL_OP_NO_TICKET; } #ifndef OPENSSL_NO_NEXTPROTONEG else if (strcmp(*argv, "-nextprotoneg") == 0) { if (--argc < 1) goto bad; next_proto_neg_in = *(++argv); } #endif #endif else if (strcmp(*argv, "-serverpref") == 0) off |= SSL_OP_CIPHER_SERVER_PREFERENCE; else if (strcmp(*argv, "-legacy_renegotiation") == 0) ; /* no-op */ else if (strcmp(*argv, "-legacy_server_connect") == 0) { off |= SSL_OP_LEGACY_SERVER_CONNECT; } else if (strcmp(*argv, "-no_legacy_server_connect") == 0) { clr |= SSL_OP_LEGACY_SERVER_CONNECT; } else if (strcmp(*argv, "-cipher") == 0) { if (--argc < 1) goto bad; cipher = *(++argv); } else if (strcmp(*argv, "-nbio") == 0) { c_nbio = 1; } else if (strcmp(*argv, "-starttls") == 0) { if (--argc < 1) goto bad; ++argv; if (strcmp(*argv, "smtp") == 0) starttls_proto = PROTO_SMTP; else if (strcmp(*argv, "lmtp") == 0) starttls_proto = PROTO_LMTP; else if (strcmp(*argv, "pop3") == 0) starttls_proto = PROTO_POP3; else if (strcmp(*argv, "imap") == 0) starttls_proto = PROTO_IMAP; else if (strcmp(*argv, "ftp") == 0) starttls_proto = PROTO_FTP; else if (strcmp(*argv, "xmpp") == 0) starttls_proto = PROTO_XMPP; else goto bad; } #ifndef OPENSSL_NO_ENGINE else if (strcmp(*argv, "-engine") == 0) { if (--argc < 1) goto bad; engine_id = *(++argv); } else if (strcmp(*argv, "-ssl_client_engine") == 0) { if (--argc < 1) goto bad; ssl_client_engine_id = *(++argv); } #endif else if (strcmp(*argv, "-4") == 0) { af = AF_INET; } else if (strcmp(*argv, "-6") == 0) { af = AF_INET6; } #ifndef OPENSSL_NO_TLSEXT else if (strcmp(*argv, "-servername") == 0) { if (--argc < 1) goto bad; servername = *(++argv); /* meth=TLSv1_client_method(); */ } #endif #ifndef OPENSSL_NO_SRTP else if (strcmp(*argv, "-use_srtp") == 0) { if (--argc < 1) goto bad; srtp_profiles = *(++argv); } #endif else if (strcmp(*argv, "-keymatexport") == 0) { if (--argc < 1) goto bad; keymatexportlabel = *(++argv); } else if (strcmp(*argv, "-keymatexportlen") == 0) { const char *errstr; if (--argc < 1) goto bad; keymatexportlen = strtonum(*(++argv), 1, INT_MAX, &errstr); if (errstr) goto bad; } else { BIO_printf(bio_err, "unknown option %s\n", *argv); badop = 1; break; } argc--; argv++; } if (badop) { bad: if (errstr) BIO_printf(bio_err, "invalid argument %s: %s\n", *argv, errstr); else sc_usage(); goto end; } #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) next_proto.status = -1; if (next_proto_neg_in) { next_proto.data = next_protos_parse(&next_proto.len, next_proto_neg_in); if (next_proto.data == NULL) { BIO_printf(bio_err, "Error parsing -nextprotoneg argument\n"); goto end; } } else next_proto.data = NULL; #endif #ifndef OPENSSL_NO_ENGINE e = setup_engine(bio_err, engine_id, 1); if (ssl_client_engine_id) { ssl_client_engine = ENGINE_by_id(ssl_client_engine_id); if (!ssl_client_engine) { BIO_printf(bio_err, "Error getting client auth engine\n"); goto end; } } #endif if (!app_passwd(bio_err, passarg, NULL, &pass, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } if (key_file == NULL) key_file = cert_file; if (key_file) { key = load_key(bio_err, key_file, key_format, 0, pass, e, "client certificate private key file"); if (!key) { ERR_print_errors(bio_err); goto end; } } if (cert_file) { cert = load_cert(bio_err, cert_file, cert_format, NULL, e, "client certificate file"); if (!cert) { ERR_print_errors(bio_err); goto end; } } if (bio_c_out == NULL) { if (c_quiet && !c_debug && !c_msg) { bio_c_out = BIO_new(BIO_s_null()); } else { if (bio_c_out == NULL) bio_c_out = BIO_new_fp(stdout, BIO_NOCLOSE); } } ctx = SSL_CTX_new(meth); if (ctx == NULL) { ERR_print_errors(bio_err); goto end; } if (vpm) SSL_CTX_set1_param(ctx, vpm); #ifndef OPENSSL_NO_ENGINE if (ssl_client_engine) { if (!SSL_CTX_set_client_cert_engine(ctx, ssl_client_engine)) { BIO_puts(bio_err, "Error setting client auth engine\n"); ERR_print_errors(bio_err); ENGINE_free(ssl_client_engine); goto end; } ENGINE_free(ssl_client_engine); } #endif #ifndef OPENSSL_NO_SRTP if (srtp_profiles != NULL) SSL_CTX_set_tlsext_use_srtp(ctx, srtp_profiles); #endif if (bugs) SSL_CTX_set_options(ctx, SSL_OP_ALL | off); else SSL_CTX_set_options(ctx, off); if (clr) SSL_CTX_clear_options(ctx, clr); /* * DTLS: partial reads end up discarding unread UDP bytes :-( Setting * read ahead solves this problem. */ if (socket_type == SOCK_DGRAM) SSL_CTX_set_read_ahead(ctx, 1); #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) if (next_proto.data) SSL_CTX_set_next_proto_select_cb(ctx, next_proto_cb, &next_proto); #endif if (state) SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback); if (cipher != NULL) if (!SSL_CTX_set_cipher_list(ctx, cipher)) { BIO_printf(bio_err, "error setting cipher list\n"); ERR_print_errors(bio_err); goto end; } SSL_CTX_set_verify(ctx, verify, verify_callback); if (!set_cert_key_stuff(ctx, cert, key)) goto end; if ((!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) || (!SSL_CTX_set_default_verify_paths(ctx))) { /* * BIO_printf(bio_err,"error setting default verify * locations\n"); */ ERR_print_errors(bio_err); /* goto end; */ } #ifndef OPENSSL_NO_TLSEXT if (servername != NULL) { tlsextcbp.biodebug = bio_err; SSL_CTX_set_tlsext_servername_callback(ctx, ssl_servername_cb); SSL_CTX_set_tlsext_servername_arg(ctx, &tlsextcbp); } #endif con = SSL_new(ctx); if (sess_in) { SSL_SESSION *sess; BIO *stmp = BIO_new_file(sess_in, "r"); if (!stmp) { BIO_printf(bio_err, "Can't open session file %s\n", sess_in); ERR_print_errors(bio_err); goto end; } sess = PEM_read_bio_SSL_SESSION(stmp, NULL, 0, NULL); BIO_free(stmp); if (!sess) { BIO_printf(bio_err, "Can't open session file %s\n", sess_in); ERR_print_errors(bio_err); goto end; } SSL_set_session(con, sess); SSL_SESSION_free(sess); } #ifndef OPENSSL_NO_TLSEXT if (servername != NULL) { if (!SSL_set_tlsext_host_name(con, servername)) { BIO_printf(bio_err, "Unable to set TLS servername extension.\n"); ERR_print_errors(bio_err); goto end; } } #endif /* SSL_set_cipher_list(con,"RC4-MD5"); */ re_start: if (init_client(&s, host, port, socket_type, af) == 0) { BIO_printf(bio_err, "connect:errno=%d\n", errno); shutdown(s, SHUT_RD); close(s); goto end; } BIO_printf(bio_c_out, "CONNECTED(%08X)\n", s); if (c_nbio) { unsigned long l = 1; BIO_printf(bio_c_out, "turning on non blocking io\n"); if (BIO_socket_ioctl(s, FIONBIO, &l) < 0) { ERR_print_errors(bio_err); goto end; } } if (c_Pause & 0x01) SSL_set_debug(con, 1); if (SSL_version(con) == DTLS1_VERSION) { sbio = BIO_new_dgram(s, BIO_NOCLOSE); if (getsockname(s, &peer, (void *) &peerlen) < 0) { BIO_printf(bio_err, "getsockname:errno=%d\n", errno); shutdown(s, SHUT_RD); close(s); goto end; } (void) BIO_ctrl_set_connected(sbio, 1, &peer); if (enable_timeouts) { timeout.tv_sec = 0; timeout.tv_usec = DGRAM_RCV_TIMEOUT; BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout); timeout.tv_sec = 0; timeout.tv_usec = DGRAM_SND_TIMEOUT; BIO_ctrl(sbio, BIO_CTRL_DGRAM_SET_SEND_TIMEOUT, 0, &timeout); } if (socket_mtu > 28) { SSL_set_options(con, SSL_OP_NO_QUERY_MTU); SSL_set_mtu(con, socket_mtu - 28); } else /* want to do MTU discovery */ BIO_ctrl(sbio, BIO_CTRL_DGRAM_MTU_DISCOVER, 0, NULL); } else sbio = BIO_new_socket(s, BIO_NOCLOSE); if (nbio_test) { BIO *test; test = BIO_new(BIO_f_nbio_test()); sbio = BIO_push(test, sbio); } if (c_debug) { SSL_set_debug(con, 1); BIO_set_callback(sbio, bio_dump_callback); BIO_set_callback_arg(sbio, (char *) bio_c_out); } if (c_msg) { SSL_set_msg_callback(con, msg_cb); SSL_set_msg_callback_arg(con, bio_c_out); } #ifndef OPENSSL_NO_TLSEXT if (c_tlsextdebug) { SSL_set_tlsext_debug_callback(con, tlsext_cb); SSL_set_tlsext_debug_arg(con, bio_c_out); } if (c_status_req) { SSL_set_tlsext_status_type(con, TLSEXT_STATUSTYPE_ocsp); SSL_CTX_set_tlsext_status_cb(ctx, ocsp_resp_cb); SSL_CTX_set_tlsext_status_arg(ctx, bio_c_out); } #endif SSL_set_bio(con, sbio, sbio); SSL_set_connect_state(con); /* ok, lets connect */ width = SSL_get_fd(con) + 1; read_tty = 1; write_tty = 0; tty_on = 0; read_ssl = 1; write_ssl = 1; cbuf_len = 0; cbuf_off = 0; sbuf_len = 0; sbuf_off = 0; /* This is an ugly hack that does a lot of assumptions */ /* * We do have to handle multi-line responses which may come in a * single packet or not. We therefore have to use BIO_gets() which * does need a buffering BIO. So during the initial chitchat we do * push a buffering BIO into the chain that is removed again later on * to not disturb the rest of the s_client operation. */ if (starttls_proto == PROTO_SMTP || starttls_proto == PROTO_LMTP) { int foundit = 0; BIO *fbio = BIO_new(BIO_f_buffer()); BIO_push(fbio, sbio); /* wait for multi-line response to end from SMTP */ do { mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); } while (mbuf_len > 3 && mbuf[3] == '-'); /* STARTTLS command requires EHLO... */ BIO_printf(fbio, "%cHLO openssl.client.net\r\n", starttls_proto == PROTO_SMTP ? 'E' : 'L'); (void) BIO_flush(fbio); /* wait for multi-line response to end EHLO SMTP response */ do { mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); if (strstr(mbuf, "STARTTLS")) foundit = 1; } while (mbuf_len > 3 && mbuf[3] == '-'); (void) BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); if (!foundit) BIO_printf(bio_err, "didn't found starttls in server response," " try anyway...\n"); BIO_printf(sbio, "STARTTLS\r\n"); BIO_read(sbio, sbuf, BUFSIZZ); } else if (starttls_proto == PROTO_POP3) { mbuf_len = BIO_read(sbio, mbuf, BUFSIZZ); if (mbuf_len == -1) { BIO_printf(bio_err, "BIO_read failed\n"); goto end; } BIO_printf(sbio, "STLS\r\n"); BIO_read(sbio, sbuf, BUFSIZZ); } else if (starttls_proto == PROTO_IMAP) { int foundit = 0; BIO *fbio = BIO_new(BIO_f_buffer()); BIO_push(fbio, sbio); BIO_gets(fbio, mbuf, BUFSIZZ); /* STARTTLS command requires CAPABILITY... */ BIO_printf(fbio, ". CAPABILITY\r\n"); (void) BIO_flush(fbio); /* wait for multi-line CAPABILITY response */ do { mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); if (strstr(mbuf, "STARTTLS")) foundit = 1; } while (mbuf_len > 3 && mbuf[0] != '.'); (void) BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); if (!foundit) BIO_printf(bio_err, "didn't found STARTTLS in server response," " try anyway...\n"); BIO_printf(sbio, ". STARTTLS\r\n"); BIO_read(sbio, sbuf, BUFSIZZ); } else if (starttls_proto == PROTO_FTP) { BIO *fbio = BIO_new(BIO_f_buffer()); BIO_push(fbio, sbio); /* wait for multi-line response to end from FTP */ do { mbuf_len = BIO_gets(fbio, mbuf, BUFSIZZ); } while (mbuf_len > 3 && mbuf[3] == '-'); (void) BIO_flush(fbio); BIO_pop(fbio); BIO_free(fbio); BIO_printf(sbio, "AUTH TLS\r\n"); BIO_read(sbio, sbuf, BUFSIZZ); } if (starttls_proto == PROTO_XMPP) { int seen = 0; BIO_printf(sbio, "<stream:stream " "xmlns:stream='http://etherx.jabber.org/streams' " "xmlns='jabber:client' to='%s' version='1.0'>", host); seen = BIO_read(sbio, mbuf, BUFSIZZ); mbuf[seen] = 0; while (!strstr(mbuf, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'")) { if (strstr(mbuf, "/stream:features>")) goto shut; seen = BIO_read(sbio, mbuf, BUFSIZZ); mbuf[seen] = 0; } BIO_printf(sbio, "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>"); seen = BIO_read(sbio, sbuf, BUFSIZZ); sbuf[seen] = 0; if (!strstr(sbuf, "<proceed")) goto shut; mbuf[0] = 0; } for (;;) { FD_ZERO(&readfds); FD_ZERO(&writefds); if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_get_timeout(con, &timeout)) timeoutp = &timeout; else timeoutp = NULL; if (SSL_in_init(con) && !SSL_total_renegotiations(con)) { in_init = 1; tty_on = 0; } else { tty_on = 1; if (in_init) { in_init = 0; if (sess_out) { BIO *stmp = BIO_new_file(sess_out, "w"); if (stmp) { PEM_write_bio_SSL_SESSION(stmp, SSL_get_session(con)); BIO_free(stmp); } else BIO_printf(bio_err, "Error writing session file %s\n", sess_out); } print_stuff(bio_c_out, con, full_log); if (full_log > 0) full_log--; if (starttls_proto) { BIO_write(bio_err, mbuf, mbuf_len); /* We don't need to know any more */ starttls_proto = PROTO_OFF; } if (reconnect) { reconnect--; BIO_printf(bio_c_out, "drop connection and then reconnect\n"); SSL_shutdown(con); SSL_set_connect_state(con); shutdown(SSL_get_fd(con), SHUT_RD); close(SSL_get_fd(con)); goto re_start; } } } ssl_pending = read_ssl && SSL_pending(con); /* XXX should add tests for fd_set overflow */ if (!ssl_pending) { if (tty_on) { if (read_tty) FD_SET(fileno(stdin), &readfds); if (write_tty) FD_SET(fileno(stdout), &writefds); } if (read_ssl) FD_SET(SSL_get_fd(con), &readfds); if (write_ssl) FD_SET(SSL_get_fd(con), &writefds); /* printf("mode tty(%d %d%d) ssl(%d%d)\n", tty_on,read_tty,write_tty,read_ssl,write_ssl);*/ i = select(width, &readfds, &writefds, NULL, timeoutp); if (i < 0) { BIO_printf(bio_err, "bad select %d\n", errno); goto shut; /* goto end; */ } } if ((SSL_version(con) == DTLS1_VERSION) && DTLSv1_handle_timeout(con) > 0) { BIO_printf(bio_err, "TIMEOUT occured\n"); } if (!ssl_pending && FD_ISSET(SSL_get_fd(con), &writefds)) { k = SSL_write(con, &(cbuf[cbuf_off]), (unsigned int) cbuf_len); switch (SSL_get_error(con, k)) { case SSL_ERROR_NONE: cbuf_off += k; cbuf_len -= k; if (k <= 0) goto end; /* we have done a write(con,NULL,0); */ if (cbuf_len <= 0) { read_tty = 1; write_ssl = 0; } else { /* if (cbuf_len > 0) */ read_tty = 0; write_ssl = 1; } break; case SSL_ERROR_WANT_WRITE: BIO_printf(bio_c_out, "write W BLOCK\n"); write_ssl = 1; read_tty = 0; break; case SSL_ERROR_WANT_READ: BIO_printf(bio_c_out, "write R BLOCK\n"); write_tty = 0; read_ssl = 1; write_ssl = 0; break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_c_out, "write X BLOCK\n"); break; case SSL_ERROR_ZERO_RETURN: if (cbuf_len != 0) { BIO_printf(bio_c_out, "shutdown\n"); ret = 0; goto shut; } else { read_tty = 1; write_ssl = 0; break; } case SSL_ERROR_SYSCALL: if ((k != 0) || (cbuf_len != 0)) { BIO_printf(bio_err, "write:errno=%d\n", errno); goto shut; } else { read_tty = 1; write_ssl = 0; } break; case SSL_ERROR_SSL: ERR_print_errors(bio_err); goto shut; } } else if (!ssl_pending && FD_ISSET(fileno(stdout), &writefds)) { i = write(fileno(stdout), &(sbuf[sbuf_off]), sbuf_len); if (i <= 0) { BIO_printf(bio_c_out, "DONE\n"); ret = 0; goto shut; /* goto end; */ } sbuf_len -= i; sbuf_off += i; if (sbuf_len <= 0) { read_ssl = 1; write_tty = 0; } } else if (ssl_pending || FD_ISSET(SSL_get_fd(con), &readfds)) { #ifdef RENEG { static int iiii; if (++iiii == 52) { SSL_renegotiate(con); iiii = 0; } } #endif k = SSL_read(con, sbuf, 1024 /* BUFSIZZ */ ); switch (SSL_get_error(con, k)) { case SSL_ERROR_NONE: if (k <= 0) goto end; sbuf_off = 0; sbuf_len = k; read_ssl = 0; write_tty = 1; break; case SSL_ERROR_WANT_WRITE: BIO_printf(bio_c_out, "read W BLOCK\n"); write_ssl = 1; read_tty = 0; break; case SSL_ERROR_WANT_READ: BIO_printf(bio_c_out, "read R BLOCK\n"); write_tty = 0; read_ssl = 1; if ((read_tty == 0) && (write_ssl == 0)) write_ssl = 1; break; case SSL_ERROR_WANT_X509_LOOKUP: BIO_printf(bio_c_out, "read X BLOCK\n"); break; case SSL_ERROR_SYSCALL: ret = errno; BIO_printf(bio_err, "read:errno=%d\n", ret); goto shut; case SSL_ERROR_ZERO_RETURN: BIO_printf(bio_c_out, "closed\n"); ret = 0; goto shut; case SSL_ERROR_SSL: ERR_print_errors(bio_err); goto shut; /* break; */ } } else if (FD_ISSET(fileno(stdin), &readfds)) { if (crlf) { int j, lf_num; i = read(fileno(stdin), cbuf, BUFSIZZ / 2); lf_num = 0; /* both loops are skipped when i <= 0 */ for (j = 0; j < i; j++) if (cbuf[j] == '\n') lf_num++; for (j = i - 1; j >= 0; j--) { cbuf[j + lf_num] = cbuf[j]; if (cbuf[j] == '\n') { lf_num--; i++; cbuf[j + lf_num] = '\r'; } } assert(lf_num == 0); } else i = read(fileno(stdin), cbuf, BUFSIZZ); if ((!c_ign_eof) && ((i <= 0) || (cbuf[0] == 'Q'))) { BIO_printf(bio_err, "DONE\n"); ret = 0; goto shut; } if ((!c_ign_eof) && (cbuf[0] == 'R')) { BIO_printf(bio_err, "RENEGOTIATING\n"); SSL_renegotiate(con); cbuf_len = 0; } else { cbuf_len = i; cbuf_off = 0; } write_ssl = 1; read_tty = 0; } } ret = 0; shut: if (in_init) print_stuff(bio_c_out, con, full_log); SSL_shutdown(con); shutdown(SSL_get_fd(con), SHUT_RD); close(SSL_get_fd(con)); end: if (con != NULL) { if (prexit != 0) print_stuff(bio_c_out, con, 1); SSL_free(con); } #if !defined(OPENSSL_NO_TLSEXT) && !defined(OPENSSL_NO_NEXTPROTONEG) free(next_proto.data); #endif if (ctx != NULL) SSL_CTX_free(ctx); if (cert) X509_free(cert); if (key) EVP_PKEY_free(key); free(pass); if (vpm) X509_VERIFY_PARAM_free(vpm); if (cbuf != NULL) { OPENSSL_cleanse(cbuf, BUFSIZZ); free(cbuf); } if (sbuf != NULL) { OPENSSL_cleanse(sbuf, BUFSIZZ); free(sbuf); } if (mbuf != NULL) { OPENSSL_cleanse(mbuf, BUFSIZZ); free(mbuf); } if (bio_c_out != NULL) { BIO_free(bio_c_out); bio_c_out = NULL; } return (ret); }
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; }
MONO_API int mono_btls_ssl_ctx_set_verify_param (MonoBtlsSslCtx *ctx, const MonoBtlsX509VerifyParam *param) { return SSL_CTX_set1_param (ctx->ctx, mono_btls_x509_verify_param_peek_param (param)); }
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 }