summaryrefslogtreecommitdiff
path: root/src/openvpn/ssl_polarssl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/ssl_polarssl.c')
-rw-r--r--src/openvpn/ssl_polarssl.c323
1 files changed, 181 insertions, 142 deletions
diff --git a/src/openvpn/ssl_polarssl.c b/src/openvpn/ssl_polarssl.c
index 30c7395..cd8ee1a 100644
--- a/src/openvpn/ssl_polarssl.c
+++ b/src/openvpn/ssl_polarssl.c
@@ -46,12 +46,13 @@
#include "manage.h"
#include "ssl_common.h"
-#include <polarssl/sha2.h>
#include <polarssl/havege.h>
#include "ssl_verify_polarssl.h"
#include <polarssl/error.h>
+#include <polarssl/oid.h>
#include <polarssl/pem.h>
+#include <polarssl/sha256.h>
#include <polarssl/version.h>
void
@@ -76,11 +77,8 @@ tls_ctx_server_new(struct tls_root_ctx *ctx, unsigned int ssl_flags)
CLEAR(*ctx);
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);
+ ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt);
ctx->endpoint = SSL_IS_SERVER;
ctx->initialised = true;
@@ -93,10 +91,7 @@ tls_ctx_client_new(struct tls_root_ctx *ctx, unsigned int ssl_flags)
CLEAR(*ctx);
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);
+ ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt);
ctx->endpoint = SSL_IS_CLIENT;
ctx->initialised = true;
@@ -107,17 +102,21 @@ tls_ctx_free(struct tls_root_ctx *ctx)
{
if (ctx)
{
- rsa_free(ctx->priv_key);
- free(ctx->priv_key);
+ pk_free(ctx->priv_key);
+ if (ctx->priv_key)
+ free(ctx->priv_key);
- x509_free(ctx->ca_chain);
- free(ctx->ca_chain);
+ x509_crt_free(ctx->ca_chain);
+ if (ctx->ca_chain)
+ free(ctx->ca_chain);
- x509_free(ctx->crt_chain);
- free(ctx->crt_chain);
+ x509_crt_free(ctx->crt_chain);
+ if (ctx->crt_chain)
+ free(ctx->crt_chain);
dhm_free(ctx->dhm_ctx);
- free(ctx->dhm_ctx);
+ if (ctx->dhm_ctx)
+ free(ctx->dhm_ctx);
#if defined(ENABLE_PKCS11)
if (ctx->priv_key_pkcs11 != NULL) {
@@ -191,7 +190,7 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
/* Parse allowed ciphers, getting IDs */
i = 0;
- tmp_ciphers_orig = tmp_ciphers = strdup(ciphers);
+ tmp_ciphers_orig = tmp_ciphers = string_alloc (ciphers, NULL);
token = strtok (tmp_ciphers, ":");
while(token)
@@ -206,19 +205,39 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
}
void
+tls_ctx_check_cert_time (const struct tls_root_ctx *ctx)
+{
+ ASSERT (ctx);
+ if (ctx->crt_chain == NULL)
+ {
+ return; /* Nothing to check if there is no certificate */
+ }
+
+ if (x509_time_future (&ctx->crt_chain->valid_from))
+ {
+ msg (M_WARN, "WARNING: Your certificate is not yet valid!");
+ }
+
+ if (x509_time_expired (&ctx->crt_chain->valid_to))
+ {
+ msg (M_WARN, "WARNING: Your certificate has expired!");
+ }
+}
+
+void
tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file,
const char *dh_inline
)
{
if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_inline)
{
- if (0 != x509parse_dhm(ctx->dhm_ctx, (const unsigned char *) dh_inline,
+ if (0 != dhm_parse_dhm(ctx->dhm_ctx, (const unsigned char *) dh_inline,
strlen(dh_inline)))
msg (M_FATAL, "Cannot read inline DH parameters");
}
else
{
- if (0 != x509parse_dhmfile(ctx->dhm_ctx, dh_file))
+ if (0 != dhm_parse_dhmfile(ctx->dhm_ctx, dh_file))
msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file);
}
@@ -251,15 +270,20 @@ tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
{
ASSERT(NULL != ctx);
+ if (!ctx->crt_chain)
+ {
+ ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_crt);
+ }
+
if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_inline)
{
- if (0 != x509parse_crt(ctx->crt_chain,
+ if (0 != x509_crt_parse(ctx->crt_chain,
(const unsigned char *) cert_inline, strlen(cert_inline)))
msg (M_FATAL, "Cannot load inline certificate file");
}
else
{
- if (0 != x509parse_crtfile(ctx->crt_chain, cert_file))
+ if (0 != x509_crt_parse_file(ctx->crt_chain, cert_file))
msg (M_FATAL, "Cannot load certificate file %s", cert_file);
}
}
@@ -272,34 +296,40 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
int status;
ASSERT(NULL != ctx);
+ if (!ctx->priv_key)
+ {
+ ALLOC_OBJ_CLEAR(ctx->priv_key, pk_context);
+ }
+
if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_inline)
{
- status = x509parse_key(ctx->priv_key,
+ status = pk_parse_key(ctx->priv_key,
(const unsigned char *) priv_key_inline, strlen(priv_key_inline),
NULL, 0);
- if (POLARSSL_ERR_X509_PASSWORD_REQUIRED == status)
+
+ if (POLARSSL_ERR_PK_PASSWORD_REQUIRED == status)
{
char passbuf[512] = {0};
pem_password_callback(passbuf, 512, 0, NULL);
- status = x509parse_key(ctx->priv_key,
+ status = pk_parse_key(ctx->priv_key,
(const unsigned char *) priv_key_inline, strlen(priv_key_inline),
- (const unsigned char *) passbuf, strlen(passbuf));
+ (unsigned char *) passbuf, strlen(passbuf));
}
}
else
{
- status = x509parse_keyfile(ctx->priv_key, priv_key_file, NULL);
- if (POLARSSL_ERR_X509_PASSWORD_REQUIRED == status)
+ status = pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL);
+ if (POLARSSL_ERR_PK_PASSWORD_REQUIRED == status)
{
char passbuf[512] = {0};
pem_password_callback(passbuf, 512, 0, NULL);
- status = x509parse_keyfile(ctx->priv_key, priv_key_file, passbuf);
+ status = pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf);
}
}
if (0 != status)
{
#ifdef ENABLE_MANAGEMENT
- if (management && (POLARSSL_ERR_X509_PASSWORD_MISMATCH == status))
+ if (management && (POLARSSL_ERR_PK_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);
@@ -323,43 +353,43 @@ struct external_context {
size_t signature_length;
};
-int
-tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
- const char *cert_file, const char *cert_file_inline)
-{
- 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;
-}
-
+/**
+ * external_pkcs1_sign implements a PolarSSL rsa_sign_func callback, that uses
+ * the management interface to request an RSA signature for the supplied hash.
+ *
+ * @param ctx_voidptr Management external key context.
+ * @param f_rng (Unused)
+ * @param p_rng (Unused)
+ * @param mode RSA mode (should be RSA_PRIVATE).
+ * @param md_alg Message digest ('hash') algorithm type.
+ * @param hashlen Length of hash (overridden by length specified by md_alg
+ * if md_alg != POLARSSL_MD_NONE).
+ * @param hash The digest ('hash') to sign. Should have a size
+ * matching the length of md_alg (if != POLARSSL_MD_NONE),
+ * or hashlen otherwise.
+ * @param sig Buffer that returns the signature. Should be at least of
+ * size ctx->signature_length.
+ *
+ * @return 0 on success, non-zero polarssl error code on failure.
+ */
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,
+ md_type_t md_alg, 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;
+ unsigned char *p = sig;
+ size_t asn_len = 0, oid_size = 0, sig_len = 0;
+ const char *oid = NULL;
- ASSERT(NULL != ctx);
+ if( NULL == ctx )
+ return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
- if (RSA_PRIVATE != mode)
- {
- rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA;
- goto done;
- }
+ if( RSA_PRIVATE != mode )
+ return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
/*
* Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW,
@@ -367,67 +397,54 @@ static inline int external_pkcs1_sign( void *ctx_voidptr,
*
* 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;
+ if( md_alg != POLARSSL_MD_NONE )
+ {
+ const md_info_t *md_info = md_info_from_type( md_alg );
+ if( md_info == NULL )
+ return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+ if( oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 )
+ return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+ hashlen = md_get_size( md_info );
+ asn_len = 10 + oid_size;
+ }
+
+ sig_len = ctx->signature_length;
+ if ( (SIZE_MAX - hashlen) < asn_len || (hashlen + asn_len) > sig_len )
+ return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
+
+ if( md_alg != POLARSSL_MD_NONE )
+ {
+ /*
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * digest Digest }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * Digest ::= OCTET STRING
+ */
+ *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED;
+ *p++ = (unsigned char) ( 0x08 + oid_size + hashlen );
+ *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED;
+ *p++ = (unsigned char) ( 0x04 + oid_size );
+ *p++ = ASN1_OID;
+ *p++ = oid_size & 0xFF;
+ memcpy( p, oid, oid_size );
+ p += oid_size;
+ *p++ = ASN1_NULL;
+ *p++ = 0x00;
+ *p++ = ASN1_OCTET_STRING;
+ *p++ = hashlen;
+
+ /* Determine added ASN length */
+ asn_len = p - sig;
}
+ /* Copy the hash to be signed */
+ memcpy( p, hash, hashlen );
+
/* convert 'from' to base64 */
if (openvpn_base64_encode (sig, asn_len + hashlen, &in_b64) <= 0)
{
@@ -454,7 +471,7 @@ static inline int external_pkcs1_sign( void *ctx_voidptr,
rv = 0;
- done:
+done:
if (in_b64)
free (in_b64);
if (out_b64)
@@ -468,6 +485,28 @@ static inline size_t external_key_len(void *vctx)
return ctx->signature_length;
}
+
+int
+tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
+ const char *cert_file, const char *cert_file_inline)
+{
+ ASSERT(NULL != ctx);
+
+ tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline);
+
+ if (ctx->crt_chain == NULL)
+ return 0;
+
+ ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context);
+ ctx->external_key->signature_length = pk_get_len(&ctx->crt_chain->pk);
+
+ ALLOC_OBJ_CLEAR (ctx->priv_key, pk_context);
+ if (0 != pk_init_ctx_rsa_alt(ctx->priv_key, ctx->external_key,
+ NULL, external_pkcs1_sign, external_key_len))
+ return 0;
+
+ return 1;
+}
#endif
void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
@@ -480,14 +519,14 @@ void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_inline)
{
- if (0 != x509parse_crt(ctx->ca_chain, (const unsigned char *) ca_inline,
+ if (0 != x509_crt_parse(ctx->ca_chain, (unsigned char *) ca_inline,
strlen(ca_inline)))
msg (M_FATAL, "Cannot load inline CA certificates");
}
else
{
/* Load CA file for verifying peer supplied certificate */
- if (0 != x509parse_crtfile(ctx->ca_chain, ca_file))
+ if (0 != x509_crt_parse_file(ctx->ca_chain, ca_file))
msg (M_FATAL, "Cannot load CA certificate file %s", ca_file);
}
}
@@ -499,16 +538,21 @@ tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file
{
ASSERT(NULL != ctx);
+ if (!ctx->crt_chain)
+ {
+ ALLOC_OBJ_CLEAR (ctx->crt_chain, x509_crt);
+ }
+
if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_inline)
{
- if (0 != x509parse_crt(ctx->crt_chain,
- (const unsigned char *) extra_certs_inline,
+ if (0 != x509_crt_parse(ctx->crt_chain,
+ (const unsigned char *) extra_certs_inline,
strlen(extra_certs_inline)))
msg (M_FATAL, "Cannot load inline extra-certs file");
}
else
{
- if (0 != x509parse_crtfile(ctx->crt_chain, extra_certs_file))
+ if (0 != x509_crt_parse_file(ctx->crt_chain, extra_certs_file))
msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file);
}
}
@@ -631,9 +675,9 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
if (NULL != ctx->crt_chain)
{
- x509_cert *cert = ctx->crt_chain;
+ x509_crt *cert = ctx->crt_chain;
- sha2(cert->tbs.p, cert->tbs.len, sha256_hash, false);
+ sha256(cert->tbs.p, cert->tbs.len, sha256_hash, false);
if ( 0 != memcmp(old_sha256_hash, sha256_hash, sizeof(sha256_hash)))
{
ctr_drbg_update(cd_ctx, sha256_hash, 32);
@@ -707,24 +751,19 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
if (ssl_ctx->allowed_ciphers)
ssl_set_ciphersuites (ks_ssl->ctx, ssl_ctx->allowed_ciphers);
+ /* Disable record splitting (for now). OpenVPN assumes records are sent
+ * unfragmented, and changing that will require thorough review and
+ * testing. Since OpenVPN is not susceptible to BEAST, we can just
+ * disable record splitting as a quick fix. */
+#if defined(POLARSSL_SSL_CBC_RECORD_SPLITTING)
+ ssl_set_cbc_record_splitting (ks_ssl->ctx, SSL_CBC_RECORD_SPLITTING_DISABLED);
+#endif /* POLARSSL_SSL_CBC_RECORD_SPLITTING */
+
/* Initialise authentication information */
if (is_server)
- ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx );
-#if defined(ENABLE_PKCS11)
- if (ssl_ctx->priv_key_pkcs11 != NULL)
- ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain,
- 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 );
+ ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx);
+
+ ssl_set_own_cert (ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key);
/* Initialise SSL verification */
#if P2MP_SERVER
@@ -815,8 +854,8 @@ key_state_write_plaintext (struct key_state_ssl *ks, struct buffer *buf)
if (0 == buf->len)
{
- return 0;
perf_pop ();
+ return 0;
}
retval = ssl_write(ks->ctx, BPTR(buf), buf->len);
@@ -1055,7 +1094,7 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf,
void
print_details (struct key_state_ssl * ks_ssl, const char *prefix)
{
- const x509_cert *cert;
+ const x509_crt *cert;
char s1[256];
char s2[256];
@@ -1068,7 +1107,7 @@ print_details (struct key_state_ssl * ks_ssl, const char *prefix)
cert = ssl_get_peer_cert(ks_ssl->ctx);
if (cert != NULL)
{
- openvpn_snprintf (s2, sizeof (s2), ", " counter_format " bit RSA", (counter_type) cert->rsa.len * 8);
+ openvpn_snprintf (s2, sizeof (s2), ", %zu bit key", pk_get_size(&cert->pk));
}
msg (D_HANDSHAKE, "%s%s", s1, s2);