Skip to content

Commit

Permalink
Issue skupperproject#1572: make sslProfile configuration updatable (p…
Browse files Browse the repository at this point in the history
…art 1: raw conn only)

This does not solve skupperproject#1572. It is part of a series of changes that will
address skupperproject#1572.
  • Loading branch information
kgiusti committed Jul 30, 2024
1 parent f1f61ee commit f4edf4a
Show file tree
Hide file tree
Showing 29 changed files with 1,744 additions and 301 deletions.
19 changes: 0 additions & 19 deletions include/qpid/dispatch/connection_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,24 +27,10 @@
#include "qpid/dispatch/server.h"

typedef struct qd_connection_manager_t qd_connection_manager_t;
typedef struct qd_config_ssl_profile_t qd_config_ssl_profile_t;
typedef struct qd_connection_t qd_connection_t;

typedef void (*qd_connection_manager_handler_t) (void *context, qd_connection_t *conn);

struct qd_config_ssl_profile_t {
DEQ_LINKS(qd_config_ssl_profile_t);
char *name;
char *ssl_password;
char *ssl_trusted_certificate_db;
char *ssl_uid_format;
char *uid_name_mapping_file;
char *ssl_certificate_file;
char *ssl_private_key_file;
char *ssl_ciphers;
char *ssl_protocols;
};

/**
* Allocate a connection manager
*
Expand All @@ -69,9 +55,4 @@ void qd_connection_manager_free(qd_connection_manager_t *cm);
*/
QD_EXPORT void qd_connection_manager_start(qd_dispatch_t *qd);

/**
* Find named qd_config_ssl_profile_t object
*/
qd_config_ssl_profile_t *qd_find_ssl_profile(const qd_connection_manager_t *cm, const char *name);

#endif
1 change: 1 addition & 0 deletions include/qpid/dispatch/protocol_adaptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,7 @@ qdr_connection_info_t *qdr_connection_info(bool is_encrypted,
bool connection_trunking);

void qdr_connection_info_set_group_correlator(qdr_connection_info_t *info, const char *correlator);
void qdr_connection_info_set_tls(qdr_connection_info_t *info, bool enabled, char *version, char *ciphers);

void qd_adaptor_listener_init(void);
void qd_adaptor_listener_finalize(void);
Expand Down
109 changes: 109 additions & 0 deletions include/qpid/dispatch/tls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#ifndef __tls_h__
#define __tls_h__ 1
/*
* 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.
*/

/**@file
* Management of TLS configuration and state
*/


#include "qpid/dispatch/log.h"

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>


typedef struct qd_tls2_domain_t qd_tls2_domain_t; // SSL configuration domain
typedef struct qd_tls2_session_t qd_tls2_session_t; // per connection SSL state
typedef struct qd_ssl2_profile_t qd_ssl2_profile_t; // sslProfile configuration record

// Proton has two different SSL/TLS implementations: one for AMQP and a buffer-based one for use with Raw Connections:
typedef enum {
QD_TLS_TYPE_NONE = 0, // unset
QD_TLS_TYPE_PROTON_AMQP, // for use with AMQP transport
QD_TLS_TYPE_PROTON_RAW, // use raw connection/qd_buffer_t interface
} qd_tls_type_t;

typedef enum {
QD_TLS_DOMAIN_MODE_NONE = 0, // unset
QD_TLS_DOMAIN_SERVER_MODE, // Operate as an SSL server (i.e. listener socket)
QD_TLS_DOMAIN_CLIENT_MODE, // Operate as an SSL client (i.e. outgoing connections)
} qd_tls_domain_mode_t;

// sslProfile configuration record
struct qd_ssl2_profile_t {
char *ssl_ciphers;
char *ssl_protocols;
char *ssl_trusted_certificate_db;
char *ssl_certificate_file;
char *ssl_private_key_file;
char *ssl_password;
char *ssl_uid_format;
char *uid_name_mapping_file;
};

void qd_tls2_initialize(void);
void qd_tls2_finalize(void);

