PROTON-911: Implemented encryption/decryption functionality for Cyrus SASL
Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/395b23f5 Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/395b23f5 Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/395b23f5 Branch: refs/heads/cjansen-cpp-client Commit: 395b23f5fee57d55ed7395723f560eefe3747c07 Parents: c78392f Author: Andrew Stitcher <astitc...@apache.org> Authored: Tue Jun 30 13:09:51 2015 -0400 Committer: Andrew Stitcher <astitc...@apache.org> Committed: Wed Jul 1 14:29:46 2015 -0400 ---------------------------------------------------------------------- proton-c/src/config.h | 8 ++- proton-c/src/sasl/cyrus_sasl.c | 91 +++++++++++++++++++++++++++------ proton-c/src/sasl/none_sasl.c | 11 ++-- proton-c/src/sasl/sasl-internal.h | 6 ++- proton-c/src/sasl/sasl.c | 57 +++++++++++++++++---- proton-c/src/transport/transport.c | 2 +- 6 files changed, 141 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/395b23f5/proton-c/src/config.h ---------------------------------------------------------------------- diff --git a/proton-c/src/config.h b/proton-c/src/config.h index 9bc5b27..5a2e7bc 100644 --- a/proton-c/src/config.h +++ b/proton-c/src/config.h @@ -21,6 +21,12 @@ #ifndef _PROTON_SRC_CONFIG_H #define _PROTON_SRC_CONFIG_H -#define TRANSPORT_INITIAL_FRAME_SIZE (512) /* bytes */ +#ifndef PN_TRANSPORT_INITIAL_FRAME_SIZE +# define PN_TRANSPORT_INITIAL_FRAME_SIZE (512) /* bytes */ +#endif + +#ifndef PN_SASL_MAX_BUFFSIZE +# define PN_SASL_MAX_BUFFSIZE (32768) /* bytes */ +#endif #endif /* _PROTON_SRC_CONFIG_H */ http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/395b23f5/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 cdcd0bf..b71a435 100644 --- a/proton-c/src/sasl/cyrus_sasl.c +++ b/proton-c/src/sasl/cyrus_sasl.c @@ -19,6 +19,7 @@ * */ +#include "config.h" #include "sasl-internal.h" #include "engine/engine-internal.h" @@ -125,7 +126,10 @@ bool pni_init_client(pn_transport_t* transport) { sasl_security_properties_t secprops = {0}; secprops.security_flags = SASL_SEC_NOPLAINTEXT | - ( transport->auth_required ? SASL_SEC_NOANONYMOUS : 0 ) ; + ( transport->auth_required ? SASL_SEC_NOANONYMOUS : 0 ) ; + secprops.min_ssf = 0; + secprops.max_ssf = 2048; + secprops.maxbufsize = PN_SASL_MAX_BUFFSIZE; result = sasl_setprop(cyrus_conn, SASL_SEC_PROPS, &secprops); if (result!=SASL_OK) break; @@ -256,6 +260,9 @@ bool pni_init_server(pn_transport_t* transport) secprops.security_flags = SASL_SEC_NOPLAINTEXT | ( transport->auth_required ? SASL_SEC_NOANONYMOUS : 0 ) ; + secprops.min_ssf = 0; + secprops.max_ssf = 2048; + secprops.maxbufsize = PN_SASL_MAX_BUFFSIZE; result = sasl_setprop(cyrus_conn, SASL_SEC_PROPS, &secprops); if (result!=SASL_OK) break; @@ -369,31 +376,83 @@ void pni_process_response(pn_transport_t *transport, const pn_bytes_t *recv) pni_process_server_result(transport, result); } -void pni_sasl_impl_free(pn_transport_t *transport) +bool pni_sasl_impl_can_encrypt(pn_transport_t *transport) { - sasl_conn_t *cyrus_conn = (sasl_conn_t*)transport->sasl->impl_context; - sasl_dispose(&cyrus_conn); - transport->sasl->impl_context = cyrus_conn; - if (transport->sasl->client) { - sasl_client_done(); - } else { - sasl_server_done(); - } + if (!transport->sasl->impl_context) return false; + + sasl_conn_t *cyrus_conn = (sasl_conn_t*)transport->sasl->impl_context; + // Get SSF to find out if we need to encrypt or not + const void* value; + int r = sasl_getprop(cyrus_conn, SASL_SSF, &value); + if (r != SASL_OK) { + // TODO: Should log an error here too, maybe assert here + return false; + } + int ssf = *(int *) value; + if (ssf > 0) { + pn_transport_logf(transport, "SASL Encryption enabled: ssf=%d", ssf); + return true; + } + return false; } -bool pni_sasl_impl_can_encrypt(pn_transport_t *transport) +ssize_t pni_sasl_impl_max_encrypt_size(pn_transport_t *transport) { - return false; + if (!transport->sasl->impl_context) return PN_ERR; + + sasl_conn_t *cyrus_conn = (sasl_conn_t*)transport->sasl->impl_context; + const void* value; + int r = sasl_getprop(cyrus_conn, SASL_MAXOUTBUF, &value); + if (r != SASL_OK) { + // TODO: Should log an error here too, maybe assert here + return PN_ERR; + } + int outbuf_size = *(int *) value; + return outbuf_size; +} + +ssize_t pni_sasl_impl_encode(pn_transport_t *transport, pn_bytes_t in, pn_bytes_t *out) +{ + if ( in.size==0 ) return 0; + sasl_conn_t *cyrus_conn = (sasl_conn_t*)transport->sasl->impl_context; + const char *output; + unsigned int outlen; + int r = sasl_encode(cyrus_conn, in.start, in.size, &output, &outlen); + if (outlen==0) return 0; + if ( r==SASL_OK ) { + *out = pn_bytes(outlen, output); + return outlen; + } + pn_transport_logf(transport, "SASL encode error: %s", sasl_errdetail(cyrus_conn)); + return PN_ERR; } -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_bytes_t *out) { - return 0; + if ( in.size==0 ) return 0; + sasl_conn_t *cyrus_conn = (sasl_conn_t*)transport->sasl->impl_context; + const char *output; + unsigned int outlen; + int r = sasl_decode(cyrus_conn, in.start, in.size, &output, &outlen); + if (outlen==0) return 0; + if ( r==SASL_OK ) { + *out = pn_bytes(outlen, output); + return outlen; + } + pn_transport_logf(transport, "SASL decode error: %s", sasl_errdetail(cyrus_conn)); + return PN_ERR; } -ssize_t pni_sasl_impl_decode(pn_transport_t *transport, pn_bytes_t in, pn_buffer_t *out) +void pni_sasl_impl_free(pn_transport_t *transport) { - return 0; + sasl_conn_t *cyrus_conn = (sasl_conn_t*)transport->sasl->impl_context; + sasl_dispose(&cyrus_conn); + transport->sasl->impl_context = cyrus_conn; + if (transport->sasl->client) { + sasl_client_done(); + } else { + sasl_server_done(); + } } bool pn_sasl_extended(void) http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/395b23f5/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 ccb4818..7cbf8d4 100644 --- a/proton-c/src/sasl/none_sasl.c +++ b/proton-c/src/sasl/none_sasl.c @@ -174,15 +174,20 @@ 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; + return false; +} + +ssize_t pni_sasl_impl_max_encrypt_size(pn_transport_t *transport) +{ + return 0; } -ssize_t pni_sasl_impl_encode(pn_transport_t *transport, pn_bytes_t in, pn_buffer_t *out) +ssize_t pni_sasl_impl_encode(pn_transport_t *transport, pn_bytes_t in, pn_bytes_t *out) { return 0; } -ssize_t pni_sasl_impl_decode(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_bytes_t *out) { return 0; } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/395b23f5/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 fb40b9c..b81cf03 100644 --- a/proton-c/src/sasl/sasl-internal.h +++ b/proton-c/src/sasl/sasl-internal.h @@ -47,8 +47,9 @@ 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); +ssize_t pni_sasl_impl_max_encrypt_size(pn_transport_t *transport); +ssize_t pni_sasl_impl_encode(pn_transport_t *transport, pn_bytes_t in, pn_bytes_t *out); +ssize_t pni_sasl_impl_decode(pn_transport_t *transport, pn_bytes_t in, pn_bytes_t *out); // Shared SASL API used by the actual SASL authenticators @@ -74,6 +75,7 @@ struct pni_sasl_t { const char *remote_fqdn; char *external_auth; int external_ssf; + size_t max_encrypt_size; pn_sasl_outcome_t outcome; pn_buffer_t* decoded_buffer; pn_buffer_t* encoded_buffer; http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/395b23f5/proton-c/src/sasl/sasl.c ---------------------------------------------------------------------- diff --git a/proton-c/src/sasl/sasl.c b/proton-c/src/sasl/sasl.c index ac177c7..a7e02e8 100644 --- a/proton-c/src/sasl/sasl.c +++ b/proton-c/src/sasl/sasl.c @@ -281,10 +281,13 @@ static ssize_t pn_input_read_sasl(pn_transport_t* transport, unsigned int layer, return n; } + pni_sasl_t *sasl = transport->sasl; if (pni_sasl_impl_can_encrypt(transport)) { transport->io_layers[layer] = &sasl_encrypt_layer; + sasl->max_encrypt_size = pni_sasl_impl_max_encrypt_size(transport); + pn_transport_logf(transport, "SASL max buffer: %d", sasl->max_encrypt_size); return transport->io_layers[layer]->process_input(transport, layer, bytes, available); - } else if (transport->sasl->client) { + } else if (sasl->client) { transport->io_layers[layer] = &pni_passthru_layer; } return pni_passthru_layer.process_input(transport, layer, bytes, available ); @@ -293,11 +296,28 @@ static ssize_t pn_input_read_sasl(pn_transport_t* transport, unsigned int layer, 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); + const size_t max_buffer = transport->sasl->max_encrypt_size; + for (size_t processed = 0; processed<available;) { + pn_bytes_t decoded = pn_bytes(0, NULL); + size_t decode_size = (available-processed)<=max_buffer?(available-processed):max_buffer; + ssize_t size = pni_sasl_impl_decode(transport, pn_bytes(decode_size, bytes+processed), &decoded); + if (size<0) return size; + if (size>0) { + size = pn_buffer_append(in, decoded.start, decoded.size); + if (size) return size; + } + processed += decode_size; + } 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; + size_t processed_size = 0; + while (processed_size < decoded.size) { + ssize_t size = pni_passthru_layer.process_input(transport, layer, decoded.start+processed_size, decoded.size-processed_size); + if (size==0) break; + if (size<0) return size; + pn_buffer_trim(in, size, 0); + processed_size += size; + } + return available; } static ssize_t pn_output_write_sasl_header(pn_transport_t *transport, unsigned int layer, char *bytes, size_t size) @@ -316,26 +336,30 @@ 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) { + pni_sasl_t *sasl = transport->sasl; + // 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_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); + return PN_EOS; } } } if (pni_sasl_impl_can_encrypt(transport)) { transport->io_layers[layer] = &sasl_encrypt_layer; + sasl->max_encrypt_size = pni_sasl_impl_max_encrypt_size(transport); + pn_transport_logf(transport, "SASL max buffer: %d", sasl->max_encrypt_size); return transport->io_layers[layer]->process_output(transport, layer, bytes, available); - } else if (!transport->sasl->client) { + } else if (!sasl->client) { transport->io_layers[layer] = &pni_passthru_layer; } return pni_passthru_layer.process_output(transport, layer, bytes, available ); @@ -343,12 +367,23 @@ static ssize_t pn_output_write_sasl(pn_transport_t* transport, unsigned int laye 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; + ssize_t clear_size = pni_passthru_layer.process_output(transport, layer, bytes, available ); + if (clear_size<0) return clear_size; + const ssize_t max_buffer = transport->sasl->max_encrypt_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); + for (ssize_t processed = 0; processed<clear_size;) { + pn_bytes_t encoded = pn_bytes(0, NULL); + ssize_t encode_size = (clear_size-processed)<=max_buffer?(clear_size-processed):max_buffer; + size_t size = pni_sasl_impl_encode(transport, pn_bytes(encode_size, bytes+processed), &encoded); + if (size<0) return size; + if (size>0) { + size = pn_buffer_append(out, encoded.start, encoded.size); + if (size) return size; + } + processed += encode_size; + } + ssize_t size = pn_buffer_get(out, 0, available, bytes); pn_buffer_trim(out, size, 0); return size; } http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/395b23f5/proton-c/src/transport/transport.c ---------------------------------------------------------------------- diff --git a/proton-c/src/transport/transport.c b/proton-c/src/transport/transport.c index 2271f27..a4b07c3 100644 --- a/proton-c/src/transport/transport.c +++ b/proton-c/src/transport/transport.c @@ -373,7 +373,7 @@ static void pn_transport_initialize(void *object) transport->scratch = pn_string(NULL); transport->args = pn_data(16); transport->output_args = pn_data(16); - transport->frame = pn_buffer(TRANSPORT_INITIAL_FRAME_SIZE); + transport->frame = pn_buffer(PN_TRANSPORT_INITIAL_FRAME_SIZE); transport->input_frames_ct = 0; transport->output_frames_ct = 0; --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@qpid.apache.org For additional commands, e-mail: commits-h...@qpid.apache.org