[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [SAMBA4][PATCH] Fix up AES sign/seal on DCE/RPC



On Sat, 2005-09-10 at 14:29 +1000, Andrew Bartlett wrote:
> On Sat, 2005-09-10 at 10:57 +1000, Andrew Bartlett wrote:
> > This patch, inspired by the lukeh's heimdal-mechglue branch appears to
> > fix up gesnec_gssapi for sign/seal, samba->samba when using AES.  It
> > also works Samba->Windows and Windows->Samba.
> > 
> > However, I'm not sure if I've broken the original intent of this
> > function, and it might make more sense to have a direct
> > gss_sig_length(conext, data_len, &length) function.  I'm going to have a
> > look at that approach now.
> 
> This patch adds a new function:
> OM_uint32
> gss_wrap_size (
>             OM_uint32 * /*minor_status*/,
>             const gss_ctx_id_t /*context_handle*/,
>             int /*conf_req_flag*/,
>             gss_qop_t /*qop_req*/,
>             OM_uint32 /*req_input_size*/,
>             OM_uint32 * /*output_size*/
>         );
> 
> This tells the caller what the wrapped size would be, given an input
> size.  From there, I can tell what the 'signature' portion would be.
> 
> My testing so far has been on AES and ARCFOUR, where this seems to match
> up with the results of the actual sealing.  I'm looking for comments on
> this patch. (as well as any hints towards any testing setup that may
> already exist for the size_limit function).

And this patch should compile (missed a couple of callers to the
sig_size code).

Andrew Bartlett

-- 
Andrew Bartlett                                http://samba.org/~abartlet/
Samba Developer, SuSE Labs, Novell Inc.        http://suse.de
Authentication Developer, Samba Team           http://samba.org
Student Network Administrator, Hawker College  http://hawkerc.net
Index: auth/gensec/gensec.c
===================================================================
--- auth/gensec/gensec.c	(revision 10115)
+++ auth/gensec/gensec.c	(working copy)
@@ -559,7 +559,7 @@
 	return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
 }
 
-size_t gensec_sig_size(struct gensec_security *gensec_security) 
+size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size) 
 {
 	if (!gensec_security->ops->sig_size) {
 		return 0;
@@ -568,7 +568,7 @@
 		return 0;
 	}
 	
-	return gensec_security->ops->sig_size(gensec_security);
+	return gensec_security->ops->sig_size(gensec_security, data_size);
 }
 
 NTSTATUS gensec_wrap(struct gensec_security *gensec_security, 
Index: auth/gensec/gensec.h
===================================================================
--- auth/gensec/gensec.h	(revision 10115)
+++ auth/gensec/gensec.h	(working copy)
@@ -73,7 +73,7 @@
 				const uint8_t *data, size_t length, 
 				const uint8_t *whole_pdu, size_t pdu_length, 
 				DATA_BLOB *sig);
-	size_t   (*sig_size)(struct gensec_security *gensec_security);
+	size_t   (*sig_size)(struct gensec_security *gensec_security, size_t data_size);
 	NTSTATUS (*check_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx, 
 				 const uint8_t *data, size_t length, 
 				 const uint8_t *whole_pdu, size_t pdu_length, 
Index: auth/gensec/gensec_gssapi.c
===================================================================
--- auth/gensec/gensec_gssapi.c	(revision 10115)
+++ auth/gensec/gensec_gssapi.c	(working copy)
@@ -480,10 +480,31 @@
 	return NT_STATUS_OK;
 }
 
-static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security) 
+static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size) 
 {
-	/* not const but work for DCERPC packets and arcfour */
-	return 45;
+	struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
+	OM_uint32 maj_stat, min_stat;
+	OM_uint32 output_size;
+	maj_stat = gss_wrap_size(&min_stat, 
+				 gensec_gssapi_state->gssapi_context,
+				 gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
+				 GSS_C_QOP_DEFAULT,
+				 data_size, 
+				 &output_size);
+	if (GSS_ERROR(maj_stat)) {
+		TALLOC_CTX *mem_ctx = talloc_new(NULL); 
+		DEBUG(1, ("gensec_gssapi_seal_packet: determinaing signature size with gss_wrap_size_limit failed: %s\n", 
+			  gssapi_error_string(mem_ctx, maj_stat, min_stat)));
+		talloc_free(mem_ctx);
+		return 0;
+	}
+
+	if (output_size < data_size) {
+		return 0;
+	}
+
+	/* The difference between the max output and the max input must be the signature */
+	return output_size - data_size;
 }
 
 static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security, 
