From d6e51630dcae4b9982a84fcd68b92b5c709d4c52 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 23 Nov 2013 14:08:51 +0100 Subject: Update OpenVPN source code (closes issue #209) --HG-- extra : rebase_source : 26d053a6a25472491471f00c12f93965f20e6068 --- build.gradle | 5 +- jni/Android.mk | 4 +- openvpn/src/openvpn/error.c | 6 +- openvpn/src/openvpn/options.c | 2 +- openvpn/src/openvpn/ssl.c | 10 +- openvpn/src/openvpn/ssl_backend.h | 26 ++--- openvpn/src/openvpn/ssl_openssl.c | 23 ++++- openvpn/src/openvpn/ssl_polarssl.c | 176 ++++++++++++++++++++++++++++++---- openvpn/src/openvpn/ssl_polarssl.h | 5 + openvpn/src/openvpn/syshead.h | 2 +- src/de/blinkt/openvpn/VpnProfile.java | 2 +- 11 files changed, 205 insertions(+), 56 deletions(-) diff --git a/build.gradle b/build.gradle index cce54af2..643c604b 100644 --- a/build.gradle +++ b/build.gradle @@ -50,11 +50,12 @@ android { } } - + + /* compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 - } + }*/ signingConfigs { release diff --git a/jni/Android.mk b/jni/Android.mk index 58cfa757..fc2158d2 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -16,7 +16,9 @@ WITH_BREAKPAD=0 endif -#include polarssl/Android.mk +ifeq ($(USE_POLAR),1) + include polarssl/Android.mk +endif include openvpn/Android.mk diff --git a/openvpn/src/openvpn/error.c b/openvpn/src/openvpn/error.c index 9fdd78b2..af865f32 100644 --- a/openvpn/src/openvpn/error.c +++ b/openvpn/src/openvpn/error.c @@ -88,7 +88,7 @@ static bool use_syslog; /* GLOBAL */ /* Should stdout/stderr be be parsable and always be prefixed with time * and message flags */ -static bool parsable_output; /* GLOBAL */ +static bool machine_readable_output; /* GLOBAL */ /* Should timestamps be included on messages to stdout/stderr? */ static bool suppress_timestamps; /* GLOBAL */ @@ -350,14 +350,14 @@ void x_msg_va (const unsigned int flags, const char *format, va_list arglist) struct timeval tv; gettimeofday (&tv, NULL); - fprintf (fp, "%ld.%06d %x %s%s%s%s", + fprintf (fp, "%lu.%06lu %x %s%s%s%s", tv.tv_sec, tv.tv_usec, flags, prefix, prefix_sep, m1, - (flags&M_NOLF) ? "" : "\n"); + "\n"); } else if ((flags & M_NOPREFIX) || suppress_timestamps) diff --git a/openvpn/src/openvpn/options.c b/openvpn/src/openvpn/options.c index 77ccf107..6e9377ac 100644 --- a/openvpn/src/openvpn/options.c +++ b/openvpn/src/openvpn/options.c @@ -1512,7 +1512,7 @@ show_settings (const struct options *o) SHOW_INT (inetd); SHOW_BOOL (log); SHOW_BOOL (suppress_timestamps); - SHOW_BOOL (parsable_output); + SHOW_BOOL (machine_readable_output); SHOW_INT (nice); SHOW_INT (verbosity); SHOW_INT (mute); diff --git a/openvpn/src/openvpn/ssl.c b/openvpn/src/openvpn/ssl.c index 4203fc5c..bd19d754 100644 --- a/openvpn/src/openvpn/ssl.c +++ b/openvpn/src/openvpn/ssl.c @@ -509,12 +509,8 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) #ifdef MANAGMENT_EXTERNAL_KEY else if ((options->management_flags & MF_EXTERNAL_KEY) && options->cert_file) { - openvpn_x509_cert_t *my_cert = NULL; - tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline, - &my_cert); - tls_ctx_use_external_private_key(new_ctx, my_cert); - - tls_ctx_free_cert_file(my_cert); + tls_ctx_use_external_private_key(new_ctx, options->cert_file, + options->cert_file_inline); } #endif else @@ -522,7 +518,7 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) /* Load Certificate */ if (options->cert_file) { - tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline, NULL); + tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline); } /* Load Private Key */ diff --git a/openvpn/src/openvpn/ssl_backend.h b/openvpn/src/openvpn/ssl_backend.h index 4d2958c7..07cb9abc 100644 --- a/openvpn/src/openvpn/ssl_backend.h +++ b/openvpn/src/openvpn/ssl_backend.h @@ -215,27 +215,13 @@ void tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert * Load certificate file into the given TLS context. If the given certificate * file contains a certificate chain, load the whole chain. * - * If the x509 parameter is not NULL, the certificate will be returned in it. - * * @param ctx TLS context to use * @param cert_file The file name to load the certificate from, or * "[[INLINE]]" in the case of inline files. * @param cert_file_inline A string containing the certificate - * @param x509 An optional certificate, if x509 is NULL, - * do nothing, if x509 is not NULL, *x509 will be - * allocated and filled with the loaded certificate. - * *x509 must be NULL. */ void tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline, openvpn_x509_cert_t **x509 - ); - -/** - * Free the given certificate - * - * @param x509 certificate to free - */ -void tls_ctx_free_cert_file (openvpn_x509_cert_t *x509); + const char *cert_file_inline); /** * Load private key file into the given TLS context. @@ -255,17 +241,19 @@ int tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, #ifdef MANAGMENT_EXTERNAL_KEY /** - * Tell the management interface to load the external private key matching - * the given certificate. + * Tell the management interface to load the given certificate and the external + * private key matching the given certificate. * * @param ctx TLS context to use - * @param cert The certificate file to load the private key for + * @param cert_file The file name to load the certificate from, or * "[[INLINE]]" in the case of inline files. + * @param cert_file_inline A string containing the certificate * * @return 1 if an error occurred, 0 if parsing was * successful. */ -int tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, openvpn_x509_cert_t *cert); +int tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline); #endif diff --git a/openvpn/src/openvpn/ssl_openssl.c b/openvpn/src/openvpn/ssl_openssl.c index e3926914..120aa666 100644 --- a/openvpn/src/openvpn/ssl_openssl.c +++ b/openvpn/src/openvpn/ssl_openssl.c @@ -473,9 +473,10 @@ tls_ctx_add_extra_certs (struct tls_root_ctx *ctx, BIO *bio) } } -void -tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline, X509 **x509 +/* Like tls_ctx_load_cert, but returns a copy of the certificate in **X509 */ +static void +tls_ctx_load_cert_file_and_copy (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline, X509 **x509 ) { BIO *in = NULL; @@ -529,6 +530,13 @@ end: X509_free (x); } +void +tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, + const char *cert_file_inline) +{ + tls_ctx_load_cert_file_and_copy (ctx, cert_file, cert_file_inline, NULL); +} + void tls_ctx_free_cert_file (X509 *x509) { @@ -665,15 +673,19 @@ rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i } int -tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, X509 *cert) +tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline) { RSA *rsa = NULL; RSA *pub_rsa; RSA_METHOD *rsa_meth; + X509 *cert = NULL; ASSERT (NULL != ctx); ASSERT (NULL != cert); + tls_ctx_load_cert_file_and_copy (ctx, cert_file, cert_file_inline, &cert); + /* allocate custom RSA method object */ ALLOC_OBJ_CLEAR (rsa_meth, RSA_METHOD); rsa_meth->name = "OpenVPN external private key RSA Method"; @@ -708,10 +720,13 @@ tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, X509 *cert) if (!SSL_CTX_use_RSAPrivateKey(ctx->ctx, rsa)) goto err; + X509_free(cert); RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */ return 1; err: + if (cert) + X509_free(cert); if (rsa) RSA_free(rsa); else diff --git a/openvpn/src/openvpn/ssl_polarssl.c b/openvpn/src/openvpn/ssl_polarssl.c index fb732254..cdd91890 100644 --- a/openvpn/src/openvpn/ssl_polarssl.c +++ b/openvpn/src/openvpn/ssl_polarssl.c @@ -7,6 +7,7 @@ * * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. * Copyright (C) 2010 Fox Crypto B.V. + * Copyright (C) 2006-2010, Brainspark B.V. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 @@ -121,6 +122,10 @@ tls_ctx_free(struct tls_root_ctx *ctx) free(ctx->priv_key_pkcs11); } #endif +#if defined(MANAGMENT_EXTERNAL_KEY) + if (ctx->external_key != NULL) + free(ctx->external_key); +#endif if (ctx->allowed_ciphers) free(ctx->allowed_ciphers); @@ -237,13 +242,10 @@ tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert) void tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, - const char *cert_file_inline, - openvpn_x509_cert_t **x509 + const char *cert_file_inline ) { ASSERT(NULL != ctx); - if (NULL != x509) - ASSERT(NULL == *x509); if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_file_inline) { @@ -256,16 +258,6 @@ tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file, 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; - } -} - -void -tls_ctx_free_cert_file (openvpn_x509_cert_t *x509) -{ - x509_free(x509); } int @@ -322,13 +314,156 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file, #ifdef MANAGMENT_EXTERNAL_KEY + +struct external_context { + size_t signature_length; +}; + int -tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, openvpn_x509_cert_t *cert) +tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, + const char *cert_file, const char *cert_file_inline) { - msg(M_FATAL, "Use of management external keys not yet supported for PolarSSL."); - return false; + ASSERT(NULL != ctx); + + tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline); + + if (ctx->crt_chain == NULL) + return 0; + + /* Most of the initialization happens in key_state_ssl_init() */ + ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context); + ctx->external_key->signature_length = ctx->crt_chain->rsa.len; + + return 1; +} + +static inline int external_pkcs1_sign( void *ctx_voidptr, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode, + int hash_id, unsigned int hashlen, const unsigned char *hash, + unsigned char *sig ) +{ + struct external_context * const ctx = ctx_voidptr; + char *in_b64 = NULL; + char *out_b64 = NULL; + int rv; + unsigned char * const p = sig; + size_t asn_len; + + ASSERT(NULL != ctx); + + if (RSA_PRIVATE != mode) + { + rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA; + goto done; + } + + /* + * Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW, + * but TLSv1.2 needs the full suite of hashes. + * + * This code has been taken from PolarSSL pkcs11_sign(), under the GPLv2.0+. + */ + switch( hash_id ) + { + case SIG_RSA_RAW: + asn_len = 0; + memcpy( p, hash, hashlen ); + break; + + case SIG_RSA_MD2: + asn_len = OID_SIZE(ASN1_HASH_MDX); + memcpy( p, ASN1_HASH_MDX, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[13] = 2; break; + + case SIG_RSA_MD4: + asn_len = OID_SIZE(ASN1_HASH_MDX); + memcpy( p, ASN1_HASH_MDX, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[13] = 4; break; + + case SIG_RSA_MD5: + asn_len = OID_SIZE(ASN1_HASH_MDX); + memcpy( p, ASN1_HASH_MDX, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[13] = 5; break; + + case SIG_RSA_SHA1: + asn_len = OID_SIZE(ASN1_HASH_SHA1); + memcpy( p, ASN1_HASH_SHA1, asn_len ); + memcpy( p + 15, hash, hashlen ); + break; + + case SIG_RSA_SHA224: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 4; p[18] += hashlen; break; + + case SIG_RSA_SHA256: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 1; p[18] += hashlen; break; + + case SIG_RSA_SHA384: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 2; p[18] += hashlen; break; + + case SIG_RSA_SHA512: + asn_len = OID_SIZE(ASN1_HASH_SHA2X); + memcpy( p, ASN1_HASH_SHA2X, asn_len ); + memcpy( p + asn_len, hash, hashlen ); + p[1] += hashlen; p[14] = 3; p[18] += hashlen; break; + + /* End of copy */ + default: + rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA; + goto done; + } + + /* convert 'from' to base64 */ + if (openvpn_base64_encode (sig, asn_len + hashlen, &in_b64) <= 0) + { + rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA; + goto done; + } + + /* call MI for signature */ + if (management) + out_b64 = management_query_rsa_sig (management, in_b64); + if (!out_b64) + { + rv = POLARSSL_ERR_RSA_PRIVATE_FAILED; + goto done; + } + + /* decode base64 signature to binary and verify length */ + if ( openvpn_base64_decode (out_b64, sig, ctx->signature_length) != + ctx->signature_length ) + { + rv = POLARSSL_ERR_RSA_PRIVATE_FAILED; + goto done; + } + + rv = 0; + + done: + if (in_b64) + free (in_b64); + if (out_b64) + free (out_b64); + return rv; } +static inline size_t external_key_len(void *vctx) +{ + struct external_context * const ctx = vctx; + + return ctx->signature_length; +} #endif void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file, @@ -541,6 +676,13 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl, ssl_ctx->priv_key_pkcs11, ssl_pkcs11_decrypt, ssl_pkcs11_sign, ssl_pkcs11_key_len ); else +#endif +#if defined(MANAGMENT_EXTERNAL_KEY) + if (ssl_ctx->external_key != NULL) + ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain, + ssl_ctx->external_key, NULL, external_pkcs1_sign, + external_key_len ); + else #endif ssl_set_own_cert( ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key ); diff --git a/openvpn/src/openvpn/ssl_polarssl.h b/openvpn/src/openvpn/ssl_polarssl.h index da936998..fc9aa784 100644 --- a/openvpn/src/openvpn/ssl_polarssl.h +++ b/openvpn/src/openvpn/ssl_polarssl.h @@ -30,6 +30,8 @@ #ifndef SSL_POLARSSL_H_ #define SSL_POLARSSL_H_ +#include "syshead.h" + #include #if defined(ENABLE_PKCS11) @@ -67,6 +69,9 @@ struct tls_root_ctx { rsa_context *priv_key; /**< Local private key */ #if defined(ENABLE_PKCS11) pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */ +#endif +#ifdef MANAGMENT_EXTERNAL_KEY + struct external_context *external_key; /**< Management external key */ #endif int * allowed_ciphers; /**< List of allowed ciphers for this connection */ }; diff --git a/openvpn/src/openvpn/syshead.h b/openvpn/src/openvpn/syshead.h index df6927de..51b24028 100644 --- a/openvpn/src/openvpn/syshead.h +++ b/openvpn/src/openvpn/syshead.h @@ -539,7 +539,7 @@ socket_defined (const socket_descriptor_t sd) /* * Enable external private key */ -#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_SSL) && !defined(ENABLE_CRYPTO_POLARSSL) +#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_SSL) #define MANAGMENT_EXTERNAL_KEY #endif diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index 79c94779..f4771bc1 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -184,7 +184,7 @@ public class VpnProfile implements Serializable { cfg += "management-hold\n\n"; cfg += getVersionEnvString(context); - cfg += "parsable-output\n"; + cfg += "machine-readable-output\n"; boolean useTLSClient = (mAuthenticationType != TYPE_STATICKEYS); -- cgit v1.2.3