qd_tls2_domain_t *qd_tls2_new_domain(const char *name,
const char *ssl_profile_name,
qd_tls_type_t p_type,
qd_tls_domain_mode_t mode,
bool verify_hostname, // for client mode
bool authenticate_peer, // for server mode
const char **alpn_protocols, // for server mode
size_t alpn_protocol_count,
qd_log_module_t log_module);
void qd_tls2_domain_decref(qd_tls2_domain_t *domain);

typedef void qd_tls2_session_on_secure_cb_t(qd_tls2_session_t *session, void *context);
qd_tls2_session_t *qd_tls2_domain_new_session(qd_tls2_domain_t *domain,
uint64_t conn_id,
const char *peer_hostname,
// override default ALPN config for this session
const char **alpn_protocols, size_t alpn_protocol_count,
void *context, qd_tls2_session_on_secure_cb_t *on_secure);

void qd_tls2_session_free(qd_tls2_session_t *session);


// Get the negotiated ALPN value from the session. Returned string buffer must be free()d by caller. Return 0 if no ALPN
// (yet) negotiated.
char *qd_tls2_session_get_alpn_protocol(const qd_tls2_session_t *session);

// Get the version of TLS/SSL in use by the session. Returned string buffer must be free()d by caller. Return 0 if
// version not known.
char *qd_tls2_session_get_protocol_version(const qd_tls2_session_t *session);

// Get the cipher string for the ciphers in use by the session. Returned string buffer must be free()d by caller. Return
// 0 if ciphers not known.
char *qd_tls2_session_get_protocol_ciphers(const qd_tls2_session_t *session);

// Fill out the given *profile with the configuration from the named sslProfile record. Return a pointer to the profile
// parameter on success else 0. Use qd_tls2_cleanup_ssl_profile() release resources in use by *profile when done.
qd_ssl2_profile_t *qd_tls2_read_ssl_profile(const char *ssl_profile_name, qd_ssl2_profile_t *profile);

// Release any resources allocated by qd_tls2_get_ssl_profile() and reset the *profile. Note this only releases
// internal resources associated with the profile, the memory pointed to by *profile is not modified.
void qd_tls2_cleanup_ssl_profile(qd_ssl2_profile_t *profile);

#endif

118 changes: 118 additions & 0 deletions include/qpid/dispatch/tls_raw_io.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#ifndef __tls_raw_io_h__
#define __tls_raw_io_h__ 1
/*
* 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 "qpid/dispatch/tls.h"
#include "qpid/dispatch/buffer.h"

typedef struct pn_raw_connection_t pn_raw_connection_t;

/**
* API for TLS encryption/decryption using raw connections and qd_buffer_t data.
* See tls_manager.h for qd_tls_session_t management.
*
* Note well: these APIs are intended to work for qd_tls_session_t of type QD_SSL_PROTON_RAW ONLY! AMQP-based TLS
* encryption/decryption is done internally by Proton - these APIs are not necessary for AMQP TLS and should not be used
* by AMQP connections!
*/


/**
* Fetch output (cleartext) buffers from the application for encryption and transmission.
*
* This callback is supplied by the application when calling the qd_tls2_session_do_io() work loop. The work loop will
* call this callback to get output data buffers from the application. The work loop will encrypt these buffers via TLS
* and send them out the raw connection.
*
* @param context - application supplied context (see qd_tls2_session_do_io())
* @param blist - buffer list for output buffers. The application should append output buffers to the end of the list in
* FIFO order of transmission.
* @param limit - limit the number of buffers that can be appended to the list during the call. The application may
* append up to limit buffers but not more.
* @return - the total number of octets worth of data appended to blist. Zero if there is no output available at the
* time of the call. QD_IO_EOS to force the work loop to close the output side of the stream. No buffers
* should be appended to blist when QD_IO_EOS is returned. Once QD_IO_EOS is returned no further output
* buffers will be taken/sent.
*/
#define QD_IO_EOS (-1)
typedef int64_t qd_tls2_take_output_buffers_cb_t(void *context, qd_buffer_list_t *blist, size_t limit);