@@ -496,7 +517,7 @@
 	OM_uint32 maj_stat, min_stat;
 	gss_buffer_desc input_token, output_token;
 	int conf_state;
-	ssize_t sig_length = 0;
+	ssize_t sig_length;
 
 	input_token.length = length;
 	input_token.value = data;
@@ -514,12 +535,15 @@
 		return NT_STATUS_ACCESS_DENIED;
 	}
 
-	if (output_token.length < length) {
+	sig_length = gensec_gssapi_sig_size(gensec_security, length);
+
+	/* Caller must pad to right boundary */
+	if (output_token.length != (length + sig_length)) {
+		DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%d] does not match caller length [%d] plus sig size [%d] = [%d]\n", 
+			  output_token.length, length, sig_length, length + sig_length));
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
-	sig_length = 45;
-
 	memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
 	*sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
 
@@ -618,7 +642,7 @@
 		return NT_STATUS_INTERNAL_ERROR;
 	}
 
-	sig_length = 45;
+	sig_length = gensec_gssapi_sig_size(gensec_security, length);
 
 	/*memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);*/
 	*sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
Index: auth/gensec/schannel.c
===================================================================
--- auth/gensec/schannel.c	(revision 10115)
+++ auth/gensec/schannel.c	(working copy)
@@ -26,7 +26,7 @@
 #include "auth/auth.h"
 #include "auth/gensec/schannel.h"
 
-static size_t schannel_sig_size(struct gensec_security *gensec_security)
+static size_t schannel_sig_size(struct gensec_security *gensec_security, size_t data_size)
 {
 	return 32;
 }
Index: auth/gensec/spnego.c
===================================================================
--- auth/gensec/spnego.c	(revision 10115)
+++ auth/gensec/spnego.c	(working copy)
@@ -198,7 +198,7 @@
 			     mem_ctx, in, out);
 }
 
-static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security) 
+static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security, size_t data_size) 
 {
 	struct spnego_state *spnego_state = gensec_security->private_data;
 
@@ -207,7 +207,7 @@
 		return 0;
 	}
 	
-	return gensec_sig_size(spnego_state->sub_sec_security);
+	return gensec_sig_size(spnego_state->sub_sec_security, data_size);
 }
 
 static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security, 
Index: heimdal/lib/gssapi/wrap.c
===================================================================
--- heimdal/lib/gssapi/wrap.c	(revision 10115)
+++ heimdal/lib/gssapi/wrap.c	(working copy)
@@ -120,7 +120,7 @@
 }
 
 static OM_uint32
