PROTON-911: Create SASL encryption layer, and logic which switches it on - Currently no encryption is implemented - Simplify SASL state a little too
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/2c383aaa Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/2c383aaa Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/2c383aaa Branch: refs/heads/master Commit: 2c383aaa83dc1b0dff7c473762cd49d7ce207c74 Parents: 37730cc Author: Andrew Stitcher <astitc...@apache.org> Authored: Fri Jun 19 17:39:02 2015 -0400 Committer: Andrew Stitcher <astitc...@apache.org> Committed: Tue Jun 30 13:33:08 2015 -0400 ---------------------------------------------------------------------- proton-c/src/sasl/cyrus_sasl.c | 15 ++++++ proton-c/src/sasl/none_sasl.c | 15 ++++++ proton-c/src/sasl/sasl-internal.h | 21 +++++--- proton-c/src/sasl/sasl.c | 91 +++++++++++++++++++++++----------- 4 files changed, 108 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2c383aaa/proton-c/src/sasl/cyrus_sasl.c ---------------------------------------------------------------------- diff --git a/proton-c/src/sasl/cyrus_sasl.c b/proton-c/src/sasl/cyrus_sasl.c index c84d0af..cdcd0bf 100644 --- a/proton-c/src/sasl/cyrus_sasl.c +++ b/proton-c/src/sasl/cyrus_sasl.c @@ -381,6 +381,21 @@ void pni_sasl_impl_free(pn_transport_t *transport) } } +bool pni_sasl_impl_can_encrypt(pn_transport_t *transport) +{ + return false; +} + +ssize_t pni_sasl_impl_encode(pn_transport_t *transport, pn_bytes_t in, pn_buffer_t *out) +{ + return 0; +} + +ssize_t pni_sasl_impl_decode(pn_transport_t *transport, pn_bytes_t in, pn_buffer_t *out) +{ + return 0; +} + bool pn_sasl_extended(void) { return true; http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2c383aaa/proton-c/src/sasl/none_sasl.c ---------------------------------------------------------------------- diff --git a/proton-c/src/sasl/none_sasl.c b/proton-c/src/sasl/none_sasl.c index be27871..ccb4818 100644 --- a/proton-c/src/sasl/none_sasl.c +++ b/proton-c/src/sasl/none_sasl.c @@ -172,6 +172,21 @@ void pni_process_response(pn_transport_t *transport, const pn_bytes_t *recv) { } +bool pni_sasl_impl_can_encrypt(pn_transport_t *transport) +{ + return false; +} + +ssize_t pni_sasl_impl_encode(pn_transport_t *transport, pn_bytes_t in, pn_buffer_t *out) +{ + return 0; +} + +ssize_t pni_sasl_impl_decode(pn_transport_t *transport, pn_bytes_t in, pn_buffer_t *out) +{ + return 0; +} + bool pn_sasl_extended(void) { return false; http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2c383aaa/proton-c/src/sasl/sasl-internal.h ---------------------------------------------------------------------- diff --git a/proton-c/src/sasl/sasl-internal.h b/proton-c/src/sasl/sasl-internal.h index 71205f5..fb40b9c 100644 --- a/proton-c/src/sasl/sasl-internal.h +++ b/proton-c/src/sasl/sasl-internal.h @@ -22,9 +22,12 @@ #ifndef PROTON_SASL_INTERNAL_H #define PROTON_SASL_INTERNAL_H 1 +#include "buffer.h" #include "proton/types.h" #include "proton/sasl.h" +#include "engine/engine-internal.h" + // SASL APIs used by transport code void pn_sasl_free(pn_transport_t *transport); void pni_sasl_set_user_password(pn_transport_t *transport, const char *user, const char *password); @@ -33,15 +36,21 @@ void pni_sasl_set_external_security(pn_transport_t *transport, int ssf, const ch // Internal SASL authenticator interface void pni_sasl_impl_free(pn_transport_t *transport); -int pni_sasl_impl_list_mechs(pn_transport_t* transport, char** mechlist); -bool pni_init_server(pn_transport_t* transport); +int pni_sasl_impl_list_mechs(pn_transport_t *transport, char **mechlist); +bool pni_init_server(pn_transport_t *transport); void pni_process_init(pn_transport_t *transport, const char *mechanism, const pn_bytes_t *recv); void pni_process_response(pn_transport_t *transport, const pn_bytes_t *recv); -bool pni_init_client(pn_transport_t* transport); +bool pni_init_client(pn_transport_t *transport); bool pni_process_mechanisms(pn_transport_t *transport, const char *mechs); void pni_process_challenge(pn_transport_t *transport, const pn_bytes_t *recv); +// Internal SASL security layer interface +bool pni_sasl_impl_can_encrypt(pn_transport_t *transport); +ssize_t pni_sasl_impl_encode(pn_transport_t *transport, pn_bytes_t in, pn_buffer_t *out); +ssize_t pni_sasl_impl_decode(pn_transport_t *transport, pn_bytes_t in, pn_buffer_t *out); + + // Shared SASL API used by the actual SASL authenticators enum pni_sasl_state { SASL_NONE, @@ -56,7 +65,6 @@ enum pni_sasl_state { struct pni_sasl_t { void *impl_context; - // Client selected mechanism char *selected_mechanism; char *included_mechanisms; const char *username; @@ -67,14 +75,15 @@ struct pni_sasl_t { char *external_auth; int external_ssf; pn_sasl_outcome_t outcome; + pn_buffer_t* decoded_buffer; + pn_buffer_t* encoded_buffer; pn_bytes_t bytes_out; enum pni_sasl_state desired_state; enum pni_sasl_state last_state; bool client; - bool input_bypass; - bool output_bypass; }; +// Shared Utility used by sasl implementations void pni_split_mechs(char *mechlist, const char* included_mechs, char *mechs[], int *count); bool pni_included_mech(const char *included_mech_list, pn_bytes_t s); void pni_sasl_set_desired_state(pn_transport_t *transport, enum pni_sasl_state desired_state); http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/2c383aaa/proton-c/src/sasl/sasl.c ---------------------------------------------------------------------- diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c index 4ef9e99..ac177c7 100644 --- a/proton-c/src/sasl/sasl.c +++ b/proton-c/src/sasl/sasl.c @@ -25,6 +25,7 @@ #include "engine/engine-internal.h" #include "protocol.h" #include "proton/ssl.h" +#include "proton/types.h" #include "util.h" #include "transport/autodetect.h" @@ -44,8 +45,10 @@ static inline pni_sasl_t *get_sasl_internal(pn_sasl_t *sasl) static ssize_t pn_input_read_sasl_header(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available); static ssize_t pn_input_read_sasl(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available); +static ssize_t pn_input_read_sasl_encrypt(pn_transport_t *transport, unsigned int layer, const char *bytes, size_t available); static ssize_t pn_output_write_sasl_header(pn_transport_t* transport, unsigned int layer, char* bytes, size_t size); static ssize_t pn_output_write_sasl(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available); +static ssize_t pn_output_write_sasl_encrypt(pn_transport_t *transport, unsigned int layer, char *bytes, size_t available); const pn_io_layer_t sasl_header_layer = { pn_input_read_sasl_header, @@ -75,6 +78,13 @@ const pn_io_layer_t sasl_layer = { NULL }; +const pn_io_layer_t sasl_encrypt_layer = { + pn_input_read_sasl_encrypt, + pn_output_write_sasl_encrypt, + NULL, + NULL +}; + #define SASL_HEADER ("AMQP\x03\x01\x00\x00") #define SASL_HEADER_LEN 8 @@ -262,23 +272,34 @@ static ssize_t pn_input_read_sasl(pn_transport_t* transport, unsigned int layer, return PN_EOS; } - if (!transport->sasl->input_bypass) { - pni_sasl_start_server_if_needed(transport); + pni_sasl_start_server_if_needed(transport); - bool dummy = false; - ssize_t n = pn_dispatcher_input(transport, bytes, available, false, &dummy); + bool dummy = false; + ssize_t n = pn_dispatcher_input(transport, bytes, available, false, &dummy); - if (n!=0 || !pni_sasl_is_final_input_state(transport->sasl)) { - return n; - } + if (n!=0 || !pni_sasl_is_final_input_state(transport->sasl)) { + return n; + } - transport->sasl->input_bypass = true; - if (transport->sasl->output_bypass) - transport->io_layers[layer] = &pni_passthru_layer; + if (pni_sasl_impl_can_encrypt(transport)) { + transport->io_layers[layer] = &sasl_encrypt_layer; + return transport->io_layers[layer]->process_input(transport, layer, bytes, available); + } else if (transport->sasl->client) { + transport->io_layers[layer] = &pni_passthru_layer; } return pni_passthru_layer.process_input(transport, layer, bytes, available ); } +static ssize_t pn_input_read_sasl_encrypt(pn_transport_t* transport, unsigned int layer, const char* bytes, size_t available) +{ + pn_buffer_t *in = transport->sasl->decoded_buffer; + pni_sasl_impl_decode(transport, pn_bytes(available, bytes), in); + pn_bytes_t decoded = pn_buffer_bytes(in); + ssize_t size = pni_passthru_layer.process_input(transport, layer, decoded.start, decoded.size ); + pn_buffer_trim(in, size, 0); + return size; +} + static ssize_t pn_output_write_sasl_header(pn_transport_t *transport, unsigned int layer, char *bytes, size_t size) { if (transport->trace & PN_TRACE_FRM) @@ -295,30 +316,43 @@ static ssize_t pn_output_write_sasl_header(pn_transport_t *transport, unsigned i static ssize_t pn_output_write_sasl(pn_transport_t* transport, unsigned int layer, char* bytes, size_t available) { - if (!transport->sasl->output_bypass) { - // this accounts for when pn_do_error is invoked, e.g. by idle timeout - if (!transport->close_sent) { - pni_sasl_start_server_if_needed(transport); + // this accounts for when pn_do_error is invoked, e.g. by idle timeout + if (!transport->close_sent) { + pni_sasl_start_server_if_needed(transport); - pni_post_sasl_frame(transport); + pni_post_sasl_frame(transport); - pni_sasl_t *sasl = transport->sasl; - if (transport->available != 0 || !pni_sasl_is_final_output_state(sasl)) { - return pn_dispatcher_output(transport, bytes, available); - } else { - if (sasl->outcome != PN_SASL_OK && pni_sasl_is_final_input_state(sasl)) { - pn_transport_close_tail(transport); - } + pni_sasl_t *sasl = transport->sasl; + if (transport->available != 0 || !pni_sasl_is_final_output_state(sasl)) { + return pn_dispatcher_output(transport, bytes, available); + } else { + if (sasl->outcome != PN_SASL_OK && pni_sasl_is_final_input_state(sasl)) { + pn_transport_close_tail(transport); } } + } - transport->sasl->output_bypass = true; - if (transport->sasl->input_bypass) - transport->io_layers[layer] = &pni_passthru_layer; + if (pni_sasl_impl_can_encrypt(transport)) { + transport->io_layers[layer] = &sasl_encrypt_layer; + return transport->io_layers[layer]->process_output(transport, layer, bytes, available); + } else if (!transport->sasl->client) { + transport->io_layers[layer] = &pni_passthru_layer; } return pni_passthru_layer.process_output(transport, layer, bytes, available ); } +static ssize_t pn_output_write_sasl_encrypt(pn_transport_t* transport, unsigned int layer, char* bytes, size_t available) +{ + ssize_t size = pni_passthru_layer.process_output(transport, layer, bytes, available ); + if (size<=0) return size; + + pn_buffer_t *out = transport->sasl->encoded_buffer; + pni_sasl_impl_encode(transport, pn_bytes(size, bytes), out); + size = pn_buffer_get(out, 0, available, bytes); + pn_buffer_trim(out, size, 0); + return size; +} + // Look for symbol in the mech include list - not particlarly efficient, // but probably not used enough to matter. // @@ -394,12 +428,12 @@ pn_sasl_t *pn_sasl(pn_transport_t *transport) sasl->external_ssf = 0; sasl->outcome = PN_SASL_NONE; sasl->impl_context = NULL; + sasl->decoded_buffer = pn_buffer(0); + sasl->encoded_buffer = pn_buffer(0); sasl->bytes_out.size = 0; sasl->bytes_out.start = NULL; sasl->desired_state = SASL_NONE; sasl->last_state = SASL_NONE; - sasl->input_bypass = false; - sasl->output_bypass = false; transport->sasl = sasl; } @@ -424,7 +458,8 @@ void pn_sasl_free(pn_transport_t *transport) if (sasl->impl_context) { pni_sasl_impl_free(transport); } - + pn_buffer_free(sasl->decoded_buffer); + pn_buffer_free(sasl->encoded_buffer); free(sasl); } } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org