Skip to content

Commit

Permalink
fixup: add AMQP SSL subsystem
Browse files Browse the repository at this point in the history
  • Loading branch information
kgiusti committed Aug 12, 2024
1 parent 09d58d1 commit 3365bc0
Show file tree
Hide file tree
Showing 35 changed files with 1,518 additions and 1,098 deletions.
2 changes: 1 addition & 1 deletion include/qpid/dispatch/protocol_adaptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +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 qdr_connection_info_set_tls(qdr_connection_info_t *info, bool enabled, char *version, char *ciphers, int ssf);

void qd_adaptor_listener_init(void);
void qd_adaptor_listener_finalize(void);
Expand Down
12 changes: 1 addition & 11 deletions include/qpid/dispatch/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@

#include <proton/engine.h>
#include <proton/event.h>
#include <proton/ssl.h>

typedef struct qd_server_t qd_server_t;
typedef struct qd_container_t qd_container_t;
Expand Down Expand Up @@ -108,14 +107,6 @@ typedef enum {
*/
void qd_server_set_container(qd_dispatch_t *qd, struct qd_container_t *container);

/**
* Store address of display name service py object for C code use
*
* @param qd The dispatch handle returned by qd_dispatch.
* @param display_name_service address of python object
*/
qd_error_t qd_register_display_name_service(qd_dispatch_t *qd, void *display_name_service);

pn_proactor_t *qd_server_proactor(const qd_server_t *qd_server);
qd_http_server_t *qd_server_http(const qd_server_t *qd_server);
uint64_t qd_server_allocate_connection_id(qd_server_t *server);
Expand All @@ -130,8 +121,7 @@ typedef struct qd_handler_context_t {
qd_server_event_handler_t handler;
} qd_handler_context_t;

// Use displayName lookup to translate user_id to user name
char *qd_server_query_user_name(const qd_server_t *server, const char *ssl_profile, const char *user_id);

const char *qd_server_get_container_name(const qd_server_t *server);
sys_mutex_t *qd_server_get_activation_lock(qd_server_t *server);

Expand Down
56 changes: 35 additions & 21 deletions include/qpid/dispatch/tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,39 +56,49 @@ struct qd_ssl2_profile_t {
char *ssl_certificate_file;
char *ssl_private_key_file;
char *ssl_password;

/**
* Holds the list of component fields of the client certificate from which a unique identifier is constructed. For
* e.g, this field could have the format of 'cou' indicating that the uid will consist of c - common name
* concatenated with o - organization-company name concatenated with u - organization unit
*
* Allowed values can be any combination of the comma separated codes (no duplicates):
* '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 one of the following:
* '1'(sha1 certificate fingerprint, the fingerprint, as displayed in the fingerprints section when looking at a certificate
* with say a web browser is the hash of the entire certificate in DER form)
* '2'(sha256 certificate fingerprint)
* '5'(sha512 certificate fingerprint)
*/
char *ssl_uid_format;

/**
* Full path to the file that contains the uid to display name mapping.
*/
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);
qd_tls2_domain_t *qd_tls2_domain(const char *ssl_profile_name,
qd_tls_type_t p_type,
qd_tls_domain_mode_t mode,
bool verify_hostname,
bool authenticate_peer);

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_domain_decref(qd_tls2_domain_t *domain);

// TLS session creation is Proton protocol specific: see the protocol specific header files
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);
Expand All @@ -97,6 +107,10 @@ char *qd_tls2_session_get_protocol_version(const qd_tls2_session_t *session);
// 0 if ciphers not known.
char *qd_tls2_session_get_protocol_ciphers(const qd_tls2_session_t *session);

// Get the Security Strength Factor (SSF) of the Cipher in use by the session
//
int qd_tls2_session_get_ssf(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);
Expand Down
56 changes: 56 additions & 0 deletions include/qpid/dispatch/tls_amqp.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#ifndef __tls_amqp_h__
#define __tls_amqp_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"

typedef struct pn_transport_t pn_transport_t;

/**
* API for TLS operations specific to Proton AMQP connections.
*
* Note well: these APIs apply only to TLS domain/sessions of type QD_TLS_TYPE_PROTON_AMQP! Proton raw connection
* based TLS sessions are not supported. See tls.h and tls_raw_io.h.
*/