-sub_wrap_size (
+sub_wrap_size_limit (
             OM_uint32 req_output_size,
             OM_uint32 * max_input_size,
 	    int blocksize,
@@ -156,6 +156,8 @@
   krb5_keyblock *key;
   OM_uint32 ret;
   krb5_keytype keytype;
+  OM_uint32 output_size;
+  OM_uint32 blocksize;
 
   ret = gss_krb5_get_subkey(context_handle, &key);
   if (ret) {
@@ -167,17 +169,102 @@
 
   switch (keytype) {
   case KEYTYPE_DES :
+      ret = sub_wrap_size_limit(req_output_size, max_input_size, 8, 22);
+      break;
+  case KEYTYPE_DES3 :
+      ret = sub_wrap_size_limit(req_output_size, max_input_size, 8, 34);
+      break;
   case KEYTYPE_ARCFOUR:
   case KEYTYPE_ARCFOUR_56:
-      ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
+      ret = _gssapi_wrap_size_arcfour(minor_status, context_handle, 
+				      conf_req_flag, qop_req, 
+				      req_output_size, &output_size, 
+				      &blocksize, key);
+      
+      if (output_size > req_output_size) {
+	      *max_input_size = req_output_size - (output_size - req_output_size);
+	      (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
+      } else {
+	      *max_input_size = 0;
+      }
       break;
+  default :
+      ret = _gssapi_wrap_size_cfx(minor_status, context_handle, 
+				  conf_req_flag, qop_req, 
+				  req_output_size, &output_size, 
+				  &blocksize, key);
+      if (output_size > req_output_size) {
+	      *max_input_size = req_output_size - (output_size - req_output_size);
+	      (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
+      } else {
+	      *max_input_size = 0;
+      }
+      break;
+  }
+  krb5_free_keyblock (gssapi_krb5_context, key);
+  *minor_status = 0;
+  return ret;
+}
+
+static OM_uint32
+sub_wrap_size (
+            OM_uint32 req_input_size,
+            OM_uint32 * output_size,
+	    int blocksize,
+	    int extrasize
+           )
+{
+    size_t len, total_len, padlength, datalen;
+
+    padlength = blocksize - (req_input_size % blocksize);
+    datalen = req_input_size + padlength + 8;
+    len = datalen + extrasize;
+    gssapi_krb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
+    
+    *output_size = total_len;
+
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gss_wrap_size (
+            OM_uint32 * minor_status,
+            const gss_ctx_id_t context_handle,
+            int conf_req_flag,
+            gss_qop_t qop_req,
+            OM_uint32 req_input_size,
+            OM_uint32 * output_size
+           )
+{
+  krb5_keyblock *key;
+  OM_uint32 ret, padlen;
+  krb5_keytype keytype;
+
+  ret = gss_krb5_get_subkey(context_handle, &key);
+  if (ret) {
+      gssapi_krb5_set_error_string ();
+      *minor_status = ret;
+      return GSS_S_FAILURE;
+  }
+  krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+
+  switch (keytype) {
+  case KEYTYPE_DES :
+      ret = sub_wrap_size(req_input_size, output_size, 8, 22);
+      break;
   case KEYTYPE_DES3 :
-      ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
+      ret = sub_wrap_size(req_input_size, output_size, 8, 34);
       break;
+  case KEYTYPE_ARCFOUR:
+  case KEYTYPE_ARCFOUR_56:
+      ret = _gssapi_wrap_size_arcfour(minor_status, context_handle, 
+				      conf_req_flag, qop_req, 
+				      req_input_size, output_size, &padlen, key);
+      break;
   default :
       ret = _gssapi_wrap_size_cfx(minor_status, context_handle, 
 				  conf_req_flag, qop_req, 
-				  req_output_size, max_input_size, key);
+				  req_input_size, output_size, &padlen, key);
       break;
   }
   krb5_free_keyblock (gssapi_krb5_context, key);
Index: heimdal/lib/gssapi/cfx.c
===================================================================
--- heimdal/lib/gssapi/cfx.c	(revision 10115)
+++ heimdal/lib/gssapi/cfx.c	(working copy)
@@ -48,7 +48,8 @@
 		size_t input_length,
 		size_t *output_length,
 		size_t *cksumsize,
-		u_int16_t *padlength)
+		u_int16_t *padlength, 
+	        size_t *padsize)
 {
     krb5_error_code ret;
     krb5_cksumtype type;
@@ -68,18 +69,17 @@
     }
 
     if (conf_req_flag) {
-	size_t padsize;
 
 	/* Header is concatenated with data before encryption */
 	input_length += sizeof(gss_cfx_wrap_token_desc);
 
-	ret = krb5_crypto_getpadsize(gssapi_krb5_context, crypto, &padsize);
+	ret = krb5_crypto_getpadsize(gssapi_krb5_context, crypto, padsize);
 	if (ret) {
 	    return ret;
 	}
 	if (padsize > 1) {
 	    /* XXX check this */
-	    *padlength = padsize - (input_length % padsize);
+	    *padlength = *padsize - (input_length % *padsize);
 	}
 
 	/* We add the pad ourselves (noted here for completeness only) */
@@ -90,6 +90,7 @@
     } else {
 	/* Checksum is concatenated with data */
 	*output_length += input_length + *cksumsize;
+	*padsize = 0;
     }
 
     assert(*output_length > input_length);
@@ -101,13 +102,15 @@
 				const gss_ctx_id_t context_handle,
 				int conf_req_flag,
 				gss_qop_t qop_req,
-				OM_uint32 req_output_size,
-				OM_uint32 *max_input_size,
+				OM_uint32 req_input_size,
+				OM_uint32 *output_len,
+				OM_uint32 *padsize,
 				krb5_keyblock *key)
 {
     krb5_error_code ret;
     krb5_crypto crypto;
-    u_int16_t padlength;
+    u_int16_t pad_length;
+    size_t pad_size;
     size_t output_length, cksumsize;
 
     ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
@@ -118,8 +121,8 @@
     }
 
     ret = wrap_length_cfx(crypto, conf_req_flag, 
-			  req_output_size,
-			  &output_length, &cksumsize, &padlength);
+			  req_input_size,
+			  &output_length, &cksumsize, &pad_length, &pad_size);
     if (ret != 0) {
 	gssapi_krb5_set_error_string();
 	*minor_status = ret;
@@ -127,13 +130,8 @@
 	return GSS_S_FAILURE;
     }
 
-    if (output_length < req_output_size) {
-	*max_input_size = (req_output_size - output_length);
-	*max_input_size -= padlength;
-    } else {
-	/* Should this return an error? */
-	*max_input_size = 0;
-    }
+    *output_len = output_length;
+    *padsize = pad_size;
 
     krb5_crypto_destroy(gssapi_krb5_context, crypto);
 
@@ -201,7 +199,7 @@
     krb5_data cipher;
     size_t wrapped_len, cksumsize;
     u_int16_t padlength, rrc = 0;
-    OM_uint32 seq_number;
+    OM_uint32 seq_number, padsize;
     u_char *p;
 
     ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
@@ -213,7 +211,7 @@
 
     ret = wrap_length_cfx(crypto, conf_req_flag, 
 			  input_message_buffer->length,
-			  &wrapped_len, &cksumsize, &padlength);
+			  &wrapped_len, &cksumsize, &padlength, &padsize);
     if (ret != 0) {
 	gssapi_krb5_set_error_string();
 	*minor_status = ret;
Index: heimdal/lib/gssapi/cfx.h
===================================================================
--- heimdal/lib/gssapi/cfx.h	(revision 10115)
+++ heimdal/lib/gssapi/cfx.h	(working copy)
@@ -66,8 +66,9 @@
 				const gss_ctx_id_t context_handle,
 				int conf_req_flag,
 				gss_qop_t qop_req,
-				OM_uint32 req_output_size,
-				OM_uint32 *max_input_size,
+				OM_uint32 req_input_size,
+				OM_uint32 *output_len,
+				OM_uint32 *padlen,
 				krb5_keyblock *key);
 
 OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
