apr-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From minf...@apache.org
Subject svn commit: r692949 [1/2] - in /apr/apr-util/trunk: ./ build/ crypto/ test/ test/data/
Date Sun, 07 Sep 2008 20:42:48 GMT
Author: minfrin
Date: Sun Sep  7 13:42:47 2008
New Revision: 692949

URL: http://svn.apache.org/viewvc?rev=692949&view=rev
Log:
Add apr_crypto implementations for OpenSSL and Mozilla NSS. Add a unit
test to verify the interoperability of the two modules. Builds default
to disabled unless explicitly enabled.

Added:
    apr/apr-util/trunk/build/crypto.m4
    apr/apr-util/trunk/crypto/apr_crypto_nss.c
    apr/apr-util/trunk/crypto/apr_crypto_openssl.c
    apr/apr-util/trunk/test/testcrypto.c
Modified:
    apr/apr-util/trunk/CHANGES
    apr/apr-util/trunk/Makefile.in
    apr/apr-util/trunk/build.conf
    apr/apr-util/trunk/build/dso.m4
    apr/apr-util/trunk/configure.in
    apr/apr-util/trunk/test/Makefile.in
    apr/apr-util/trunk/test/abts_tests.h
    apr/apr-util/trunk/test/data/   (props changed)
    apr/apr-util/trunk/test/testutil.h

Modified: apr/apr-util/trunk/CHANGES
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/CHANGES?rev=692949&r1=692948&r2=692949&view=diff
==============================================================================
--- apr/apr-util/trunk/CHANGES [utf-8] (original)
+++ apr/apr-util/trunk/CHANGES [utf-8] Sun Sep  7 13:42:47 2008
@@ -1,6 +1,11 @@
                                                      -*- coding: utf-8 -*-
 Changes with APR-util 1.4.0
 
+  *) Add apr_crypto implementations for OpenSSL and Mozilla NSS. Add a unit
+     test to verify the interoperability of the two modules. Builds default
+     to disabled unless explicitly enabled.
+     [Graham Leggett]
+
   *) Add the apr_crypto interface, a rewrite of the earlier apr_ssl code,
      based on the modular dso interface used for dbd and ldap. Initially,
      the interface supports symmetrical encryption and decryption. The

Modified: apr/apr-util/trunk/Makefile.in
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/Makefile.in?rev=692949&r1=692948&r2=692949&view=diff
==============================================================================
--- apr/apr-util/trunk/Makefile.in (original)
+++ apr/apr-util/trunk/Makefile.in Sun Sep  7 13:42:47 2008
@@ -38,6 +38,8 @@
 LDADD_dbd_freetds = @LDADD_dbd_freetds@
 LDADD_dbd_odbc = @LDADD_dbd_odbc@
 LDADD_ldap = @LDADD_ldap@
+LDADD_crypto_openssl = @LDADD_crypto_openssl@
+LDADD_crypto_nss = @LDADD_crypto_nss@
 
 TARGETS = $(TARGET_LIB) aprutil.exp apu-config.out $(APU_MODULES)
 

