📄 sslcontext.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** SSL Context wrapper
*
* @author Mladen Turk
* @version $Revision: 481766 $, $Date: 2006-12-03 13:40:18 +0100 (dim., 03 déc. 2006) $
*/
#include "tcn.h"
#include "apr_file_io.h"
#include "apr_thread_mutex.h"
#include "apr_poll.h"
#ifdef HAVE_OPENSSL
#include "ssl_private.h"
static apr_status_t ssl_context_cleanup(void *data)
{
tcn_ssl_ctxt_t *c = (tcn_ssl_ctxt_t *)data;
if (c) {
int i;
if (c->crl)
X509_STORE_free(c->crl);
c->crl = NULL;
if (c->ctx)
SSL_CTX_free(c->ctx);
c->ctx = NULL;
for (i = 0; i < SSL_AIDX_MAX; i++) {
if (c->certs[i]) {
X509_free(c->certs[i]);
c->certs[i] = NULL;
}
if (c->keys[i]) {
EVP_PKEY_free(c->keys[i]);
c->keys[i] = NULL;
}
}
if (c->bio_is) {
SSL_BIO_close(c->bio_is);
c->bio_is = NULL;
}
if (c->bio_os) {
SSL_BIO_close(c->bio_os);
c->bio_os = NULL;
}
}
return APR_SUCCESS;
}
/* Initialize server context */
TCN_IMPLEMENT_CALL(jlong, SSLContext, make)(TCN_STDARGS, jlong pool,
jint protocol, jint mode)
{
apr_pool_t *p = J2P(pool, apr_pool_t *);
tcn_ssl_ctxt_t *c = NULL;
SSL_CTX *ctx = NULL;
UNREFERENCED(o);
switch (protocol) {
case SSL_PROTOCOL_SSLV2:
case SSL_PROTOCOL_SSLV2 | SSL_PROTOCOL_TLSV1:
if (mode == SSL_MODE_CLIENT)
ctx = SSL_CTX_new(SSLv2_client_method());
else if (mode == SSL_MODE_SERVER)
ctx = SSL_CTX_new(SSLv2_server_method());
else
ctx = SSL_CTX_new(SSLv2_method());
break;
case SSL_PROTOCOL_SSLV3:
case SSL_PROTOCOL_SSLV3 | SSL_PROTOCOL_TLSV1:
if (mode == SSL_MODE_CLIENT)
ctx = SSL_CTX_new(SSLv3_client_method());
else if (mode == SSL_MODE_SERVER)
ctx = SSL_CTX_new(SSLv3_server_method());
else
ctx = SSL_CTX_new(SSLv3_method());
break;
case SSL_PROTOCOL_SSLV2 | SSL_PROTOCOL_SSLV3:
case SSL_PROTOCOL_ALL:
if (mode == SSL_MODE_CLIENT)
ctx = SSL_CTX_new(SSLv23_client_method());
else if (mode == SSL_MODE_SERVER)
ctx = SSL_CTX_new(SSLv23_server_method());
else
ctx = SSL_CTX_new(SSLv23_method());
break;
case SSL_PROTOCOL_TLSV1:
if (mode == SSL_MODE_CLIENT)
ctx = SSL_CTX_new(TLSv1_client_method());
else if (mode == SSL_MODE_SERVER)
ctx = SSL_CTX_new(TLSv1_server_method());
else
ctx = SSL_CTX_new(TLSv1_method());
break;
}
if (!ctx) {
tcn_ThrowException(e, "Invalid Server SSL Protocol");
goto init_failed;
}
if ((c = apr_pcalloc(p, sizeof(tcn_ssl_ctxt_t))) == NULL) {
tcn_ThrowAPRException(e, apr_get_os_error());
goto init_failed;
}
c->protocol = protocol;
c->mode = mode;
c->ctx = ctx;
c->pool = p;
c->bio_os = BIO_new(BIO_s_file());
if (c->bio_os != NULL)
BIO_set_fp(c->bio_os, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
SSL_CTX_set_options(c->ctx, SSL_OP_ALL);
if (!(protocol & SSL_PROTOCOL_SSLV2))
SSL_CTX_set_options(c->ctx, SSL_OP_NO_SSLv2);
if (!(protocol & SSL_PROTOCOL_SSLV3))
SSL_CTX_set_options(c->ctx, SSL_OP_NO_SSLv3);
if (!(protocol & SSL_PROTOCOL_TLSV1))
SSL_CTX_set_options(c->ctx, SSL_OP_NO_TLSv1);
/*
* Configure additional context ingredients
*/
SSL_CTX_set_options(c->ctx, SSL_OP_SINGLE_DH_USE);
#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
/*
* Disallow a session from being resumed during a renegotiation,
* so that an acceptable cipher suite can be negotiated.
*/
SSL_CTX_set_options(c->ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
#endif
/* Default session context id and cache size */
SSL_CTX_sess_set_cache_size(c->ctx, SSL_DEFAULT_CACHE_SIZE);
MD5((const unsigned char *)SSL_DEFAULT_VHOST_NAME,
(unsigned long)(sizeof(SSL_DEFAULT_VHOST_NAME) - 1),
&(c->context_id[0]));
if (mode) {
SSL_CTX_set_tmp_rsa_callback(c->ctx, SSL_callback_tmp_RSA);
SSL_CTX_set_tmp_dh_callback(c->ctx, SSL_callback_tmp_DH);
}
/* Set default Certificate verification level
* and depth for the Client Authentication
*/
c->verify_depth = 1;
c->verify_mode = SSL_CVERIFY_UNSET;
c->shutdown_type = SSL_SHUTDOWN_TYPE_UNSET;
/* Set default password callback */
SSL_CTX_set_default_passwd_cb(c->ctx, (pem_password_cb *)SSL_password_callback);
SSL_CTX_set_default_passwd_cb_userdata(c->ctx, (void *)(&tcn_password_callback));
/*
* Let us cleanup the ssl context when the pool is destroyed
*/
apr_pool_cleanup_register(p, (const void *)c,
ssl_context_cleanup,
apr_pool_cleanup_null);
return P2J(c);
init_failed:
return 0;
}
TCN_IMPLEMENT_CALL(jint, SSLContext, free)(TCN_STDARGS, jlong ctx)
{
tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
UNREFERENCED_STDARGS;
TCN_ASSERT(ctx != 0);
/* Run and destroy the cleanup callback */
return apr_pool_cleanup_run(c->pool, c, ssl_context_cleanup);
}
TCN_IMPLEMENT_CALL(void, SSLContext, setContextId)(TCN_STDARGS, jlong ctx,
jstring id)
{
tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
TCN_ALLOC_CSTRING(id);
TCN_ASSERT(ctx != 0);
UNREFERENCED(o);
if (J2S(id)) {
MD5((const unsigned char *)J2S(id),
(unsigned long)strlen(J2S(id)),
&(c->context_id[0]));
}
TCN_FREE_CSTRING(id);
}
TCN_IMPLEMENT_CALL(void, SSLContext, setBIO)(TCN_STDARGS, jlong ctx,
jlong bio, jint dir)
{
tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
BIO *bio_handle = J2P(bio, BIO *);
UNREFERENCED_STDARGS;
TCN_ASSERT(ctx != 0);
if (dir == 0) {
if (c->bio_os && c->bio_os != bio_handle)
SSL_BIO_close(c->bio_os);
c->bio_os = bio_handle;
}
else if (dir == 1) {
if (c->bio_is && c->bio_is != bio_handle)
SSL_BIO_close(c->bio_is);
c->bio_is = bio_handle;
}
else
return;
SSL_BIO_doref(bio_handle);
}
TCN_IMPLEMENT_CALL(void, SSLContext, setOptions)(TCN_STDARGS, jlong ctx,
jint opt)
{
tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
UNREFERENCED_STDARGS;
TCN_ASSERT(ctx != 0);
SSL_CTX_set_options(c->ctx, opt);
}
TCN_IMPLEMENT_CALL(void, SSLContext, setQuietShutdown)(TCN_STDARGS, jlong ctx,
jboolean mode)
{
tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
UNREFERENCED_STDARGS;
TCN_ASSERT(ctx != 0);
SSL_CTX_set_quiet_shutdown(c->ctx, mode ? 1 : 0);
}
TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCipherSuite)(TCN_STDARGS, jlong ctx,
jstring ciphers)
{
tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
TCN_ALLOC_CSTRING(ciphers);
jboolean rv = JNI_TRUE;
UNREFERENCED(o);
TCN_ASSERT(ctx != 0);
if (!J2S(ciphers))
return JNI_FALSE;
if (!SSL_CTX_set_cipher_list(c->ctx, J2S(ciphers))) {
char err[256];
ERR_error_string(ERR_get_error(), err);
tcn_Throw(e, "Unable to configure permitted SSL ciphers (%s)", err);
rv = JNI_FALSE;
}
TCN_FREE_CSTRING(ciphers);
return rv;
}
TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCARevocation)(TCN_STDARGS, jlong ctx,
jstring file,
jstring path)
{
tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
TCN_ALLOC_CSTRING(file);
TCN_ALLOC_CSTRING(path);
jboolean rv = JNI_FALSE;
X509_LOOKUP *lookup;
char err[256];
UNREFERENCED(o);
TCN_ASSERT(ctx != 0);
if (J2S(file) == NULL && J2S(path) == NULL)
return JNI_FALSE;
if (!c->crl) {
if ((c->crl = X509_STORE_new()) == NULL)
goto cleanup;
}
if (J2S(file)) {
lookup = X509_STORE_add_lookup(c->crl, X509_LOOKUP_file());
if (lookup == NULL) {
ERR_error_string(ERR_get_error(), err);
X509_STORE_free(c->crl);
c->crl = NULL;
tcn_Throw(e, "Lookup failed for file %s (%s)", J2S(file), err);
goto cleanup;
}
X509_LOOKUP_load_file(lookup, J2S(file), X509_FILETYPE_PEM);
}
if (J2S(path)) {
lookup = X509_STORE_add_lookup(c->crl, X509_LOOKUP_hash_dir());
if (lookup == NULL) {
ERR_error_string(ERR_get_error(), err);
X509_STORE_free(c->crl);
c->crl = NULL;
tcn_Throw(e, "Lookup failed for path %s (%s)", J2S(file), err);
goto cleanup;
}
X509_LOOKUP_add_dir(lookup, J2S(path), X509_FILETYPE_PEM);
}
rv = JNI_TRUE;
cleanup:
TCN_FREE_CSTRING(file);
TCN_FREE_CSTRING(path);
return rv;
}
TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCertificateChainFile)(TCN_STDARGS, jlong ctx,
jstring file,
jboolean skipfirst)
{
tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
jboolean rv = JNI_FALSE;
TCN_ALLOC_CSTRING(file);
UNREFERENCED(o);
TCN_ASSERT(ctx != 0);
if (!J2S(file))
return JNI_FALSE;
if (SSL_CTX_use_certificate_chain(c->ctx, J2S(file), skipfirst) > 0)
rv = JNI_TRUE;
TCN_FREE_CSTRING(file);
return rv;
}
TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCACertificate)(TCN_STDARGS,
jlong ctx,
jstring file,
jstring path)
{
tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
jboolean rv = JNI_TRUE;
TCN_ALLOC_CSTRING(file);
TCN_ALLOC_CSTRING(path);
UNREFERENCED(o);
TCN_ASSERT(ctx != 0);
if (file == NULL && path == NULL)
return JNI_FALSE;
/*
* Configure Client Authentication details
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -