apr-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From david reid <da...@jetnet.co.uk>
Subject [PROPOSAL/PATCH] add ssl sockets
Date Tue, 13 Jun 2006 21:35:49 GMT
The attached patch is a first pass at getting some support for using
openssl directly for ssl sockets within APR. I've tried to be generic in
the basic configure code, but the actaul guts are basically openssl related.

Disclaimer - this is based on some code I had written a while back and
never really gotten finished, so this has a lot of it's flaws and
unfinished feeling. It does however show the approach I've been taking.
There isn't even documentation yet!

What's attached isn't anywhere near finished or even heavily tested, but
it works as far as it has been tested and at least will (hopefully) spur
some discussion about

 - whether this is desired
 - whether this is the right way to do it (other methods are apparent)

I think it's something we should have and it's something I'll likely
persue, but I would like it to be in the main tree of apr-util. I'm not
proposing that what's included be submitted directly, but if this is the
approach then it'll give a starter for people to hack about.

With that background, here is the code... I'm away from tomorrow until
Friday, so don't be offended if i don't reply...

Index: test/Makefile.in
===================================================================
--- test/Makefile.in	(revision 413480)
+++ test/Makefile.in	(working copy)
@@ -3,7 +3,7 @@
 INCLUDES = @APRUTIL_PRIV_INCLUDES@ @APR_INCLUDES@ @APRUTIL_INCLUDES@

 PROGRAMS = testall testdbm testdate testxml testrmm \
-	   testreslist testqueue testxlate dbd
+	   testreslist testqueue testxlate dbd testssl
 TARGETS = $(PROGRAMS)

 APRUTIL_DOTTED_VERSION=@APRUTIL_DOTTED_VERSION@
@@ -73,6 +73,11 @@
 testxlate: $(testxlate_OBJECTS) $(testxlate_LDADD)
 	$(LINK) $(APRUTIL_LDFLAGS) $(testxlate_OBJECTS) $(testxlate_LDADD)
$(PROGRAM_DEPENDENCIES)

+testssl_OBJECTS = testssl.lo
+testssl_LDADD =  $(TARGET_LIB_PATH)
+testssl: $(testssl_OBJECTS) $(testssl_LDADD)
+	$(LINK) $(APRUTIL_LDFLAGS) $(testssl_OBJECTS) $(testssl_LDADD)
$(PROGRAM_DEPENDENCIES)
+
 testall_OBJECTS = teststrmatch.lo testuri.lo testuuid.lo abts.lo
testutil.lo \
 	testbuckets.lo testpass.lo testmd4.lo testmd5.lo testldap.lo \
 	testdaterfc.lo testdbd.lo