Modified: apr/apr-util/trunk/build.conf
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/build.conf?rev=692949&r1=692948&r2=692949&view=diff
==============================================================================
--- apr/apr-util/trunk/build.conf (original)
+++ apr/apr-util/trunk/build.conf Sun Sep  7 13:42:47 2008
@@ -7,7 +7,12 @@
 # the platform-independent .c files
 paths =
   buckets/*.c
-  crypto/*.c
+  crypto/apr_crypto.c
+  crypto/apr_md4.c
+  crypto/apr_md5.c
+  crypto/apr_sha1.c
+  crypto/getuuid.c
+  crypto/uuid.c
   dbm/*.c
   dbm/sdbm/*.c
   encoding/*.c
@@ -28,13 +33,21 @@
 # the public headers
 headers = include/*.h include/private/*.h
 
-modules = ldap dbd_pgsql dbd_sqlite2 dbd_sqlite3 dbd_oracle dbd_mysql dbd_freetds dbd_odbc
+modules = crypto_openssl crypto_nss ldap dbd_pgsql dbd_sqlite2 dbd_sqlite3 dbd_oracle dbd_mysql dbd_freetds dbd_odbc
 
 # gen_uri_delim.c
 
 # we have a recursive makefile for the test files (for now)
 # test/*.c
 
+[crypto_openssl]
+paths = crypto/apr_crypto_openssl.c
+target = crypto/apr_crypto_openssl.la
+
+[crypto_nss]
+paths = crypto/apr_crypto_nss.c
+target = crypto/apr_crypto_nss.la
+
 [dbd_pgsql]
 paths = dbd/apr_dbd_pgsql.c
 target = dbd/apr_dbd_pgsql.la

Added: apr/apr-util/trunk/build/crypto.m4
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/build/crypto.m4?rev=692949&view=auto
==============================================================================
--- apr/apr-util/trunk/build/crypto.m4 (added)
+++ apr/apr-util/trunk/build/crypto.m4 Sun Sep  7 13:42:47 2008
@@ -0,0 +1,205 @@
+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 Crypto module
+dnl
+
+dnl
+dnl APU_CHECK_CRYPTO: look for crypto libraries and headers
+dnl
+AC_DEFUN([APU_CHECK_CRYPTO], [
+  apu_have_crypto=0
+
+  old_libs="$LIBS"
+  old_cppflags="$CPPFLAGS"
+  old_ldflags="$LDFLAGS"
+
+  AC_ARG_WITH([crypto], [APR_HELP_STRING([--with-crypto], [enable crypto support])],
+  [
+    if test "$withval" = "yes"; then
+      APU_CHECK_CRYPTO_OPENSSL
+      APU_CHECK_CRYPTO_NSS
+      dnl add checks for other varieties of ssl here
+    fi
+  ], [
+      apu_have_crypto=0
+  ])
+
+  if test "$apu_have_crypto" = "1"; then
+    AC_DEFINE([APU_HAVE_CRYPTO], 1, [Define that we have crypto capability])
+  fi
+
+])
+dnl
+
+AC_DEFUN([APU_CHECK_CRYPTO_OPENSSL], [
+  apu_have_openssl=0
+  openssl_have_headers=0
+  openssl_have_libs=0
+
+  AC_ARG_WITH([openssl], 
+  [APR_HELP_STRING([--with-openssl=DIR], [specify location of OpenSSL])],
+  [
+    if test "$withval" = "yes"; 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],,-lcrypto))
+      if test "$openssl_have_headers" != "0" && test "$openssl_have_libs" != "0"; then
+        apu_have_openssl=1
+      fi
+    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],,-lcrypto))
+      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],,-lcrypto))
+        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
+
+      AC_CHECK_DECLS([EVP_PKEY_CTX_new], [], [],
+                     [#include <openssl/evp.h>])
+
+      CPPFLAGS="$old_cppflags"
+      LDFLAGS="$old_ldflags"
+    fi
+  ], [
+    apu_have_openssl=0
+  ])
+
+  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
+    LDADD_crypto_openssl="$openssl_LDFLAGS -lssl -lcrypto"
+    apu_have_crypto=1
+    AC_DEFINE([APU_HAVE_CRYPTO], 1, [Define that we have crypto capability])
+
+    AC_MSG_CHECKING([for const input buffers in OpenSSL])
+    AC_TRY_COMPILE([#include <openssl/rsa.h>],
+        [ const unsigned char * buf;
+          unsigned char * outbuf;
+          RSA rsa;
+
+                RSA_private_decrypt(1,
+                                                        buf,
+                                                        outbuf,
+                                                        &rsa,
+                                                        RSA_PKCS1_PADDING);
+
+        ],
+        [AC_MSG_RESULT([yes])]
+        [AC_DEFINE([CRYPTO_OPENSSL_CONST_BUFFERS], 1, [Define that OpenSSL uses const buffers])],
+        [AC_MSG_RESULT([no])])
+
+  fi  
+  AC_SUBST(LDADD_crypto_openssl)
+
+  LIBS="$old_libs"
+  CPPFLAGS="$old_cppflags"
+  LDFLAGS="$old_ldflags"
+])
+
+AC_DEFUN([APU_CHECK_CRYPTO_NSS], [
+  apu_have_nss=0
+  nss_have_headers=0
+  nss_have_libs=0
+
+  AC_ARG_WITH([nss], 
+  [APR_HELP_STRING([--with-nss=DIR], [specify location of OpenSSL])],
+  [
+    if test "$withval" = "yes"; then
+      AC_CHECK_HEADERS(nspr/nspr.h nss/nss.h, [nss_have_headers=1])
+      AC_CHECK_LIB(nspr4, PR_Initialize, AC_CHECK_LIB(nss3, PK11_CreatePBEV2AlgorithmID, [nss_have_libs=1],,-lnspr4))
+      if test "$nss_have_headers" != "0" && test "$nss_have_libs" != "0"; then
+        apu_have_nss=1
+      fi
+    elif test "$withval" = "no"; then
+      apu_have_nss=0
+    elif test "x$withval" != "x"; then
+      old_cppflags="$CPPFLAGS"
+      old_ldflags="$LDFLAGS"
+
+      nss_CPPFLAGS="-I$withval/include -I$withval/../public"
+      nss_LDFLAGS="-L$withval/lib "
+
+      APR_ADDTO(CPPFLAGS, [$nss_CPPFLAGS])
+      APR_ADDTO(LDFLAGS, [$nss_LDFLAGS])
+
+      AC_MSG_NOTICE(checking for nss in $withval)
+      AC_CHECK_HEADERS(nspr/nspr.h nss/nss.h, [nss_have_headers=1])
+      AC_CHECK_LIB(nspr4, PR_Initialize, AC_CHECK_LIB(nss3, PK11_CreatePBEV2AlgorithmID, [nss_have_libs=1],,-lnspr4))
+      if test "$nss_have_headers" != "0" && test "$nss_have_libs" != "0"; then
+        apu_have_nss=1
+        APR_ADDTO(APRUTIL_LDFLAGS, [-L$withval/lib])
+        APR_ADDTO(APRUTIL_INCLUDES, [-I$withval/include -I$withval/../public])
+      fi
+
+      if test "$apu_have_nss" != "1"; then
+        AC_CHECK_HEADERS(nspr/nspr.h nss/nss.h, [nss_have_headers=1])
+        AC_CHECK_LIB(nspr4, PR_Initialize, AC_CHECK_LIB(nss3, PK11_CreatePBEV2AlgorithmID, [nss_have_libs=1],,-lnspr4))
+        if test "$nss_have_headers" != "0" && test "$nss_have_libs" != "0"; then
+          apu_have_nss=1
+          APR_ADDTO(APRUTIL_LDFLAGS, [-L$withval/lib])
+          APR_ADDTO(APRUTIL_INCLUDES, [-I$withval/include -I$withval/../public])
+        fi
+      fi
+
+      CPPFLAGS="$old_cppflags"
+      LDFLAGS="$old_ldflags"
+    fi
+  ], [
+    apu_have_nss=0
+  ])
+
+  AC_SUBST(apu_have_nss)
+
+  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_nss" = "1"; then
+    LDADD_crypto_nss="$nss_LDFLAGS -lnspr4 -lnss3"
+    apu_have_crypto=1
+    AC_DEFINE([APU_HAVE_CRYPTO], 1, [Define that we have crypto capability])
+  fi
+  AC_SUBST(LDADD_crypto_nss)
+
+  LIBS="$old_libs"
+  CPPFLAGS="$old_cppflags"
+  LDFLAGS="$old_ldflags"
+])
+dnl

Modified: apr/apr-util/trunk/build/dso.m4
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/build/dso.m4?rev=692949&r1=692948&r2=692949&view=diff
==============================================================================
--- apr/apr-util/trunk/build/dso.m4 (original)
+++ apr/apr-util/trunk/build/dso.m4 Sun Sep  7 13:42:47 2008
@@ -22,12 +22,14 @@
 
   AC_ARG_ENABLE([util-dso], 
      APR_HELP_STRING([--disable-util-dso],
-       [disable DSO build of modular components (dbd, ldap)]))
+       [disable DSO build of modular components (crypto, dbd, ldap)]))
 
   if test "$enable_util_dso" = "no"; then
      # Statically link the DBD drivers:
 
      objs=
+     test $apu_have_openssl = 1 && objs="$objs crypto/apr_crypto_openssl.lo"
+     test $apu_have_nss = 1 && objs="$objs crypto/apr_crypto_nss.lo"
      test $apu_have_oracle = 1 && objs="$objs dbd/apr_dbd_oracle.lo"
      test $apu_have_pgsql = 1 && objs="$objs dbd/apr_dbd_pgsql.lo"
      test $apu_have_mysql = 1 && objs="$objs dbd/apr_dbd_mysql.lo"
@@ -54,14 +56,18 @@
        done
      fi
 
+     APRUTIL_LIBS="$APRUTIL_LIBS $LDADD_crypto_openssl $LDADD_crypto_nss"
      APRUTIL_LIBS="$APRUTIL_LIBS $LDADD_dbd_pgsql $LDADD_dbd_sqlite2 $LDADD_dbd_sqlite3 $LDADD_dbd_oracle $LDADD_dbd_mysql $LDADD_dbd_freetds $LDADD_dbd_odbc"
      APRUTIL_LIBS="$APRUTIL_LIBS $LDADD_ldap"
+     APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_crypto_openssl $LDADD_crypto_nss"
      APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_dbd_pgsql $LDADD_dbd_sqlite2 $LDADD_dbd_sqlite3 $LDADD_dbd_oracle $LDADD_dbd_mysql $LDADD_dbd_freetds $LDADD_dbd_odbc"
      APRUTIL_EXPORT_LIBS="$APRUTIL_EXPORT_LIBS $LDADD_ldap"
   else
      AC_DEFINE([APU_DSO_BUILD], 1, [Define if modular components are built as DSOs])
      
      dsos=
+     test $apu_have_openssl = 1 && dsos="$dsos crypto/apr_crypto_openssl.la"
+     test $apu_have_nss = 1 && dsos="$dsos crypto/apr_crypto_nss.la"
      test $apu_have_oracle = 1 && dsos="$dsos dbd/apr_dbd_oracle.la"
      test $apu_have_pgsql = 1 && dsos="$dsos dbd/apr_dbd_pgsql.la"
      test $apu_have_mysql = 1 && dsos="$dsos dbd/apr_dbd_mysql.la"

Modified: apr/apr-util/trunk/configure.in
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/configure.in?rev=692949&r1=692948&r2=692949&view=diff
==============================================================================
--- apr/apr-util/trunk/configure.in (original)
+++ apr/apr-util/trunk/configure.in Sun Sep  7 13:42:47 2008
@@ -13,6 +13,7 @@
 sinclude(build/apu-hints.m4)
 sinclude(build/apr_common.m4)
 sinclude(build/find_apr.m4)
+sinclude(build/crypto.m4)
 sinclude(build/dbm.m4)
 sinclude(build/dbd.m4)
 sinclude(build/dso.m4)
@@ -149,6 +150,9 @@
 dnl Determine what DBM backend type to use.
 dnl Find Expat
 dnl Find an iconv library
+APU_CHECK_CRYPTO
+APU_CHECK_CRYPTO_OPENSSL
+APU_CHECK_CRYPTO_NSS
 APU_FIND_LDAP
 APU_CHECK_DBM
 APU_CHECK_DBD

Added: apr/apr-util/trunk/crypto/apr_crypto_nss.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/crypto/apr_crypto_nss.c?rev=692949&view=auto
==============================================================================
--- apr/apr-util/trunk/crypto/apr_crypto_nss.c (added)
+++ apr/apr-util/trunk/crypto/apr_crypto_nss.c Sun Sep  7 13:42:47 2008
@@ -0,0 +1,766 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 "apu.h"
+
+#include "apu_config.h"
+#include "apu_errno.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "apr_strings.h"
+#include "apr_time.h"
+#include "apr_buckets.h"
+
+#include "apr_crypto_internal.h"
+
+#if APU_HAVE_CRYPTO
+
+#include <prerror.h>
+#include <nss/nss.h>
+#include <nss/pk11pub.h>
+
+struct apr_crypto_config_t {
+};
+
+struct apr_crypto_key_t {
+    CK_MECHANISM_TYPE cipherMech;
+    SECOidTag cipherOid;
+    PK11SymKey *symKey;
+    int ivSize;
+};
+
+struct apr_crypto_block_t {
+    const apr_crypto_t *factory;
+    apr_pool_t *pool;
+    PK11Context *ctx;
+    apr_crypto_key_t *key;
+    int blockSize;
+};
+
+
+/**
+ * Shutdown the crypto library and release resources.
+ *
+ * It is safe to shut down twice.
+ */
+static apr_status_t crypto_shutdown(apr_pool_t *pool)
+{
+    if (NSS_IsInitialized()) {
+        SECStatus s = NSS_Shutdown();
+        if (s != SECSuccess) {
+            return APR_EINIT;
+        }
+    }
+    return APR_SUCCESS;
+}
+
+static apr_status_t crypto_shutdown_helper(void *data)
+{
+    apr_pool_t *pool = (apr_pool_t *) data;
+    return crypto_shutdown(pool);
+}
+
+/**
+ * Initialise the crypto library and perform one time initialisation.
+ */
+static apr_status_t crypto_init(apr_pool_t *pool, const apr_array_header_t *params)
+{
+    SECStatus s;
+    const char *dir = NULL;
+    const char *keyPrefix = NULL;
+    const char *certPrefix = NULL;
+    const char *secmod = NULL;
+    PRUint32 flags = 0;
+    struct apr_crypto_param_t *ents = params ? (struct apr_crypto_param_t *)params->elts : NULL;
+    int i = 0;
+
+    /* sanity check - we can only initialise NSS once */
+    if (NSS_IsInitialized()) {
+        return APR_EREINIT;
+    }
+
+    apr_pool_cleanup_register(pool, pool,
+                              crypto_shutdown_helper,
+                              apr_pool_cleanup_null);
+
+    for (i = 0; params && i < params->nelts; i++) {
+        switch (ents[i].type) {
+        case APR_CRYPTO_CA_TYPE_DIR:
+            dir = ents[i].path;
+            break;
+        case APR_CRYPTO_CERT_TYPE_KEY3_DB:
+            keyPrefix = ents[i].path;
+            break;
+        case APR_CRYPTO_CA_TYPE_CERT7_DB:
+            certPrefix = ents[i].path;
+            break;
+        case APR_CRYPTO_CA_TYPE_SECMOD:
+            secmod = ents[i].path;
+            break;
+        default:
+            return APR_EINIT;
+        }
+    }
+
+    if (keyPrefix || certPrefix || secmod) {
+        s = NSS_Initialize(dir, certPrefix, keyPrefix, secmod, flags);
+    }
+    else if (dir) {
+        s = NSS_InitReadWrite(dir);
+    }
+    else {
+        s = NSS_NoDB_Init(NULL);
+    }
+    if (s != SECSuccess) {
+        return APR_ECRYPT;
+    }
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Clean encryption / decryption context.
+ * @note After cleanup, a context is free to be reused if necessary.
+ * @param driver - driver to use
+ * @param ctx The block context to use.
+ * @return Returns APR_ENOTIMPL if not supported.
+ */
+static apr_status_t crypto_block_cleanup(apr_crypto_block_t *block)
+{
+
+    if (block->ctx) {
+        PK11_DestroyContext(block->ctx, PR_TRUE);
+        block->ctx = NULL;
+    }
+
+    return APR_SUCCESS;
+
+}
+
+static apr_status_t crypto_block_cleanup_helper(void *data)
+{
+    apr_crypto_block_t *block = (apr_crypto_block_t *) data;
+    return crypto_block_cleanup(block);
+}
+
+/**
+ * @brief Clean encryption / decryption factory.
+ * @note After cleanup, a factory is free to be reused if necessary.
+ * @param driver - driver to use
+ * @param f The factory to use.
+ * @return Returns APR_ENOTIMPL if not supported.
+ */
+static apr_status_t crypto_cleanup(apr_crypto_t *f)
+{
+    apr_crypto_key_t *key;
+    if (f->keys) {
+        while ((key = apr_array_pop(f->keys))) {
+            if (key->symKey) {
+                PK11_FreeSymKey(key->symKey);
+                key->symKey = NULL;
+            }
+        }
+    }
+    return APR_SUCCESS;
+}
+
+static apr_status_t crypto_cleanup_helper(void *data)
+{
+    apr_crypto_t *f = (apr_crypto_t *) data;
+    return crypto_cleanup(f);
+}
+
+/**
+ * @brief Create a context for supporting encryption. Keys, certificates,
+ *        algorithms and other parameters will be set per context. More than
+ *        one context can be created at one time. A cleanup will be automatically
+ *        registered with the given pool to guarantee a graceful shutdown.
+ * @param driver - driver to use
+ * @param pool - process pool
+ * @param params - array of key parameters
+ * @param factory - factory pointer will be written here
+ * @return APR_ENOENGINE when the engine specified does not exist. APR_EINITENGINE
+ * if the engine cannot be initialised.
+ */
+static apr_status_t crypto_factory(apr_pool_t *pool,
+                                   const apr_array_header_t *params,
+                                   apr_crypto_t **factory)
+{
+    apr_crypto_config_t *config = NULL;
+    /* struct apr_crypto_param_t *ents = params ? (struct apr_crypto_param_t *)params->elts : NULL; */
+    /* int i = 0; */
+    apr_crypto_t *f;
+
+    f = apr_pcalloc(pool, sizeof(apr_crypto_t));
+    if (!f) {
+        return APR_ENOMEM;
+    }
+    *factory = f;
+    f->pool = pool;
+    config = f->config = apr_pcalloc(pool, sizeof(apr_crypto_config_t));
+    if (!config) {
+        return APR_ENOMEM;
+    }
+    f->result = apr_pcalloc(pool, sizeof(apu_err_t));
+    if (!f->result) {
+        return APR_ENOMEM;
+    }
+    f->keys = apr_array_make(pool,
+                             10, sizeof(apr_crypto_key_t));
+
+    apr_pool_cleanup_register(pool, f,
+                              crypto_cleanup_helper,
+                              apr_pool_cleanup_null);
+
+    /*
+    for (i = 0; params && i < params->nelts; i++) {
+        switch (ents[i].type) {
+        default:
+            f->result->rc = -1;
+            f->result->reason = "The NSS module currently supports "
+                "no per factory initialisation parameters at this time, but "
+                "may do in future.";
+            return APR_EINIT;
+        }
+    }
+    */
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Create a key from the given passphrase. By default, the PBKDF2
+ *        algorithm is used to generate the key from the passphrase. It is expected
+ *        that the same pass phrase will generate the same key, regardless of the
+ *        backend crypto platform used. The key is cleaned up when the context
+ *        is cleaned, and may be reused with multiple encryption or decryption
+ *        operations.
+ * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
+ *       *key is not NULL, *key must point at a previously created structure.
+ * @param driver - driver to use
+ * @param p The pool to use.
+ * @param f The context to use.
+ * @param pass The passphrase to use.
+ * @param passLen The passphrase length in bytes
+ * @param salt The salt to use.
+ * @param saltLen The salt length in bytes
+ * @param type 3DES_192, AES_128, AES_192, AES_256.
+ * @param mode Electronic Code Book / Cipher Block Chaining.
+ * @param doPad Pad if necessary.
+ * @param key The key returned, see note.
+ * @param ivSize The size of the initialisation vector will be returned, based
+ *               on whether an IV is relevant for this type of crypto.
+ * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
+ *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
+ *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
+ *         not known. APR_EPADDING if padding was requested but is not supported.
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_passphrase(apr_pool_t *p,
+                                      const apr_crypto_t *f,
+                                      const char *pass,
+                                      apr_size_t passLen,
+                                      const unsigned char * salt,
+                                      apr_size_t saltLen,
+                                      const apr_crypto_block_key_type_e type,
+                                      const apr_crypto_block_key_mode_e mode,
+                                      const int doPad,
+                                      const int iterations,
+                                      apr_crypto_key_t **k,
+                                      apr_size_t *ivSize)
+{
+    apr_status_t rv = APR_SUCCESS;
+    PK11SlotInfo * slot;
+    SECItem passItem;
+    SECItem saltItem;
+    SECAlgorithmID *algid;
+    void *wincx = NULL; /* what is wincx? */
+    apr_crypto_key_t *key = *k;
+
+    if (!key) {
+        *k = key = apr_array_push(f->keys);
+    }
+    if (!key) {
+        return APR_ENOMEM;
+    }
+
+    /* decide on what cipher mechanism we will be using */
+    switch (type) {
+
+    case (KEY_3DES_192) :
+        if (MODE_CBC == mode) {
+            key->cipherOid = SEC_OID_DES_EDE3_CBC;
+        }
+        else if (MODE_ECB == mode) {
+            return APR_ENOCIPHER;
+            /* No OID for CKM_DES3_ECB; */
+        }
+        break;
+    case (KEY_AES_128) :
+        if (MODE_CBC == mode) {
+            key->cipherOid = SEC_OID_AES_128_CBC;
+        }
+        else {
+            key->cipherOid = SEC_OID_AES_128_ECB;
+        }
+        break;
+    case (KEY_AES_192) :
+        if (MODE_CBC == mode) {
+            key->cipherOid = SEC_OID_AES_192_CBC;
+        }
+        else {
+            key->cipherOid = SEC_OID_AES_192_ECB;
+        }
+        break;
+    case (KEY_AES_256) :
+        if (MODE_CBC == mode) {
+            key->cipherOid = SEC_OID_AES_256_CBC;
+        }
+        else {
+            key->cipherOid = SEC_OID_AES_256_ECB;
+        }
+        break;
+    default:
+        /* unknown key type, give up */
+        return APR_EKEYTYPE;
+    }
+
+    /* AES_128_CBC --> CKM_AES_CBC --> CKM_AES_CBC_PAD */
+    key->cipherMech = PK11_AlgtagToMechanism(key->cipherOid);
+    if (key->cipherMech == CKM_INVALID_MECHANISM) {
+        return APR_ENOCIPHER;
+    }
+    if (doPad) {
+        CK_MECHANISM_TYPE paddedMech;
+        paddedMech = PK11_GetPadMechanism(key->cipherMech);
+        if (CKM_INVALID_MECHANISM == paddedMech || key->cipherMech == paddedMech) {
+            return APR_EPADDING;
+        }
+        key->cipherMech = paddedMech;
+    }
+
+    /* Turn the raw passphrase and salt into SECItems */
+    passItem.data = (unsigned char*)pass;
+    passItem.len = passLen;
+    saltItem.data = (unsigned char*)salt;
+    saltItem.len = saltLen;
+
+    /* generate the key */
+    /* pbeAlg and cipherAlg are the same. NSS decides the keylength. */
+    algid = PK11_CreatePBEV2AlgorithmID(key->cipherOid, key->cipherOid, SEC_OID_HMAC_SHA1, 0, iterations, &saltItem);
+    if (algid) {
+        slot = PK11_GetBestSlot(key->cipherMech, wincx);
+        if (slot) {
+            key->symKey = PK11_PBEKeyGen(slot, algid, &passItem, PR_FALSE, wincx);
+            PK11_FreeSlot(slot);
+        }
+        SECOID_DestroyAlgorithmID(algid, PR_TRUE);
+    }
+
+    /* sanity check? */
+    if (!key->symKey) {
+        PRErrorCode perr = PORT_GetError();
+        if (perr) {
+            f->result->rc = perr;
+            f->result->msg = PR_ErrorToName(perr);
+            rv = APR_ENOKEY;
+        }
+    }
+
+    key->ivSize = PK11_GetIVLength(key->cipherMech);
+    if (ivSize) {
+    *ivSize = key->ivSize;
+    }
+
+    return rv;
+}
+
+/**
+ * @brief Initialise a context for encrypting arbitrary data using the given key.
+ * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If
+ *       *ctx is not NULL, *ctx must point at a previously created structure.
+ * @param p The pool to use.
+ * @param f The block factory to use.
+ * @param key The key structure.
+ * @param iv Optional initialisation vector. If the buffer pointed to is NULL,
+ *           an IV will be created at random, in space allocated from the pool.
+ *           If the buffer pointed to is not NULL, the IV in the buffer will be
+ *           used.
+ * @param ctx The block context returned, see note.
+ * @param blockSize The block size of the cipher.
+ * @return Returns APR_ENOIV if an initialisation vector is required but not specified.
+ *         Returns APR_EINIT if the backend failed to initialise the context. Returns
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_block_encrypt_init(apr_pool_t *p,
+                                              const apr_crypto_t *f,
+                                              const apr_crypto_key_t *key,
+                                              const unsigned char **iv,
+                                              apr_crypto_block_t **ctx,
+                                              apr_size_t *blockSize)
+{
+    PRErrorCode perr;
+    SECItem * secParam;
+    int usedIvSize;
+    SECItem ivItem;
+    unsigned char * usedIv;
+    apr_crypto_block_t *block = *ctx;
+    if (!block) {
+        *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t));
+    }
+    if (!block) {
+        return APR_ENOMEM;
+    }
+    block->factory = f;
+    block->pool = p;
+
+    apr_pool_cleanup_register(p, block,
+                              crypto_block_cleanup_helper,
+                              apr_pool_cleanup_null);
+
+    if (key->ivSize) {
+        if (iv == NULL) {
+            return APR_ENOIV;
+        }
+        if (*iv == NULL) {
+            usedIv = apr_pcalloc(p, key->ivSize);
+            if (!usedIv) {
+                return APR_ENOMEM;
+            }
+            SECStatus s = PK11_GenerateRandom(usedIv, key->ivSize);
+            if (s != SECSuccess) {
+                return APR_ENOIV;
+            }
+            *iv = usedIv;
+        }
+        else {
+             usedIv = (unsigned char *)*iv;
+        }
+        ivItem.data = usedIv;
+        ivItem.len = usedIvSize;
+        secParam = PK11_ParamFromIV(key->cipherMech, &ivItem);
+    }
+    else {
+        secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey);
+    }
+    block->blockSize = PK11_GetBlockSize(key->cipherMech, secParam);
+    block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_ENCRYPT, key->symKey, secParam);
+
+    /* did an error occur? */
+    perr = PORT_GetError();
+    if (perr || !block->ctx) {
+        f->result->rc = perr;
+        f->result->msg = PR_ErrorToName(perr);
+        return APR_EINIT;
+    }
+
+    if (blockSize) {
+    *blockSize = PK11_GetBlockSize(key->cipherMech, secParam);
+    }
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Encrypt data provided by in, write it to out.
+ * @note The number of bytes written will be written to outlen. If
+ *       out is NULL, outlen will contain the maximum size of the
+ *       buffer needed to hold the data, including any data
+ *       generated by apr_crypto_block_encrypt_finish below. If *out points
+ *       to NULL, a buffer sufficiently large will be created from
+ *       the pool provided. If *out points to a not-NULL value, this
+ *       value will be used as a buffer instead.
+ * @param ctx The block context to use.
+ * @param out Address of a buffer to which data will be written,
+ *        see note.
+ * @param outlen Length of the output will be written here.
+ * @param in Address of the buffer to read.
+ * @param inlen Length of the buffer to read.
+ * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if
+ *         not implemented.
+ */
+static apr_status_t crypto_block_encrypt(apr_crypto_block_t *block,
+                                         unsigned char **out,
+                                         apr_size_t *outlen,
+                                         const unsigned char *in,
+                                         apr_size_t inlen)
+{
+
+    unsigned char *buffer;
+    int outl = (int) *outlen;
+    if (!out) {
+        *outlen = inlen + block->blockSize;
+        return APR_SUCCESS;
+    }
+    if (!*out) {
+        buffer = apr_palloc(block->pool, inlen + block->blockSize);
+        if (!buffer) {
+            return APR_ENOMEM;
+        }
+        *out = buffer;
+    }
+
+    SECStatus s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*)in, inlen);
+    if (s != SECSuccess) {
+        PRErrorCode perr = PORT_GetError();
+        if (perr) {
+            block->factory->result->rc = perr;
+            block->factory->result->msg = PR_ErrorToName(perr);
+        }
+        return APR_ECRYPT;
+    }
+    *outlen = outl;
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Encrypt final data block, write it to out.
+ * @note If necessary the final block will be written out after being
+ *       padded. Typically the final block will be written to the
+ *       same buffer used by apr_crypto_block_encrypt, offset by the
+ *       number of bytes returned as actually written by the
+ *       apr_crypto_block_encrypt() call. After this call, the context
+ *       is cleaned and can be reused by apr_crypto_block_encrypt_init().
+ * @param ctx The block context to use.
+ * @param out Address of a buffer to which data will be written. This
+ *            buffer must already exist, and is usually the same
+ *            buffer used by apr_evp_crypt(). See note.
+ * @param outlen Length of the output will be written here.
+ * @return APR_ECRYPT if an error occurred.
+ * @return APR_EPADDING if padding was enabled and the block was incorrectly
+ *         formatted.
+ * @return APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_block_encrypt_finish(apr_crypto_block_t *block,
+                                                unsigned char *out,
+                                                apr_size_t *outlen)
+{
+
+    apr_status_t rv = APR_SUCCESS;
+    unsigned int outl = *outlen;
+
+    SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize);
+    *outlen = outl;
+
+    if (s != SECSuccess) {
+        PRErrorCode perr = PORT_GetError();
+        if (perr) {
+            block->factory->result->rc = perr;
+            block->factory->result->msg = PR_ErrorToName(perr);
+        }
+        rv = APR_ECRYPT;
+    }
+    crypto_block_cleanup(block);
+
+    return rv;
+
+}
+
+/**
+ * @brief Initialise a context for decrypting arbitrary data using the given key.
+ * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If
+ *       *ctx is not NULL, *ctx must point at a previously created structure.
+ * @param p The pool to use.
+ * @param f The block factory to use.
+ * @param key The key structure.
+ * @param iv Optional initialisation vector. If the buffer pointed to is NULL,
+ *           an IV will be created at random, in space allocated from the pool.
+ *           If the buffer pointed to is not NULL, the IV in the buffer will be
+ *           used.
+ * @param ctx The block context returned, see note.
+ * @param blockSize The block size of the cipher.
+ * @return Returns APR_ENOIV if an initialisation vector is required but not specified.
+ *         Returns APR_EINIT if the backend failed to initialise the context. Returns
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_block_decrypt_init(apr_pool_t *p,
+                                              const apr_crypto_t *f,
+                                              const apr_crypto_key_t *key,
+                                              const unsigned char *iv,
+                                              apr_crypto_block_t **ctx,
+                                              apr_size_t *blockSize)
+{
+    PRErrorCode perr;
+    SECItem * secParam;
+    apr_crypto_block_t *block = *ctx;
+    if (!block) {
+        *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t));
+    }
+    if (!block) {
+        return APR_ENOMEM;
+    }
+    block->factory = f;
+    block->pool = p;
+
+    apr_pool_cleanup_register(p, block,
+                              crypto_block_cleanup_helper,
+                              apr_pool_cleanup_null);
+
+    if (key->ivSize) {
+        SECItem ivItem;
+        if (iv == NULL) {
+            return APR_ENOIV; /* Cannot initialise without an IV */
+        }
+        ivItem.data = (unsigned char*)iv;
+        ivItem.len = key->ivSize;
+        secParam = PK11_ParamFromIV(key->cipherMech, &ivItem);
+    }
+    else {
+        secParam = PK11_GenerateNewParam(key->cipherMech, key->symKey);
+    }
+    block->blockSize = PK11_GetBlockSize(key->cipherMech, secParam);
+    block->ctx = PK11_CreateContextBySymKey(key->cipherMech, CKA_DECRYPT, key->symKey, secParam);
+
+    /* did an error occur? */
+    perr = PORT_GetError();
+    if (perr || !block->ctx) {
+        f->result->rc = perr;
+        f->result->msg = PR_ErrorToName(perr);
+        return APR_EINIT;
+    }
+
+    if (blockSize) {
+        *blockSize = PK11_GetBlockSize(key->cipherMech, secParam);
+    }
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Decrypt data provided by in, write it to out.
+ * @note The number of bytes written will be written to outlen. If
+ *       out is NULL, outlen will contain the maximum size of the
+ *       buffer needed to hold the data, including any data
+ *       generated by apr_crypto_block_final below. If *out points
+ *       to NULL, a buffer sufficiently large will be created from
+ *       the pool provided. If *out points to a not-NULL value, this
+ *       value will be used as a buffer instead.
+ * @param ctx The block context to use.
+ * @param out Address of a buffer to which data will be written,
+ *        see note.
+ * @param outlen Length of the output will be written here.
+ * @param in Address of the buffer to read.
+ * @param inlen Length of the buffer to read.
+ * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if
+ *         not implemented.
+ */
+static apr_status_t crypto_block_decrypt(apr_crypto_block_t *block,
+                                         unsigned char **out,
+                                         apr_size_t *outlen,
+                                         const unsigned char *in,
+                                         apr_size_t inlen)
+{
+
+    unsigned char *buffer;
+    int outl = (int) *outlen;
+    if (!out) {
+        *outlen = inlen + block->blockSize;
+        return APR_SUCCESS;
+    }
+    if (!*out) {
+        buffer = apr_palloc(block->pool, inlen + block->blockSize);
+        if (!buffer) {
+            return APR_ENOMEM;
+        }
+        *out = buffer;
+    }
+
+    SECStatus s = PK11_CipherOp(block->ctx, *out, &outl, inlen, (unsigned char*)in, inlen);
+    if (s != SECSuccess) {
+        PRErrorCode perr = PORT_GetError();
+        if (perr) {
+            block->factory->result->rc = perr;
+            block->factory->result->msg = PR_ErrorToName(perr);
+        }
+        return APR_ECRYPT;
+    }
+    *outlen = outl;
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Encrypt final data block, write it to out.
+ * @note If necessary the final block will be written out after being
+ *       padded. Typically the final block will be written to the
+ *       same buffer used by apr_evp_crypt, offset by the number of
+ *       bytes returned as actually written by the apr_evp_crypt()
+ *       call. After this call, the context is cleaned and can be
+ *       reused by apr_env_encrypt_init() or apr_env_decrypt_init().
+ * @param ctx The block context to use.
+ * @param out Address of a buffer to which data will be written. This
+ *            buffer must already exist, and is usually the same
+ *            buffer used by apr_evp_crypt(). See note.
+ * @param outlen Length of the output will be written here.
+ * @return APR_ECRYPT if an error occurred.
+ * @return APR_EPADDING if padding was enabled and the block was incorrectly
+ *         formatted.
+ * @return APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_block_decrypt_finish(apr_crypto_block_t *block,
+                                                unsigned char *out,
+                                                apr_size_t *outlen)
+{
+
+    apr_status_t rv = APR_SUCCESS;
+    unsigned int outl = *outlen;
+
+    SECStatus s = PK11_DigestFinal(block->ctx, out, &outl, block->blockSize);
+    *outlen = outl;
+
+    if (s != SECSuccess) {
+        PRErrorCode perr = PORT_GetError();
+        if (perr) {
+            block->factory->result->rc = perr;
+            block->factory->result->msg = PR_ErrorToName(perr);
+        }
+        rv = APR_ECRYPT;
+    }
+    crypto_block_cleanup(block);
+
+    return rv;
+
+}
+
+/**
+ * OpenSSL module.
+ */
+APU_MODULE_DECLARE_DATA const apr_crypto_driver_t apr_crypto_nss_driver = {
+    "nss",
+    crypto_init,
+    crypto_factory,
+    crypto_passphrase,
+    crypto_block_encrypt_init,
+    crypto_block_encrypt,
+    crypto_block_encrypt_finish,
+    crypto_block_decrypt_init,
+    crypto_block_decrypt,
+    crypto_block_decrypt_finish,
+    crypto_block_cleanup,
+    crypto_cleanup,
+    crypto_shutdown
+};
+
+#endif

Added: apr/apr-util/trunk/crypto/apr_crypto_openssl.c
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/crypto/apr_crypto_openssl.c?rev=692949&view=auto
==============================================================================
--- apr/apr-util/trunk/crypto/apr_crypto_openssl.c (added)
+++ apr/apr-util/trunk/crypto/apr_crypto_openssl.c Sun Sep  7 13:42:47 2008
@@ -0,0 +1,649 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 "apu.h"
+
+#include "apu_config.h"
+#include "apu_errno.h"
+
+#include <ctype.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "apr_strings.h"
+#include "apr_time.h"
+#include "apr_buckets.h"
+
+#include "apr_crypto_internal.h"
+
+#if APU_HAVE_CRYPTO
+
+#include <openssl/evp.h>
+#include <openssl/engine.h>
+
+#define LOG_PREFIX "apr_crypto_openssl: "
+
+struct apr_crypto_config_t {
+    ENGINE *engine;
+};
+
+struct apr_crypto_key_t {
+    const EVP_CIPHER * cipher;
+    unsigned char *key;
+    int keyLen;
+    int doPad;
+    int ivSize;
+};
+
+struct apr_crypto_block_t {
+    const apr_crypto_t *factory;
+    apr_pool_t *pool;
+    EVP_CIPHER_CTX cipherCtx;
+    int initialised;
+    int ivSize;
+    int blockSize;
+    int doPad;
+};
+
+/**
+ * Shutdown the crypto library and release resources.
+ */
+static apr_status_t crypto_shutdown(apr_pool_t *pool) {
+    ERR_free_strings();
+    EVP_cleanup();
+    ENGINE_cleanup();
+    return APR_SUCCESS;
+}
+
+static apr_status_t crypto_shutdown_helper(void *data) {
+    apr_pool_t *pool = (apr_pool_t *) data;
+    return crypto_shutdown(pool);
+}
+
+/**
+ * Initialise the crypto library and perform one time initialisation.
+ */
+static apr_status_t crypto_init(apr_pool_t *pool,
+        const apr_array_header_t *params) {
+    CRYPTO_malloc_init();
+    ERR_load_crypto_strings();
+    /* SSL_load_error_strings(); */
+    OpenSSL_add_all_algorithms();
+    ENGINE_load_builtin_engines();
+    ENGINE_register_all_complete();
+
+    apr_pool_cleanup_register(pool, pool, crypto_shutdown_helper,
+            apr_pool_cleanup_null);
+
+    return APR_SUCCESS;
+}
+
+/**
+ * @brief Clean encryption / decryption context.
+ * @note After cleanup, a context is free to be reused if necessary.
+ * @param driver - driver to use
+ * @param ctx The block context to use.
+ * @return Returns APR_ENOTIMPL if not supported.
+ */
+static apr_status_t crypto_block_cleanup(apr_crypto_block_t *ctx) {
+
+    if (ctx->initialised) {
+        EVP_CIPHER_CTX_cleanup(&ctx->cipherCtx);
+        ctx->initialised = 0;
+    }
+
+    return APR_SUCCESS;
+
+}
+
+static apr_status_t crypto_block_cleanup_helper(void *data) {
+    apr_crypto_block_t *block = (apr_crypto_block_t *) data;
+    return crypto_block_cleanup(block);
+}
+
+/**
+ * @brief Clean encryption / decryption factory.
+ * @note After cleanup, a factory is free to be reused if necessary.
+ * @param driver - driver to use
+ * @param f The factory to use.
+ * @return Returns APR_ENOTIMPL if not supported.
+ */
+static apr_status_t crypto_cleanup(apr_crypto_t *f) {
+
+    if (f->config->engine) {
+        ENGINE_finish(f->config->engine);
+        ENGINE_free(f->config->engine);
+        f->config->engine = NULL;
+    }
+    return APR_SUCCESS;
+
+}
+
+static apr_status_t crypto_cleanup_helper(void *data) {
+    apr_crypto_t *f = (apr_crypto_t *) data;
+    return crypto_cleanup(f);
+}
+
+/**
+ * @brief Create a context for supporting encryption. Keys, certificates,
+ *        algorithms and other parameters will be set per context. More than
+ *        one context can be created at one time. A cleanup will be automatically
+ *        registered with the given pool to guarantee a graceful shutdown.
+ * @param driver - driver to use
+ * @param pool - process pool
+ * @param params - array of key parameters
+ * @param factory - factory pointer will be written here
+ * @return APR_ENOENGINE when the engine specified does not exist. APR_EINITENGINE
+ * if the engine cannot be initialised.
+ */
+static apr_status_t crypto_factory(apr_pool_t *pool,
+        const apr_array_header_t *params, apr_crypto_t **factory) {
+    apr_crypto_config_t *config = NULL;
+    struct apr_crypto_param_t *ents =
+            params ? (struct apr_crypto_param_t *) params->elts : NULL;
+    int i = 0;
+    apr_crypto_t *f = apr_pcalloc(pool, sizeof(apr_crypto_t));
+    if (!f) {
+        return APR_ENOMEM;
+    }
+    *factory = f;
+    f->pool = pool;
+    config = f->config = apr_pcalloc(pool, sizeof(apr_crypto_config_t));
+    if (!config) {
+        return APR_ENOMEM;
+    }
+    f->result = apr_pcalloc(pool, sizeof(apu_err_t));
+    if (!f->result) {
+        return APR_ENOMEM;
+    }
+    f->keys = apr_array_make(pool, 10, sizeof(apr_crypto_key_t));
+
+    apr_pool_cleanup_register(pool, f, crypto_cleanup_helper,
+            apr_pool_cleanup_null);
+
+    for (i = 0; params && i < params->nelts; i++) {
+        switch (ents[i].type) {
+        case APR_CRYPTO_ENGINE:
+            config->engine = ENGINE_by_id(ents[i].path);
+            if (!config->engine) {
+                return APR_ENOENGINE;
+            }
+            if (!ENGINE_init(config->engine)) {
+                ENGINE_free(config->engine);
+                config->engine = NULL;
+                return APR_EINITENGINE;
+            }
+            break;
+        }
+    }
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Create a key from the given passphrase. By default, the PBKDF2
+ *        algorithm is used to generate the key from the passphrase. It is expected
+ *        that the same pass phrase will generate the same key, regardless of the
+ *        backend crypto platform used. The key is cleaned up when the context
+ *        is cleaned, and may be reused with multiple encryption or decryption
+ *        operations.
+ * @note If *key is NULL, a apr_crypto_key_t will be created from a pool. If
+ *       *key is not NULL, *key must point at a previously created structure.
+ * @param driver - driver to use
+ * @param p The pool to use.
+ * @param f The context to use.
+ * @param pass The passphrase to use.
+ * @param passLen The passphrase length in bytes
+ * @param salt The salt to use.
+ * @param saltLen The salt length in bytes
+ * @param type 3DES_192, AES_128, AES_192, AES_256.
+ * @param mode Electronic Code Book / Cipher Block Chaining.
+ * @param doPad Pad if necessary.
+ * @param key The key returned, see note.
+ * @param ivSize The size of the initialisation vector will be returned, based
+ *               on whether an IV is relevant for this type of crypto.
+ * @return Returns APR_ENOKEY if the pass phrase is missing or empty, or if a backend
+ *         error occurred while generating the key. APR_ENOCIPHER if the type or mode
+ *         is not supported by the particular backend. APR_EKEYTYPE if the key type is
+ *         not known. APR_EPADDING if padding was requested but is not supported.
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_passphrase(apr_pool_t *p, const apr_crypto_t *f,
+        const char *pass, apr_size_t passLen, const unsigned char * salt,
+        apr_size_t saltLen, const apr_crypto_block_key_type_e type,
+        const apr_crypto_block_key_mode_e mode, const int doPad,
+        const int iterations, apr_crypto_key_t **k, apr_size_t *ivSize) {
+    apr_crypto_key_t *key = *k;
+
+    if (!key) {
+        *k = key = apr_array_push(f->keys);
+    }
+    if (!key) {
+        return APR_ENOMEM;
+    }
+
+    /* determine the cipher to be used */
+    switch (type) {
+
+    case (KEY_3DES_192):
+
+        /* A 3DES key */
+        if (mode == MODE_CBC) {
+            key->cipher = EVP_des_ede3_cbc();
+        } else {
+            key->cipher = EVP_des_ede3_ecb();
+        }
+        break;
+
+    case (KEY_AES_128):
+
+        if (mode == MODE_CBC) {
+            key->cipher = EVP_aes_128_cbc();
+        } else {
+            key->cipher = EVP_aes_128_ecb();
+        }
+        break;
+
+    case (KEY_AES_192):
+
+        if (mode == MODE_CBC) {
+            key->cipher = EVP_aes_192_cbc();
+        } else {
+            key->cipher = EVP_aes_192_ecb();
+        }
+        break;
+
+    case (KEY_AES_256):
+
+        if (mode == MODE_CBC) {
+            key->cipher = EVP_aes_256_cbc();
+        } else {
+            key->cipher = EVP_aes_256_ecb();
+        }
+        break;
+
+    default:
+
+        /* unknown key type, give up */
+        return APR_EKEYTYPE;
+
+    }
+
+    /* find the length of the key we need */
+    key->keyLen = EVP_CIPHER_key_length(key->cipher);
+
+    /* make space for the key */
+    key->key = apr_pcalloc(p, key->keyLen);
+    if (!key->key) {
+        return APR_ENOMEM;
+    }
+
+    /* generate the key */
+    if (PKCS5_PBKDF2_HMAC_SHA1(pass, passLen, (unsigned char *) salt, saltLen,
+            iterations, key->keyLen, key->key) == 0) {
+        return APR_ENOKEY;
+    }
+
+    key->doPad = doPad;
+
+    /* note: openssl incorrectly returns non zero IV size values for ECB
+     * algorithms, so work around this by ignoring the IV size.
+     */
+    if (MODE_ECB != mode) {
+        key->ivSize = EVP_CIPHER_iv_length(key->cipher);
+    }
+    if (ivSize) {
+        *ivSize = key->ivSize;
+    }
+
+    return APR_SUCCESS;
+}
+
+/**
+ * @brief Initialise a context for encrypting arbitrary data using the given key.
+ * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If
+ *       *ctx is not NULL, *ctx must point at a previously created structure.
+ * @param p The pool to use.
+ * @param f The block factory to use.
+ * @param type 3DES_192, AES_128, AES_192, AES_256.
+ * @param mode Electronic Code Book / Cipher Block Chaining.
+ * @param key The key
+ * @param keyLen The key length in bytes
+ * @param iv Optional initialisation vector.
+ * @param doPad Pad if necessary.
+ * @param ctx The block context returned, see note.
+ * @param blockSize The block size of the cipher.
+ * @return Returns APR_ENOIV if an initialisation vector is required but not specified.
+ *         Returns APR_EINIT if the backend failed to initialise the context. Returns
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_block_encrypt_init(apr_pool_t *p,
+        const apr_crypto_t *f, const apr_crypto_key_t *key,
+        const unsigned char **iv, apr_crypto_block_t **ctx,
+        apr_size_t *blockSize) {
+    unsigned char *usedIv;
+    apr_crypto_config_t *config = f->config;
+    apr_crypto_block_t *block = *ctx;
+    if (!block) {
+        *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t));
+    }
+    if (!block) {
+        return APR_ENOMEM;
+    }
+    block->factory = f;
+    block->pool = p;
+
+    apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper,
+            apr_pool_cleanup_null);
+
+    /* create a new context for encryption */
+    EVP_CIPHER_CTX_init(&block->cipherCtx);
+    block->initialised = 1;
+
+    /* generate an IV, if necessary */
+    usedIv = NULL;
+    if (key->ivSize) {
+        if (iv == NULL) {
+            return APR_ENOIV;
+        }
+        if (*iv == NULL) {
+            usedIv = apr_pcalloc(p, key->ivSize);
+            if (!usedIv) {
+                return APR_ENOMEM;
+            }
+            if (!((RAND_status() == 1)
+                    && (RAND_bytes(usedIv, key->ivSize) == 1))) {
+                return APR_ENOIV;
+            }
+            *iv = usedIv;
+        } else {
+            usedIv = (unsigned char *) *iv;
+        }
+    }
+
+    /* set up our encryption context */
+#if CRYPTO_OPENSSL_CONST_BUFFERS
+    if (!EVP_EncryptInit_ex(&block->cipherCtx, key->cipher, config->engine,
+            key->key, usedIv)) {
+#else
+        if (!EVP_EncryptInit_ex(&block->cipherCtx, key->cipher, config->engine, (unsigned char *) key->key, (unsigned char *) usedIv)) {
+#endif
+        return APR_EINIT;
+    }
+
+    /* Clear up any read padding */
+    if (!EVP_CIPHER_CTX_set_padding(&block->cipherCtx, key->doPad)) {
+        return APR_EPADDING;
+    }
+
+    if (blockSize) {
+        *blockSize = EVP_CIPHER_block_size(key->cipher);
+    }
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Encrypt data provided by in, write it to out.
+ * @note The number of bytes written will be written to outlen. If
+ *       out is NULL, outlen will contain the maximum size of the
+ *       buffer needed to hold the data, including any data
+ *       generated by apr_crypto_block_encrypt_finish below. If *out points
+ *       to NULL, a buffer sufficiently large will be created from
+ *       the pool provided. If *out points to a not-NULL value, this
+ *       value will be used as a buffer instead.
+ * @param ctx The block context to use.
+ * @param out Address of a buffer to which data will be written,
+ *        see note.
+ * @param outlen Length of the output will be written here.
+ * @param in Address of the buffer to read.
+ * @param inlen Length of the buffer to read.
+ * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if
+ *         not implemented.
+ */
+static apr_status_t crypto_block_encrypt(apr_crypto_block_t *ctx,
+        unsigned char **out, apr_size_t *outlen, const unsigned char *in,
+        apr_size_t inlen) {
+    int outl = *outlen;
+    unsigned char *buffer;
+
+    /* are we after the maximum size of the out buffer? */
+    if (!out) {
+        *outlen = inlen + EVP_MAX_BLOCK_LENGTH;
+        return APR_SUCCESS;
+    }
+
+    /* must we allocate the output buffer from a pool? */
+    if (!*out) {
+        buffer = apr_palloc(ctx->pool, inlen + EVP_MAX_BLOCK_LENGTH);
+        if (!buffer) {
+            return APR_ENOMEM;
+        }
+        *out = buffer;
+    }
+
+#if CRYPT_OPENSSL_CONST_BUFFERS
+    if (!EVP_EncryptUpdate(&ctx->cipherCtx, (*out), &outl, in, inlen)) {
+#else
+    if (!EVP_EncryptUpdate(&ctx->cipherCtx, (*out), &outl,
+            (unsigned char *) in, inlen)) {
+#endif
+        return APR_ECRYPT;
+    }
+    *outlen = outl;
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Encrypt final data block, write it to out.
+ * @note If necessary the final block will be written out after being
+ *       padded. Typically the final block will be written to the
+ *       same buffer used by apr_crypto_block_encrypt, offset by the
+ *       number of bytes returned as actually written by the
+ *       apr_crypto_block_encrypt() call. After this call, the context
+ *       is cleaned and can be reused by apr_crypto_block_encrypt_init().
+ * @param ctx The block context to use.
+ * @param out Address of a buffer to which data will be written. This
+ *            buffer must already exist, and is usually the same
+ *            buffer used by apr_evp_crypt(). See note.
+ * @param outlen Length of the output will be written here.
+ * @return APR_ECRYPT if an error occurred.
+ * @return APR_EPADDING if padding was enabled and the block was incorrectly
+ *         formatted.
+ * @return APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_block_encrypt_finish(apr_crypto_block_t *ctx,
+        unsigned char *out, apr_size_t *outlen) {
+    int len = *outlen;
+
+    if (EVP_EncryptFinal_ex(&ctx->cipherCtx, out, &len) == 0) {
+        return APR_EPADDING;
+    }
+    *outlen = len;
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Initialise a context for decrypting arbitrary data using the given key.
+ * @note If *ctx is NULL, a apr_crypto_block_t will be created from a pool. If
+ *       *ctx is not NULL, *ctx must point at a previously created structure.
+ * @param p The pool to use.
+ * @param f The block factory to use.
+ * @param key The key structure.
+ * @param iv Optional initialisation vector. If the buffer pointed to is NULL,
+ *           an IV will be created at random, in space allocated from the pool.
+ *           If the buffer is not NULL, the IV in the buffer will be used.
+ * @param ctx The block context returned, see note.
+ * @param blockSize The block size of the cipher.
+ * @return Returns APR_ENOIV if an initialisation vector is required but not specified.
+ *         Returns APR_EINIT if the backend failed to initialise the context. Returns
+ *         APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_block_decrypt_init(apr_pool_t *p,
+        const apr_crypto_t *f, const apr_crypto_key_t *key,
+        const unsigned char *iv, apr_crypto_block_t **ctx,
+        apr_size_t *blockSize) {
+    apr_crypto_config_t *config = f->config;
+    apr_crypto_block_t *block = *ctx;
+    if (!block) {
+        *ctx = block = apr_pcalloc(p, sizeof(apr_crypto_block_t));
+    }
+    if (!block) {
+        return APR_ENOMEM;
+    }
+    block->factory = f;
+    block->pool = p;
+
+    apr_pool_cleanup_register(p, block, crypto_block_cleanup_helper,
+            apr_pool_cleanup_null);
+
+    /* create a new context for encryption */
+    EVP_CIPHER_CTX_init(&block->cipherCtx);
+    block->initialised = 1;
+
+    /* generate an IV, if necessary */
+    if (key->ivSize) {
+        if (iv == NULL) {
+            return APR_ENOIV;
+        }
+    }
+
+    /* set up our encryption context */
+#if CRYPTO_OPENSSL_CONST_BUFFERS
+    if (!EVP_DecryptInit_ex(&block->cipherCtx, key->cipher, config->engine,
+            key->key, iv)) {
+#else
+        if (!EVP_DecryptInit_ex(&block->cipherCtx, key->cipher, config->engine, (unsigned char *) key->key, (unsigned char *) iv)) {
+#endif
+        return APR_EINIT;
+    }
+
+    /* Clear up any read padding */
+    if (!EVP_CIPHER_CTX_set_padding(&block->cipherCtx, key->doPad)) {
+        return APR_EPADDING;
+    }
+
+    if (blockSize) {
+        *blockSize = EVP_CIPHER_block_size(key->cipher);
+    }
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Decrypt data provided by in, write it to out.
+ * @note The number of bytes written will be written to outlen. If
+ *       out is NULL, outlen will contain the maximum size of the
+ *       buffer needed to hold the data, including any data
+ *       generated by apr_crypto_block_final below. If *out points
+ *       to NULL, a buffer sufficiently large will be created from
+ *       the pool provided. If *out points to a not-NULL value, this
+ *       value will be used as a buffer instead.
+ * @param ctx The block context to use.
+ * @param out Address of a buffer to which data will be written,
+ *        see note.
+ * @param outlen Length of the output will be written here.
+ * @param in Address of the buffer to read.
+ * @param inlen Length of the buffer to read.
+ * @return APR_ECRYPT if an error occurred. Returns APR_ENOTIMPL if
+ *         not implemented.
+ */
+static apr_status_t crypto_block_decrypt(apr_crypto_block_t *ctx,
+        unsigned char **out, apr_size_t *outlen, const unsigned char *in,
+        apr_size_t inlen) {
+
+    int outl = *outlen;
+    unsigned char *buffer;
+
+    /* are we after the maximum size of the out buffer? */
+    if (!out) {
+        *outlen = inlen + EVP_MAX_BLOCK_LENGTH;
+        return APR_SUCCESS;
+    }
+
+    /* must we allocate the output buffer from a pool? */
+    if (!(*out)) {
+        buffer = apr_palloc(ctx->pool, inlen + EVP_MAX_BLOCK_LENGTH);
+        if (!buffer) {
+            return APR_ENOMEM;
+        }
+        *out = buffer;
+    }
+
+#if CRYPT_OPENSSL_CONST_BUFFERS
+    if (!EVP_DecryptUpdate(&ctx->cipherCtx, *out, &outl, in, inlen)) {
+#else
+    if (!EVP_DecryptUpdate(&ctx->cipherCtx, *out, &outl, (unsigned char *) in,
+            inlen)) {
+#endif
+        return APR_ECRYPT;
+    }
+    *outlen = outl;
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * @brief Decrypt final data block, write it to out.
+ * @note If necessary the final block will be written out after being
+ *       padded. Typically the final block will be written to the
+ *       same buffer used by apr_evp_crypt, offset by the number of
+ *       bytes returned as actually written by the apr_evp_crypt()
+ *       call. After this call, the context is cleaned and can be
+ *       reused by apr_env_encrypt_init() or apr_env_decrypt_init().
+ * @param ctx The block context to use.
+ * @param out Address of a buffer to which data will be written. This
+ *            buffer must already exist, and is usually the same
+ *            buffer used by apr_evp_crypt(). See note.
+ * @param outlen Length of the output will be written here.
+ * @return APR_ECRYPT if an error occurred.
+ * @return APR_EPADDING if padding was enabled and the block was incorrectly
+ *         formatted.
+ * @return APR_ENOTIMPL if not implemented.
+ */
+static apr_status_t crypto_block_decrypt_finish(apr_crypto_block_t *ctx,
+        unsigned char *out, apr_size_t *outlen) {
+
+    int len = *outlen;
+
+    if (EVP_DecryptFinal_ex(&ctx->cipherCtx, out, &len) == 0) {
+        return APR_EPADDING;
+    }
+    *outlen = len;
+
+    return APR_SUCCESS;
+
+}
+
+/**
+ * OpenSSL module.
+ */
+APU_MODULE_DECLARE_DATA const apr_crypto_driver_t apr_crypto_openssl_driver = {
+        "openssl", crypto_init, crypto_factory, crypto_passphrase,
+        crypto_block_encrypt_init, crypto_block_encrypt,
+        crypto_block_encrypt_finish, crypto_block_decrypt_init,
+        crypto_block_decrypt, crypto_block_decrypt_finish,
+        crypto_block_cleanup, crypto_cleanup, crypto_shutdown };
+
+#endif

Modified: apr/apr-util/trunk/test/Makefile.in
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/test/Makefile.in?rev=692949&r1=692948&r2=692949&view=diff
==============================================================================
--- apr/apr-util/trunk/test/Makefile.in (original)
+++ apr/apr-util/trunk/test/Makefile.in Sun Sep  7 13:42:47 2008
@@ -17,7 +17,7 @@
 TESTS = teststrmatch.lo testuri.lo testuuid.lo testbuckets.lo testpass.lo \
 	testmd4.lo testmd5.lo testldap.lo testdate.lo testdbm.lo testdbd.lo \
 	testxml.lo testrmm.lo testreslist.lo testqueue.lo testxlate.lo \
-	testmemcache.lo 
+	testmemcache.lo testcrypto.lo
 
 PROGRAMS = $(STDTEST_PORTABLE)
 
@@ -62,7 +62,7 @@
 	for prog in $(STDTEST_PORTABLE) $(STDTEST_NONPORTABLE); do \
 	        if test "$$prog" = 'dbd'; then \
 			for driver in sqlite2 sqlite3; do \
-				@apr_shlibpath_var@="`echo "../dbd/.libs:../ldap/.libs:$$@apr_shlibpath_var@" | sed -e 's/::*$$//'`" \
+				@apr_shlibpath_var@="`echo "../crypto/.libs:../dbd/.libs:../ldap/.libs:$$@apr_shlibpath_var@" | sed -e 's/::*$$//'`" \
 				./$$prog $$driver; \
 				status=$$?; \
 				if test $$status != 0; then \
@@ -71,7 +71,7 @@
 				fi; \
 			done; \
 	        else \
-			@apr_shlibpath_var@="`echo "../dbd/.libs:../ldap/.libs:$$@apr_shlibpath_var@" | sed -e 's/::*$$//'`" \
+			@apr_shlibpath_var@="`echo "../crypto/.libs:../dbd/.libs:../ldap/.libs:$$@apr_shlibpath_var@" | sed -e 's/::*$$//'`" \
 			./$$prog; \
 			status=$$?; \
 			if test $$status != 0; then \

Modified: apr/apr-util/trunk/test/abts_tests.h
URL: http://svn.apache.org/viewvc/apr/apr-util/trunk/test/abts_tests.h?rev=692949&r1=692948&r2=692949&view=diff
==============================================================================
--- apr/apr-util/trunk/test/abts_tests.h (original)
+++ apr/apr-util/trunk/test/abts_tests.h Sun Sep  7 13:42:47 2008
@@ -30,6 +30,7 @@
     {testpass},
     {testmd4},
     {testmd5},
+    {testcrypto},
     {testldap},
     {testdbd},
     {testdate},

Propchange: apr/apr-util/trunk/test/data/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Sun Sep  7 13:42:47 2008
@@ -1,2 +1,7 @@
 sqlite2.db
 sqlite3.db
+test-sdbm.dir
+test-sdbm.pag
+secmod.db
+key3.db
+cert8.db



Mime
View raw message