Hi, I have started to add SSL support to mod_webapp. I have prepared a test patch for client certificates, it works.
I will now add the missing part and improve it a little: Storing the ssl_cert and other in a substructure of wa_request instead directly in wa_request. Something like: +++ typedef struct wa_ssldata wa_ssldata; struct wa_ssldata { char *ssl_cert; char *ssl_cipher; char *ssl_session; int ssl_key_size; } struct wa_request { ... wa_ssldata *ssld; } +++ Changing the protocol elements: TYPE_CBK_READ to TYPE_ASK_READ TYPE_CBK_DATA to TYPE_REP_DATA TYPE_CBK_DOME to TYPE_REP_DONE To see more easly was it from web server (REP: Reponse) and to web server (ASK: Ask). I will (from the patch) remove (TYPE_REP_SSL_SESSION, TYPE_REP_SSL_CIPHER, TYPE_REP_SSL_KEYSIZ and replace them by TYPE_REP_SSL that will carry SSL_SESSION, SSL_CIPHER and KEYSIZ in its payload. The things like "SSL_CLIENT_CERT", that are extracted from mod_ssl I will put them in an include file I think that they have fixed values in a webserver implementation. req->ssl_cert = (char *)ap_table_get(r->subprocess_env,"SSL_CLIENT_CERT"); Any comments? Cheers Jean-frederic
Index: apache-1.3/mod_webapp.c =================================================================== RCS file: /home/cvs/mirror/jakarta-tomcat-connectors/webapp/apache-1.3/mod_webapp.c,v retrieving revision 1.24 diff -u -r1.24 mod_webapp.c --- apache-1.3/mod_webapp.c 2001/10/09 10:41:25 1.24 +++ apache-1.3/mod_webapp.c 2001/10/18 15:15:59 @@ -462,6 +462,7 @@ req->clen=0; req->ctyp="\0"; req->rlen=0; + req->ssl_cert = (char *)ap_table_get(r->subprocess_env,"SSL_CLIENT_CERT"); /* Copy headers into webapp request structure */ if (r->headers_in!=NULL) { Index: include/wa_request.h =================================================================== RCS file: /home/cvs/mirror/jakarta-tomcat-connectors/webapp/include/wa_request.h,v retrieving revision 1.6 diff -u -r1.6 wa_request.h --- include/wa_request.h 2001/07/19 23:47:31 1.6 +++ include/wa_request.h 2001/10/18 15:16:02 @@ -128,6 +128,8 @@ long rlen; /** The current headers table. */ apr_table_t *hdrs; + /** The client certificate string */ + char *ssl_cert; }; /** Index: java/Constants.java.in =================================================================== RCS file: /home/cvs/mirror/jakarta-tomcat-connectors/webapp/java/Constants.java.in,v retrieving revision 1.11 diff -u -r1.11 Constants.java.in --- java/Constants.java.in 2001/08/09 20:02:15 1.11 +++ java/Constants.java.in 2001/10/18 15:16:03 @@ -363,4 +363,62 @@ * No payload.<br> */ public static final int TYPE_CBK_DONE=0x42; + + /** + * ASK_SSL: The WARP client (HTTP server) asks the WARP server to + * transfer the basic SSL information (cypher, keysize and session). + * <br> + * No payload.<br> + */ + public static final int TYPE_ASK_SSL=0x43; + + /** + * ASK_SSL_CLIENT: The WARP client (HTTP server) asks the WARP server to + * transfer the client certificate. + * (just the first element of the chain and the webserver should request + * for it to the browser if possible). + * <br> + * No payload.<br> + */ + public static final int TYPE_ASK_SSL_CLIENT=0x44; + + /** + * REP_SSL_CERT: The client certificate (remote peer). + * <br> + * Payload description:<br> + * [string] The client certificate. + */ + public static final int TYPE_REP_SSL_CERT=0x52; + + /** + * REP_SSL_CIPHER: The cipher used between client and server. + * <br> + * Payload description:<br> + * [string] The cipher_suite. + */ + public static final int TYPE_REP_SSL_CIPHER=0x53; + + /** + * REP_SSL_SESSION: The ssl session. + * <br> + * Payload description:<br> + * [string] The ssl session. (That is not in the spec's). + */ + public static final int TYPE_REP_SSL_SESSION=0x54; + + /** + * REP_SSL_KEYSIZ: size of the used algorithm. + * <br> + * Payload description:<br> + * [ushort] size of the algorithm (56-128). + */ + public static final int TYPE_REP_SSL_KEYSIZ=0x55; + + /** + * REP_SSL_NO: Request SSL information is not available. + * <br> + * No payload.<br> + */ + public static final int TYPE_REP_SSL_NO=0x5F; } + Index: java/Makefile.in =================================================================== RCS file: /home/cvs/mirror/jakarta-tomcat-connectors/webapp/java/Makefile.in,v retrieving revision 1.3 diff -u -r1.3 Makefile.in --- java/Makefile.in 2001/09/17 05:04:02 1.3 +++ java/Makefile.in 2001/10/18 15:16:04 @@ -70,6 +70,7 @@ WarpRequest.java \ WarpRequestHandler.java \ WarpResponse.java \ + WarpCertificates.java ARCHIVE = warp.jar Index: java/WarpConnector.java =================================================================== RCS file: /home/cvs/mirror/jakarta-tomcat-connectors/webapp/java/WarpConnector.java,v retrieving revision 1.21 diff -u -r1.21 WarpConnector.java --- java/WarpConnector.java 2001/10/13 01:33:00 1.21 +++ java/WarpConnector.java 2001/10/18 15:16:06 @@ -481,6 +481,8 @@ } } catch (IOException e) { throw new LifecycleException("Error creating server socket",e); + } catch (java.security.GeneralSecurityException e) { + throw new LifecycleException("Error creating SSL server socket",e); } } Index: java/WarpRequest.java =================================================================== RCS file: /home/cvs/mirror/jakarta-tomcat-connectors/webapp/java/WarpRequest.java,v retrieving revision 1.9 diff -u -r1.9 WarpRequest.java --- java/WarpRequest.java 2001/07/25 22:32:05 1.9 +++ java/WarpRequest.java 2001/10/18 15:16:06 @@ -77,6 +77,20 @@ this.setStream(this.localstream); } + /** Process the SSL attributes */ + public Object getAttribute(String name) { + if (name.equals("javax.servlet.request.X509Certificate")) { + WarpCertificates cert = null; + try { + cert = new WarpCertificates(localstream.getX509Certificates()); + } catch (IOException e) { + return null; + } + return(cert.getCertificates()); + } + return(super.getAttribute(name)); + } + public void setHost(Host host) { this.host=host; } @@ -150,6 +164,22 @@ this.request.getConnection().recv(packet); return(this.read()); } + public String getX509Certificates() + throws IOException { + if (closed) throw new IOException("Stream closed"); + this.packet.reset(); + this.packet.setType(Constants.TYPE_ASK_SSL_CLIENT); + this.request.getConnection().send(packet); + packet.reset(); + + this.request.getConnection().recv(packet); + if (closed) throw new IOException("Stream closed"); + if (packet.getType()==Constants.TYPE_REP_SSL_NO) return(null); + if (packet.getType()!=Constants.TYPE_REP_SSL_CERT) + throw new IOException("Invalid WARP packet type for CC"); + return(this.packet.readString()); + } + public void close() throws IOException { Index: lib/pr_warp.c =================================================================== RCS file: /home/cvs/mirror/jakarta-tomcat-connectors/webapp/lib/pr_warp.c,v retrieving revision 1.16 diff -u -r1.16 pr_warp.c --- lib/pr_warp.c 2001/10/09 10:41:25 1.16 +++ lib/pr_warp.c 2001/10/18 15:16:08 @@ -428,6 +428,22 @@ } break; } + case TYPE_ASK_SSL_CLIENT: { + /* Request for client certificate */ + if (r->ssl_cert==NULL) { + pack->type=TYPE_REP_SSL_NO; + pack->size=0; + } else { + pack->type=TYPE_REP_SSL_CERT; + p_write_string(pack,r->ssl_cert); + } + wa_debug(WA_MARK,"CC bytes: (Sent=%d)",pack->size); + if (n_send(conf->sock,pack)!=wa_true) { + n_disconnect(conn); + return(wa_rerror(WA_MARK,r,500,"Communitcation interrupted")); + } + break; + } case TYPE_ERROR: { char *mesg=NULL; p_read_string(pack,&mesg);
package org.apache.catalina.connector.warp; import java.security.cert.X509Certificate; import java.security.cert.CertificateFactory; import java.io.ByteArrayInputStream; /* * Certificates handling. */ public class WarpCertificates { X509Certificate jsseCerts[] = null; /** * Create the certificate using the String. */ public WarpCertificates(String certString) { byte[] certData = certString.getBytes(); ByteArrayInputStream bais = new ByteArrayInputStream(certData); // Fill the first element. try { CertificateFactory cf = CertificateFactory.getInstance("X.509"); X509Certificate cert = (X509Certificate) cf.generateCertificate(bais); jsseCerts = new X509Certificate[1]; jsseCerts[0] = cert; } catch(java.security.cert.CertificateException e) { // Certificate convertion failed. return; } } public X509Certificate [] getCertificates() { return jsseCerts; } }