diff options
author | Adriaan de Jong <dejong@fox-it.com> | 2011-06-30 08:57:52 +0200 |
---|---|---|
committer | David Sommerseth <davids@redhat.com> | 2011-10-19 22:46:41 +0200 |
commit | 5f4eb537d7a4eb28db8bd6211bc8e29ae5c4465a (patch) | |
tree | e7ab99b1822bb9cf5720e9f87b073af0bba62f78 | |
parent | d67c3147b006aed24f0c3f6e0e288bf0d6a55973 (diff) | |
download | openvpn-5f4eb537d7a4eb28db8bd6211bc8e29ae5c4465a.tar.gz openvpn-5f4eb537d7a4eb28db8bd6211bc8e29ae5c4465a.tar.xz openvpn-5f4eb537d7a4eb28db8bd6211bc8e29ae5c4465a.zip |
Refactored external key loading from management
Fixed a bug in external key loading, where if no certificate file was
specified, the program would still try to use an external private key.
Signed-off-by: Adriaan de Jong <dejong@fox-it.com>
Acked-by: James Yonan <james@openvpn.net>
Signed-off-by: David Sommerseth <davids@redhat.com>
-rw-r--r-- | ssl.c | 146 | ||||
-rw-r--r-- | ssl_backend.h | 17 | ||||
-rw-r--r-- | ssl_openssl.c | 138 |
3 files changed, 159 insertions, 142 deletions
@@ -1602,140 +1602,6 @@ tls_deauthenticate (struct tls_multi *multi) } } -#ifdef MANAGMENT_EXTERNAL_KEY - -/* encrypt */ -static int -rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) -{ - ASSERT(0); - return -1; -} - -/* verify arbitrary data */ -static int -rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) -{ - ASSERT(0); - return -1; -} - -/* decrypt */ -static int -rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) -{ - ASSERT(0); - return -1; -} - -/* called at RSA_free */ -static int -rsa_finish(RSA *rsa) -{ - free ((void*)rsa->meth); - rsa->meth = NULL; - return 1; -} - -/* sign arbitrary data */ -static int -rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) -{ - /* optional app data in rsa->meth->app_data; */ - char *in_b64 = NULL; - char *out_b64 = NULL; - int ret = -1; - int len; - - if (padding != RSA_PKCS1_PADDING) - { - RSAerr (RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); - goto done; - } - - /* convert 'from' to base64 */ - if (base64_encode (from, flen, &in_b64) <= 0) - goto done; - - /* call MI for signature */ - if (management) - out_b64 = management_query_rsa_sig (management, in_b64); - if (!out_b64) - goto done; - - /* decode base64 signature to binary */ - len = RSA_size(rsa); - ret = base64_decode (out_b64, to, len); - - /* verify length */ - if (ret != len) - ret = -1; - - done: - if (in_b64) - free (in_b64); - if (out_b64) - free (out_b64); - return ret; -} - -static int -use_external_private_key (SSL_CTX *ssl_ctx, X509 *cert) -{ - RSA *rsa = NULL; - RSA *pub_rsa; - RSA_METHOD *rsa_meth; - - /* allocate custom RSA method object */ - ALLOC_OBJ_CLEAR (rsa_meth, RSA_METHOD); - rsa_meth->name = "OpenVPN external private key RSA Method"; - rsa_meth->rsa_pub_enc = rsa_pub_enc; - rsa_meth->rsa_pub_dec = rsa_pub_dec; - rsa_meth->rsa_priv_enc = rsa_priv_enc; - rsa_meth->rsa_priv_dec = rsa_priv_dec; - rsa_meth->init = NULL; - rsa_meth->finish = rsa_finish; - rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; - rsa_meth->app_data = NULL; - - /* allocate RSA object */ - rsa = RSA_new(); - if (rsa == NULL) - { - SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE); - goto err; - } - - /* get the public key */ - ASSERT(cert->cert_info->key->pkey); /* NULL before SSL_CTX_use_certificate() is called */ - pub_rsa = cert->cert_info->key->pkey->pkey.rsa; - - /* initialize RSA object */ - rsa->n = BN_dup(pub_rsa->n); - rsa->flags |= RSA_FLAG_EXT_PKEY; - if (!RSA_set_method(rsa, rsa_meth)) - goto err; - - /* bind our custom RSA object to ssl_ctx */ - if (!SSL_CTX_use_RSAPrivateKey(ssl_ctx, rsa)) - goto err; - - RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */ - return 1; - - err: - if (rsa) - RSA_free(rsa); - else - { - if (rsa_meth) - free(rsa_meth); - } - return 0; -} - -#endif - #if ENABLE_INLINE_FILES static int @@ -1891,17 +1757,13 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx) } #endif #ifdef MANAGMENT_EXTERNAL_KEY - else if (options->management_flags & MF_EXTERNAL_KEY) + else if ((options->management_flags & MF_EXTERNAL_KEY) && options->cert_file) { X509 *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); - if (options->cert_file) - { - tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline, &my_cert); - } - ASSERT (my_cert); - if (!use_external_private_key(new_ctx->ctx, my_cert)) - msg (M_SSLERR, "Cannot enable SSL external private key capability"); X509_free(my_cert); } #endif diff --git a/ssl_backend.h b/ssl_backend.h index 3beee19..024b547 100644 --- a/ssl_backend.h +++ b/ssl_backend.h @@ -209,6 +209,23 @@ int tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file #endif ); +#ifdef MANAGMENT_EXTERNAL_KEY + +/** + * Tell the management interface to load 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 + * "[[INLINE]]" in the case of inline files. + * + * @return 1 if an error occurred, 0 if parsing was + * successful. + */ +int tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, X509 *cert); + +#endif + /** * Show the TLS ciphers that are available for us to use in the OpenSSL * library. diff --git a/ssl_openssl.c b/ssl_openssl.c index a53bcdb..45b83d2 100644 --- a/ssl_openssl.c +++ b/ssl_openssl.c @@ -507,6 +507,144 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file } +#ifdef MANAGMENT_EXTERNAL_KEY + +/* encrypt */ +static int +rsa_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + ASSERT(0); + return -1; +} + +/* verify arbitrary data */ +static int +rsa_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + ASSERT(0); + return -1; +} + +/* decrypt */ +static int +rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + ASSERT(0); + return -1; +} + +/* called at RSA_free */ +static int +rsa_finish(RSA *rsa) +{ + free ((void*)rsa->meth); + rsa->meth = NULL; + return 1; +} + +/* sign arbitrary data */ +static int +rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) +{ + /* optional app data in rsa->meth->app_data; */ + char *in_b64 = NULL; + char *out_b64 = NULL; + int ret = -1; + int len; + + if (padding != RSA_PKCS1_PADDING) + { + RSAerr (RSA_F_RSA_EAY_PRIVATE_ENCRYPT, RSA_R_UNKNOWN_PADDING_TYPE); + goto done; + } + + /* convert 'from' to base64 */ + if (base64_encode (from, flen, &in_b64) <= 0) + goto done; + + /* call MI for signature */ + if (management) + out_b64 = management_query_rsa_sig (management, in_b64); + if (!out_b64) + goto done; + + /* decode base64 signature to binary */ + len = RSA_size(rsa); + ret = base64_decode (out_b64, to, len); + + /* verify length */ + if (ret != len) + ret = -1; + + done: + if (in_b64) + free (in_b64); + if (out_b64) + free (out_b64); + return ret; +} + +int +tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, X509 *cert) +{ + RSA *rsa = NULL; + RSA *pub_rsa; + RSA_METHOD *rsa_meth; + + ASSERT (NULL != ctx); + ASSERT (NULL != cert); + + /* allocate custom RSA method object */ + ALLOC_OBJ_CLEAR (rsa_meth, RSA_METHOD); + rsa_meth->name = "OpenVPN external private key RSA Method"; + rsa_meth->rsa_pub_enc = rsa_pub_enc; + rsa_meth->rsa_pub_dec = rsa_pub_dec; + rsa_meth->rsa_priv_enc = rsa_priv_enc; + rsa_meth->rsa_priv_dec = rsa_priv_dec; + rsa_meth->init = NULL; + rsa_meth->finish = rsa_finish; + rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; + rsa_meth->app_data = NULL; + + /* allocate RSA object */ + rsa = RSA_new(); + if (rsa == NULL) + { + SSLerr(SSL_F_SSL_USE_PRIVATEKEY, ERR_R_MALLOC_FAILURE); + goto err; + } + + /* get the public key */ + ASSERT(cert->cert_info->key->pkey); /* NULL before SSL_CTX_use_certificate() is called */ + pub_rsa = cert->cert_info->key->pkey->pkey.rsa; + + /* initialize RSA object */ + rsa->n = BN_dup(pub_rsa->n); + rsa->flags |= RSA_FLAG_EXT_PKEY; + if (!RSA_set_method(rsa, rsa_meth)) + goto err; + + /* bind our custom RSA object to ssl_ctx */ + if (!SSL_CTX_use_RSAPrivateKey(ctx->ctx, rsa)) + goto err; + + RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */ + return 1; + + err: + if (rsa) + RSA_free(rsa); + else + { + if (rsa_meth) + free(rsa_meth); + } + msg (M_SSLERR, "Cannot enable SSL external private key capability"); + return 0; +} + +#endif + void show_available_tls_ciphers () { |