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]