/**
* TLS I/O work loop.
*
* This API will perform TLS data encryption and decryption between a raw connection and and application. Outgoing
* application cleartext data will be fetched from the application as needed via the take_output_cb() callback. The
* cleartext data will be encrypted and written to the raw connection (write buffers). On return any incoming decrypted
* (cleartext) data will be appended to the input_data list. Ownership of the input_data buffers is transferred to the
* caller: the application must release them when no longer needed.
*
* This function will close the raw_conn connection when TLS cleanly closes or if a TLS error occurs.
*
* @param session - the TLS session context
* @param raw_conn - the raw connection for reading/writing encrypted buffers.
* @param take_output_cb - invoked by the I/O loop to get outgoing cleartext application data
* @param take_output_context - passed back to take_output_cb()
* @param input_data - incoming decrypted data is appended to this list.
* @param input_data_count - (output) total number of cleartext octets added to input_data
*
* @return 0 if I/O in progress, QD_TLS_DONE if the TLS session has closed, or fatal error if < 0
*/
#define QD_TLS_DONE 1
int qd_tls2_session_do_io(qd_tls2_session_t *session,
pn_raw_connection_t *raw_conn,
qd_tls2_take_output_buffers_cb_t *take_output_cb,
void *take_output_context,
qd_buffer_list_t *input_data,
uint64_t *input_data_count);

/* True if the given session has failed
*/
bool qd_tls2_session_is_error(const qd_tls2_session_t *session);

/* True after the TLS handshake has completed successfully
*/
bool qd_tls2_session_is_secure(const qd_tls2_session_t *session);

/**
* True if all input (decrypt) data has been received and the receive side of the raw connection has closed. No further
* input data is available from this TLS session.
*
* Sets close_notify to true if a proper close_notify was received from the peer. A missing close_notify is allowed in
* HTTP/1.x if the received message has an explicit length and the framing is valid (see RFC9112, section TLS Connection
* Closure)
*/
bool qd_tls2_session_is_input_drained(const qd_tls2_session_t *session, bool *close_notify);

/**
* True if the output (encrypt) side of the TLS session is closed and all pending output has been written to the raw
* connection (including close_notify).
*/
bool qd_tls2_session_is_output_flushed(const qd_tls2_session_t *session);

/**
* Retrieve octet counters for encrypted I/O. It is expected that the application maintains counters for the cleartext data
* itself.
*/
uint64_t qd_tls2_session_encrypted_output_octet_count(const qd_tls2_session_t *session); // outbound to network
uint64_t qd_tls2_session_encrypted_input_octet_count(const qd_tls2_session_t *session); // inbound from network

#endif