/**
* Create a new TLS session
*
* @param domain the TLS domain mused when creating the session
* @param tport transport associated with the session's connection
* @param allow_unencrypted if true permit accepting incoming unencrypted connections
* @return a new TLS session or 0 on error. If error qd_error() is set.
*/
qd_tls2_session_t *qd_tls2_session_amqp(qd_tls2_domain_t *domain, pn_transport_t *tport, bool allow_unencrypted);


/**
* Get the user identifier associated with the TLS session.
*
* @param session the active TLS session to retrieve the user id from.
* @return string containing user name if query succeeds else 0. Caller must free() returned user name string when no
* longer used.
*/
char *qd_tls_session_get_user_id(qd_tls2_session_t *session);


#endif

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#ifndef __tls_raw_io_h__
#define __tls_raw_io_h__ 1
#ifndef __tls_raw_h__
#define __tls_raw_h__ 1
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
Expand All @@ -25,15 +25,40 @@
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.
* API for TLS operations specific to Proton Raw connections.
*
* Note well: these APIs are intended to work for qd_tls_session_t of type QD_SSL_PROTON_RAW ONLY! AMQP-based TLS
* Note well: these APIs apply only to TLS domain/sessions of type QD_TLS_TYPE_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!
* with AMQP connections! See tls.h and tls_amqp.h.
*/


/**
* Create a new TLS session
*
* @param domain the TLS domain used when creating the session
* @param peer_hostname the expected name of the peer host (for verification)
* @param alpn_protocols optional ALPN protocols for negotiation
* @param alpn_protocol_count length of alpn_protocols array (must be zero if no ALPN)
* @param context passed to the on_secure callback
* @param on_secure optional callback that is invoked if/when the TLS handshake succeeds
* @return the new TLS session or 0 on error. If error qd_error() is set.
*/
typedef void qd_tls2_session_on_secure_cb_t(qd_tls2_session_t *session, void *context);
qd_tls2_session_t *qd_tls2_session_raw(qd_tls2_domain_t *domain,
const char *peer_hostname,
const char **alpn_protocols, size_t alpn_protocol_count,
void *context, qd_tls2_session_on_secure_cb_t *on_secure);

/**
* Get the negotiated ALPN value from the session.
*
* @param session the TLS session to query.
* @return null terminated string containing the negotiated ALPN value. 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);

/**
* Fetch output (cleartext) buffers from the application for encryption and transmission.
*
Expand Down Expand Up @@ -72,16 +97,20 @@ typedef int64_t qd_tls2_take_output_buffers_cb_t(void *context, qd_buffer_list_t
* @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
* @param log_module - log module for logging output
* @param conn_id - connection id for logging
*
* @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);
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,
qd_log_module_t log_module,
uint64_t conn_id);

/* True if the given session has failed
*/
Expand Down
3 changes: 1 addition & 2 deletions python/skupper_router_internal/dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ def __init__(self) -> None:
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_tls_register_display_name_service, None, [py_object])

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 All @@ -134,8 +135,6 @@ def __init__(self) -> None:
self._prototype(self.qd_dispatch_policy_host_pattern_remove, None, [self.qd_dispatch_p, py_object])
self._prototype(self.qd_dispatch_policy_host_pattern_lookup, c_char_p, [self.qd_dispatch_p, py_object])

self._prototype(self.qd_dispatch_register_display_name_service, None, [self.qd_dispatch_p, py_object])

self._prototype(self.qd_dispatch_set_agent, None, [self.qd_dispatch_p, py_object])

self._prototype(self.qd_router_setup_late, None, [self.qd_dispatch_p])
Expand Down
2 changes: 1 addition & 1 deletion python/skupper_router_internal/management/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def configure(attributes):

from skupper_router_internal.display_name.display_name import DisplayNameService
displayname_service = DisplayNameService()
qd.qd_dispatch_register_display_name_service(dispatch, displayname_service)
qd.qd_tls_register_display_name_service(displayname_service)