Index: test/testssl.c
===================================================================
--- test/testssl.c	(revision 0)
+++ test/testssl.c	(revision 0)
@@ -0,0 +1,133 @@
+/* Copyright 2000-2006 The Apache Software Foundation or its licensors, as
+ * applicable.
+ *
+ * Licensed 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.
+ */
+/* This file came from the SDBM package (written by oz@nexus.yorku.ca).
+ * That package was under public domain. This file has been ported to
+ * APR, updated to ANSI C and other, newer idioms, and added to the Apache
+ * codebase under the above copyright and license.
+ */
+
+/*
+ * testssl: Simple APR dbm tester.
+ * Automatic test case: ./testssl auto foo
+ *  - Attempts to create a factory
+ *
+ * Run the program for more help.
+ */
+
+#include "apr.h"
+#include "apr_general.h"
+#include "apr_pools.h"
+#include "apr_errno.h"
+#include "apr_getopt.h"
+#include "apr_time.h"
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+
+#include "apr_ssl.h"
+#include "apr_network_io.h"
+
+#if APR_HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if APR_HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>     /* for atexit(), malloc() */
+#include <string.h>
+
+static const char *progname;
+static int rflag;
+
+int main(int argc, const char * const * argv)
+{
+    apr_pool_t *pool;
+    apr_getopt_t *os;
+    char optch;
+    const char *optarg;
+    const char*dbtype;
+    apr_ssl_factory_t *asf = NULL;
+    apr_sockaddr_t *remoteSA;
+    apr_status_t rv;
+
+    (void) apr_initialize();
+    apr_pool_create(&pool, NULL);
+    atexit(apr_terminate);
+
+    (void) apr_getopt_init(&os, pool, argc, argv);
+
+    progname = argv[0];
+    dbtype = "default";
+
+    while (apr_getopt(os, "Rt:", &optch, &optarg) == APR_SUCCESS) {
+        switch (optch) {
+        case 'R':       /* raw processing  */
+            rflag++;
+            break;
+        case 't':
+            dbtype = optarg;
+            break;
+        default:
+//            show_usage();
+            fputs("unknown option.",stderr);
+            exit(-1);
+            break;
+        }
+    }
+
+    if (apr_ssl_factory_create(&asf, NULL, NULL, NULL, pool) !=
APR_SUCCESS) {
+        fprintf(stderr, "Unable to create client factory\n");
+
+    } else {
+        apr_ssl_socket_t *sslSock;
+        fprintf(stdout, "Client factory created\n");
+        if (apr_ssl_socket_create(&sslSock, AF_INET, SOCK_STREAM, 0,
asf) != APR_SUCCESS) {
+            printf("failed to create socket\n");
+        } else {
+            printf("created ssl socket\n");
+
+            rv = apr_sockaddr_info_get(&remoteSA, "svn.apache.org",
APR_UNSPEC,
+                                       443, 0, pool);
+            if (rv == APR_SUCCESS) {
+                apr_size_t len = 16;
+                char buffer[4096];
+
+                rv = apr_ssl_socket_connect(sslSock, remoteSA);
+                printf("Connect = %s\n", (rv == APR_SUCCESS ? "OK" :
"Failed"));
+
+                printf("send: %s\n",
+                       (apr_ssl_socket_send(sslSock, "GET /
HTTP/1.0\n\n", &len) == APR_SUCCESS ?
+                        "OK" : "Failed"));
+
+                len = 4096;
+                printf("recv: %s\n%s\n",
+                       (apr_ssl_socket_recv(sslSock, buffer, &len) ==
APR_SUCCESS ? "OK" : "Failed"),
+                       buffer);
+
+
+
+            }
+
+            printf("close = %s\n",
+                   (apr_ssl_socket_close(sslSock) == APR_SUCCESS ? "OK"
: "Failed"));
+
+        }
+    }
+
+    apr_pool_destroy(pool);
+
+    return 0;
+}
+
Index: build.conf
===================================================================
--- build.conf	(revision 413480)
+++ build.conf	(working copy)
@@ -20,6 +20,7 @@
   strmatch/*.c
   xlate/*.c
   dbd/*.c
+  ssl/*.c

 # we have no platform-specific subdirs
 platform_dirs =
Index: configure.in
===================================================================
--- configure.in	(revision 413480)
+++ configure.in	(working copy)
@@ -15,6 +15,7 @@
 sinclude(build/find_apr.m4)
 sinclude(build/dbm.m4)
 sinclude(build/dbd.m4)
+sinclude(build/ssl.m4)

 dnl Generate ./config.nice for reproducing runs of configure
 dnl
@@ -158,6 +159,13 @@
   APU_CHECK_CRYPT_R_STYLE
 fi

+APU_FIND_SSL
+
+dnl Check for OpenSSL libraries and headers
+dnl AC_CHECK_HEADERS([openssl/x509.h])
+dnl AC_CHECK_LIB(crypto, BN_init)
+dnl AC_CHECK_LIB(ssl, SSL_accept)
+
 so_ext=$APR_SO_EXT
 lib_target=$APR_LIB_TARGET
 AC_SUBST(so_ext)
Index: build/ssl.m4
===================================================================
--- build/ssl.m4	(revision 0)
+++ build/ssl.m4	(revision 0)
@@ -0,0 +1,129 @@
+dnl -------------------------------------------------------- -*-
autoconf -*-
+dnl Copyright 2006 The Apache Software Foundation or its licensors, as
+dnl applicable.
+dnl
+dnl Licensed under the Apache License, Version 2.0 (the "License");
+dnl you may not use this file except in compliance with the License.
+dnl You may obtain a copy of the License at
+dnl
+dnl     http://www.apache.org/licenses/LICENSE-2.0
+dnl
+dnl Unless required by applicable law or agreed to in writing, software
+dnl distributed under the License is distributed on an "AS IS" BASIS,
+dnl WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
+dnl See the License for the specific language governing permissions and
+dnl limitations under the License.
+
+dnl
+dnl SSL module
+dnl
+
+dnl
+dnl APU_FIND_SSL: look for ssl libraries and headers
+dnl
+AC_DEFUN([APU_FIND_SSL], [
+  apu_have_ssl=0
+
+  APU_CHECK_OPENSSL
+
+  dnl add checks for other varieties of ssl here
+
+  if test "$apu_have_ssl" = "1"; then
+    AC_DEFINE([APU_HAVE_SSL], 1, [Define that we have SSL capability])
+  fi
+
+])
+dnl
+
+AC_DEFUN([APU_CHECK_OPENSSL], [
+  apu_have_openssl=0
+  openssl_have_headers=0
+  openssl_have_libs=0
+
+  AC_ARG_WITH([openssl], [
+    --with-openssl=DIR
+  ], [
+    if test "$withval" = "yes"; then
+      old_cppflags="$CPPFLAGS"
+      old_ldflags="$LDFLAGS"
+
+      openssl_CPPFLAGS="-I$withval/include"
+      openssl_LDFLAGS="-L$withval/lib "
+
+      APR_ADDTO(CPPFLAGS, [$openssl_CPPFLAGS])
+      APR_ADDTO(LDFLAGS, [$openssl_LDFLAGS])
+
+      AC_MSG_NOTICE(checking for openssl in $withval)
+      AC_CHECK_HEADERS(openssl/x509.h, [openssl_have_headers=1])
+      AC_CHECK_LIB(crypto, BN_init, AC_CHECK_LIB(ssl, SSL_accept,
[openssl_have_libs=1]))
+      if test "$openssl_have_headers" != "0" && test
"$openssl_have_libs" != "0"; then
+        apu_have_openssl=1
+        APR_ADDTO(APRUTIL_LDFLAGS, [-L$withval/lib])
+        APR_ADDTO(APRUTIL_INCLUDES, [-I$withval/include])
+      fi
+
+      CPPFLAGS="$old_cppflags"
+      LDFLAGS="$old_ldflags"
+    elif test "$withval" = "no"; then
+      apu_have_openssl=0
+    else
+      old_cppflags="$CPPFLAGS"
+      old_ldflags="$LDFLAGS"
+
+      openssl_CPPFLAGS="-I$withval/include"
+      openssl_LDFLAGS="-L$withval/lib "
+
+      APR_ADDTO(CPPFLAGS, [$openssl_CPPFLAGS])
+      APR_ADDTO(LDFLAGS, [$openssl_LDFLAGS])
+
+      AC_MSG_NOTICE(checking for openssl in $withval)
+      AC_CHECK_HEADERS(openssl/x509.h, [openssl_have_headers=1])
+      AC_CHECK_LIB(crypto, BN_init, AC_CHECK_LIB(ssl, SSL_accept,
[openssl_have_libs=1]))
+      if test "$openssl_have_headers" != "0" && test
"$openssl_have_libs" != "0"; then
+        apu_have_openssl=1
+        APR_ADDTO(APRUTIL_LDFLAGS, [-L$withval/lib])
+        APR_ADDTO(APRUTIL_INCLUDES, [-I$withval/include])
+      fi
+
+      if test "$apu_have_openssl" != "1"; then
+        AC_CHECK_HEADERS(openssl/x509.h, [openssl_have_headers=1])
+        AC_CHECK_LIB(crypto, BN_init, AC_CHECK_LIB(ssl, SSL_accept,
[openssl_have_libs=1]))
+        if test "$openssl_have_headers" != "0" && test
"$openssl_have_libs" != "0"; then
+          apu_have_openssl=1
+          APR_ADDTO(APRUTIL_LDFLAGS, [-L$withval/lib])
+          APR_ADDTO(APRUTIL_INCLUDES, [-I$withval/include])
+        fi
+      fi
+
+      CPPFLAGS="$old_cppflags"
+      LDFLAGS="$old_ldflags"
+    fi
+  ], [
+    old_cppflags="$CPPFLAGS"
+    old_ldflags="$LDFLAGS"
+
+    AC_CHECK_HEADERS(openssl/x509.h, [openssl_have_headers=1])
+    AC_CHECK_LIB(crypto, BN_init, AC_CHECK_LIB(ssl, SSL_accept,
[openssl_have_libs=1]))
+    if test "$openssl_have_headers" != "0" && test "$openssl_have_libs"
!= "0"; then
+      apu_have_openssl=1
+      APR_ADDTO(APRUTIL_LDFLAGS, [-L$withval/lib])
+      APR_ADDTO(APRUTIL_INCLUDES, [-I$withval/include])
+    fi
+
+    CPPFLAGS="$old_cppflags"
+    LDFLAGS="$old_ldflags"
+  ])
+
+
+  AC_SUBST(apu_have_openssl)
+
+  dnl Since we have already done the AC_CHECK_LIB tests, if we have it,
+  dnl we know the library is there.
+  if test "$apu_have_openssl" = "1"; then
+    AC_DEFINE([APU_HAVE_OPENSSL], 1, [Define that we have OpenSSL
available])
+    APR_ADDTO(APRUTIL_EXPORT_LIBS,[-lcrypto -lssl])
+    APR_ADDTO(APRUTIL_LIBS,[-lcrypto -lssl])
+    apu_have_ssl=1
+  fi
+])
+dnl
Index: ssl/apr_ssl.c
===================================================================
--- ssl/apr_ssl.c	(revision 0)
+++ ssl/apr_ssl.c	(revision 0)
@@ -0,0 +1,98 @@
+/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
+ * applicable.
+ *
+ * Licensed 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.
+ */
+
+#include "apr.h"
+#include "apr_errno.h"
+#include "apr_pools.h"
+#include "apr_strings.h"
+#define APR_WANT_MEMFUNC
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+#include "apr_general.h"
+
+#include "apu_config.h"
+
+#ifdef APU_HAVE_SSL
+
+#include "apu.h"
+#include "apr_ssl.h"
+#include "apr_ssl_private.h"
+
+#include <stdio.h>
+
+static int sslInit = 0;
+
+static void initOpenSSL(void)
+{
+    SSL_library_init();
+    OpenSSL_add_all_algorithms();
+    OpenSSL_add_all_digests();
+    SSL_load_error_strings();
+
+    sslInit = 1;
+}
+
+APU_DECLARE(apr_status_t) apr_ssl_factory_create(apr_ssl_factory_t **fact,
+                                                 const char *privateKeyFn,
+                                                 const char *certFn,
+                                                 const char *digestType,
+                                                 apr_pool_t *p)
+
+{
+    apr_ssl_factory_t *asf;
+
+    if (!p)
+        return APR_ENOPOOL;
+
+    asf = apr_pcalloc(p, sizeof(*asf));
+    if (!asf)
+        return ENOMEM;
+
+    if (! sslInit)
+        initOpenSSL();
+
+    *fact = NULL;
+    asf->pool = p;
+
+    if (privateKeyFn && certFn) {
+        asf->ctx = SSL_CTX_new(SSLv23_server_method());
+        if (asf->ctx) {
+            if (!SSL_CTX_use_PrivateKey_file(asf->ctx, privateKeyFn,
SSL_FILETYPE_PEM) ||
+                !SSL_CTX_use_certificate_file(asf->ctx, certFn,
SSL_FILETYPE_PEM) ||
+                !SSL_CTX_check_private_key(asf->ctx)) {
+                SSL_CTX_free(asf->ctx);
+                return -1; // code?
+            }
+        }
+    } else {
+        asf->ctx = SSL_CTX_new(SSLv23_client_method());
+    }
+
+    if (digestType) {
+        asf->md = EVP_get_digestbyname(digestType);
+        // we don't care if this fails...
+    }
+
+    if (!asf->ctx)
+        return APR_EGENERAL; // what code?
+
+    // should register a cleanup here
+    *fact = asf;
+    return APR_SUCCESS;
+}
+
+
+#endif
Index: ssl/apr_ssl_socket.c
===================================================================
--- ssl/apr_ssl_socket.c	(revision 0)
+++ ssl/apr_ssl_socket.c	(revision 0)
@@ -0,0 +1,217 @@
+/* Copyright 2000-2006 The Apache Software Foundation or its licensors, as
+ * applicable.
+ *
+ * Licensed 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.
+ */
+
+#include "apr.h"
+#include "apr_errno.h"
+#include "apr_pools.h"
+#include "apr_strings.h"
+#define APR_WANT_MEMFUNC
+#define APR_WANT_STRFUNC
+#include "apr_want.h"
+#include "apr_general.h"
+
+#include "apu_config.h"
+
+#ifdef APU_HAVE_SSL
+
+#include "apu.h"
+#include "apr_ssl.h"
+#include "apr_ssl_private.h"
+
+#include "apr_network_io.h"
+#include "apr_portable.h"
+
+#include <stdio.h>
+
+
+APU_DECLARE(apr_status_t) apr_ssl_socket_create(apr_ssl_socket_t **sock,
+                                                int family, int type,
int protocol,
+                                                apr_ssl_factory_t *asf,
+                                                apr_pool_t *pool)
+{
+    SSL *ssl;
+    apr_ssl_socket_t *sslSock;
+    apr_socket_t *plainSock;
+    apr_os_sock_t fd;
+    apr_pool_t *thepool;
+
+    if (!asf)
+        return -1;
+    thepool = pool ? pool : asf->pool;
+    if (!thepool)
+        return APR_ENOPOOL;
+
+    sslSock = apr_pcalloc(asf->pool, sizeof(*sslSock));
+    if (!sslSock)
+        return ENOMEM;
+
+    if (apr_socket_create(&plainSock, family, type, protocol, thepool)
!= APR_SUCCESS) {
+        return -1;
+    }
+    sslSock->ssl = SSL_new(asf->ctx);
+    if (!sslSock->ssl) {
+        apr_socket_close(plainSock);
+        return APR_EGENERAL;
+    }
+
+    if (apr_os_sock_get(&fd, plainSock) == APR_SUCCESS) {
+        SSL_set_fd(sslSock->ssl, fd);
+        sslSock->plain = plainSock;
+    } else {
+        SSL_free(sslSock->ssl);
+        apr_socket_close(plainSock);
+        return -1;
+    }
+
+    sslSock->factory = asf;
+
+    *sock = sslSock;
+    return APR_SUCCESS;
+}
+
+APU_DECLARE(apr_status_t) apr_ssl_socket_close(apr_ssl_socket_t *sock)
+{
+    int rv;
+    if (!sock || !sock->ssl)
+        return EINVAL;
+    if (sock->connected) {
+        if ((rv = SSL_shutdown(sock->ssl)) == 0)
+            rv = SSL_shutdown(sock->ssl);
+        if (rv == -1)
+            return APR_EGENERAL; // what return code?
+    }
+    if (sock->plain)
+        apr_socket_close(sock->plain);
+    if (sock->ssl) {
+        SSL_free(sock->ssl);
+        sock->ssl = NULL;
+    }
+    return APR_SUCCESS;
+}
+
+APU_DECLARE(apr_status_t) apr_ssl_socket_connect(apr_ssl_socket_t *sock,
+                                                 apr_sockaddr_t *sa)
+{
+    apr_status_t rv;
+    int sslErr;
+
+    if (!sock || !sock->plain)
+        return APR_EINVAL;
+
+    if ((rv = apr_socket_connect(sock->plain, sa)) != APR_SUCCESS)
+        return rv;
+
+    sslErr = SSL_connect(sock->ssl);
+    if (sslErr == 1) {
+        sock->connected = 1;
+        return APR_SUCCESS;
+    }
+
+    return -1;
+}
+
+APU_DECLARE(apr_status_t) apr_ssl_socket_send(apr_ssl_socket_t *sock,
+                                              const char *buf,
+                                              apr_size_t *len)
+{
+    apr_status_t rv;
+    int sslOp;
+
+    sslOp = SSL_write(sock->ssl, buf, *len);
+    if (sslOp > 0) {
+        *len = sslOp;
+        return APR_SUCCESS;
+    }
+    return -1;
+}
+
+APU_DECLARE(apr_status_t) apr_ssl_socket_recv(apr_ssl_socket_t * sock,
+                                              char *buf, apr_size_t *len)
+{
+    int sslOp;
+
+    sslOp = SSL_read(sock->ssl, buf, *len);
+    if (sslOp > 0) {
+        *len = sslOp;
+        return APR_SUCCESS;
+    }
+    return -1;
+}
+
+APU_DECLARE(apr_status_t) apr_ssl_socket_bind(apr_ssl_socket_t *sock,
+                                              apr_sockaddr_t *sa)
+{
+    return apr_socket_bind(sock->plain, sa);
+}
+
+APU_DECLARE(apr_status_t) apr_ssl_socket_listen(apr_ssl_socket_t *sock,
+                                                apr_int32_t backlog)
+{
+    return apr_socket_listen(sock->plain, backlog);
+}
+
+APU_DECLARE(apr_status_t) apr_ssl_socket_accept(apr_ssl_socket_t **news,
+                                                apr_ssl_socket_t *sock,
+                                                apr_pool_t *conn)
+{
+    apr_status_t rv;
+    apr_socket_t *newSock;
+    apr_ssl_socket_t *newSSLSock;
+    apr_pool_t *thepool;
+    SSL *ssl;
+    apr_os_sock_t fd;
+
+    if (!sock || !sock->ssl)
+        return APR_EINVAL;
+
+    thepool = (conn ? conn : sock->pool);
+    if (!thepool)
+        return APR_ENOPOOL;
+
+    rv = apr_socket_accept(&newSock, sock->plain, thepool);
+    if (rv != APR_SUCCESS)
+        return rv;
+
+    newSSLSock = apr_pcalloc(thepool, sizeof(*newSSLSock));
+    if (!newSSLSock) {
+        apr_socket_close(newSock);
+        return ENOMEM;
+    }
+
+    newSSLSock->ssl = SSL_new(sock->factory->ctx);
+    if (!newSSLSock->ssl) {
+        apr_socket_close(newSock);
+        return APR_EGENERAL;
+    }
+
+    if (apr_os_sock_get(&fd, newSock) == APR_SUCCESS) {
+        SSL_set_fd(newSSLSock->ssl, fd);
+        newSSLSock->plain = newSock;
+    } else {
+        SSL_free(newSSLSock->ssl);
+        apr_socket_close(newSock);
+        return -1;
+    }
+
+    newSSLSock->factory = sock->factory;
+    *news = newSSLSock;
+    return APR_SUCCESS;
+}
+
+
+
+
+#endif


Mime
View raw message