26 changes: 17 additions & 9 deletions python/skupper_router/management/skrouter.json
Original file line number Diff line number Diff line change
Expand Up @@ -661,50 +661,58 @@
"description":"Attributes for setting TLS/SSL configuration for connections.",
"referential": true,
"extends": "configurationEntity",
"operations": ["CREATE", "DELETE"],
"operations": ["CREATE", "UPDATE", "DELETE"],
"attributes": {
"ciphers": {
"type": "string",
"description": "Specifies the enabled ciphers so the SSL Ciphers can be hardened. In other words, use this field to disable weak ciphers. The ciphers are specified in the format understood by the OpenSSL library. For example, ciphers can be set to ALL:!aNULL:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP; -- The full list of allowed ciphers can be viewed using the openssl ciphers command",
"create": true
"create": true,
"update": true
},
"protocols": {
"type": "string",
"description": "The TLS protocols that this sslProfile can use. You can specify a list of one or more of TLSv1, TLSv1.1, or TLSv1.2. To specify multiple protocols, separate the protocols with a space. For example, to permit the sslProfile to use TLS v1.1 and TLS v1.2 only, you would set the value to TLSv1.1 TLSv1.2. If you do not specify a value, the sslProfile uses the TLS protocol specified by the system-wide configuration.",
"create": true
"create": true,
"update": true
},
"caCertFile": {
"type": "path",
"description": "The absolute path to the database that contains the public certificates of trusted certificate authorities (CA).",
"create": true
"create": true,
"update": true
},
"certFile": {
"type": "path",
"description": "The absolute path to the file containing the PEM-formatted public certificate to be used on the local end of any connections using this profile.",
"create": true
"create": true,
"update": true

},
"privateKeyFile": {
"type": "path",
"description": "The absolute path to the file containing the PEM-formatted private key for the above certificate.",
"create": true
"create": true,
"update": true

},
"password": {
"type": "string",
"description": "The password that unlocks the certificate key. You can specify the password by specifying an environment variable that stores the password, a file that stores the password, or by entering the password in clear text. To use an environment variable, specify 'password: env:<var>'. Use this option with caution, because the environment of other processes is visible on certain platforms (for example, ps on certain Unix OSs). To use a file, specify 'password: file:<absolute-path-to-file>'. This option is the most secure, because permissions can be set on the file that contains the password. To specify the password in clear text, specify 'password: pass:<password>', or 'password: literal:<password>', or 'password: <password>'. This option is insecure, so it should only be used if security is not a concern.",
"create": true
"create": true,
"update": true

},
"uidFormat": {
"type": "string",
"description": "A list of x509 client certificate fields that will be used to build a string that will uniquely identify the client certificate owner. For e.g. a value of 'cou' indicates that the uid will consist of c - common name concatenated with o - organization-company name concatenated with u - organization unit; or a value of 'o2' indicates that the uid will consist of o (organization name) concatenated with 2 (the sha256 fingerprint of the entire certificate) . Allowed values can be any combination of 'c'( ISO3166 two character country code), 's'(state or province), 'l'(Locality; generally - city), 'o'(Organization - Company Name), 'u'(Organization Unit - typically certificate type or brand), 'n'(CommonName - typically a user name for client certificates) and '1'(sha1 certificate fingerprint, as displayed in the fingerprints section when looking at a certificate with say a web browser is the hash of the entire certificate) and 2 (sha256 certificate fingerprint) and 5 (sha512 certificate fingerprint). The user identifier (uid) that is generated based on the uidFormat is a string which has a semi-colon as a separator between the components",
"create": true
"create": true,
"update": true
},
"uidNameMappingFile": {
"type": "string",
"description": "The absolute path to the file containing the unique id to display name mapping",
"create": true
"create": true,
"update": true
}
}
},
Expand Down
6 changes: 4 additions & 2 deletions python/skupper_router_internal/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ def __init__(self) -> None:
self._prototype(self.qd_dispatch_prepare, None, [self.qd_dispatch_p])
self._prototype(self.qd_dispatch_configure_listener, c_void_p, [self.qd_dispatch_p, py_object])
self._prototype(self.qd_dispatch_configure_connector, c_void_p, [self.qd_dispatch_p, py_object])
self._prototype(self.qd_dispatch_configure_ssl_profile, c_void_p, [self.qd_dispatch_p, py_object])
self._prototype(self.qd_dispatch_configure_tcp_listener, c_void_p, [self.qd_dispatch_p, py_object])
self._prototype(self.qd_dispatch_configure_tcp_connector, c_void_p, [self.qd_dispatch_p, py_object])
self._prototype(self.qd_dispatch_configure_http_listener, c_void_p, [self.qd_dispatch_p, py_object])
Expand All @@ -119,7 +118,10 @@ def __init__(self) -> None:
self._prototype(self.qd_dispatch_delete_http_connector, None, [self.qd_dispatch_p, c_void_p])
self._prototype(self.qd_connection_manager_delete_listener, None, [self.qd_dispatch_p, c_void_p])
self._prototype(self.qd_connection_manager_delete_connector, None, [self.qd_dispatch_p, c_void_p])
self._prototype(self.qd_connection_manager_delete_ssl_profile, c_bool, [self.qd_dispatch_p, c_void_p])

self._prototype(self.qd_tls_configure_ssl_profile, c_void_p, [self.qd_dispatch_p, py_object])
self._prototype(self.qd_tls_update_ssl_profile, c_void_p, [self.qd_dispatch_p, py_object, c_void_p])
self._prototype(self.qd_tls_delete_ssl_profile, None, [self.qd_dispatch_p, c_void_p])

self._prototype(self.qd_dispatch_configure_address, None, [self.qd_dispatch_p, py_object])
self._prototype(self.qd_dispatch_configure_auto_link, None, [self.qd_dispatch_p, py_object])
Expand Down
Loading

0 comments on commit f4edf4a

Please sign in to comment.