You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2015/07/10 00:11:52 UTC

[12/50] qpid-proton git commit: PROTON-911: Implemented encryption/decryption functionality for Cyrus SASL

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 <as...@apache.org>
Authored: Tue Jun 30 13:09:51 2015 -0400
Committer: Andrew Stitcher <as...@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-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org