mturk 2005/06/02 00:44:39 Modified: jni/java/org/apache/tomcat/jni SSLContext.java jni/native/include ssl_private.h jni/native/src ssl.c sslcontext.c sslutils.c Log: Add more configuration directives to SSL Context. Revision Changes Path 1.9 +126 -1 jakarta-tomcat-connectors/jni/java/org/apache/tomcat/jni/SSLContext.java Index: SSLContext.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jni/java/org/apache/tomcat/jni/SSLContext.java,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- SSLContext.java 1 Jun 2005 12:36:24 -0000 1.8 +++ SSLContext.java 2 Jun 2005 07:44:38 -0000 1.9 @@ -118,4 +118,129 @@ */ public static native void setQuietShutdown(long ctx, boolean mode); + /** + * Cipher Suite available for negotiation in SSL handshake. + * <br /> + * This complex directive uses a colon-separated cipher-spec string consisting + * of OpenSSL cipher specifications to configure the Cipher Suite the client + * is permitted to negotiate in the SSL handshake phase. Notice that this + * directive can be used both in per-server and per-directory context. + * In per-server context it applies to the standard SSL handshake when a + * connection is established. In per-directory context it forces a SSL + * renegotation with the reconfigured Cipher Suite after the HTTP request + * was read but before the HTTP response is sent. + * @param ctx Server or Client context to use. + * @param ciphers An SSL cipher specification. + */ + public static native boolean setCipherSuite(long ctx, String ciphers); + + /** + * Set Directory of PEM-encoded CA Certificates for Client Auth + * <br /> + * This directive sets the directory where you keep the Certificates of + * Certification Authorities (CAs) whose clients you deal with. These are + * used to verify the client certificate on Client Authentication. + * <br /> + * The files in this directory have to be PEM-encoded and are accessed through + * hash filenames. So usually you can't just place the Certificate files there: + * you also have to create symbolic links named hash-value.N. And you should + * always make sure this directory contains the appropriate symbolic links. + * Use the Makefile which comes with mod_ssl to accomplish this task. + * @param ctx Server or Client context to use. + * @param path Directory of PEM-encoded CA Certificates for Client Auth. + */ + public static native boolean setCARevocationPath(long ctx, String path); + + /** + * Set File of concatenated PEM-encoded CA CRLs for Client Auth + * <br /> + * This directive sets the all-in-one file where you can assemble the + * Certificate Revocation Lists (CRL) of Certification Authorities (CA) + * whose clients you deal with. These are used for Client Authentication. + * Such a file is simply the concatenation of the various PEM-encoded CRL + * files, in order of preference. This can be used alternatively and/or + * additionally to <code>setCARevocationPath</code>. + * @param ctx Server or Client context to use. + * @param file File of concatenated PEM-encoded CA CRLs for Client Auth. + */ + public static native boolean setCARevocationFile(long ctx, String file); + + /** + * Set File of PEM-encoded Server CA Certificates + * <br /> + * This directive sets the optional all-in-one file where you can assemble the + * certificates of Certification Authorities (CA) which form the certificate + * chain of the server certificate. This starts with the issuing CA certificate + * of of the server certificate and can range up to the root CA certificate. + * Such a file is simply the concatenation of the various PEM-encoded CA + * Certificate files, usually in certificate chain order. + * <br /> + * But be careful: Providing the certificate chain works only if you are using + * a single (either RSA or DSA) based server certificate. If you are using a + * coupled RSA+DSA certificate pair, this will work only if actually both + * certificates use the same certificate chain. Else the browsers will be + * confused in this situation. + * @param ctx Server or Client context to use. + * @param file File of PEM-encoded Server CA Certificates. + */ + public static native boolean setCertificateChainFile(long ctx, String file); + + /** + * Set Server Certificate + * <br /> + * Point setCertificateFile at a PEM encoded certificate. If + * the certificate is encrypted, then you will be prompted for a + * pass phrase. Note that a kill -HUP will prompt again. A test + * certificate can be generated with `make certificate' under + * built time. Keep in mind that if you've both a RSA and a DSA + * certificate you can configure both in parallel (to also allow + * the use of DSA ciphers, etc.) + * @param ctx Server or Client context to use. + * @param file Certificate file. + */ + public static native boolean setCertificateFile(long ctx, String file); + + /** + * Set Server Private Key + * <br /> + * If the key is not combined with the certificate, use this + * directive to point at the key file. Keep in mind that if + * you've both a RSA and a DSA private key you can configure + * both in parallel (to also allow the use of DSA ciphers, etc.) + * @param ctx Server or Client context to use. + * @param file Server Private Key file. + */ + public static native boolean setCertificateKeyFile(long ctx, String file); + + /** + * Set File of concatenated PEM-encoded CA Certificates for Client Auth + * <br /> + * This directive sets the all-in-one file where you can assemble the + * Certificates of Certification Authorities (CA) whose clients you deal with. + * These are used for Client Authentication. Such a file is simply the + * concatenation of the various PEM-encoded Certificate files, in order of + * preference. This can be used alternatively and/or additionally to + * <code>setCACertificatePath</code>. + * @param ctx Server or Client context to use. + * @param file File of concatenated PEM-encoded CA Certificates for Client Auth. + */ + public static native boolean setCACertificateFile(long ctx, String file); + + /** + * Set Directory of PEM-encoded CA Certificates for Client Auth + * <br /> + * This directive sets the directory where you keep the Certificates of + * Certification Authorities (CAs) whose clients you deal with. These are used + * to verify the client certificate on Client Authentication. + * <br /> + * The files in this directory have to be PEM-encoded and are accessed through + * hash filenames. So usually you can't just place the Certificate files there: + * you also have to create symbolic links named hash-value.N. And you should always + * make sure this directory contains the appropriate symbolic links. + * Use the Makefile which comes with mod_ssl to accomplish this task. + * @param ctx Server or Client context to use. + * @param path Directory of PEM-encoded CA Certificates for Client Auth. + */ + public static native boolean setCACertificatePath(long ctx, String path); + } 1.10 +7 -5 jakarta-tomcat-connectors/jni/native/include/ssl_private.h Index: ssl_private.h =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jni/native/include/ssl_private.h,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- ssl_private.h 1 Jun 2005 15:20:14 -0000 1.9 +++ ssl_private.h 2 Jun 2005 07:44:38 -0000 1.10 @@ -86,7 +86,8 @@ #define SSL_BIO_FLAG_RDONLY (1<<0) #define SSL_BIO_FLAG_CALLBACK (1<<1) #define SSL_DEFAULT_CACHE_SIZE (256) - +#define SSL_DEFAULT_VHOST_NAME ("_default_:443") +#define SSL_MAX_STR_LEN 2048 /* public cert/private key */ typedef struct { /* @@ -128,8 +129,6 @@ const char *cert_chain; /* certificate revocation list */ - const char *crl_path; - const char *crl_file; X509_STORE *crl; /* known/trusted CAs */ @@ -151,6 +150,9 @@ typedef struct tcn_ssl_conn tcn_ssl_conn_t; +#define SSL_CTX_get_extra_certs(ctx) (ctx->extra_certs) +#define SSL_CTX_set_extra_certs(ctx,value) {ctx->extra_certs = value;} + /* * Additional Functions */ @@ -164,6 +166,6 @@ DH *SSL_dh_get_param_from_file(const char *); RSA *SSL_callback_tmp_RSA(SSL *, int, int); DH *SSL_callback_tmp_DH(SSL *, int, int); - +void SSL_vhost_algo_id(const unsigned char *, unsigned char *, int); #endif /* SSL_PRIVATE_H */ 1.17 +11 -4 jakarta-tomcat-connectors/jni/native/src/ssl.c Index: ssl.c =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jni/native/src/ssl.c,v retrieving revision 1.16 retrieving revision 1.17 diff -u -r1.16 -r1.17 --- ssl.c 1 Jun 2005 10:45:03 -0000 1.16 +++ ssl.c 2 Jun 2005 07:44:39 -0000 1.17 @@ -26,6 +26,7 @@ #include "apr_thread_mutex.h" #include "apr_strings.h" #include "apr_atomic.h" +#include "apr_hash.h" #include "tcn.h" @@ -36,6 +37,9 @@ extern apr_pool_t *tcn_global_pool; ENGINE *tcn_ssl_engine = NULL; +apr_hash_t *tcn_private_keys = NULL; +apr_hash_t *tcn_public_certs = NULL; + TCN_IMPLEMENT_CALL(jint, SSL, version)(TCN_STDARGS) { UNREFERENCED_STDARGS; @@ -172,7 +176,7 @@ CRYPTO_set_locking_callback(ssl_thread_lock); apr_pool_cleanup_register(p, NULL, ssl_thread_cleanup, - apr_pool_cleanup_null); + apr_pool_cleanup_null); } static int ssl_rand_choosenum(int l, int h) @@ -353,7 +357,10 @@ ssl_rand_seed(NULL); /* For SSL_get_app_data2() at request time */ SSL_init_app_data2_idx(); - + + /* Create tables for global private keys and certs */ + tcn_private_keys = apr_hash_make(tcn_global_pool); + tcn_public_certs = apr_hash_make(tcn_global_pool); /* * Let us cleanup the ssl library when the library is unloaded */ @@ -555,7 +562,7 @@ static BIO_METHOD jbs_methods = { BIO_TYPE_FILE, - "JavaString Stream", + "Java Callback", jbs_write, jbs_read, jbs_puts, 1.15 +218 -5 jakarta-tomcat-connectors/jni/native/src/sslcontext.c Index: sslcontext.c =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jni/native/src/sslcontext.c,v retrieving revision 1.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- sslcontext.c 1 Jun 2005 15:20:14 -0000 1.14 +++ sslcontext.c 2 Jun 2005 07:44:39 -0000 1.15 @@ -175,7 +175,11 @@ */ SSL_CTX_set_options(c->ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); #endif + /* Default vhost 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->vhost_id[0])); SSL_CTX_set_tmp_rsa_callback(c->ctx, SSL_callback_tmp_RSA); SSL_CTX_set_tmp_dh_callback(c->ctx, SSL_callback_tmp_DH); @@ -252,8 +256,11 @@ */ SSL_CTX_set_options(c->ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); #endif - + /* Default vhost 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->vhost_id[0])); /* * Let us cleanup the ssl context when the pool is destroyed */ @@ -283,10 +290,11 @@ TCN_ASSERT(ctx != 0); UNREFERENCED(o); - if (J2S(id)) - MD5((const unsigned char *)J2S(id), (unsigned long)strlen(J2S(id)), + if (J2S(id)) { + MD5((const unsigned char *)J2S(id), + (unsigned long)strlen(J2S(id)), &(c->vhost_id[0])); - + } TCN_FREE_CSTRING(id); } @@ -333,6 +341,211 @@ 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))) { + BIO_printf(c->bio_os, + "[ERROR] Unable to configure permitted SSL ciphers"); + rv = JNI_FALSE; + } + TCN_FREE_CSTRING(ciphers); + return rv; +} + +TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCARevocationFile)(TCN_STDARGS, jlong ctx, + jstring file) +{ + tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *); + TCN_ALLOC_CSTRING(file); + jboolean rv = JNI_FALSE; + X509_LOOKUP *lookup; + + UNREFERENCED(o); + TCN_ASSERT(ctx != 0); + if (!J2S(file)) + return JNI_FALSE; + + if (!c->crl) { + if ((c->crl = X509_STORE_new()) == NULL) + goto cleanup; + } + lookup = X509_STORE_add_lookup(c->crl, X509_LOOKUP_file()); + if (lookup == NULL) { + X509_STORE_free(c->crl); + c->crl = NULL; + goto cleanup; + } + X509_LOOKUP_load_file(lookup, J2S(file), X509_FILETYPE_PEM); + rv = JNI_TRUE; +cleanup: + TCN_FREE_CSTRING(file); + return rv; +} + +TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCARevocationPath)(TCN_STDARGS, jlong ctx, + jstring path) +{ + tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *); + TCN_ALLOC_CSTRING(path); + jboolean rv = JNI_FALSE; + X509_LOOKUP *lookup; + + UNREFERENCED(o); + TCN_ASSERT(ctx != 0); + if (!J2S(path)) + return JNI_FALSE; + + if (!c->crl) { + if ((c->crl = X509_STORE_new()) == NULL) + goto cleanup; + } + lookup = X509_STORE_add_lookup(c->crl, X509_LOOKUP_hash_dir()); + if (lookup == NULL) { + X509_STORE_free(c->crl); + c->crl = NULL; + goto cleanup; + } + X509_LOOKUP_add_dir(lookup, J2S(path), X509_FILETYPE_PEM); + rv = JNI_TRUE; +cleanup: + TCN_FREE_CSTRING(path); + return rv; +} + +TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCertificateChainFile)(TCN_STDARGS, jlong ctx, + jstring file) +{ + tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *); + jboolean rv = JNI_TRUE; + + UNREFERENCED(o); + TCN_ASSERT(ctx != 0); + if (!file) + return JNI_FALSE; + if ((c->cert_chain = tcn_pstrdup(e, file, c->pool)) == NULL) + rv = JNI_FALSE; + + return rv; +} + +TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCertificateFile)(TCN_STDARGS, jlong ctx, + jstring file) +{ + tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *); + int i; + + UNREFERENCED(o); + TCN_ASSERT(ctx != 0); + if (!file) + return JNI_FALSE; + for (i = 0; i < SSL_AIDX_MAX; i++) { + if (!c->pk.s.cert_files[i]) { + c->pk.s.cert_files[i] = tcn_pstrdup(e, file, c->pool); + return JNI_TRUE; + } + } + BIO_printf(c->bio_os, "[ERROR] Only up to %d " + "different certificates per virtual host allowed", + SSL_AIDX_MAX); + return JNI_FALSE; +} + +TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCertificateKeyFile)(TCN_STDARGS, jlong ctx, + jstring file) +{ + tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *); + int i; + + UNREFERENCED(o); + TCN_ASSERT(ctx != 0); + if (!file) + return JNI_FALSE; + for (i = 0; i < SSL_AIDX_MAX; i++) { + if (!c->pk.s.key_files[i]) { + c->pk.s.key_files[i] = tcn_pstrdup(e, file, c->pool); + return JNI_TRUE; + } + } + BIO_printf(c->bio_os, "[ERROR] Only up to %d " + "different private keys per virtual host allowed", + SSL_AIDX_MAX); + return JNI_FALSE; +} + +TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCACertificateFile)(TCN_STDARGS, jlong ctx, + jstring file) +{ + tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *); + jboolean rv = JNI_TRUE; + + UNREFERENCED(o); + TCN_ASSERT(ctx != 0); + if (!file) + return JNI_FALSE; + if ((c->ca_cert_file = tcn_pstrdup(e, file, c->pool)) == NULL) + rv = JNI_FALSE; + + return rv; +} + +TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCACertificatePath)(TCN_STDARGS, jlong ctx, + jstring path) +{ + tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *); + jboolean rv = JNI_TRUE; + + UNREFERENCED(o); + TCN_ASSERT(ctx != 0); + if (!path) + return JNI_FALSE; + if ((c->ca_cert_path = tcn_pstrdup(e, path, c->pool)) == NULL) + rv = JNI_FALSE; + + return rv; +} + +TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCANDRCertificateFile)(TCN_STDARGS, jlong ctx, + jstring file) +{ + tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *); + jboolean rv = JNI_TRUE; + + UNREFERENCED(o); + TCN_ASSERT(ctx != 0); + if (!file) + return JNI_FALSE; + if ((c->pk.s.ca_name_file = tcn_pstrdup(e, file, c->pool)) == NULL) + rv = JNI_FALSE; + + return rv; +} + +TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCANDRCertificatePath)(TCN_STDARGS, jlong ctx, + jstring path) +{ + tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *); + jboolean rv = JNI_TRUE; + + UNREFERENCED(o); + TCN_ASSERT(ctx != 0); + if (!path) + return JNI_FALSE; + if ((c->pk.s.ca_name_path = tcn_pstrdup(e, path, c->pool)) == NULL) + rv = JNI_FALSE; + + return rv; +} + #else /* OpenSSL is not supported * If someday we make OpenSSL optional 1.9 +81 -1 jakarta-tomcat-connectors/jni/native/src/sslutils.c Index: sslutils.c =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jni/native/src/sslutils.c,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- sslutils.c 1 Jun 2005 15:20:14 -0000 1.8 +++ sslutils.c 2 Jun 2005 07:44:39 -0000 1.9 @@ -24,12 +24,16 @@ #include "apr_file_io.h" #include "apr_portable.h" #include "apr_thread_mutex.h" +#include "apr_hash.h" #include "tcn.h" #ifdef HAVE_OPENSSL #include "ssl_private.h" +extern apr_hash_t *tcn_private_keys; +extern apr_hash_t *tcn_public_certs; + /* _________________________________________________________________ ** @@ -351,6 +355,82 @@ return (DH *)conn->ctx->temp_keys[idx]; } +void SSL_vhost_algo_id(const unsigned char *vhost_id, unsigned char *md, int algo) +{ + MD5_CTX c; + MD5_Init(&c); + MD5_Update(&c, vhost_id, MD5_DIGEST_LENGTH); + switch (algo) { + case SSL_ALGO_UNKNOWN: + MD5_Update(&c, "UNKNOWN", 7); + break; + case SSL_ALGO_RSA: + MD5_Update(&c, "RSA", 3); + break; + case SSL_ALGO_DSA: + MD5_Update(&c, "DSA", 3); + break; + } + MD5_Final(md, &c); +} + +/* + * Read a file that optionally contains the server certificate in PEM + * format, possibly followed by a sequence of CA certificates that + * should be sent to the peer in the SSL Certificate message. + */ +int SSL_CTX_use_certificate_chain(SSL_CTX *ctx, char *file, + int skipfirst) +{ + BIO *bio; + X509 *x509; + unsigned long err; + int n; + STACK *extra_certs; + + if ((bio = BIO_new(BIO_s_file_internal())) == NULL) + return -1; + if (BIO_read_filename(bio, file) <= 0) { + BIO_free(bio); + return -1; + } + /* optionally skip a leading server certificate */ + if (skipfirst) { + if ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) == NULL) { + BIO_free(bio); + return -1; + } + X509_free(x509); + } + /* free a perhaps already configured extra chain */ + extra_certs=SSL_CTX_get_extra_certs(ctx); + if (extra_certs != NULL) { + sk_X509_pop_free((STACK_OF(X509) *)extra_certs, X509_free); + SSL_CTX_set_extra_certs(ctx,NULL); + } + /* create new extra chain by loading the certs */ + n = 0; + while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) { + if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) { + X509_free(x509); + BIO_free(bio); + return -1; + } + n++; + } + /* Make sure that only the error is just an EOF */ + if ((err = ERR_peek_error()) > 0) { + if (!( ERR_GET_LIB(err) == ERR_LIB_PEM + && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) { + BIO_free(bio); + return -1; + } + while (ERR_get_error() > 0) ; + } + BIO_free(bio); + return n; +} + #else /* OpenSSL is not supported * If someday we make OpenSSL optional
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]