mturk 2005/06/12 03:31:17 Modified: jni/examples/org/apache/tomcat/jni SSLServer.java jni/java/org/apache/tomcat/jni SSLSocket.java jni/native/include ssl_private.h jni/native/src sslnetwork.c sslutils.c Log: Implement SSLSocket.read and SSLSocket.write, as well as example. Use 'openssl s_clent to test' Revision Changes Path 1.6 +64 -13 jakarta-tomcat-connectors/jni/examples/org/apache/tomcat/jni/SSLServer.java Index: SSLServer.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jni/examples/org/apache/tomcat/jni/SSLServer.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- SSLServer.java 11 Jun 2005 07:03:45 -0000 1.5 +++ SSLServer.java 12 Jun 2005 10:31:16 -0000 1.6 @@ -18,12 +18,14 @@ public static int serverPort = 0; public static int serverNmax = 0; public static int serverNrun = 0; - public static long serverPool = 0; public static long serverCtx = 0; + public static long serverPool = 0; public static String serverCert = null; public static String serverKey = null; public static String serverCiphers = null; public static String serverPassword = null; + public static String serverCAFile = null; + private static Acceptor serverAcceptor = null; private static Object threadLock = new Object(); @@ -41,6 +43,7 @@ serverNmax = Integer.decode(props.getProperty("server.max", "1")).intValue(); serverCert = props.getProperty("server.cert", "server.pem"); serverKey = props.getProperty("server.key", null); + serverCAFile = props.getProperty("server.cacertificate", null); serverCiphers = props.getProperty("server.ciphers", "ALL"); serverPassword = props.getProperty("server.password", null); } @@ -60,7 +63,7 @@ SSLContext.setCipherSuite(serverCtx, serverCiphers); /* Load Server key and certificate */ SSLContext.setCertificate(serverCtx, serverCert, serverKey, serverPassword, SSL.SSL_AIDX_RSA); - SSLContext.setVerify(serverCtx, SSL.SSL_CVERIFY_REQUIRE, 10); + SSLContext.setVerify(serverCtx, SSL.SSL_CVERIFY_NONE, 10); serverAcceptor = new Acceptor(); serverAcceptor.start(); @@ -97,14 +100,6 @@ pool); serverSock = Socket.create(Socket.APR_INET, Socket.SOCK_STREAM, Socket.APR_PROTO_TCP, pool); - long sa = Address.get(Socket.APR_LOCAL, serverSock); - Sockaddr addr = new Sockaddr(); - if (Address.fill(addr, sa)) { - System.out.println("Host: " + addr.hostname); - System.out.println("Server: " + addr.servname); - System.out.println("IP: " + Address.getip(sa) + - ":" + addr.port); - } int rc = Socket.bind(serverSock, inetAddress); if (rc != 0) { throw(new Exception("Can't create Acceptor: bind: " + Error.strerror(rc))); @@ -149,9 +144,18 @@ Socket.timeoutSet(clientSock, 10000000); long sslSocket = SSLSocket.attach(SSLServer.serverCtx, clientSock, pool); i = SSLSocket.handshake(sslSocket); - System.out.println("Handskake : " + i); + if (i == 0) { - SSLSocket.close(sslSocket); + Worker worker = new Worker(sslSocket, i++, + this.getClass().getName()); + SSLServer.incThreads(); + worker.start(); + + } + else { + System.out.println("Handshake error: " + SSL.getLastError()); + SSLSocket.close(sslSocket); + } } } catch( Exception ex ) { @@ -159,6 +163,53 @@ } } } + + private class Worker extends Thread { + private int workerId = 0; + private long clientSock = 0; + private byte [] wellcomeMsg = null; + + public Worker(long clientSocket, int workerId, String from) { + this.clientSock = clientSocket; + this.workerId = workerId; + wellcomeMsg = ("SSLServer server id: " + this.workerId + " from " + + from + "\r\n").getBytes(); + } + + public void run() { + boolean doClose = false; + try { + SSLSocket.send(clientSock, wellcomeMsg, 0, wellcomeMsg.length); + while (!doClose) { + /* Do a blocking read byte at a time */ + byte [] buf = new byte[1]; + while (SSLSocket.recv(clientSock, buf, 0, 1) == 1) { + if (buf[0] == '\n') + break; + else if (buf[0] == 'Q') { + doClose = true; + break; + } + } + if (doClose) { + try { + byte [] msg = ("Bye from worker: " + workerId + "\r\n").getBytes(); + SSLSocket.send(clientSock, msg, 0, msg.length); + } catch(Exception e) { } + + SSLSocket.close(clientSock); + } + } + } catch (Exception e) { + SSLSocket.close(clientSock); + e.printStackTrace(); + } + Echo.decThreads(); + System.out.println("Worker: " + workerId + " finished"); + } + } + + public static void main(String [] args) { try { Library.initialize(null); 1.6 +42 -1 jakarta-tomcat-connectors/jni/java/org/apache/tomcat/jni/SSLSocket.java Index: SSLSocket.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jni/java/org/apache/tomcat/jni/SSLSocket.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- SSLSocket.java 11 Jun 2005 07:03:45 -0000 1.5 +++ SSLSocket.java 12 Jun 2005 10:31:16 -0000 1.6 @@ -68,5 +68,46 @@ */ public static native int close(long thesocket); + /** + * Send data over a network. + * <PRE> + * This functions acts like a blocking write by default. To change + * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK + * socket option. + * + * It is possible for both bytes to be sent and an error to be returned. + * + * APR_EINTR is never returned. + * </PRE> + * @param sock The socket to send the data over. + * @param buf The buffer which contains the data to be sent. + * @param offset Offset in the byte buffer. + * @param len The number of bytes to write; (-1) for full array. + * @return The number of bytes send. + * + */ + public static native int send(long sock, byte[] buf, int offset, int len); + + /** + * Read data from a network. + * + * <PRE> + * This functions acts like a blocking read by default. To change + * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK + * socket option. + * The number of bytes actually received is stored in argument 3. + * + * It is possible for both bytes to be received and an APR_EOF or + * other error to be returned. + * + * APR_EINTR is never returned. + * </PRE> + * @param sock The socket to read the data from. + * @param buf The buffer to store the data in. + * @param offset Offset in the byte buffer. + * @param nbytes The number of bytes to read (-1) for full array. + * @return the number of bytes received. + */ + public static native int recv(long sock, byte[] buf, int offset, int nbytes); } 1.28 +2 -2 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.27 retrieving revision 1.28 diff -u -r1.27 -r1.28 --- ssl_private.h 12 Jun 2005 07:33:08 -0000 1.27 +++ ssl_private.h 12 Jun 2005 10:31:16 -0000 1.28 @@ -208,7 +208,7 @@ apr_pool_t *pool; tcn_ssl_ctxt_t *ctx; SSL *ssl; - X509 *cert; + X509 *peer; int shutdown_type; apr_socket_t *sock; apr_pollset_t *pollset; 1.9 +197 -28 jakarta-tomcat-connectors/jni/native/src/sslnetwork.c Index: sslnetwork.c =================================================================== RCS file: /home/cvs/jakarta-tomcat-connectors/jni/native/src/sslnetwork.c,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- sslnetwork.c 11 Jun 2005 18:25:23 -0000 1.8 +++ sslnetwork.c 12 Jun 2005 10:31:17 -0000 1.9 @@ -105,9 +105,9 @@ SSL_free(con->ssl); con->ssl = NULL; } - if (con->cert) { - X509_free(con->cert); - con->cert = NULL; + if (con->peer) { + X509_free(con->peer); + con->peer = NULL; } if (con->sock) { apr_socket_close(con->sock); @@ -236,9 +236,9 @@ SSL_free(con->ssl); con->ssl = NULL; } - if (con->cert) { - X509_free(con->cert); - con->cert = NULL; + if (con->peer) { + X509_free(con->peer); + con->peer = NULL; } if (con->sock) { apr_status_t rc; @@ -422,38 +422,207 @@ TCN_IMPLEMENT_CALL(jint, SSLSocket, handshake)(TCN_STDARGS, jlong sock) { tcn_ssl_conn_t *con = J2P(sock, tcn_ssl_conn_t *); - int s, i; + int s; apr_status_t rv; + X509 *peer; + UNREFERENCED_STDARGS; TCN_ASSERT(sock != 0); + while (!SSL_is_init_finished(con->ssl)) { + if ((s = SSL_do_handshake(con->ssl)) <= 0) { + int i = SSL_get_error(con->ssl, s); + switch (i) { + case SSL_ERROR_NONE: + return APR_SUCCESS; + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) { + return rv; + } + break; + case SSL_ERROR_SYSCALL: + s = apr_get_netos_error(); + if (!APR_STATUS_IS_EAGAIN(s) && + !APR_STATUS_IS_EINTR(s)) { + con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD; + return s; + } + break; + default: + /* + * Anything else is a fatal error + */ + con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD; + return SSL_TO_APR_ERROR(i); + break; + } + } + /* + * Check for failed client authentication + */ + if (SSL_get_verify_result(con->ssl) != X509_V_OK) { + /* TODO: Log SSL client authentication failed */ + con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD; + /* TODO: Figure out the correct return value */ + return APR_EGENERAL; + } + + /* + * Remember the peer certificate + */ + if ((peer = SSL_get_peer_certificate(con->ssl)) != NULL) { + if (con->peer) + X509_free(con->peer); + con->peer = peer; + } + } + fprintf(stderr, "Handshake done\n"); + fflush(stderr); + return APR_SUCCESS; +} + +static apr_status_t ssl_socket_recv(tcn_ssl_conn_t *con, char *buf, apr_size_t *len) +{ + int s, rd = (int)(*len); + apr_status_t rv = APR_SUCCESS; + for (;;) { - s = SSL_do_handshake(con->ssl); - i = SSL_get_error(con->ssl, s); - switch (i) { - case SSL_ERROR_NONE: - return APR_SUCCESS; - break; - case SSL_ERROR_WANT_READ: - case SSL_ERROR_WANT_WRITE: - if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) { - return rv; - } - break; - case SSL_ERROR_SYSCALL: - s = apr_get_netos_error(); - if (!APR_STATUS_IS_EAGAIN(s) && - !APR_STATUS_IS_EINTR(s)) - return s; + if ((s = SSL_read(con->ssl, buf, rd)) <= 0) { + int i = SSL_get_error(con->ssl, s); + /* Special case if the "close notify" alert send by peer */ + if (s == 0 && (con->ssl->shutdown & SSL_RECEIVED_SHUTDOWN)) { + *len = 0; + return APR_EOF; + } + switch (i) { + case SSL_ERROR_ZERO_RETURN: + *len = 0; + return APR_EOF; + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) { + return rv; + } + break; + case SSL_ERROR_SYSCALL: + s = apr_get_netos_error(); + if (!APR_STATUS_IS_EAGAIN(s) && + !APR_STATUS_IS_EINTR(s)) { + con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD; + return s; + } + break; + default: + return apr_get_netos_error(); + break; + } + } + else { + *len = s; break; - default: - return SSL_TO_APR_ERROR(i); + } + } + return rv; +} + +static apr_status_t ssl_socket_send(tcn_ssl_conn_t *con, const char *buf, + apr_size_t *len) +{ + int s, rd = (int)(*len); + apr_status_t rv = APR_SUCCESS; + + for (;;) { + if ((s = SSL_write(con->ssl, buf, rd)) <= 0) { + int i = SSL_get_error(con->ssl, s); + switch (i) { + case SSL_ERROR_ZERO_RETURN: + *len = 0; + return APR_EOF; + break; + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) { + return rv; + } + break; + case SSL_ERROR_SYSCALL: + s = apr_get_netos_error(); + if (!APR_STATUS_IS_EAGAIN(s) && + !APR_STATUS_IS_EINTR(s)) { + con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD; + return s; + } + break; + default: + return apr_get_netos_error(); + break; + } + } + else { + *len = s; break; } } - return APR_SUCCESS; + return rv; } +TCN_IMPLEMENT_CALL(jint, SSLSocket, send)(TCN_STDARGS, jlong sock, + jbyteArray buf, jint offset, + jint tosend) +{ + tcn_ssl_conn_t *s = J2P(sock, tcn_ssl_conn_t *); + apr_size_t nbytes = (apr_size_t)tosend; + jbyte *bytes; + apr_int32_t nb; + apr_status_t ss; + + UNREFERENCED(o); + TCN_ASSERT(sock != 0); + apr_socket_opt_get(s->sock, APR_SO_NONBLOCK, &nb); + if (nb) + bytes = (*e)->GetPrimitiveArrayCritical(e, buf, NULL); + else + bytes = (*e)->GetByteArrayElements(e, buf, NULL); + ss = ssl_socket_send(s, bytes + offset, &nbytes); + + if (nb) + (*e)->ReleasePrimitiveArrayCritical(e, buf, bytes, JNI_ABORT); + else + (*e)->ReleaseByteArrayElements(e, buf, bytes, JNI_ABORT); + if (ss == APR_SUCCESS) + return (jint)nbytes; + else { + TCN_ERROR_WRAP(ss); + return -(jint)ss; + } +} + +TCN_IMPLEMENT_CALL(jint, SSLSocket, recv)(TCN_STDARGS, jlong sock, + jbyteArray buf, jint offset, + jint toread) +{ + tcn_ssl_conn_t *s = J2P(sock, tcn_ssl_conn_t *); + apr_size_t nbytes = (apr_size_t)toread; + jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL); + apr_status_t ss; + + UNREFERENCED(o); + TCN_ASSERT(sock != 0); + TCN_ASSERT(bytes != NULL); + ss = ssl_socket_recv(s, bytes + offset, &nbytes); + + (*e)->ReleaseByteArrayElements(e, buf, bytes, + nbytes ? 0 : JNI_ABORT); + if (ss == APR_SUCCESS) + return (jint)nbytes; + else { + TCN_ERROR_WRAP(ss); + return -(jint)ss; + } +} #else /* OpenSSL is not supported 1.28 +4 -4 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.27 retrieving revision 1.28 diff -u -r1.27 -r1.28 --- sslutils.c 12 Jun 2005 07:33:08 -0000 1.27 +++ sslutils.c 12 Jun 2005 10:31:17 -0000 1.28 @@ -663,9 +663,9 @@ /* TODO: Some logging * Certificate Verification: Error */ - if (con->cert) { - X509_free(con->cert); - con->cert = NULL; + if (con->peer) { + X509_free(con->peer); + con->peer = NULL; } } if (errdepth > depth) {
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]