# Configure policy and policy manager before vhosts
policyDir = config.by_type('policy')[0]['policyDir']
Expand Down
4 changes: 3 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,9 @@ set(qpid_dispatch_SOURCES
router_core/modules/mobile_sync/mobile.c
router_core/modules/streaming_link_scrubber/streaming_link_scrubber.c
tls/tls.c
tls/tls_raw_io.c
tls/tls_raw.c
tls/tls_amqp.c
tls/display_name.c
router_pynode.c
schema_enum.c
static_assert.c
Expand Down
30 changes: 13 additions & 17 deletions src/adaptors/amqp/amqp_adaptor.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <qpid/dispatch/protocols.h>
#include <qpid/dispatch/connection_counters.h>
#include <qpid/dispatch/amqp_adaptor.h>
#include <qpid/dispatch/tls_amqp.h>

#include <proton/sasl.h>

Expand Down Expand Up @@ -1377,7 +1378,6 @@ static void AMQP_opened_handler(qd_router_t *router, qd_connection_t *conn, bool
pn_connection_t *pn_conn = qd_connection_pn(conn);
pn_transport_t *tport = 0;
pn_sasl_t *sasl = 0;
pn_ssl_t *ssl = 0;
const char *mech = 0;
const char *user = 0;
const char *container = conn->pn_conn ? pn_connection_remote_container(conn->pn_conn) : 0;
Expand All @@ -1387,7 +1387,6 @@ static void AMQP_opened_handler(qd_router_t *router, qd_connection_t *conn, bool
conn->strip_annotations_out = false;
if (conn->pn_conn) {
tport = pn_connection_transport(conn->pn_conn);
ssl = conn->ssl;
}
if (tport) {
sasl = pn_sasl(tport);
Expand Down Expand Up @@ -1537,22 +1536,16 @@ static void AMQP_opened_handler(qd_router_t *router, qd_connection_t *conn, bool
}
}

char proto[50];
memset(proto, 0, 50);
char cipher[50];
memset(cipher, 0, 50);

char *proto = 0;
char *cipher = 0;
int ssl_ssf = 0;
bool is_ssl = false;

if (ssl) {
pn_ssl_get_protocol_name(ssl, proto, 50);
pn_ssl_get_cipher_name(ssl, cipher, 50);
ssl_ssf = pn_ssl_get_ssf(ssl);
is_ssl = true;
if (conn->ssl) {
proto = qd_tls2_session_get_protocol_version(conn->ssl);
cipher = qd_tls2_session_get_protocol_ciphers(conn->ssl);
ssl_ssf = qd_tls2_session_get_ssf(conn->ssl);
}


bool encrypted = tport && pn_transport_is_encrypted(tport);
bool authenticated = tport && pn_transport_is_authenticated(tport);

Expand All @@ -1568,7 +1561,7 @@ static void AMQP_opened_handler(qd_router_t *router, qd_connection_t *conn, bool
container,
props,
ssl_ssf,
is_ssl,
!!conn->ssl,
rversion,
streaming_links,
connection_trunking);
Expand Down Expand Up @@ -1611,6 +1604,9 @@ static void AMQP_opened_handler(qd_router_t *router, qd_connection_t *conn, bool
authenticated ? mech : "no", (char*) user, container);
sys_mutex_unlock(&conn->connector->lock);
}

free(proto);
free(cipher);
}


Expand Down Expand Up @@ -2394,8 +2390,7 @@ static void qd_amqp_adaptor_final(void *adaptor_context)
pn_connection_set_context(ctx->pn_conn, 0);
}
qd_connection_invoke_deferred_calls(ctx, true); // Discard any pending deferred calls
if (ctx->free_user_id)
free((char*)ctx->user_id);
free(ctx->user_id);
sys_mutex_free(&ctx->deferred_call_lock);
free(ctx->name);
free(ctx->role);
Expand All @@ -2409,6 +2404,7 @@ static void qd_amqp_adaptor_final(void *adaptor_context)
qd_listener_remove_connection(ctx->listener, ctx);
ctx->listener = 0;
}
qd_tls2_session_free(ctx->ssl);
sys_atomic_destroy(&ctx->wake_core);
sys_atomic_destroy(&ctx->wake_cutthrough_inbound);
sys_atomic_destroy(&ctx->wake_cutthrough_outbound);
Expand Down
Loading

0 comments on commit 3365bc0

Please sign in to comment.