Index: heimdal/lib/gssapi/gssapi.h
===================================================================
--- heimdal/lib/gssapi/gssapi.h	(revision 10115)
+++ heimdal/lib/gssapi/gssapi.h	(working copy)
@@ -628,6 +628,16 @@
             int * /*open_context*/
            );
 
+OM_uint32
+gss_wrap_size (
+            OM_uint32 * /*minor_status*/,
+            const gss_ctx_id_t /*context_handle*/,
+            int /*conf_req_flag*/,
+            gss_qop_t /*qop_req*/,
+            OM_uint32 /*req_input_size*/,
+            OM_uint32 * /*output_size*/
+	);
+
 OM_uint32 gss_wrap_size_limit (
             OM_uint32 * /*minor_status*/,
             const gss_ctx_id_t /*context_handle*/,
Index: heimdal/lib/gssapi/arcfour.c
===================================================================
--- heimdal/lib/gssapi/arcfour.c	(revision 10115)
+++ heimdal/lib/gssapi/arcfour.c	(working copy)
@@ -326,6 +326,37 @@
 }
 
 OM_uint32
+_gssapi_wrap_size_arcfour(OM_uint32 * minor_status,
+			  const gss_ctx_id_t context_handle,
+			  int conf_req_flag,
+			  gss_qop_t qop_req,
+			  OM_uint32 req_input_size,
+			  OM_uint32 * output_size,
+			  OM_uint32 * padlen,
+			  krb5_keyblock *key)
+{
+    size_t len, total_len, datalen;
+    *padlen = 0;
+    datalen = req_input_size;
+    len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+    /* if GSS_C_DCE_STYLE is in use:
+     *  - we only need to encapsulate the WRAP token
+     *  - we should not add padding
+     */
+    if (!(context_handle->flags & GSS_C_DCE_STYLE)) {
+    	datalen += 1 /* padding */;
+    	len += datalen;
+    }
+    _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
+    if (context_handle->flags & GSS_C_DCE_STYLE) {
+    	total_len += datalen;
+    }
+
+    *output_size = total_len;
+    return GSS_S_COMPLETE;
+}
+	
+OM_uint32
 _gssapi_wrap_arcfour(OM_uint32 * minor_status,
 		     const gss_ctx_id_t context_handle,
 		     int conf_req_flag,
Index: heimdal/lib/gssapi/arcfour.h
===================================================================
--- heimdal/lib/gssapi/arcfour.h	(revision 10115)
+++ heimdal/lib/gssapi/arcfour.h	(working copy)
@@ -70,5 +70,14 @@
 				     gss_qop_t *qop_state,
 				     krb5_keyblock *key,
 				     char *type);
+OM_uint32
+_gssapi_wrap_size_arcfour(OM_uint32 * minor_status,
+			  const gss_ctx_id_t context_handle,
+			  int conf_req_flag,
+			  gss_qop_t qop_req,
+			  OM_uint32 req_input_size,
+			  OM_uint32 * output_size,
+			  OM_uint32 * padlen,
+			  krb5_keyblock *key);
 
 #endif /* GSSAPI_ARCFOUR_H_ */

This is a digitally signed message part