mirror of
https://github.com/OpenVPN/openvpn.git
synced 2024-09-19 19:42:30 +02:00
Added PolarSSL support:
- Crypto library - SSL library - PKCS#11 support For missing features, please see README.polarssl Signed-off-by: Adriaan de Jong <dejong@fox-it.com> Acked-by: James Yonan <james@openvpn.net> Acked-by: Gert Doering <gert@greenie.muc.de> Signed-off-by: David Sommerseth <davids@redhat.com>
This commit is contained in:
parent
725336282d
commit
53f97e1e91
@ -160,6 +160,13 @@ openvpn_SOURCES += \
|
||||
ssl_openssl.c ssl_openssl.h \
|
||||
ssl_verify_openssl.c ssl_verify_openssl.h
|
||||
endif
|
||||
if USE_POLARSSL
|
||||
openvpn_SOURCES += \
|
||||
crypto_polarssl.c crypto_polarssl.h \
|
||||
pkcs11_polarssl.c \
|
||||
ssl_polarssl.c ssl_polarssl.h \
|
||||
ssl_verify_polarssl.c ssl_verify_polarssl.h
|
||||
endif
|
||||
|
||||
dist-hook:
|
||||
cd $(distdir) && for i in $(EXTRA_DIST) $(SUBDIRS) ; do find $$i -name .svn -type d -prune -exec rm -rf '{}' ';' ; rm -f `find $$i -type f | grep -E '(^|\/)\.?\#|\~$$|\.s?o$$'` ; done
|
||||
|
23
README.polarssl
Normal file
23
README.polarssl
Normal file
@ -0,0 +1,23 @@
|
||||
This version of OpenVPN has PolarSSL support. To enable follow the following
|
||||
instructions:
|
||||
|
||||
To Build and Install,
|
||||
|
||||
./configure --with-ssl-type=polarssl
|
||||
make
|
||||
make install
|
||||
|
||||
*************************************************************************
|
||||
|
||||
The following features are missing in the PolarSSL version of OpenVPN:
|
||||
|
||||
* ca_path support - Loading certificate authorities from a directory
|
||||
* PKCS#12 file support
|
||||
* Windows CryptoAPI support
|
||||
* Management external key support
|
||||
* X509 alternative username fields (must be "CN")
|
||||
|
||||
TODO:
|
||||
* serial is in Hex
|
||||
* X509 certificate export
|
||||
* X.509 tracking
|
67
configure.ac
67
configure.ac
@ -291,14 +291,16 @@ AC_ARG_WITH(mem-check,
|
||||
)
|
||||
|
||||
AC_ARG_WITH([ssl-type],
|
||||
[ --with-ssl-type=TYPE Build with the given SSL library, TYPE = openssl ],
|
||||
[ --with-ssl-type=TYPE Build with the given SSL library, TYPE = openssl or polarssl ],
|
||||
[case "${withval}" in
|
||||
openssl) SSL_LIB=openssl ;;
|
||||
polarssl) SSL_LIB=polarssl ;;
|
||||
*) AC_MSG_ERROR([bad value ${withval} for --with-ssl-type]) ;;
|
||||
esac],
|
||||
[SSL_LIB="openssl"]
|
||||
)
|
||||
AM_CONDITIONAL([USE_OPENSSL], [test x$SSL_LIB = xopenssl])
|
||||
AM_CONDITIONAL([USE_POLARSSL], [test x$SSL_LIB = xpolarssl])
|
||||
|
||||
dnl fix search path, to allow compilers to find syshead.h
|
||||
CPPFLAGS="$CPPFLAGS -I${srcdir}"
|
||||
@ -709,6 +711,24 @@ if test "$LZO_STUB" = "yes"; then
|
||||
AC_DEFINE(LZO_STUB, 1, [Enable LZO stub capability])
|
||||
fi
|
||||
|
||||
dnl
|
||||
dnl enable pkcs11 capability
|
||||
dnl
|
||||
|
||||
if test "$PKCS11" = "yes"; then
|
||||
AC_CHECKING([for pkcs11-helper Library and Header files])
|
||||
AC_CHECK_HEADER(pkcs11-helper-1.0/pkcs11h-core.h,
|
||||
[AC_CHECK_LIB(pkcs11-helper, pkcs11h_initialize,
|
||||
[
|
||||
AC_DEFINE(USE_PKCS11, 1, [Enable PKCS11 capability])
|
||||
OPENVPN_ADD_LIBS(-lpkcs11-helper)
|
||||
],
|
||||
[AC_MSG_RESULT([pkcs11-helper library not found.])]
|
||||
)],
|
||||
[AC_MSG_RESULT([pkcs11-helper headers not found.])]
|
||||
)
|
||||
fi
|
||||
|
||||
dnl
|
||||
dnl check for SSL-crypto library
|
||||
dnl
|
||||
@ -752,7 +772,20 @@ if test "$CRYPTO" = "yes"; then
|
||||
[AC_MSG_ERROR([OpenSSL crypto Library is too old.])]
|
||||
)
|
||||
fi
|
||||
|
||||
if test "$SSL_LIB" = "polarssl"; then
|
||||
AC_CHECKING([for PolarSSL Crypto Library and Header files])
|
||||
AC_CHECK_HEADER(polarssl/aes.h,
|
||||
[AC_CHECK_LIB(polarssl, aes_crypt_cbc,
|
||||
[
|
||||
OPENVPN_ADD_LIBS(-lpolarssl)
|
||||
AC_DEFINE(USE_CRYPTO, 1, [Use crypto library])
|
||||
AC_DEFINE(USE_POLARSSL, 1, [Use PolarSSL library])
|
||||
],
|
||||
[AC_MSG_ERROR([PolarSSL Crypto library not found.])]
|
||||
)],
|
||||
[AC_MSG_ERROR([PolarSSL Crypto headers not found.])]
|
||||
)
|
||||
fi
|
||||
dnl
|
||||
dnl check for OpenSSL-SSL library
|
||||
dnl
|
||||
@ -788,6 +821,20 @@ if test "$CRYPTO" = "yes"; then
|
||||
|
||||
AC_DEFINE(USE_SSL, 1, [Use OpenSSL SSL library])
|
||||
fi
|
||||
if test "$SSL_LIB" = "polarssl"; then
|
||||
AC_CHECKING([for PolarSSL SSL Library and Header files])
|
||||
AC_CHECK_HEADER(polarssl/ssl.h,
|
||||
[AC_CHECK_LIB(polarssl, ssl_init,
|
||||
[
|
||||
OPENVPN_ADD_LIBS(-lpolarssl)
|
||||
AC_DEFINE(USE_SSL, 1, [Use SSL library])
|
||||
AC_DEFINE(USE_POLARSSL, 1, [Use PolarSSL library])
|
||||
],
|
||||
[AC_MSG_ERROR([PolarSSL SSL library not found.])]
|
||||
)],
|
||||
[AC_MSG_ERROR([PolarSSL SSL headers not found.])]
|
||||
)
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -796,22 +843,6 @@ if test "$X509ALTUSERNAME" = "yes"; then
|
||||
AC_DEFINE(ENABLE_X509ALTUSERNAME, 1, [Enable --x509-username-field feature])
|
||||
fi
|
||||
|
||||
dnl enable pkcs11 capability
|
||||
|
||||
if test "$PKCS11" = "yes"; then
|
||||
AC_CHECKING([for pkcs11-helper Library and Header files])
|
||||
AC_CHECK_HEADER(pkcs11-helper-1.0/pkcs11h-core.h,
|
||||
[AC_CHECK_LIB(pkcs11-helper, pkcs11h_initialize,
|
||||
[
|
||||
AC_DEFINE(USE_PKCS11, 1, [Enable PKCS11 capability])
|
||||
OPENVPN_ADD_LIBS(-lpkcs11-helper)
|
||||
],
|
||||
[AC_MSG_RESULT([pkcs11-helper library not found.])]
|
||||
)],
|
||||
[AC_MSG_RESULT([pkcs11-helper headers not found.])]
|
||||
)
|
||||
fi
|
||||
|
||||
dnl enable multi-client mode
|
||||
if test "$MULTI" = "yes"; then
|
||||
AC_DEFINE(ENABLE_CLIENT_SERVER, 1, [Enable client/server capability])
|
||||
|
@ -35,7 +35,9 @@
|
||||
#ifdef USE_OPENSSL
|
||||
#include "crypto_openssl.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_POLARSSL
|
||||
#include "crypto_polarssl.h"
|
||||
#endif
|
||||
#include "basic.h"
|
||||
|
||||
|
||||
|
577
crypto_polarssl.c
Normal file
577
crypto_polarssl.c
Normal file
@ -0,0 +1,577 @@
|
||||
/*
|
||||
* OpenVPN -- An application to securely tunnel IP networks
|
||||
* over a single TCP/UDP port, with support for SSL/TLS-based
|
||||
* session authentication and key exchange,
|
||||
* packet encryption, packet authentication, and
|
||||
* packet compression.
|
||||
*
|
||||
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
|
||||
* Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see the file COPYING included with this
|
||||
* distribution); if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Data Channel Cryptography PolarSSL-specific backend interface
|
||||
*/
|
||||
|
||||
#include "syshead.h"
|
||||
|
||||
#include "errlevel.h"
|
||||
#include "basic.h"
|
||||
#include "buffer.h"
|
||||
#include "integer.h"
|
||||
#include "crypto_backend.h"
|
||||
|
||||
#include <polarssl/des.h>
|
||||
#include <polarssl/md5.h>
|
||||
#include <polarssl/cipher.h>
|
||||
#include <polarssl/havege.h>
|
||||
|
||||
/*
|
||||
*
|
||||
* Hardware engine support. Allows loading/unloading of engines.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
crypto_init_lib_engine (const char *engine_name)
|
||||
{
|
||||
msg (M_WARN, "Note: PolarSSL hardware crypto engine functionality is not "
|
||||
"available");
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Functions related to the core crypto library
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
crypto_init_lib (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
crypto_uninit_lib (void)
|
||||
{
|
||||
prng_uninit();
|
||||
}
|
||||
|
||||
void
|
||||
crypto_clear_error (void)
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef DMALLOC
|
||||
void
|
||||
crypto_init_dmalloc (void)
|
||||
{
|
||||
msg (M_ERR, "Error: dmalloc support is not available for PolarSSL.");
|
||||
}
|
||||
#endif /* DMALLOC */
|
||||
|
||||
void
|
||||
show_available_ciphers ()
|
||||
{
|
||||
const int *ciphers = cipher_list();
|
||||
|
||||
#ifndef ENABLE_SMALL
|
||||
printf ("The following ciphers and cipher modes are available\n"
|
||||
"for use with " PACKAGE_NAME ". Each cipher shown below may be\n"
|
||||
"used as a parameter to the --cipher option. The default\n"
|
||||
"key size is shown as well as whether or not it can be\n"
|
||||
"changed with the --keysize directive. Using a CBC mode\n"
|
||||
"is recommended.\n\n");
|
||||
#endif
|
||||
|
||||
while (*ciphers != 0)
|
||||
{
|
||||
const cipher_info_t *info = cipher_info_from_type(*ciphers);
|
||||
|
||||
if (info && info->mode == POLARSSL_MODE_CBC)
|
||||
printf ("%s %d bit default key\n",
|
||||
info->name, info->key_length);
|
||||
|
||||
ciphers++;
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
void
|
||||
show_available_digests ()
|
||||
{
|
||||
const int *digests = md_list();
|
||||
|
||||
#ifndef ENABLE_SMALL
|
||||
printf ("The following message digests are available for use with\n"
|
||||
PACKAGE_NAME ". A message digest is used in conjunction with\n"
|
||||
"the HMAC function, to authenticate received packets.\n"
|
||||
"You can specify a message digest as parameter to\n"
|
||||
"the --auth option.\n\n");
|
||||
#endif
|
||||
|
||||
while (*digests != 0)
|
||||
{
|
||||
const md_info_t *info = md_info_from_type(*digests);
|
||||
|
||||
if (info)
|
||||
printf ("%s %d bit default key\n",
|
||||
info->name, info->size * 8);
|
||||
digests++;
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
void
|
||||
show_available_engines ()
|
||||
{
|
||||
printf ("Sorry, PolarSSL hardware crypto engine functionality is not "
|
||||
"available\n");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Random number functions, used in cases where we want
|
||||
* reasonably strong cryptographic random number generation
|
||||
* without depleting our entropy pool. Used for random
|
||||
* IV values and a number of other miscellaneous tasks.
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
rand_bytes (uint8_t *output, int len)
|
||||
{
|
||||
static havege_state hs = {0};
|
||||
static bool hs_initialised = false;
|
||||
const int int_size = sizeof(int);
|
||||
|
||||
if (!hs_initialised)
|
||||
{
|
||||
/* Initialise PolarSSL RNG */
|
||||
havege_init(&hs);
|
||||
hs_initialised = true;
|
||||
}
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
const int blen = min_int (len, int_size);
|
||||
const int rand_int = havege_rand(&hs);
|
||||
|
||||
memcpy (output, &rand_int, blen);
|
||||
output += blen;
|
||||
len -= blen;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Key functions, allow manipulation of keys.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
int
|
||||
key_des_num_cblocks (const cipher_info_t *kt)
|
||||
{
|
||||
int ret = 0;
|
||||
if (kt->type == POLARSSL_CIPHER_DES_CBC)
|
||||
ret = 1;
|
||||
if (kt->type == POLARSSL_CIPHER_DES_EDE_CBC)
|
||||
ret = 2;
|
||||
if (kt->type == POLARSSL_CIPHER_DES_EDE3_CBC)
|
||||
ret = 3;
|
||||
|
||||
dmsg (D_CRYPTO_DEBUG, "CRYPTO INFO: n_DES_cblocks=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
key_des_check (uint8_t *key, int key_len, int ndc)
|
||||
{
|
||||
int i;
|
||||
struct buffer b;
|
||||
|
||||
buf_set_read (&b, key, key_len);
|
||||
|
||||
for (i = 0; i < ndc; ++i)
|
||||
{
|
||||
unsigned char *key = buf_read_alloc(&b, DES_KEY_SIZE);
|
||||
if (!key)
|
||||
{
|
||||
msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: insufficient key material");
|
||||
goto err;
|
||||
}
|
||||
if (0 != des_key_check_weak(key))
|
||||
{
|
||||
msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: weak key detected");
|
||||
goto err;
|
||||
}
|
||||
if (0 != des_key_check_key_parity(key))
|
||||
{
|
||||
msg (D_CRYPT_ERRORS, "CRYPTO INFO: check_key_DES: bad parity detected");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
err:
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
key_des_fixup (uint8_t *key, int key_len, int ndc)
|
||||
{
|
||||
int i;
|
||||
struct buffer b;
|
||||
|
||||
buf_set_read (&b, key, key_len);
|
||||
for (i = 0; i < ndc; ++i)
|
||||
{
|
||||
unsigned char *key = buf_read_alloc(&b, DES_KEY_SIZE);
|
||||
if (!key)
|
||||
{
|
||||
msg (D_CRYPT_ERRORS, "CRYPTO INFO: fixup_key_DES: insufficient key material");
|
||||
return;
|
||||
}
|
||||
des_key_set_parity(key);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Generic cipher key type functions
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
const cipher_info_t *
|
||||
cipher_kt_get (const char *ciphername)
|
||||
{
|
||||
const cipher_info_t *cipher = NULL;
|
||||
|
||||
ASSERT (ciphername);
|
||||
|
||||
cipher = cipher_info_from_string(ciphername);
|
||||
|
||||
if (NULL == cipher)
|
||||
msg (M_FATAL, "Cipher algorithm '%s' not found", ciphername);
|
||||
|
||||
if (cipher->key_length/8 > MAX_CIPHER_KEY_LENGTH)
|
||||
msg (M_FATAL, "Cipher algorithm '%s' uses a default key size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum key size (%d bytes)",
|
||||
ciphername,
|
||||
cipher->key_length/8,
|
||||
MAX_CIPHER_KEY_LENGTH);
|
||||
|
||||
return cipher;
|
||||
}
|
||||
|
||||
const char *
|
||||
cipher_kt_name (const cipher_info_t *cipher_kt)
|
||||
{
|
||||
if (NULL == cipher_kt)
|
||||
return "[null-cipher]";
|
||||
return cipher_kt->name;
|
||||
}
|
||||
|
||||
int
|
||||
cipher_kt_key_size (const cipher_info_t *cipher_kt)
|
||||
{
|
||||
if (NULL == cipher_kt)
|
||||
return 0;
|
||||
return cipher_kt->key_length/8;
|
||||
}
|
||||
|
||||
int
|
||||
cipher_kt_iv_size (const cipher_info_t *cipher_kt)
|
||||
{
|
||||
if (NULL == cipher_kt)
|
||||
return 0;
|
||||
return cipher_kt->iv_size;
|
||||
}
|
||||
|
||||
int
|
||||
cipher_kt_block_size (const cipher_info_t *cipher_kt)
|
||||
{
|
||||
if (NULL == cipher_kt)
|
||||
return 0;
|
||||
return cipher_kt->block_size;
|
||||
}
|
||||
|
||||
bool
|
||||
cipher_kt_mode (const cipher_info_t *cipher_kt)
|
||||
{
|
||||
ASSERT(NULL != cipher_kt);
|
||||
return cipher_kt->mode;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Generic cipher context functions
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
void
|
||||
cipher_ctx_init (cipher_context_t *ctx, uint8_t *key, int key_len,
|
||||
const cipher_info_t *kt, int enc, const char *prefix)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
|
||||
ASSERT(NULL != kt && NULL != ctx);
|
||||
|
||||
CLEAR (*ctx);
|
||||
|
||||
if (0 != cipher_init_ctx(ctx, kt))
|
||||
msg (M_FATAL, "PolarSSL cipher context init #1");
|
||||
|
||||
if (0 != cipher_setkey(ctx, key, key_len*8, enc))
|
||||
msg (M_FATAL, "PolarSSL cipher set key");
|
||||
|
||||
msg (D_HANDSHAKE, "%s: Cipher '%s' initialized with %d bit key",
|
||||
prefix,
|
||||
cipher_kt_name(kt),
|
||||
cipher_get_key_size(ctx));
|
||||
|
||||
/* make sure we used a big enough key */
|
||||
ASSERT (ctx->key_length <= key_len*8);
|
||||
|
||||
dmsg (D_SHOW_KEYS, "%s: CIPHER KEY: %s", prefix,
|
||||
format_hex (key, key_len, 0, &gc));
|
||||
dmsg (D_CRYPTO_DEBUG, "%s: CIPHER block_size=%d iv_size=%d",
|
||||
prefix,
|
||||
cipher_get_block_size(ctx),
|
||||
cipher_get_iv_size(ctx));
|
||||
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
void cipher_ctx_cleanup (cipher_context_t *ctx)
|
||||
{
|
||||
cipher_free_ctx(ctx);
|
||||
}
|
||||
|
||||
int cipher_ctx_iv_length (const cipher_context_t *ctx)
|
||||
{
|
||||
return cipher_get_iv_size(ctx);
|
||||
}
|
||||
|
||||
int cipher_ctx_block_size(const cipher_context_t *ctx)
|
||||
{
|
||||
return cipher_get_block_size(ctx);
|
||||
}
|
||||
|
||||
int cipher_ctx_mode (const cipher_context_t *ctx)
|
||||
{
|
||||
ASSERT(NULL != ctx);
|
||||
|
||||
return cipher_kt_mode(ctx->cipher_info);
|
||||
}
|
||||
|
||||
int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf)
|
||||
{
|
||||
return 0 == cipher_reset(ctx, iv_buf);
|
||||
}
|
||||
|
||||
int cipher_ctx_update (cipher_context_t *ctx, uint8_t *dst, int *dst_len,
|
||||
uint8_t *src, int src_len)
|
||||
{
|
||||
return 0 == cipher_update(ctx, src, src_len, dst, dst_len);
|
||||
}
|
||||
|
||||
int cipher_ctx_final (cipher_context_t *ctx, uint8_t *dst, int *dst_len)
|
||||
{
|
||||
return 0 == cipher_finish(ctx, dst, dst_len);
|
||||
}
|
||||
|
||||
void
|
||||
cipher_des_encrypt_ecb (const unsigned char key[DES_KEY_SIZE],
|
||||
unsigned char *src,
|
||||
unsigned char *dst)
|
||||
{
|
||||
des_context ctx;
|
||||
|
||||
des_setkey_enc(&ctx, key);
|
||||
des_crypt_ecb(&ctx, src, dst);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Generic message digest information functions
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
const md_info_t *
|
||||
md_kt_get (const char *digest)
|
||||
{
|
||||
const md_info_t *md = NULL;
|
||||
ASSERT (digest);
|
||||
|
||||
md = md_info_from_string(digest);
|
||||
if (!md)
|
||||
msg (M_FATAL, "Message hash algorithm '%s' not found", digest);
|
||||
if (md->size > MAX_HMAC_KEY_LENGTH)
|
||||
msg (M_FATAL, "Message hash algorithm '%s' uses a default hash size (%d bytes) which is larger than " PACKAGE_NAME "'s current maximum hash size (%d bytes)",
|
||||
digest,
|
||||
md->size,
|
||||
MAX_HMAC_KEY_LENGTH);
|
||||
return md;
|
||||
}
|
||||
|
||||
const char *
|
||||
md_kt_name (const md_info_t *kt)
|
||||
{
|
||||
if (NULL == kt)
|
||||
return "[null-digest]";
|
||||
return md_get_name (kt);
|
||||
}
|
||||
|
||||
int
|
||||
md_kt_size (const md_info_t *kt)
|
||||
{
|
||||
if (NULL == kt)
|
||||
return 0;
|
||||
return md_get_size(kt);
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* Generic message digest functions
|
||||
*
|
||||
*/
|
||||
|
||||
int
|
||||
md_full (const md_kt_t *kt, const uint8_t *src, int src_len, uint8_t *dst)
|
||||
{
|
||||
return 0 == md(kt, src, src_len, dst);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
md_ctx_init (md_context_t *ctx, const md_info_t *kt)
|
||||
{
|
||||
ASSERT(NULL != ctx && NULL != kt);
|
||||
|
||||
CLEAR(*ctx);
|
||||
|
||||
ASSERT(0 == md_starts(kt, ctx));
|
||||
}
|
||||
|
||||
void
|
||||
md_ctx_cleanup(md_context_t *ctx)
|
||||
{
|
||||
ASSERT(0 == md_free_ctx(ctx));
|
||||
}
|
||||
|
||||
int
|
||||
md_ctx_size (const md_context_t *ctx)
|
||||
{
|
||||
if (NULL == ctx)
|
||||
return 0;
|
||||
return md_get_size(ctx->md_info);
|
||||
}
|
||||
|
||||
void
|
||||
md_ctx_update (md_context_t *ctx, const uint8_t *src, int src_len)
|
||||
{
|
||||
ASSERT(0 == md_update(ctx, src, src_len));
|
||||
}
|
||||
|
||||
void
|
||||
md_ctx_final (md_context_t *ctx, uint8_t *dst)
|
||||
{
|
||||
ASSERT(0 == md_finish(ctx, dst));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Generic HMAC functions
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* TODO: re-enable dmsg for crypto debug
|
||||
*/
|
||||
void
|
||||
hmac_ctx_init (md_context_t *ctx, const uint8_t *key, int key_len, const md_info_t *kt,
|
||||
const char *prefix)
|
||||
{
|
||||
struct gc_arena gc = gc_new ();
|
||||
|
||||
ASSERT(NULL != kt && NULL != ctx);
|
||||
|
||||
CLEAR(*ctx);
|
||||
|
||||
ASSERT(0 == md_hmac_starts(kt, ctx, key, key_len));
|
||||
|
||||
if (prefix)
|
||||
msg (D_HANDSHAKE,
|
||||
"%s: Using %d bit message hash '%s' for HMAC authentication",
|
||||
prefix, md_get_size(kt) * 8, md_get_name(kt));
|
||||
|
||||
/* make sure we used a big enough key */
|
||||
ASSERT (md_get_size(kt) <= key_len);
|
||||
|
||||
if (prefix)
|
||||
dmsg (D_SHOW_KEYS, "%s: HMAC KEY: %s", prefix,
|
||||
format_hex (key, key_len, 0, &gc));
|
||||
// if (prefix)
|
||||
// dmsg (D_CRYPTO_DEBUG, "%s: HMAC size=%d block_size=%d",
|
||||
// prefix,
|
||||
// md_get_size(md_info),
|
||||
// EVP_MD_block_size (md_info));
|
||||
|
||||
gc_free (&gc);
|
||||
}
|
||||
|
||||
void
|
||||
hmac_ctx_cleanup(md_context_t *ctx)
|
||||
{
|
||||
ASSERT(0 == md_free_ctx(ctx));
|
||||
}
|
||||
|
||||
int
|
||||
hmac_ctx_size (const md_context_t *ctx)
|
||||
{
|
||||
if (NULL == ctx)
|
||||
return 0;
|
||||
return md_get_size(ctx->md_info);
|
||||
}
|
||||
|
||||
void
|
||||
hmac_ctx_reset (md_context_t *ctx)
|
||||
{
|
||||
ASSERT(0 == md_hmac_reset(ctx));
|
||||
}
|
||||
|
||||
void
|
||||
hmac_ctx_update (md_context_t *ctx, const uint8_t *src, int src_len)
|
||||
{
|
||||
ASSERT(0 == md_hmac_update(ctx, src, src_len));
|
||||
}
|
||||
|
||||
void
|
||||
hmac_ctx_final (md_context_t *ctx, uint8_t *dst)
|
||||
{
|
||||
ASSERT(0 == md_hmac_finish(ctx, dst));
|
||||
}
|
71
crypto_polarssl.h
Normal file
71
crypto_polarssl.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* OpenVPN -- An application to securely tunnel IP networks
|
||||
* over a single TCP/UDP port, with support for SSL/TLS-based
|
||||
* session authentication and key exchange,
|
||||
* packet encryption, packet authentication, and
|
||||
* packet compression.
|
||||
*
|
||||
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
|
||||
* Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see the file COPYING included with this
|
||||
* distribution); if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Data Channel Cryptography PolarSSL-specific backend interface
|
||||
*/
|
||||
|
||||
#ifndef CRYPTO_POLARSSL_H_
|
||||
#define CRYPTO_POLARSSL_H_
|
||||
|
||||
#include <polarssl/cipher.h>
|
||||
#include <polarssl/md.h>
|
||||
|
||||
/** Generic cipher key type %context. */
|
||||
typedef cipher_info_t cipher_kt_t;
|
||||
|
||||
/** Generic message digest key type %context. */
|
||||
typedef md_info_t md_kt_t;
|
||||
|
||||
/** Generic cipher %context. */
|
||||
typedef cipher_context_t cipher_ctx_t;
|
||||
|
||||
/** Generic message digest %context. */
|
||||
typedef md_context_t md_ctx_t;
|
||||
|
||||
/** Generic HMAC %context. */
|
||||
typedef md_context_t hmac_ctx_t;
|
||||
|
||||
/** Maximum length of an IV */
|
||||
#define OPENVPN_MAX_IV_LENGTH POLARSSL_MAX_IV_LENGTH
|
||||
|
||||
/** Cipher is in CBC mode */
|
||||
#define OPENVPN_MODE_CBC POLARSSL_MODE_CBC
|
||||
|
||||
/** Cipher is in OFB mode */
|
||||
#define OPENVPN_MODE_OFB POLARSSL_MODE_OFB
|
||||
|
||||
/** Cipher is in CFB mode */
|
||||
#define OPENVPN_MODE_CFB POLARSSL_MODE_CFB
|
||||
|
||||
/** Cipher should encrypt */
|
||||
#define OPENVPN_OP_ENCRYPT POLARSSL_ENCRYPT
|
||||
|
||||
/** Cipher should decrypt */
|
||||
#define OPENVPN_OP_DECRYPT POLARSSL_DECRYPT
|
||||
|
||||
#define MD5_DIGEST_LENGTH 16
|
||||
|
||||
#endif /* CRYPTO_POLARSSL_H_ */
|
@ -79,9 +79,11 @@
|
||||
*
|
||||
* @subsection key_generation_random Source of random material
|
||||
*
|
||||
* OpenVPN uses the OpenSSL library as its source of random material. More
|
||||
* specifically, the \c RAND_bytes() function is called to supply
|
||||
* cryptographically strong pseudo-random data. The following links
|
||||
* OpenVPN uses the either the OpenSSL library or the PolarSSL library as its
|
||||
* source of random material.
|
||||
*
|
||||
* In OpenSSL, the \c RAND_bytes() function is called
|
||||
* to supply cryptographically strong pseudo-random data. The following links
|
||||
* contain more information on this subject:
|
||||
* - For OpenSSL's \c RAND_bytes() function:
|
||||
* http://www.openssl.org/docs/crypto/RAND_bytes.html
|
||||
@ -90,6 +92,9 @@
|
||||
* - For OpenSSL's support for external crypto modules:
|
||||
* http://www.openssl.org/docs/crypto/engine.html
|
||||
*
|
||||
* In PolarSSL, the Havege random number generator is used. For details, see
|
||||
* the PolarSSL documentation.
|
||||
*
|
||||
* @section key_generation_exchange Key exchange:
|
||||
*
|
||||
* The %key exchange process is initiated by the OpenVPN process running
|
||||
|
@ -28,6 +28,9 @@
|
||||
#ifdef USE_OPENSSL
|
||||
#include "ssl_verify_openssl.h"
|
||||
#endif
|
||||
#ifdef USE_POLARSSL
|
||||
#include "ssl_verify_polarssl.h"
|
||||
#endif
|
||||
|
||||
#define OPENVPN_PLUGIN_VERSION 3
|
||||
|
||||
|
25
options.c
25
options.c
@ -508,7 +508,9 @@ static const char usage_message[] =
|
||||
"--keysize n : Size of cipher key in bits (optional).\n"
|
||||
" If unspecified, defaults to cipher-specific default.\n"
|
||||
#endif
|
||||
#ifndef USE_POLARSSL
|
||||
"--engine [name] : Enable OpenSSL hardware crypto engine functionality.\n"
|
||||
#endif
|
||||
"--no-replay : Disable replay protection.\n"
|
||||
"--mute-replay-warnings : Silence the output of replay warnings to log file.\n"
|
||||
"--replay-window n [t] : Use a replay protection sliding window of size n\n"
|
||||
@ -529,13 +531,15 @@ static const char usage_message[] =
|
||||
" number, such as 1 (default), 2, etc.\n"
|
||||
"--ca file : Certificate authority file in .pem format containing\n"
|
||||
" root certificate.\n"
|
||||
#ifndef USE_POLARSSL
|
||||
"--capath dir : A directory of trusted certificates (CAs"
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
|
||||
" and CRLs).\n"
|
||||
#else
|
||||
#else /* OPENSSL_VERSION_NUMBER >= 0x00907000L */
|
||||
").\n"
|
||||
" WARNING: no support of CRL available with this version.\n"
|
||||
#endif
|
||||
#endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L */
|
||||
#endif /* USE_POLARSSL */
|
||||
"--dh file : File containing Diffie Hellman parameters\n"
|
||||
" in .pem format (for --tls-server only).\n"
|
||||
" Use \"openssl dhparam -out dh1024.pem 1024\" to generate.\n"
|
||||
@ -590,7 +594,7 @@ static const char usage_message[] =
|
||||
" nsCertType designation t = 'client' | 'server'.\n"
|
||||
"--x509-track x : Save peer X509 attribute x in environment for use by\n"
|
||||
" plugins and management interface.\n"
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L || USE_POLARSSL
|
||||
"--remote-cert-ku v ... : Require that the peer certificate was signed with\n"
|
||||
" explicit key usage, you can specify more than one value.\n"
|
||||
" value should be given in hex format.\n"
|
||||
@ -600,7 +604,7 @@ static const char usage_message[] =
|
||||
"--remote-cert-tls t: Require that peer certificate was signed with explicit\n"
|
||||
" key usage and extended key usage based on RFC3280 TLS rules.\n"
|
||||
" t = 'client' | 'server'.\n"
|
||||
#endif /* OPENSSL_VERSION_NUMBER */
|
||||
#endif /* OPENSSL_VERSION_NUMBER || USE_POLARSSL */
|
||||
#endif /* USE_SSL */
|
||||
#ifdef ENABLE_PKCS11
|
||||
"\n"
|
||||
@ -1537,7 +1541,9 @@ show_settings (const struct options *o)
|
||||
SHOW_STR (prng_hash);
|
||||
SHOW_INT (prng_nonce_secret_len);
|
||||
SHOW_INT (keysize);
|
||||
#ifndef USE_POLARSSL
|
||||
SHOW_BOOL (engine);
|
||||
#endif /* USE_POLARSSL */
|
||||
SHOW_BOOL (replay);
|
||||
SHOW_BOOL (mute_replay_warnings);
|
||||
SHOW_INT (replay_window);
|
||||
@ -2268,8 +2274,13 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef USE_POLARSSL
|
||||
if (!(options->ca_file))
|
||||
msg(M_USAGE, "You must define CA file (--ca)");
|
||||
#else
|
||||
if ((!(options->ca_file)) && (!(options->ca_path)))
|
||||
msg(M_USAGE, "You must define CA file (--ca) or CA path (--capath)");
|
||||
#endif
|
||||
if (pull)
|
||||
{
|
||||
const int sum = (options->cert_file != NULL) + (options->priv_key_file != NULL);
|
||||
@ -6114,6 +6125,7 @@ add_option (struct options *options,
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
options->test_crypto = true;
|
||||
}
|
||||
#ifndef USE_POLARSSL
|
||||
else if (streq (p[0], "engine"))
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
@ -6124,6 +6136,7 @@ add_option (struct options *options,
|
||||
else
|
||||
options->engine = "auto";
|
||||
}
|
||||
#endif /* USE_POLARSSL */
|
||||
#ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH
|
||||
else if (streq (p[0], "keysize") && p[1])
|
||||
{
|
||||
@ -6166,11 +6179,13 @@ add_option (struct options *options,
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifndef USE_POLARSSL
|
||||
else if (streq (p[0], "capath") && p[1])
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
options->ca_path = p[1];
|
||||
}
|
||||
#endif /* USE_POLARSSL */
|
||||
else if (streq (p[0], "dh") && p[1])
|
||||
{
|
||||
VERIFY_PERMISSION (OPT_P_GENERAL);
|
||||
@ -6322,7 +6337,7 @@ add_option (struct options *options,
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L || USE_POLARSSL
|
||||
else if (streq (p[0], "remote-cert-ku"))
|
||||
{
|
||||
int j;
|
||||
|
121
pkcs11_polarssl.c
Normal file
121
pkcs11_polarssl.c
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* OpenVPN -- An application to securely tunnel IP networks
|
||||
* over a single TCP/UDP port, with support for SSL/TLS-based
|
||||
* session authentication and key exchange,
|
||||
* packet encryption, packet authentication, and
|
||||
* packet compression.
|
||||
*
|
||||
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
|
||||
* Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see the file COPYING included with this
|
||||
* distribution); if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file PKCS #11 PolarSSL backend
|
||||
*/
|
||||
|
||||
#include "syshead.h"
|
||||
|
||||
#if defined(ENABLE_PKCS11)
|
||||
|
||||
#include "errlevel.h"
|
||||
#include "pkcs11_backend.h"
|
||||
#include <polarssl/pkcs11.h>
|
||||
|
||||
int
|
||||
pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
|
||||
struct tls_root_ctx * const ssl_ctx)
|
||||
{
|
||||
int ret = 1;
|
||||
pkcs11_context pkcs11_ctx;
|
||||
|
||||
ASSERT (NULL != ssl_ctx);
|
||||
|
||||
if (pkcs11_x509_cert_init(ssl_ctx->crt_chain, certificate)) {
|
||||
msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ssl_ctx->priv_key_pkcs11 = malloc(sizeof(pkcs11_context));
|
||||
|
||||
if (ssl_ctx->priv_key_pkcs11 == NULL) {
|
||||
msg (M_FATAL, "PKCS#11: Cannot allocate PolarSSL private key object");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (pkcs11_priv_key_init(ssl_ctx->priv_key_pkcs11, certificate)) {
|
||||
msg (M_FATAL, "PKCS#11: Cannot initialize PolarSSL private key object");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
pkcs11_certificate_dn (pkcs11h_certificate_t cert, char *dn,
|
||||
size_t dn_len)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
x509_cert polar_cert = {0};
|
||||
|
||||
if (pkcs11_x509_cert_init(&polar_cert, cert)) {
|
||||
msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (-1 == x509parse_dn_gets (dn, dn_len, &polar_cert.subject)) {
|
||||
msg (M_FATAL, "PKCS#11: PolarSSL cannot parse subject");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
x509_free(&polar_cert);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial,
|
||||
size_t serial_len)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
x509_cert polar_cert = {0};
|
||||
|
||||
if (pkcs11_x509_cert_init(&polar_cert, cert)) {
|
||||
msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (-1 == x509parse_serial_gets (serial, serial_len, &polar_cert.serial)) {
|
||||
msg (M_FATAL, "PKCS#11: PolarSSL cannot parse serial");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
x509_free(&polar_cert);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* defined(ENABLE_PKCS11) */
|
@ -36,6 +36,10 @@
|
||||
#ifdef USE_OPENSSL
|
||||
#include "ssl_openssl.h"
|
||||
#endif
|
||||
#ifdef USE_POLARSSL
|
||||
#include "ssl_polarssl.h"
|
||||
#include "ssl_verify_polarssl.h"
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
|
848
ssl_polarssl.c
Normal file
848
ssl_polarssl.c
Normal file
@ -0,0 +1,848 @@
|
||||
/*
|
||||
* OpenVPN -- An application to securely tunnel IP networks
|
||||
* over a single TCP/UDP port, with support for SSL/TLS-based
|
||||
* session authentication and key exchange,
|
||||
* packet encryption, packet authentication, and
|
||||
* packet compression.
|
||||
*
|
||||
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
|
||||
* Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see the file COPYING included with this
|
||||
* distribution); if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Control Channel PolarSSL Backend
|
||||
*/
|
||||
|
||||
#include "syshead.h"
|
||||
#include "errlevel.h"
|
||||
#include "ssl_backend.h"
|
||||
#include "buffer.h"
|
||||
#include "misc.h"
|
||||
#include "manage.h"
|
||||
#include "ssl_common.h"
|
||||
|
||||
#include "ssl_verify_polarssl.h"
|
||||
|
||||
void
|
||||
tls_init_lib()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
tls_free_lib()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
tls_clear_error()
|
||||
{
|
||||
}
|
||||
|
||||
static int default_ciphers[] =
|
||||
{
|
||||
SSL_EDH_RSA_AES_256_SHA,
|
||||
SSL_EDH_RSA_CAMELLIA_256_SHA,
|
||||
SSL_EDH_RSA_AES_128_SHA,
|
||||
SSL_EDH_RSA_CAMELLIA_128_SHA,
|
||||
SSL_EDH_RSA_DES_168_SHA,
|
||||
SSL_RSA_AES_256_SHA,
|
||||
SSL_RSA_CAMELLIA_256_SHA,
|
||||
SSL_RSA_AES_128_SHA,
|
||||
SSL_RSA_CAMELLIA_128_SHA,
|
||||
SSL_RSA_DES_168_SHA,
|
||||
SSL_RSA_RC4_128_SHA,
|
||||
SSL_RSA_RC4_128_MD5,
|
||||
0
|
||||
};
|
||||
|
||||
void
|
||||
tls_ctx_server_new(struct tls_root_ctx *ctx)
|
||||
{
|
||||
ASSERT(NULL != ctx);
|
||||
CLEAR(*ctx);
|
||||
|
||||
ALLOC_OBJ_CLEAR(ctx->hs, havege_state);
|
||||
havege_init(ctx->hs);
|
||||
|
||||
ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
|
||||
ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context);
|
||||
|
||||
ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_cert);
|
||||
ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_cert);
|
||||
|
||||
|
||||
ctx->endpoint = SSL_IS_SERVER;
|
||||
ctx->initialised = true;
|
||||
}
|
||||
|
||||
void
|
||||
tls_ctx_client_new(struct tls_root_ctx *ctx)
|
||||
{
|
||||
ASSERT(NULL != ctx);
|
||||
|
||||
CLEAR(*ctx);
|
||||
|
||||
ALLOC_OBJ_CLEAR(ctx->hs, havege_state);
|
||||
havege_init(ctx->hs);
|
||||
|
||||
ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
|
||||
ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context);
|
||||
|
||||
ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_cert);
|
||||
ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_cert);
|
||||
|
||||
ctx->endpoint = SSL_IS_CLIENT;
|
||||
ctx->initialised = true;
|
||||
}
|
||||
|
||||
void
|
||||
tls_ctx_free(struct tls_root_ctx *ctx)
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
rsa_free(ctx->priv_key);
|
||||
free(ctx->priv_key);
|
||||
|
||||
x509_free(ctx->ca_chain);
|
||||
free(ctx->ca_chain);
|
||||
|
||||
x509_free(ctx->crt_chain);
|
||||
free(ctx->crt_chain);
|
||||
|
||||
dhm_free(ctx->dhm_ctx);
|
||||
free(ctx->dhm_ctx);
|
||||
|
||||
#if defined(ENABLE_PKCS11)
|
||||
if (ctx->priv_key_pkcs11 != NULL) {
|
||||
pkcs11_priv_key_free(ctx->priv_key_pkcs11);
|
||||
free(ctx->priv_key_pkcs11);
|
||||
}
|
||||
#endif
|
||||
|
||||
free(ctx->hs);
|
||||
|
||||
if (ctx->allowed_ciphers)
|
||||
free(ctx->allowed_ciphers);
|
||||
|
||||
CLEAR(*ctx);
|
||||
|
||||
ctx->initialised = false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
tls_ctx_initialised(struct tls_root_ctx *ctx)
|
||||
{
|
||||
ASSERT(NULL != ctx);
|
||||
return ctx->initialised;
|
||||
}
|
||||
|
||||
void
|
||||
tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
|
||||
{
|
||||
char *tmp_ciphers, *tmp_ciphers_orig;
|
||||
int i, cipher_count;
|
||||
int ciphers_len = strlen (ciphers);
|
||||
|
||||
ASSERT (NULL != ctx);
|
||||
ASSERT (0 != ciphers_len);
|
||||
|
||||
/* Get number of ciphers */
|
||||
for (i = 0, cipher_count = 1; i < ciphers_len; i++)
|
||||
if (ciphers[i] == ':')
|
||||
cipher_count++;
|
||||
|
||||
/* Allocate an array for them */
|
||||
ALLOC_ARRAY_CLEAR(ctx->allowed_ciphers, int, cipher_count+1)
|
||||
|
||||
/* Parse allowed ciphers, getting IDs */
|
||||
i = 0;
|
||||
tmp_ciphers_orig = tmp_ciphers = strdup(ciphers);
|
||||
while(tmp_ciphers) {
|
||||
ctx->allowed_ciphers[i] = ssl_get_cipher_id (strsep (&tmp_ciphers, ":"));
|
||||
if (ctx->allowed_ciphers[i] != 0)
|
||||
i++;
|
||||
}
|
||||
free(tmp_ciphers_orig);
|
||||
}
|
||||
|
||||
void
|
||||
tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file
|
||||
#if ENABLE_INLINE_FILES
|
||||
, const char *dh_file_inline
|
||||
#endif /* ENABLE_INLINE_FILES */
|
||||
)
|
||||
{
|
||||
#if ENABLE_INLINE_FILES
|
||||
if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_file_inline)
|
||||
{
|
||||
if (0 != x509parse_dhm(ctx->dhm_ctx, dh_file_inline, strlen(dh_file_inline)))
|
||||
msg (M_FATAL, "Cannot read inline DH parameters");
|
||||
}
|
||||
else
|
||||
#endif /* ENABLE_INLINE_FILES */
|
||||
{
|
||||
if (0 != x509parse_dhmfile(ctx->dhm_ctx, dh_file))
|
||||
msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file);
|
||||
}
|
||||
|
||||
msg (D_TLS_DEBUG_LOW, "Diffie-Hellman initialized with %d bit key",
|
||||
8 * mpi_size(&ctx->dhm_ctx->P));
|
||||
}
|
||||
|
||||
int
|
||||
tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
|
||||
#if ENABLE_INLINE_FILES
|
||||
const char *pkcs12_file_inline,
|
||||
#endif /* ENABLE_INLINE_FILES */
|
||||
bool load_ca_file
|
||||
)
|
||||
{
|
||||
msg(M_FATAL, "PKCS #12 files not yet supported for PolarSSL.");
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
void
|
||||
tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert)
|
||||
{
|
||||
msg(M_FATAL, "Windows CryptoAPI not yet supported for PolarSSL.");
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
|
||||
void
|
||||
tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
|
||||
#if ENABLE_INLINE_FILES
|
||||
const char *cert_file_inline,
|
||||
#endif
|
||||
x509_cert_t **x509
|
||||
)
|
||||
{
|
||||
ASSERT(NULL != ctx);
|
||||
if (NULL != x509)
|
||||
ASSERT(NULL == *x509);
|
||||
|
||||
#if ENABLE_INLINE_FILES
|
||||
if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_file_inline)
|
||||
{
|
||||
if (0 != x509parse_crt(ctx->crt_chain, cert_file_inline,
|
||||
strlen(cert_file_inline)))
|
||||
msg (M_FATAL, "Cannot load inline certificate file");
|
||||
}
|
||||
else
|
||||
#endif /* ENABLE_INLINE_FILES */
|
||||
{
|
||||
if (0 != x509parse_crtfile(ctx->crt_chain, cert_file))
|
||||
msg (M_FATAL, "Cannot load certificate file %s", cert_file);
|
||||
}
|
||||
if (x509)
|
||||
{
|
||||
*x509 = ctx->crt_chain;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file
|
||||
#if ENABLE_INLINE_FILES
|
||||
, const char *priv_key_file_inline
|
||||
#endif /* ENABLE_INLINE_FILES */
|
||||
)
|
||||
{
|
||||
int status;
|
||||
ASSERT(NULL != ctx);
|
||||
|
||||
#if ENABLE_INLINE_FILES
|
||||
if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_file_inline)
|
||||
{
|
||||
status = x509parse_key(ctx->priv_key,
|
||||
priv_key_file_inline, strlen(priv_key_file_inline),
|
||||
NULL, 0);
|
||||
if (POLARSSL_ERR_X509_KEY_PASSWORD_REQUIRED == status)
|
||||
{
|
||||
char passbuf[512] = {0};
|
||||
pem_password_callback(passbuf, 512, 0, NULL);
|
||||
status = x509parse_key(ctx->priv_key,
|
||||
priv_key_file_inline, strlen(priv_key_file_inline),
|
||||
passbuf, strlen(passbuf));
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* ENABLE_INLINE_FILES */
|
||||
{
|
||||
status = x509parse_keyfile(ctx->priv_key, priv_key_file, NULL);
|
||||
if (POLARSSL_ERR_X509_KEY_PASSWORD_REQUIRED == status)
|
||||
{
|
||||
char passbuf[512] = {0};
|
||||
pem_password_callback(passbuf, 512, 0, NULL);
|
||||
status = x509parse_keyfile(ctx->priv_key, priv_key_file, passbuf);
|
||||
}
|
||||
}
|
||||
if (0 != status)
|
||||
{
|
||||
#ifdef ENABLE_MANAGEMENT
|
||||
if (management && (POLARSSL_ERR_X509_KEY_PASSWORD_MISMATCH == status))
|
||||
management_auth_failure (management, UP_TYPE_PRIVATE_KEY, NULL);
|
||||
#endif
|
||||
msg (M_WARN, "Cannot load private key file %s", priv_key_file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
warn_if_group_others_accessible (priv_key_file);
|
||||
|
||||
/* TODO: Check Private Key */
|
||||
// if (!SSL_CTX_check_private_key (ctx))
|
||||
// msg (M_SSLERR, "Private key does not match the certificate");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef MANAGMENT_EXTERNAL_KEY
|
||||
|
||||
int
|
||||
tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, x509_cert_t *cert)
|
||||
{
|
||||
msg(M_FATAL, "Use of management external keys not yet supported for PolarSSL.");
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
|
||||
#if ENABLE_INLINE_FILES
|
||||
const char *ca_file_inline,
|
||||
#endif
|
||||
const char *ca_path, bool tls_server
|
||||
)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (ca_path)
|
||||
msg(M_FATAL, "ERROR: PolarSSL cannot handle the capath directive");
|
||||
|
||||
#if ENABLE_INLINE_FILES
|
||||
if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline)
|
||||
{
|
||||
if (0 != x509parse_crt(ctx->ca_chain, ca_file_inline, strlen(ca_file_inline)));
|
||||
msg (M_FATAL, "Cannot load inline CA certificates");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
/* Load CA file for verifying peer supplied certificate */
|
||||
if (0 != x509parse_crtfile(ctx->ca_chain, ca_file))
|
||||
msg (M_FATAL, "Cannot load CA certificate file %s", ca_file);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file
|
||||
#if ENABLE_INLINE_FILES
|
||||
, const char *extra_certs_file_inline
|
||||
#endif
|
||||
)
|
||||
{
|
||||
ASSERT(NULL != ctx);
|
||||
|
||||
#if ENABLE_INLINE_FILES
|
||||
if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline)
|
||||
{
|
||||
if (0 != x509parse_crt(ctx->crt_chain, extra_certs_file_inline,
|
||||
strlen(extra_certs_file_inline)))
|
||||
msg (M_FATAL, "Cannot load inline extra-certs file");
|
||||
}
|
||||
else
|
||||
#endif /* ENABLE_INLINE_FILES */
|
||||
{
|
||||
if (0 != x509parse_crtfile(ctx->crt_chain, extra_certs_file))
|
||||
msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file);
|
||||
}
|
||||
}
|
||||
|
||||
/* **************************************
|
||||
*
|
||||
* Key-state specific functions
|
||||
*
|
||||
***************************************/
|
||||
|
||||
/*
|
||||
* "Endless buffer"
|
||||
*/
|
||||
|
||||
static inline void buf_free_entry(buffer_entry *entry)
|
||||
{
|
||||
if (NULL != entry)
|
||||
{
|
||||
free(entry->data);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void buf_free_entries(endless_buffer *buf)
|
||||
{
|
||||
while(buf->first_block)
|
||||
{
|
||||
buffer_entry *cur_block = buf->first_block;
|
||||
buf->first_block = cur_block->next_block;
|
||||
buf_free_entry(cur_block);
|
||||
}
|
||||
buf->last_block = NULL;
|
||||
}
|
||||
|
||||
static int endless_buf_read( void * ctx, unsigned char * out, int out_len )
|
||||
{
|
||||
endless_buffer *in = (endless_buffer *) ctx;
|
||||
int read_len = 0;
|
||||
|
||||
if (in->first_block == NULL)
|
||||
return POLARSSL_ERR_NET_TRY_AGAIN;
|
||||
|
||||
while (in->first_block != NULL && read_len < out_len)
|
||||
{
|
||||
int block_len = in->first_block->length - in->data_start;
|
||||
if (block_len <= out_len - read_len)
|
||||
{
|
||||
buffer_entry *cur_entry = in->first_block;
|
||||
memcpy(out + read_len, cur_entry->data + in->data_start,
|
||||
block_len);
|
||||
|
||||
read_len += block_len;
|
||||
|
||||
in->first_block = cur_entry->next_block;
|
||||
in->data_start = 0;
|
||||
|
||||
if (in->first_block == NULL)
|
||||
in->last_block = NULL;
|
||||
|
||||
buf_free_entry(cur_entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(out + read_len, in->first_block->data + in->data_start,
|
||||
out_len - read_len);
|
||||
in->data_start += out_len - read_len;
|
||||
read_len = out_len;
|
||||
}
|
||||
}
|
||||
|
||||
return read_len;
|
||||
}
|
||||
|
||||
static int endless_buf_write( void *ctx, unsigned char *in, int len )
|
||||
{
|
||||
endless_buffer *out = (endless_buffer *) ctx;
|
||||
buffer_entry *new_block = malloc(sizeof(buffer_entry));
|
||||
if (NULL == new_block)
|
||||
return POLARSSL_ERR_NET_SEND_FAILED;
|
||||
|
||||
new_block->data = malloc(len);
|
||||
if (NULL == new_block->data)
|
||||
{
|
||||
free(new_block);
|
||||
return POLARSSL_ERR_NET_SEND_FAILED;
|
||||
}
|
||||
|
||||
new_block->length = len;
|
||||
new_block->next_block = NULL;
|
||||
|
||||
memcpy(new_block->data, in, len);
|
||||
|
||||
if (NULL == out->first_block)
|
||||
out->first_block = new_block;
|
||||
|
||||
if (NULL != out->last_block)
|
||||
out->last_block->next_block = new_block;
|
||||
|
||||
out->last_block = new_block;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void my_debug( void *ctx, int level, const char *str )
|
||||
{
|
||||
if (level == 1)
|
||||
{
|
||||
dmsg (D_HANDSHAKE_VERBOSE, "PolarSSL alert: %s", str);
|
||||
}
|
||||
}
|
||||
|
||||
void key_state_ssl_init(struct key_state_ssl *ks_ssl,
|
||||
const struct tls_root_ctx *ssl_ctx, bool is_server, void *session)
|
||||
{
|
||||
ASSERT(NULL != ssl_ctx);
|
||||
ASSERT(ks_ssl);
|
||||
CLEAR(*ks_ssl);
|
||||
|
||||
ALLOC_OBJ_CLEAR(ks_ssl->ctx, ssl_context);
|
||||
if (0 == ssl_init(ks_ssl->ctx))
|
||||
{
|
||||
/* Initialise SSL context */
|
||||
ssl_set_dbg (ks_ssl->ctx, my_debug, NULL);
|
||||
ssl_set_endpoint (ks_ssl->ctx, ssl_ctx->endpoint);
|
||||
ssl_set_rng (ks_ssl->ctx, havege_rand, ssl_ctx->hs);
|
||||
ALLOC_OBJ_CLEAR (ks_ssl->ssn, ssl_session);
|
||||
ssl_set_session (ks_ssl->ctx, 0, 0, ks_ssl->ssn );
|
||||
if (ssl_ctx->allowed_ciphers)
|
||||
ssl_set_ciphers (ks_ssl->ctx, ssl_ctx->allowed_ciphers);
|
||||
else
|
||||
ssl_set_ciphers (ks_ssl->ctx, default_ciphers);
|
||||
|
||||
/* Initialise authentication information */
|
||||
ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx );
|
||||
if (ssl_ctx->priv_key_pkcs11 != NULL)
|
||||
ssl_set_own_cert_pkcs11( ks_ssl->ctx, ssl_ctx->crt_chain,
|
||||
ssl_ctx->priv_key_pkcs11 );
|
||||
else
|
||||
ssl_set_own_cert( ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key );
|
||||
|
||||
/* Initialise SSL verification */
|
||||
ssl_set_authmode (ks_ssl->ctx, SSL_VERIFY_REQUIRED);
|
||||
ssl_set_verify (ks_ssl->ctx, verify_callback, session);
|
||||
/* TODO: PolarSSL does not currently support sending the CA chain to the client */
|
||||
ssl_set_ca_chain (ks_ssl->ctx, ssl_ctx->ca_chain, NULL, NULL );
|
||||
|
||||
/* Initialise BIOs */
|
||||
ALLOC_OBJ_CLEAR (ks_ssl->ct_in, endless_buffer);
|
||||
ALLOC_OBJ_CLEAR (ks_ssl->ct_out, endless_buffer);
|
||||
ssl_set_bio (ks_ssl->ctx, endless_buf_read, ks_ssl->ct_in,
|
||||
endless_buf_write, ks_ssl->ct_out);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
key_state_ssl_free(struct key_state_ssl *ks_ssl)
|
||||
{
|
||||
if (ks_ssl) {
|
||||
if (ks_ssl->ctx)
|
||||
{
|
||||
ssl_free(ks_ssl->ctx);
|
||||
free(ks_ssl->ctx);
|
||||
}
|
||||
if (ks_ssl->ssn)
|
||||
free(ks_ssl->ssn);
|
||||
if (ks_ssl->ct_in) {
|
||||
buf_free_entries(ks_ssl->ct_in);
|
||||
free(ks_ssl->ct_in);
|
||||
}
|
||||
if (ks_ssl->ct_out) {
|
||||
buf_free_entries(ks_ssl->ct_out);
|
||||
free(ks_ssl->ct_out);
|
||||
}
|
||||
CLEAR(*ks_ssl);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
key_state_write_plaintext (struct key_state_ssl *ks, struct buffer *buf)
|
||||
{
|
||||
int retval = 0;
|
||||
perf_push (PERF_BIO_WRITE_PLAINTEXT);
|
||||
|
||||
ASSERT (NULL != ks);
|
||||
ASSERT (buf);
|
||||
ASSERT (buf->len >= 0);
|
||||
|
||||
if (0 == buf->len)
|
||||
{
|
||||
return 0;
|
||||
perf_pop ();
|
||||
}
|
||||
|
||||
retval = ssl_write(ks->ctx, BPTR(buf), buf->len);
|
||||
|
||||
if (retval < 0)
|
||||
{
|
||||
perf_pop ();
|
||||
if (POLARSSL_ERR_NET_TRY_AGAIN == retval )
|
||||
return 0;
|
||||
msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_plaintext error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (retval != buf->len)
|
||||
{
|
||||
msg (D_TLS_ERRORS,
|
||||
"TLS ERROR: write tls_write_plaintext incomplete %d/%d",
|
||||
retval, buf->len);
|
||||
perf_pop ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* successful write */
|
||||
dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_plaintext %d bytes", retval);
|
||||
|
||||
memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */
|
||||
buf->len = 0;
|
||||
|
||||
perf_pop ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
key_state_write_plaintext_const (struct key_state_ssl *ks, const uint8_t *data, int len)
|
||||
{
|
||||
int retval = 0;
|
||||
perf_push (PERF_BIO_WRITE_PLAINTEXT);
|
||||
|
||||
ASSERT (NULL != ks);
|
||||
ASSERT (len >= 0);
|
||||
|
||||
if (0 == len)
|
||||
{
|
||||
perf_pop ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ASSERT (data);
|
||||
|
||||
retval = ssl_write(ks->ctx, data, len);
|
||||
|
||||
if (retval < 0)
|
||||
{
|
||||
perf_pop ();
|
||||
if (POLARSSL_ERR_NET_TRY_AGAIN == retval )
|
||||
return 0;
|
||||
msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_plaintext_const error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (retval != len)
|
||||
{
|
||||
msg (D_TLS_ERRORS,
|
||||
"TLS ERROR: write tls_write_plaintext_const incomplete %d/%d",
|
||||
retval, len);
|
||||
perf_pop ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* successful write */
|
||||
dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_plaintext_const %d bytes", retval);
|
||||
|
||||
perf_pop ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf,
|
||||
int maxlen)
|
||||
{
|
||||
int retval = 0;
|
||||
int len = 0;
|
||||
|
||||
perf_push (PERF_BIO_READ_CIPHERTEXT);
|
||||
|
||||
ASSERT (NULL != ks);
|
||||
ASSERT (buf);
|
||||
ASSERT (buf->len >= 0);
|
||||
|
||||
if (buf->len)
|
||||
{
|
||||
perf_pop ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = buf_forward_capacity (buf);
|
||||
if (maxlen < len)
|
||||
len = maxlen;
|
||||
|
||||
retval = endless_buf_read(ks->ct_out, BPTR(buf), len);
|
||||
|
||||
/* Error during read, check for retry error */
|
||||
if (retval < 0)
|
||||
{
|
||||
perf_pop ();
|
||||
if (POLARSSL_ERR_NET_TRY_AGAIN == retval )
|
||||
return 0;
|
||||
msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_plaintext error");
|
||||
buf->len = 0;
|
||||
return -1;
|
||||
}
|
||||
/* Nothing read, try again */
|
||||
if (0 == retval)
|
||||
{
|
||||
buf->len = 0;
|
||||
perf_pop ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* successful read */
|
||||
dmsg (D_HANDSHAKE_VERBOSE, "read tls_read_ciphertext %d bytes", retval);
|
||||
buf->len = retval;
|
||||
perf_pop ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
key_state_write_ciphertext (struct key_state_ssl *ks, struct buffer *buf)
|
||||
{
|
||||
int retval = 0;
|
||||
perf_push (PERF_BIO_WRITE_CIPHERTEXT);
|
||||
|
||||
ASSERT (NULL != ks);
|
||||
ASSERT (buf);
|
||||
ASSERT (buf->len >= 0);
|
||||
|
||||
if (0 == buf->len)
|
||||
{
|
||||
perf_pop ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
retval = endless_buf_write(ks->ct_in, BPTR(buf), buf->len);
|
||||
|
||||
if (retval < 0)
|
||||
{
|
||||
perf_pop ();
|
||||
|
||||
if (POLARSSL_ERR_NET_TRY_AGAIN == retval )
|
||||
return 0;
|
||||
msg (D_TLS_ERRORS, "TLS ERROR: write tls_write_ciphertext error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (retval != buf->len)
|
||||
{
|
||||
msg (D_TLS_ERRORS,
|
||||
"TLS ERROR: write tls_write_ciphertext incomplete %d/%d",
|
||||
retval, buf->len);
|
||||
perf_pop ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* successful write */
|
||||
dmsg (D_HANDSHAKE_VERBOSE, "write tls_write_ciphertext %d bytes", retval);
|
||||
|
||||
memset (BPTR (buf), 0, BLEN (buf)); /* erase data just written */
|
||||
buf->len = 0;
|
||||
|
||||
perf_pop ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf,
|
||||
int maxlen)
|
||||
{
|
||||
int retval = 0;
|
||||
int len = 0;
|
||||
|
||||
perf_push (PERF_BIO_READ_PLAINTEXT);
|
||||
|
||||
ASSERT (NULL != ks);
|
||||
ASSERT (buf);
|
||||
ASSERT (buf->len >= 0);
|
||||
|
||||
if (buf->len)
|
||||
{
|
||||
perf_pop ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = buf_forward_capacity (buf);
|
||||
if (maxlen < len)
|
||||
len = maxlen;
|
||||
|
||||
retval = ssl_read(ks->ctx, BPTR(buf), len);
|
||||
|
||||
/* Error during read, check for retry error */
|
||||
if (retval < 0)
|
||||
{
|
||||
if (POLARSSL_ERR_NET_TRY_AGAIN == retval )
|
||||
return 0;
|
||||
msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_plaintext error");
|
||||
buf->len = 0;
|
||||
perf_pop ();
|
||||
return -1;
|
||||
}
|
||||
/* Nothing read, try again */
|
||||
if (0 == retval)
|
||||
{
|
||||
buf->len = 0;
|
||||
perf_pop ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* successful read */
|
||||
dmsg (D_HANDSHAKE_VERBOSE, "read tls_read_plaintext %d bytes", retval);
|
||||
buf->len = retval;
|
||||
|
||||
perf_pop ();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* **************************************
|
||||
*
|
||||
* Information functions
|
||||
*
|
||||
* Print information for the end user.
|
||||
*
|
||||
***************************************/
|
||||
void
|
||||
print_details (struct key_state_ssl * ks_ssl, const char *prefix)
|
||||
{
|
||||
x509_cert *cert;
|
||||
char s1[256];
|
||||
char s2[256];
|
||||
|
||||
s1[0] = s2[0] = 0;
|
||||
openvpn_snprintf (s1, sizeof (s1), "%s %s, cipher %s",
|
||||
prefix,
|
||||
ssl_get_version (ks_ssl->ctx),
|
||||
ssl_get_cipher(ks_ssl->ctx));
|
||||
|
||||
cert = ks_ssl->ctx->peer_cert;
|
||||
if (cert != NULL)
|
||||
{
|
||||
openvpn_snprintf (s2, sizeof (s2), ", %d bit RSA", cert->rsa.len * 8);
|
||||
}
|
||||
|
||||
msg (D_HANDSHAKE, "%s%s", s1, s2);
|
||||
}
|
||||
|
||||
void
|
||||
show_available_tls_ciphers ()
|
||||
{
|
||||
const int *ciphers = ssl_list_ciphers();
|
||||
|
||||
#ifndef ENABLE_SMALL
|
||||
printf ("Available TLS Ciphers,\n");
|
||||
printf ("listed in order of preference:\n\n");
|
||||
#endif
|
||||
|
||||
while (*ciphers != 0)
|
||||
{
|
||||
printf ("%s\n", ssl_get_cipher_name(*ciphers));
|
||||
ciphers++;
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
void
|
||||
get_highest_preference_tls_cipher (char *buf, int size)
|
||||
{
|
||||
const char *cipher_name;
|
||||
const int *ciphers = ssl_list_ciphers();
|
||||
if (*ciphers == 0)
|
||||
msg (M_FATAL, "Cannot retrieve list of supported SSL ciphers.");
|
||||
|
||||
cipher_name = ssl_get_cipher_name(*ciphers);
|
||||
strncpynt (buf, cipher_name, size);
|
||||
}
|
85
ssl_polarssl.h
Normal file
85
ssl_polarssl.h
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* OpenVPN -- An application to securely tunnel IP networks
|
||||
* over a single TCP/UDP port, with support for SSL/TLS-based
|
||||
* session authentication and key exchange,
|
||||
* packet encryption, packet authentication, and
|
||||
* packet compression.
|
||||
*
|
||||
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
|
||||
* Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see the file COPYING included with this
|
||||
* distribution); if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Control Channel PolarSSL Backend
|
||||
*/
|
||||
|
||||
#ifndef SSL_POLARSSL_H_
|
||||
#define SSL_POLARSSL_H_
|
||||
|
||||
#include <polarssl/havege.h>
|
||||
#include <polarssl/ssl.h>
|
||||
#include "config.h"
|
||||
|
||||
#if defined(ENABLE_PKCS11)
|
||||
#include <polarssl/pkcs11.h>
|
||||
#endif
|
||||
|
||||
typedef struct _buffer_entry buffer_entry;
|
||||
|
||||
struct _buffer_entry {
|
||||
size_t length;
|
||||
uint8_t *data;
|
||||
buffer_entry *next_block;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
size_t data_start;
|
||||
buffer_entry *first_block;
|
||||
buffer_entry *last_block;
|
||||
} endless_buffer;
|
||||
|
||||
/**
|
||||
* Structure that wraps the TLS context. Contents differ depending on the
|
||||
* SSL library used.
|
||||
*
|
||||
* Either \c priv_key_pkcs11 or \c priv_key must be filled in.
|
||||
*/
|
||||
struct tls_root_ctx {
|
||||
bool initialised; /**< True if the context has been initialised */
|
||||
|
||||
int endpoint; /**< Whether or not this is a server or a client */
|
||||
|
||||
havege_state *hs; /**< HAVEGE random number state */
|
||||
dhm_context *dhm_ctx; /**< Diffie-Helmann-Merkle context */
|
||||
x509_cert *crt_chain; /**< Local Certificate chain */
|
||||
x509_cert *ca_chain; /**< CA chain for remote verification */
|
||||
rsa_context *priv_key; /**< Local private key */
|
||||
#if defined(ENABLE_PKCS11)
|
||||
pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */
|
||||
#endif
|
||||
int * allowed_ciphers; /**< List of allowed ciphers for this connection */
|
||||
};
|
||||
|
||||
struct key_state_ssl {
|
||||
ssl_context *ctx;
|
||||
ssl_session *ssn;
|
||||
endless_buffer *ct_in;
|
||||
endless_buffer *ct_out;
|
||||
};
|
||||
|
||||
|
||||
#endif /* SSL_POLARSSL_H_ */
|
@ -326,7 +326,7 @@ verify_peer_cert(const struct tls_options *opt, x509_cert_t *peer_cert,
|
||||
}
|
||||
}
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x00907000L || USE_POLARSSL
|
||||
|
||||
/* verify certificate ku */
|
||||
if (opt->remote_cert_ku[0] != 0)
|
||||
|
@ -39,6 +39,9 @@
|
||||
#ifdef USE_OPENSSL
|
||||
#include "ssl_verify_openssl.h"
|
||||
#endif
|
||||
#ifdef USE_POLARSSL
|
||||
#include "ssl_verify_polarssl.h"
|
||||
#endif
|
||||
|
||||
#include "ssl_verify_backend.h"
|
||||
|
||||
|
446
ssl_verify_polarssl.c
Normal file
446
ssl_verify_polarssl.c
Normal file
@ -0,0 +1,446 @@
|
||||
/*
|
||||
* OpenVPN -- An application to securely tunnel IP networks
|
||||
* over a single TCP/UDP port, with support for SSL/TLS-based
|
||||
* session authentication and key exchange,
|
||||
* packet encryption, packet authentication, and
|
||||
* packet compression.
|
||||
*
|
||||
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
|
||||
* Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see the file COPYING included with this
|
||||
* distribution); if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Control Channel Verification Module PolarSSL backend
|
||||
*/
|
||||
|
||||
#include "ssl_verify.h"
|
||||
#include <polarssl/sha1.h>
|
||||
|
||||
#define MAX_SUBJECT_LENGTH 256
|
||||
|
||||
int
|
||||
verify_callback (void *session_obj, x509_cert *cert, int cert_depth,
|
||||
int preverify_ok)
|
||||
{
|
||||
struct tls_session *session = (struct tls_session *) session_obj;
|
||||
unsigned char *sha1_hash = NULL;
|
||||
|
||||
ASSERT (cert);
|
||||
ASSERT (session);
|
||||
|
||||
session->verified = false;
|
||||
|
||||
/* Remember certificate hash */
|
||||
sha1_hash = x509_get_sha1_hash(cert);
|
||||
cert_hash_remember (session, cert_depth, sha1_hash);
|
||||
x509_free_sha1_hash(sha1_hash);
|
||||
|
||||
/* did peer present cert which was signed by our root cert? */
|
||||
if (!preverify_ok)
|
||||
{
|
||||
char subject[MAX_SUBJECT_LENGTH] = {0};
|
||||
|
||||
/* get the X509 name */
|
||||
if (x509parse_dn_gets( subject, MAX_SUBJECT_LENGTH, &cert->subject ) < 0)
|
||||
msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, could not extract X509 "
|
||||
"subject string from certificate", cert_depth);
|
||||
else
|
||||
msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, %s", cert_depth, subject);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* verify_cert() returns 1 on success, 0 on failure.
|
||||
* PolarSSL expects the opposite.
|
||||
*/
|
||||
return 0 == verify_cert(session, cert, cert_depth);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_X509ALTUSERNAME
|
||||
# warning "X509 alt user name not yet supported for PolarSSL"
|
||||
#endif
|
||||
|
||||
bool
|
||||
x509_get_username (char *cn, int cn_len,
|
||||
char *x509_username_field, x509_cert *cert)
|
||||
{
|
||||
x509_name *name;
|
||||
|
||||
ASSERT( cn != NULL );
|
||||
|
||||
name = &cert->subject;
|
||||
|
||||
/* Find common name */
|
||||
while( name != NULL )
|
||||
{
|
||||
if( memcmp( name->oid.p, OID_CN, OID_SIZE(OID_CN) ) == 0)
|
||||
break;
|
||||
|
||||
name = name->next;
|
||||
}
|
||||
|
||||
/* Not found, return an error if this is the peer's certificate */
|
||||
if( name == NULL )
|
||||
return 1;
|
||||
|
||||
/* Found, extract CN */
|
||||
if (cn_len > name->val.len)
|
||||
memcpy( cn, name->val.p, name->val.len );
|
||||
else
|
||||
{
|
||||
memcpy( cn, name->val.p, cn_len);
|
||||
cn[cn_len-1] = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *
|
||||
x509_get_serial (x509_cert *cert)
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
char *buf = NULL;
|
||||
size_t len = cert->serial.len * 3;
|
||||
|
||||
buf = malloc(len);
|
||||
ASSERT(buf);
|
||||
|
||||
if(x509parse_serial_gets(buf, len-1, &cert->serial) < 0)
|
||||
{
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void
|
||||
x509_free_serial (char *serial)
|
||||
{
|
||||
if (serial)
|
||||
free(serial);
|
||||
}
|
||||
|
||||
unsigned char *
|
||||
x509_get_sha1_hash (x509_cert *cert)
|
||||
{
|
||||
unsigned char *sha1_hash = malloc(SHA_DIGEST_LENGTH);
|
||||
sha1(cert->tbs.p, cert->tbs.len, sha1_hash);
|
||||
return sha1_hash;
|
||||
}
|
||||
|
||||
void
|
||||
x509_free_sha1_hash (unsigned char *hash)
|
||||
{
|
||||
if (hash)
|
||||
free(hash);
|
||||
}
|
||||
|
||||
char *
|
||||
x509_get_subject(x509_cert *cert)
|
||||
{
|
||||
char tmp_subject[MAX_SUBJECT_LENGTH] = {0};
|
||||
char *subject = NULL;
|
||||
|
||||
int ret = 0;
|
||||
|
||||
ret = x509parse_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject );
|
||||
if (ret > 0)
|
||||
{
|
||||
/* Allocate the required space for the subject */
|
||||
subject = malloc(ret + 1);
|
||||
strncpy(subject, tmp_subject, ret+1);
|
||||
}
|
||||
|
||||
return subject;
|
||||
}
|
||||
|
||||
void
|
||||
x509_free_subject (char *subject)
|
||||
{
|
||||
if (subject)
|
||||
free(subject);
|
||||
}
|
||||
|
||||
/*
|
||||
* Save X509 fields to environment, using the naming convention:
|
||||
*
|
||||
* X509_{cert_depth}_{name}={value}
|
||||
*/
|
||||
void
|
||||
x509_setenv (struct env_set *es, int cert_depth, x509_cert_t *cert)
|
||||
{
|
||||
int i, ret;
|
||||
unsigned char c;
|
||||
const x509_name *name;
|
||||
char s[128];
|
||||
|
||||
name = &cert->subject;
|
||||
|
||||
memset( s, 0, sizeof( s ) );
|
||||
|
||||
while( name != NULL )
|
||||
{
|
||||
char name_expand[64+8];
|
||||
|
||||
if( name->oid.len == 2 && memcmp( name->oid.p, OID_X520, 2 ) == 0 )
|
||||
{
|
||||
switch( name->oid.p[2] )
|
||||
{
|
||||
case X520_COMMON_NAME:
|
||||
openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_CN",
|
||||
cert_depth); break;
|
||||
|
||||
case X520_COUNTRY:
|
||||
openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_C",
|
||||
cert_depth); break;
|
||||
|
||||
case X520_LOCALITY:
|
||||
openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_L",
|
||||
cert_depth); break;
|
||||
|
||||
case X520_STATE:
|
||||
openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_ST",
|
||||
cert_depth); break;
|
||||
|
||||
case X520_ORGANIZATION:
|
||||
openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_O",
|
||||
cert_depth); break;
|
||||
|
||||
case X520_ORG_UNIT:
|
||||
openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_OU",
|
||||
cert_depth); break;
|
||||
|
||||
default:
|
||||
openvpn_snprintf (name_expand, sizeof(name_expand),
|
||||
"X509_%d_0x%02X", cert_depth, name->oid.p[2]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if( name->oid.len == 8 && memcmp( name->oid.p, OID_PKCS9, 8 ) == 0 )
|
||||
{
|
||||
switch( name->oid.p[8] )
|
||||
{
|
||||
case PKCS9_EMAIL:
|
||||
openvpn_snprintf (name_expand, sizeof(name_expand),
|
||||
"X509_%d_emailAddress", cert_depth); break;
|
||||
|
||||
default:
|
||||
openvpn_snprintf (name_expand, sizeof(name_expand),
|
||||
"X509_%d_0x%02X", cert_depth, name->oid.p[8]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?",
|
||||
cert_depth);
|
||||
}
|
||||
|
||||
for( i = 0; i < name->val.len; i++ )
|
||||
{
|
||||
if( i >= (int) sizeof( s ) - 1 )
|
||||
break;
|
||||
|
||||
c = name->val.p[i];
|
||||
if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
|
||||
s[i] = '?';
|
||||
else s[i] = c;
|
||||
}
|
||||
s[i] = '\0';
|
||||
|
||||
/* Check both strings, set environment variable */
|
||||
string_mod (name_expand, CC_PRINT, CC_CRLF, '_');
|
||||
string_mod ((char*)s, CC_PRINT, CC_CRLF, '_');
|
||||
setenv_str (es, name_expand, (char*)s);
|
||||
|
||||
name = name->next;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
x509_verify_ns_cert_type(const x509_cert *cert, const int usage)
|
||||
{
|
||||
if (usage == NS_CERT_CHECK_NONE)
|
||||
return true;
|
||||
if (usage == NS_CERT_CHECK_CLIENT)
|
||||
return ((cert->ext_types & EXT_NS_CERT_TYPE)
|
||||
&& (cert->ns_cert_type & NS_CERT_TYPE_SSL_CLIENT));
|
||||
if (usage == NS_CERT_CHECK_SERVER)
|
||||
return ((cert->ext_types & EXT_NS_CERT_TYPE)
|
||||
&& (cert->ns_cert_type & NS_CERT_TYPE_SSL_SERVER));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
x509_verify_cert_ku (x509_cert *cert, const unsigned * const expected_ku,
|
||||
int expected_len)
|
||||
{
|
||||
bool fFound = false;
|
||||
|
||||
if(!(cert->ext_types & EXT_KEY_USAGE))
|
||||
{
|
||||
msg (D_HANDSHAKE, "Certificate does not have key usage extension");
|
||||
}
|
||||
else
|
||||
{
|
||||
int i;
|
||||
unsigned nku = cert->key_usage;
|
||||
|
||||
msg (D_HANDSHAKE, "Validating certificate key usage");
|
||||
for (i=0;!fFound && i<expected_len;i++)
|
||||
{
|
||||
if (expected_ku[i] != 0)
|
||||
{
|
||||
msg (D_HANDSHAKE, "++ Certificate has key usage %04x, expects "
|
||||
"%04x", nku, expected_ku[i]);
|
||||
|
||||
if (nku == expected_ku[i])
|
||||
{
|
||||
fFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return fFound;
|
||||
}
|
||||
|
||||
bool
|
||||
x509_verify_cert_eku (x509_cert *cert, const char * const expected_oid)
|
||||
{
|
||||
bool fFound = false;
|
||||
|
||||
if (!(cert->ext_types & EXT_EXTENDED_KEY_USAGE))
|
||||
{
|
||||
msg (D_HANDSHAKE, "Certificate does not have extended key usage extension");
|
||||
}
|
||||
else
|
||||
{
|
||||
x509_sequence *oid_seq = &(cert->ext_key_usage);
|
||||
|
||||
msg (D_HANDSHAKE, "Validating certificate extended key usage");
|
||||
while (oid_seq != NULL)
|
||||
{
|
||||
x509_buf *oid = &oid_seq->buf;
|
||||
char oid_num_str[1024];
|
||||
const char *oid_str;
|
||||
|
||||
oid_str = x509_oid_get_description(oid);
|
||||
if (oid_str != NULL)
|
||||
{
|
||||
msg (D_HANDSHAKE, "++ Certificate has EKU (str) %s, expects %s",
|
||||
oid_str, expected_oid);
|
||||
if (!strcmp (expected_oid, oid_str))
|
||||
{
|
||||
fFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == x509_oid_get_numeric_string( oid_num_str,
|
||||
sizeof (oid_num_str), oid))
|
||||
{
|
||||
msg (D_HANDSHAKE, "++ Certificate has EKU (oid) %s, expects %s",
|
||||
oid_num_str, expected_oid);
|
||||
if (!strcmp (expected_oid, oid_num_str))
|
||||
{
|
||||
fFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
oid_seq = oid_seq->next;
|
||||
}
|
||||
}
|
||||
|
||||
return fFound;
|
||||
}
|
||||
|
||||
const char *
|
||||
x509_write_cert(x509_cert *peercert, const char *tmp_dir, struct gc_arena *gc)
|
||||
{
|
||||
FILE *peercert_file;
|
||||
const char *peercert_filename="";
|
||||
|
||||
if(!tmp_dir)
|
||||
return NULL;
|
||||
|
||||
/* create tmp file to store peer cert */
|
||||
peercert_filename = create_temp_file (tmp_dir, "pcf", gc);
|
||||
|
||||
/* write peer-cert in tmp-file */
|
||||
peercert_file = fopen(peercert_filename, "w+");
|
||||
if(!peercert_file)
|
||||
{
|
||||
msg (M_ERR, "Failed to open temporary file : %s", peercert_filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// if(PEM_write_X509(peercert_file,peercert)<0)
|
||||
// {
|
||||
msg (M_ERR, "PolarSSL does not support writing peer certificate in PEM format");
|
||||
fclose(peercert_file);
|
||||
return NULL;
|
||||
// }
|
||||
|
||||
fclose(peercert_file);
|
||||
return peercert_filename;
|
||||
}
|
||||
|
||||
/*
|
||||
* check peer cert against CRL
|
||||
*/
|
||||
bool
|
||||
x509_verify_crl(const char *crl_file, x509_cert *cert, const char *subject)
|
||||
{
|
||||
int retval = 0;
|
||||
x509_crl crl = {0};
|
||||
|
||||
if (x509parse_crlfile(&crl, crl_file) != 0)
|
||||
{
|
||||
msg (M_ERR, "CRL: cannot read CRL from file %s", crl_file);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if(cert->issuer_raw.len != crl.issuer_raw.len ||
|
||||
memcmp(crl.issuer_raw.p, cert->issuer_raw.p, crl.issuer_raw.len) != 0)
|
||||
{
|
||||
msg (M_WARN, "CRL: CRL %s is from a different issuer than the issuer of "
|
||||
"certificate %s", crl_file, subject);
|
||||
retval = 1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (0 != x509parse_revoked(cert, &crl))
|
||||
{
|
||||
msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED", subject);
|
||||
goto end;
|
||||
}
|
||||
|
||||
retval = 1;
|
||||
msg (D_HANDSHAKE, "CRL CHECK OK: %s",subject);
|
||||
|
||||
end:
|
||||
x509_crl_free(&crl);
|
||||
|
||||
if (!retval)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
79
ssl_verify_polarssl.h
Normal file
79
ssl_verify_polarssl.h
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* OpenVPN -- An application to securely tunnel IP networks
|
||||
* over a single TCP/UDP port, with support for SSL/TLS-based
|
||||
* session authentication and key exchange,
|
||||
* packet encryption, packet authentication, and
|
||||
* packet compression.
|
||||
*
|
||||
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
|
||||
* Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see the file COPYING included with this
|
||||
* distribution); if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file Control Channel Verification Module PolarSSL backend
|
||||
*/
|
||||
|
||||
#ifndef SSL_VERIFY_POLARSSL_H_
|
||||
#define SSL_VERIFY_POLARSSL_H_
|
||||
|
||||
#include "syshead.h"
|
||||
#include "misc.h"
|
||||
#include "manage.h"
|
||||
#include <polarssl/x509.h>
|
||||
|
||||
typedef x509_cert x509_cert_t;
|
||||
|
||||
/** @name Function for authenticating a new connection from a remote OpenVPN peer
|
||||
* @{ */
|
||||
|
||||
/**
|
||||
* Verify that the remote OpenVPN peer's certificate allows setting up a
|
||||
* VPN tunnel.
|
||||
* @ingroup control_tls
|
||||
*
|
||||
* This callback function is called when a new TLS session is being setup to
|
||||
* determine whether the remote OpenVPN peer's certificate is allowed to
|
||||
* connect. It is called for once for every certificate in the chain. The
|
||||
* callback functionality is configured in the \c init_ssl() function, which
|
||||
* calls the PolarSSL library's \c ssl_set_verify_callback() function with \c
|
||||
* verify_callback() as its callback argument.
|
||||
*
|
||||
* It checks preverify_ok, and registers the certificate hash. If these steps
|
||||
* succeed, it calls the \c verify_cert() function, which performs
|
||||
* OpenVPN-specific verification.
|
||||
*
|
||||
* @param session_obj - The OpenVPN \c tls_session associated with this object,
|
||||
* as set during SSL session setup.
|
||||
* @param cert - The certificate used by PolarSSL.
|
||||
* @param cert_depth - The depth of the current certificate in the chain, with
|
||||
* 0 being the actual certificate.
|
||||
* @param preverify_ok - Whether the remote OpenVPN peer's certificate
|
||||
* past verification. A value of 1 means it
|
||||
* verified successfully, 0 means it failed.
|
||||
*
|
||||
* @return The return value indicates whether the supplied certificate is
|
||||
* allowed to set up a VPN tunnel. The following values can be
|
||||
* returned:
|
||||
* - \c 0: failure, this certificate is not allowed to connect.
|
||||
* - \c 1: success, this certificate is allowed to connect.
|
||||
*/
|
||||
int verify_callback (void *session_obj, x509_cert *cert, int cert_depth,
|
||||
int preverify_ok);
|
||||
|
||||
/** @} name Function for authenticating a new connection from a remote OpenVPN peer */
|
||||
|
||||
#endif /* SSL_VERIFY_POLARSSL_H_ */
|
Loading…
Reference in New Issue
Block a user