GUACAMOLE-623: Add support for SSL.
This commit is contained in:
parent
2e50573531
commit
83a531bc89
@ -1225,6 +1225,7 @@ AC_ARG_ENABLE([kubernetes],
|
|||||||
|
|
||||||
AM_CONDITIONAL([ENABLE_KUBERNETES], [test "x${enable_kubernetes}" = "xyes" \
|
AM_CONDITIONAL([ENABLE_KUBERNETES], [test "x${enable_kubernetes}" = "xyes" \
|
||||||
-a "x${have_libwebsockets}" = "xyes" \
|
-a "x${have_libwebsockets}" = "xyes" \
|
||||||
|
-a "x${have_ssl}" = "xyes" \
|
||||||
-a "x${have_terminal}" = "xyes"])
|
-a "x${have_terminal}" = "xyes"])
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -29,6 +29,7 @@ libguac_client_kubernetes_la_SOURCES = \
|
|||||||
io.c \
|
io.c \
|
||||||
pipe.c \
|
pipe.c \
|
||||||
settings.c \
|
settings.c \
|
||||||
|
ssl.c \
|
||||||
kubernetes.c \
|
kubernetes.c \
|
||||||
url.c \
|
url.c \
|
||||||
user.c
|
user.c
|
||||||
@ -40,6 +41,7 @@ noinst_HEADERS = \
|
|||||||
io.h \
|
io.h \
|
||||||
pipe.h \
|
pipe.h \
|
||||||
settings.h \
|
settings.h \
|
||||||
|
ssl.h \
|
||||||
kubernetes.h \
|
kubernetes.h \
|
||||||
url.h \
|
url.h \
|
||||||
user.h
|
user.h
|
||||||
@ -57,5 +59,6 @@ libguac_client_kubernetes_la_LIBADD = \
|
|||||||
libguac_client_kubernetes_la_LDFLAGS = \
|
libguac_client_kubernetes_la_LDFLAGS = \
|
||||||
-version-info 0:0:0 \
|
-version-info 0:0:0 \
|
||||||
@PTHREAD_LIBS@ \
|
@PTHREAD_LIBS@ \
|
||||||
|
@SSL_LIBS@ \
|
||||||
@WEBSOCKETS_LIBS@
|
@WEBSOCKETS_LIBS@
|
||||||
|
|
||||||
|
@ -32,12 +32,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/**
|
guac_client* guac_kubernetes_lws_current_client = NULL;
|
||||||
* Static reference to the guac_client associated with the active Kubernetes
|
|
||||||
* connection. As guacd guarantees that each main client connection is
|
|
||||||
* isolated within its own process, this is safe.
|
|
||||||
*/
|
|
||||||
static guac_client* guac_kubernetes_lws_log_client = NULL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Logging callback invoked by libwebsockets to log a single line of logging
|
* Logging callback invoked by libwebsockets to log a single line of logging
|
||||||
@ -53,15 +48,18 @@ static guac_client* guac_kubernetes_lws_log_client = NULL;
|
|||||||
* The line of logging output to log.
|
* The line of logging output to log.
|
||||||
*/
|
*/
|
||||||
static void guac_kubernetes_log(int level, const char* line) {
|
static void guac_kubernetes_log(int level, const char* line) {
|
||||||
if (guac_kubernetes_lws_log_client != NULL)
|
if (guac_kubernetes_lws_current_client != NULL)
|
||||||
guac_client_log(guac_kubernetes_lws_log_client, GUAC_LOG_DEBUG,
|
guac_client_log(guac_kubernetes_lws_current_client, GUAC_LOG_DEBUG,
|
||||||
"libwebsockets: %s", line);
|
"libwebsockets: %s", line);
|
||||||
}
|
}
|
||||||
|
|
||||||
int guac_client_init(guac_client* client) {
|
int guac_client_init(guac_client* client) {
|
||||||
|
|
||||||
|
/* Ensure reference to main guac_client remains available in all
|
||||||
|
* libwebsockets contexts */
|
||||||
|
guac_kubernetes_lws_current_client = client;
|
||||||
|
|
||||||
/* Redirect libwebsockets logging */
|
/* Redirect libwebsockets logging */
|
||||||
guac_kubernetes_lws_log_client = client;
|
|
||||||
lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO,
|
lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO,
|
||||||
guac_kubernetes_log);
|
guac_kubernetes_log);
|
||||||
|
|
||||||
|
@ -27,6 +27,13 @@
|
|||||||
*/
|
*/
|
||||||
#define GUAC_KUBERNETES_CLIPBOARD_MAX_LENGTH 262144
|
#define GUAC_KUBERNETES_CLIPBOARD_MAX_LENGTH 262144
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static reference to the guac_client associated with the active Kubernetes
|
||||||
|
* connection. While libwebsockets provides some means of storing and
|
||||||
|
* retrieving custom data in some structures, this is not always available.
|
||||||
|
*/
|
||||||
|
extern guac_client* guac_kubernetes_lws_current_client;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Free handler. Required by libguac and called when the guac_client is
|
* Free handler. Required by libguac and called when the guac_client is
|
||||||
* disconnected and must be cleaned up.
|
* disconnected and must be cleaned up.
|
||||||
|
@ -18,9 +18,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "client.h"
|
||||||
#include "common/recording.h"
|
#include "common/recording.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "kubernetes.h"
|
#include "kubernetes.h"
|
||||||
|
#include "ssl.h"
|
||||||
#include "terminal/terminal.h"
|
#include "terminal/terminal.h"
|
||||||
#include "url.h"
|
#include "url.h"
|
||||||
|
|
||||||
@ -43,8 +45,9 @@
|
|||||||
* The reason (event) that this callback was invoked.
|
* The reason (event) that this callback was invoked.
|
||||||
*
|
*
|
||||||
* @param user
|
* @param user
|
||||||
* Arbitrary data assocated with the WebSocket session. This will always
|
* Arbitrary data assocated with the WebSocket session. In some cases,
|
||||||
* be a pointer to the guac_client instance.
|
* this is actually event-specific data (such as the
|
||||||
|
* LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERT event).
|
||||||
*
|
*
|
||||||
* @param in
|
* @param in
|
||||||
* A pointer to arbitrary, reason-specific data.
|
* A pointer to arbitrary, reason-specific data.
|
||||||
@ -60,14 +63,19 @@ static int guac_kubernetes_lws_callback(struct lws* wsi,
|
|||||||
enum lws_callback_reasons reason, void* user,
|
enum lws_callback_reasons reason, void* user,
|
||||||
void* in, size_t length) {
|
void* in, size_t length) {
|
||||||
|
|
||||||
/* Request connection closure if client is stopped (note that the user
|
guac_client* client = guac_kubernetes_lws_current_client;
|
||||||
* pointer passed by libwebsockets may be NULL for some events) */
|
|
||||||
guac_client* client = (guac_client*) user;
|
/* Do not handle any further events if connection is closing */
|
||||||
if (client != NULL && client->state != GUAC_CLIENT_RUNNING)
|
if (client->state != GUAC_CLIENT_RUNNING)
|
||||||
return lws_callback_http_dummy(wsi, reason, user, in, length);
|
return lws_callback_http_dummy(wsi, reason, user, in, length);
|
||||||
|
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
|
|
||||||
|
/* Complete initialization of SSL */
|
||||||
|
case LWS_CALLBACK_OPENSSL_LOAD_EXTRA_CLIENT_VERIFY_CERTS:
|
||||||
|
guac_kubernetes_init_ssl(client, (SSL_CTX*) user);
|
||||||
|
break;
|
||||||
|
|
||||||
/* Failed to connect */
|
/* Failed to connect */
|
||||||
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
|
||||||
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND,
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_UPSTREAM_NOT_FOUND,
|
||||||
@ -256,29 +264,13 @@ void* guac_kubernetes_client_thread(void* data) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* If requested, use an SSL/TLS connection for communication with
|
/* If requested, use an SSL/TLS connection for communication with
|
||||||
* Kubernetes */
|
* Kubernetes. Note that we disable hostname checks here because we
|
||||||
|
* do our own validation - libwebsockets does not validate properly if
|
||||||
|
* IP addresses are used. */
|
||||||
if (settings->use_ssl) {
|
if (settings->use_ssl) {
|
||||||
|
|
||||||
/* Enable use of SSL/TLS */
|
|
||||||
context_info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
context_info.options = LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
|
||||||
connection_info.ssl_connection = LCCSCF_USE_SSL;
|
connection_info.ssl_connection = LCCSCF_USE_SSL
|
||||||
|
| LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK;
|
||||||
/* Bypass certificate checks if requested */
|
|
||||||
if (settings->ignore_cert) {
|
|
||||||
connection_info.ssl_connection |=
|
|
||||||
LCCSCF_ALLOW_SELFSIGNED
|
|
||||||
| LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK
|
|
||||||
| LCCSCF_ALLOW_EXPIRED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Otherwise use the given CA certificate to validate (if any) */
|
|
||||||
else
|
|
||||||
context_info.client_ssl_ca_filepath = settings->ca_cert_file;
|
|
||||||
|
|
||||||
/* Certificate and key file for SSL/TLS client auth */
|
|
||||||
context_info.client_ssl_cert_filepath = settings->client_cert_file;
|
|
||||||
context_info.client_ssl_private_key_filepath = settings->client_key_file;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create libwebsockets context */
|
/* Create libwebsockets context */
|
||||||
|
@ -31,9 +31,9 @@ const char* GUAC_KUBERNETES_CLIENT_ARGS[] = {
|
|||||||
"pod",
|
"pod",
|
||||||
"container",
|
"container",
|
||||||
"use-ssl",
|
"use-ssl",
|
||||||
"client-cert-file",
|
"client-cert",
|
||||||
"client-key-file",
|
"client-key",
|
||||||
"ca-cert-file",
|
"ca-cert",
|
||||||
"ignore-cert",
|
"ignore-cert",
|
||||||
"font-name",
|
"font-name",
|
||||||
"font-size",
|
"font-size",
|
||||||
@ -89,24 +89,26 @@ enum KUBERNETES_ARGS_IDX {
|
|||||||
IDX_USE_SSL,
|
IDX_USE_SSL,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The filename of the certificate to use if performing SSL/TLS client
|
* The certificate to use if performing SSL/TLS client authentication to
|
||||||
* authentication to authenticate with the Kubernetes server. If omitted,
|
* authenticate with the Kubernetes server, in PEM format. If omitted, SSL
|
||||||
* SSL client authentication will not be performed.
|
* client authentication will not be performed.
|
||||||
*/
|
*/
|
||||||
IDX_CLIENT_CERT_FILE,
|
IDX_CLIENT_CERT,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The filename of the key to use if performing SSL/TLS client
|
* The key to use if performing SSL/TLS client authentication to
|
||||||
* authentication to authenticate with the Kubernetes server. If omitted,
|
* authenticate with the Kubernetes server, in PEM format. If omitted, SSL
|
||||||
* SSL client authentication will not be performed.
|
* client authentication will not be performed.
|
||||||
*/
|
*/
|
||||||
IDX_CLIENT_KEY_FILE,
|
IDX_CLIENT_KEY,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The filename of the certificate of the certificate authority that signed
|
* The certificate of the certificate authority that signed the certificate
|
||||||
* the certificate of the Kubernetes server.
|
* of the Kubernetes server, in PEM format. If omitted. verification of
|
||||||
|
* the Kubernetes server certificate will use the systemwide certificate
|
||||||
|
* authorities.
|
||||||
*/
|
*/
|
||||||
IDX_CA_CERT_FILE,
|
IDX_CA_CERT,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the certificate used by the Kubernetes server for SSL/TLS should
|
* Whether the certificate used by the Kubernetes server for SSL/TLS should
|
||||||
@ -264,17 +266,17 @@ guac_kubernetes_settings* guac_kubernetes_parse_args(guac_user* user,
|
|||||||
/* Read SSL/TLS connection details only if enabled */
|
/* Read SSL/TLS connection details only if enabled */
|
||||||
if (settings->use_ssl) {
|
if (settings->use_ssl) {
|
||||||
|
|
||||||
settings->client_cert_file =
|
settings->client_cert =
|
||||||
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
|
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
|
||||||
argv, IDX_CLIENT_CERT_FILE, NULL);
|
argv, IDX_CLIENT_CERT, NULL);
|
||||||
|
|
||||||
settings->client_key_file =
|
settings->client_key =
|
||||||
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
|
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
|
||||||
argv, IDX_CLIENT_KEY_FILE, NULL);
|
argv, IDX_CLIENT_KEY, NULL);
|
||||||
|
|
||||||
settings->ca_cert_file =
|
settings->ca_cert =
|
||||||
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
|
guac_user_parse_args_string(user, GUAC_KUBERNETES_CLIENT_ARGS,
|
||||||
argv, IDX_CA_CERT_FILE, NULL);
|
argv, IDX_CA_CERT, NULL);
|
||||||
|
|
||||||
settings->ignore_cert =
|
settings->ignore_cert =
|
||||||
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS,
|
guac_user_parse_args_boolean(user, GUAC_KUBERNETES_CLIENT_ARGS,
|
||||||
@ -378,9 +380,9 @@ void guac_kubernetes_settings_free(guac_kubernetes_settings* settings) {
|
|||||||
free(settings->kubernetes_container);
|
free(settings->kubernetes_container);
|
||||||
|
|
||||||
/* Free SSL/TLS details */
|
/* Free SSL/TLS details */
|
||||||
free(settings->client_cert_file);
|
free(settings->client_cert);
|
||||||
free(settings->client_key_file);
|
free(settings->client_key);
|
||||||
free(settings->ca_cert_file);
|
free(settings->ca_cert);
|
||||||
|
|
||||||
/* Free display preferences */
|
/* Free display preferences */
|
||||||
free(settings->font_name);
|
free(settings->font_name);
|
||||||
|
@ -103,24 +103,26 @@ typedef struct guac_kubernetes_settings {
|
|||||||
bool use_ssl;
|
bool use_ssl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The filename of the certificate to use if performing SSL/TLS client
|
* The certificate to use if performing SSL/TLS client authentication to
|
||||||
* authentication to authenticate with the Kubernetes server. If omitted,
|
* authenticate with the Kubernetes server, in PEM format. If omitted, SSL
|
||||||
* SSL client authentication will not be performed.
|
* client authentication will not be performed.
|
||||||
*/
|
*/
|
||||||
char* client_cert_file;
|
char* client_cert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The filename of the key to use if performing SSL/TLS client
|
* The key to use if performing SSL/TLS client authentication to
|
||||||
* authentication to authenticate with the Kubernetes server. If omitted,
|
* authenticate with the Kubernetes server, in PEM format. If omitted, SSL
|
||||||
* SSL client authentication will not be performed.
|
* client authentication will not be performed.
|
||||||
*/
|
*/
|
||||||
char* client_key_file;
|
char* client_key;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The filename of the certificate of the certificate authority that signed
|
* The certificate of the certificate authority that signed the certificate
|
||||||
* the certificate of the Kubernetes server.
|
* of the Kubernetes server, in PEM format. If omitted. verification of
|
||||||
|
* the Kubernetes server certificate will use the systemwide certificate
|
||||||
|
* authorities.
|
||||||
*/
|
*/
|
||||||
char* ca_cert_file;
|
char* ca_cert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the certificate used by the Kubernetes server for SSL/TLS should
|
* Whether the certificate used by the Kubernetes server for SSL/TLS should
|
||||||
|
210
src/protocols/kubernetes/ssl.c
Normal file
210
src/protocols/kubernetes/ssl.c
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "kubernetes.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
#include <guacamole/client.h>
|
||||||
|
#include <openssl/asn1.h>
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/x509v3.h>
|
||||||
|
#include <openssl/x509_vfy.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the given hostname is, in fact, an IP address.
|
||||||
|
*
|
||||||
|
* @param hostname
|
||||||
|
* The hostname to test.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Non-zero if the given hostname is an IP address, zero otherwise.
|
||||||
|
*/
|
||||||
|
static int guac_kubernetes_is_address(const char* hostname) {
|
||||||
|
|
||||||
|
/* Attempt to interpret the hostname as an IP address */
|
||||||
|
ASN1_OCTET_STRING* ip = a2i_IPADDRESS(hostname);
|
||||||
|
|
||||||
|
/* If unsuccessful, the hostname is not an IP address */
|
||||||
|
if (ip == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Converted hostname must be freed */
|
||||||
|
ASN1_OCTET_STRING_free(ip);
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the given PEM certificate, returning a new OpenSSL X509 structure
|
||||||
|
* representing that certificate.
|
||||||
|
*
|
||||||
|
* @param pem
|
||||||
|
* The PEM certificate.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* An X509 structure representing the given certificate, or NULL if the
|
||||||
|
* certificate was unreadable.
|
||||||
|
*/
|
||||||
|
static X509* guac_kubernetes_read_cert(char* pem) {
|
||||||
|
|
||||||
|
/* Prepare a BIO which provides access to the in-memory CA cert */
|
||||||
|
BIO* bio = BIO_new_mem_buf(pem, -1);
|
||||||
|
if (bio == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Read the CA cert as PEM */
|
||||||
|
X509* certificate = PEM_read_bio_X509(bio, NULL, NULL, NULL);
|
||||||
|
if (certificate == NULL) {
|
||||||
|
BIO_free(bio);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return certificate;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the given PEM private key, returning a new OpenSSL EVP_PKEY structure
|
||||||
|
* representing that key.
|
||||||
|
*
|
||||||
|
* @param pem
|
||||||
|
* The PEM private key.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* An EVP_KEY representing the given private key, or NULL if the private
|
||||||
|
* key was unreadable.
|
||||||
|
*/
|
||||||
|
static EVP_PKEY* guac_kubernetes_read_key(char* pem) {
|
||||||
|
|
||||||
|
/* Prepare a BIO which provides access to the in-memory key */
|
||||||
|
BIO* bio = BIO_new_mem_buf(pem, -1);
|
||||||
|
if (bio == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* Read the private key as PEM */
|
||||||
|
EVP_PKEY* key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
|
||||||
|
if (key == NULL) {
|
||||||
|
BIO_free(bio);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return key;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void guac_kubernetes_init_ssl(guac_client* client, SSL_CTX* context) {
|
||||||
|
|
||||||
|
guac_kubernetes_client* kubernetes_client =
|
||||||
|
(guac_kubernetes_client*) client->data;
|
||||||
|
|
||||||
|
guac_kubernetes_settings* settings = kubernetes_client->settings;
|
||||||
|
|
||||||
|
/* Bypass certificate checks if requested */
|
||||||
|
if (settings->ignore_cert)
|
||||||
|
SSL_CTX_set_verify(context, SSL_VERIFY_NONE, NULL);
|
||||||
|
|
||||||
|
/* Otherwise use the given CA certificate to validate (if any) */
|
||||||
|
else if (settings->ca_cert != NULL) {
|
||||||
|
|
||||||
|
/* Read CA certificate from configuration data */
|
||||||
|
X509* ca_cert = guac_kubernetes_read_cert(settings->ca_cert);
|
||||||
|
if (ca_cert == NULL) {
|
||||||
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||||
|
"Provided CA certificate is unreadable");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add certificate to CA store */
|
||||||
|
X509_STORE* ca_store = SSL_CTX_get_cert_store(context);
|
||||||
|
if (!X509_STORE_add_cert(ca_store, ca_cert)) {
|
||||||
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||||
|
"Unable to add CA certificate to certificate store of "
|
||||||
|
"SSL context");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Certificate for SSL/TLS client auth */
|
||||||
|
if (settings->client_cert != NULL) {
|
||||||
|
|
||||||
|
/* Read client certificate from configuration data */
|
||||||
|
X509* client_cert = guac_kubernetes_read_cert(settings->client_cert);
|
||||||
|
if (client_cert == NULL) {
|
||||||
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||||
|
"Provided client certificate is unreadable");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use parsed certificate for authentication */
|
||||||
|
if (!SSL_CTX_use_certificate(context, client_cert)) {
|
||||||
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||||
|
"Client certificate could not be used for SSL/TLS "
|
||||||
|
"client authentication");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Private key for SSL/TLS client auth */
|
||||||
|
if (settings->client_key != NULL) {
|
||||||
|
|
||||||
|
/* Read client private key from configuration data */
|
||||||
|
EVP_PKEY* client_key = guac_kubernetes_read_key(settings->client_key);
|
||||||
|
if (client_key == NULL) {
|
||||||
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||||
|
"Provided client private key is unreadable");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use parsed key for authentication */
|
||||||
|
if (!SSL_CTX_use_PrivateKey(context, client_key)) {
|
||||||
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||||
|
"Client private key could not be used for SSL/TLS "
|
||||||
|
"client authentication");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Enable hostname checking */
|
||||||
|
X509_VERIFY_PARAM *param = SSL_CTX_get0_param(context);
|
||||||
|
X509_VERIFY_PARAM_set_hostflags(param,
|
||||||
|
X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
|
||||||
|
|
||||||
|
/* Validate properly depending on whether hostname is an IP address */
|
||||||
|
if (guac_kubernetes_is_address(settings->hostname)) {
|
||||||
|
if (!X509_VERIFY_PARAM_set1_ip_asc(param, settings->hostname)) {
|
||||||
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||||
|
"Server IP address validation could not be enabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!X509_VERIFY_PARAM_set1_host(param, settings->hostname, 0)) {
|
||||||
|
guac_client_abort(client, GUAC_PROTOCOL_STATUS_SERVER_ERROR,
|
||||||
|
"Server hostname validation could not be enabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
41
src/protocols/kubernetes/ssl.h
Normal file
41
src/protocols/kubernetes/ssl.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
* or more contributor license agreements. See the NOTICE file
|
||||||
|
* distributed with this work for additional information
|
||||||
|
* regarding copyright ownership. The ASF licenses this file
|
||||||
|
* to you under the Apache License, Version 2.0 (the
|
||||||
|
* "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing,
|
||||||
|
* software distributed under the License is distributed on an
|
||||||
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
* KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GUAC_KUBERNETES_SSL_H
|
||||||
|
#define GUAC_KUBERNETES_SSL_H
|
||||||
|
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the given SSL/TLS context using the configuration parameters
|
||||||
|
* associated with the given guac_client, setting up hostname/address
|
||||||
|
* validation and client authentication.
|
||||||
|
*
|
||||||
|
* @param client
|
||||||
|
* The guac_client associated with the Kubernetes connection.
|
||||||
|
*
|
||||||
|
* @param context
|
||||||
|
* The SSL_CTX in use by libwebsockets.
|
||||||
|
*/
|
||||||
|
void guac_kubernetes_init_ssl(guac_client* client, SSL_CTX* context);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user