Support DCERPC with krb5 and header signing

Stefan (metze) Metzmacher metze at samba.org
Tue Jun 23 10:34:15 MDT 2015


Hi,

here're patches to finally use gss_[un]wrap_iov[_length]()
and support DCERPC header signing in both gssapi/krb5 gensec backends we
have.

The heimdal related patches are also proposed upstream, see
https://git.samba.org/?p=metze/heimdal/wip.git;a=shortlog;h=refs/heads/heimdal-for-upstream

Please review and push.

Thanks!
metze
-------------- next part --------------
From f21c9abfe528c71c990d88db6fe74607e9995208 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 Jun 2015 15:43:32 +0200
Subject: [PATCH 1/9] heimdal:lib/gssapi/krb5: make _gssapi_verify_pad() more
 robust

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/heimdal/lib/gssapi/krb5/decapsulate.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/source4/heimdal/lib/gssapi/krb5/decapsulate.c b/source4/heimdal/lib/gssapi/krb5/decapsulate.c
index 640c064..86085f5 100644
--- a/source4/heimdal/lib/gssapi/krb5/decapsulate.c
+++ b/source4/heimdal/lib/gssapi/krb5/decapsulate.c
@@ -190,6 +190,9 @@ _gssapi_verify_pad(gss_buffer_t wrapped_token,
     size_t padlength;
     int i;
 
+    if (wrapped_token->length < 1)
+	return GSS_S_BAD_MECH;
+
     pad = (u_char *)wrapped_token->value + wrapped_token->length - 1;
     padlength = *pad;
 
-- 
1.9.1


From 9d58cfbd31866b6c7215fe8980a7dfc1d340bf75 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 Jun 2015 12:20:26 +0200
Subject: [PATCH 2/9] heimdal:lib/gssapi/krb5: fix indentation in
 _gk_wrap_iov()

Now it matches _gk_unwrap_iov() and _gk_wrap_iov_length().

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/heimdal/lib/gssapi/krb5/aeap.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/source4/heimdal/lib/gssapi/krb5/aeap.c b/source4/heimdal/lib/gssapi/krb5/aeap.c
index 47913e4..87ca06d 100644
--- a/source4/heimdal/lib/gssapi/krb5/aeap.c
+++ b/source4/heimdal/lib/gssapi/krb5/aeap.c
@@ -44,15 +44,15 @@ _gk_wrap_iov(OM_uint32 * minor_status,
 	     gss_iov_buffer_desc *iov,
 	     int iov_count)
 {
-  const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
-  krb5_context context;
+    const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
+    krb5_context context;
 
-  GSSAPI_KRB5_INIT (&context);
+    GSSAPI_KRB5_INIT (&context);
 
-  if (ctx->more_flags & IS_CFX)
-      return _gssapi_wrap_cfx_iov(minor_status, ctx, context,
-				  conf_req_flag, conf_state,
-				  iov, iov_count);
+    if (ctx->more_flags & IS_CFX)
+        return _gssapi_wrap_cfx_iov(minor_status, ctx, context,
+				    conf_req_flag, conf_state,
+				    iov, iov_count);
 
     return GSS_S_FAILURE;
 }
-- 
1.9.1


From acbd41c12a38c3269d9a808edf69eaa4fbcf8538 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 Jun 2015 14:06:57 +0200
Subject: [PATCH 3/9] heimdal:lib/gssapi/krb5: clear temporary buffer with
 cleartext data.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/heimdal/lib/gssapi/krb5/arcfour.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/source4/heimdal/lib/gssapi/krb5/arcfour.c b/source4/heimdal/lib/gssapi/krb5/arcfour.c
index f5e41e4..5cd1fe3 100644
--- a/source4/heimdal/lib/gssapi/krb5/arcfour.c
+++ b/source4/heimdal/lib/gssapi/krb5/arcfour.c
@@ -149,6 +149,7 @@ arcfour_mic_cksum(krb5_context context,
 			       0,
 			       ptr, len,
 			       &CKSUM);
+    memset(ptr, 0, len);
     free(ptr);
     if (ret == 0) {
 	memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz);
-- 
1.9.1


From cef580da590b7dd810d4a14dff0c273d09762346 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 Jun 2015 15:42:03 +0200
Subject: [PATCH 4/9] heimdal:lib/gssapi/krb5: add const to arcfour_mic_key()

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/heimdal/lib/gssapi/krb5/arcfour.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source4/heimdal/lib/gssapi/krb5/arcfour.c b/source4/heimdal/lib/gssapi/krb5/arcfour.c
index 5cd1fe3..0836cf5 100644
--- a/source4/heimdal/lib/gssapi/krb5/arcfour.c
+++ b/source4/heimdal/lib/gssapi/krb5/arcfour.c
@@ -69,7 +69,7 @@
 
 static krb5_error_code
 arcfour_mic_key(krb5_context context, krb5_keyblock *key,
-		void *cksum_data, size_t cksum_size,
+		const void *cksum_data, size_t cksum_size,
 		void *key6_data, size_t key6_size)
 {
     krb5_error_code ret;
-- 
1.9.1


From e9ed637ff7a6aefbec6faba55565cbe99de4d93b Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 18 Jun 2015 14:07:43 +0200
Subject: [PATCH 5/9] heimdal:lib/gssapi/krb5: split out a
 arcfour_mic_cksum_iov() function

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source4/heimdal/lib/gssapi/krb5/arcfour.c | 83 +++++++++++++++++++++++++++----
 1 file changed, 73 insertions(+), 10 deletions(-)

diff --git a/source4/heimdal/lib/gssapi/krb5/arcfour.c b/source4/heimdal/lib/gssapi/krb5/arcfour.c
index 0836cf5..13bf1d3 100644
--- a/source4/heimdal/lib/gssapi/krb5/arcfour.c
+++ b/source4/heimdal/lib/gssapi/krb5/arcfour.c
@@ -112,30 +112,73 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key,
 
 
 static krb5_error_code
-arcfour_mic_cksum(krb5_context context,
-		  krb5_keyblock *key, unsigned usage,
-		  u_char *sgn_cksum, size_t sgn_cksum_sz,
-		  const u_char *v1, size_t l1,
-		  const void *v2, size_t l2,
-		  const void *v3, size_t l3)
+arcfour_mic_cksum_iov(krb5_context context,
+		      krb5_keyblock *key, unsigned usage,
+		      u_char *sgn_cksum, size_t sgn_cksum_sz,
+		      const u_char *v1, size_t l1,
+		      const void *v2, size_t l2,
+		      const gss_iov_buffer_desc *iov,
+		      int iov_count,
+		      const gss_iov_buffer_desc *padding)
 {
     Checksum CKSUM;
     u_char *ptr;
     size_t len;
+    size_t ofs = 0;
+    int i;
     krb5_crypto crypto;
     krb5_error_code ret;
 
     assert(sgn_cksum_sz == 8);
 
-    len = l1 + l2 + l3;
+    len = l1 + l2;
+
+    for (i=0; i < iov_count; i++) {
+	switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+	case GSS_IOV_BUFFER_TYPE_DATA:
+	case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
+	    break;
+	default:
+	    continue;
+	}
+
+	len += iov[i].buffer.length;
+    }
+
+    if (padding) {
+	len += padding->buffer.length;
+    }
 
     ptr = malloc(len);
     if (ptr == NULL)
 	return ENOMEM;
 
-    memcpy(ptr, v1, l1);
-    memcpy(ptr + l1, v2, l2);
-    memcpy(ptr + l1 + l2, v3, l3);
+    memcpy(ptr + ofs, v1, l1);
+    ofs += l1;
+    memcpy(ptr + ofs, v2, l2);
+    ofs += l2;
+
+    for (i=0; i < iov_count; i++) {
+	switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+	case GSS_IOV_BUFFER_TYPE_DATA:
+	case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
+	    break;
+	default:
+	    continue;
+	}
+
+	memcpy(ptr + ofs,
+	       iov[i].buffer.value,
+	       iov[i].buffer.length);
+	ofs += iov[i].buffer.length;
+    }
+
+    if (padding) {
+	memcpy(ptr + ofs,
+	       padding->buffer.value,
+	       padding->buffer.length);
+	ofs += padding->buffer.length;
+    }
 
     ret = krb5_crypto_init(context, key, 0, &crypto);
     if (ret) {
@@ -160,6 +203,26 @@ arcfour_mic_cksum(krb5_context context,
     return ret;
 }
 
+static krb5_error_code
+arcfour_mic_cksum(krb5_context context,
+		  krb5_keyblock *key, unsigned usage,
+		  u_char *sgn_cksum, size_t sgn_cksum_sz,
+		  const u_char *v1, size_t l1,
+		  const void *v2, size_t l2,
+		  const void *v3, size_t l3)
+{
+    gss_iov_buffer_desc iov;
+
+    iov.type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+    iov.buffer.value = rk_UNCONST(v3);
+    iov.buffer.length = l3;
+
+    return arcfour_mic_cksum_iov(context, key, usage,
+				 sgn_cksum, sgn_cksum_sz,
+				 v1, l1, v2, l2,
+				 &iov, 1, NULL);
+}
+
 
 OM_uint32
 _gssapi_get_mic_arcfour(OM_uint32 * minor_status,
-- 
1.9.1


From f70a25a706150570471f9e8b1894e76734eba4c1 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 11 Aug 2009 19:48:50 +0200
Subject: [PATCH 6/9] heimdal:lib/gssapi/krb5: implement
 gss_[un]wrap_iov[_length] with arcfour-hmac-md5

Pair-Programmed-With: Andreas Schneider <asn at samba.org>

Signed-off-by: Stefan Metzmacher <metze at samba.org>
Signed-off-by: Andreas Schneider <asn at samba.org>
---
 source4/heimdal/lib/gssapi/krb5/aeap.c    |  84 ++++-
 source4/heimdal/lib/gssapi/krb5/arcfour.c | 559 ++++++++++++++++++++++++++++++
 2 files changed, 640 insertions(+), 3 deletions(-)

diff --git a/source4/heimdal/lib/gssapi/krb5/aeap.c b/source4/heimdal/lib/gssapi/krb5/aeap.c
index 87ca06d..fe95ecf 100644
--- a/source4/heimdal/lib/gssapi/krb5/aeap.c
+++ b/source4/heimdal/lib/gssapi/krb5/aeap.c
@@ -46,6 +46,9 @@ _gk_wrap_iov(OM_uint32 * minor_status,
 {
     const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
     krb5_context context;
+    OM_uint32 ret;
+    krb5_keyblock *key;
+    krb5_keytype keytype;
 
     GSSAPI_KRB5_INIT (&context);
 
@@ -54,7 +57,30 @@ _gk_wrap_iov(OM_uint32 * minor_status,
 				    conf_req_flag, conf_state,
 				    iov, iov_count);
 
-    return GSS_S_FAILURE;
+    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+    ret = _gsskrb5i_get_token_key(ctx, context, &key);
+    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+    if (ret) {
+	*minor_status = ret;
+	return GSS_S_FAILURE;
+    }
+    krb5_enctype_to_keytype(context, key->keytype, &keytype);
+
+    switch (keytype) {
+    case KEYTYPE_ARCFOUR:
+    case KEYTYPE_ARCFOUR_56:
+	ret = _gssapi_wrap_iov_arcfour(minor_status, ctx, context,
+				       conf_req_flag, conf_state,
+				       iov, iov_count, key);
+	break;
+
+    default:
+	ret = GSS_S_FAILURE;
+	break;
+    }
+
+    krb5_free_keyblock(context, key);
+    return ret;
 }
 
 OM_uint32 GSSAPI_CALLCONV
@@ -67,6 +93,9 @@ _gk_unwrap_iov(OM_uint32 *minor_status,
 {
     const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
     krb5_context context;
+    OM_uint32 ret;
+    krb5_keytype keytype;
+    krb5_keyblock *key;
 
     GSSAPI_KRB5_INIT (&context);
 
@@ -74,7 +103,30 @@ _gk_unwrap_iov(OM_uint32 *minor_status,
 	return _gssapi_unwrap_cfx_iov(minor_status, ctx, context,
 				      conf_state, qop_state, iov, iov_count);
 
-    return GSS_S_FAILURE;
+    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+    ret = _gsskrb5i_get_token_key(ctx, context, &key);
+    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+    if (ret) {
+	*minor_status = ret;
+	return GSS_S_FAILURE;
+    }
+    krb5_enctype_to_keytype(context, key->keytype, &keytype);
+
+    switch (keytype) {
+    case KEYTYPE_ARCFOUR:
+    case KEYTYPE_ARCFOUR_56:
+	ret = _gssapi_unwrap_iov_arcfour(minor_status, ctx, context,
+					 conf_state, qop_state,
+					 iov, iov_count, key);
+	break;
+
+    default:
+	ret = GSS_S_FAILURE;
+	break;
+    }
+
+    krb5_free_keyblock(context, key);
+    return ret;
 }
 
 OM_uint32 GSSAPI_CALLCONV
@@ -88,6 +140,9 @@ _gk_wrap_iov_length(OM_uint32 * minor_status,
 {
     const gsskrb5_ctx ctx = (const gsskrb5_ctx) context_handle;
     krb5_context context;
+    OM_uint32 ret;
+    krb5_keytype keytype;
+    krb5_keyblock *key;
 
     GSSAPI_KRB5_INIT (&context);
 
@@ -96,5 +151,28 @@ _gk_wrap_iov_length(OM_uint32 * minor_status,
 					   conf_req_flag, qop_req, conf_state,
 					   iov, iov_count);
 
-    return GSS_S_FAILURE;
+    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+    ret = _gsskrb5i_get_token_key(ctx, context, &key);
+    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+    if (ret) {
+	*minor_status = ret;
+	return GSS_S_FAILURE;
+    }
+    krb5_enctype_to_keytype(context, key->keytype, &keytype);
+
+    switch (keytype) {
+    case KEYTYPE_ARCFOUR:
+    case KEYTYPE_ARCFOUR_56:
+	ret = _gssapi_wrap_iov_length_arcfour(minor_status, ctx, context,
+					      conf_req_flag, qop_req, conf_state,
+					      iov, iov_count);
+	break;
+
+    default:
+	ret = GSS_S_FAILURE;
+	break;
+    }
+
+    krb5_free_keyblock(context, key);
+    return ret;
 }
diff --git a/source4/heimdal/lib/gssapi/krb5/arcfour.c b/source4/heimdal/lib/gssapi/krb5/arcfour.c
index 13bf1d3..a61f768 100644
--- a/source4/heimdal/lib/gssapi/krb5/arcfour.c
+++ b/source4/heimdal/lib/gssapi/krb5/arcfour.c
@@ -824,3 +824,562 @@ _gssapi_wrap_size_arcfour(OM_uint32 *minor_status,
 
     return GSS_S_COMPLETE;
 }
+
+OM_uint32
+_gssapi_wrap_iov_length_arcfour(OM_uint32 *minor_status,
+				gsskrb5_ctx ctx,
+				krb5_context context,
+				int conf_req_flag,
+				gss_qop_t qop_req,
+				int *conf_state,
+				gss_iov_buffer_desc *iov,
+				int iov_count)
+{
+    OM_uint32 major_status;
+    size_t data_len = 0;
+    int i;
+    gss_iov_buffer_desc *header = NULL;
+    gss_iov_buffer_desc *padding = NULL;
+    gss_iov_buffer_desc *trailer = NULL;
+
+    *minor_status = 0;
+
+    for (i = 0; i < iov_count; i++) {
+	switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+	case GSS_IOV_BUFFER_TYPE_EMPTY:
+	    break;
+	case GSS_IOV_BUFFER_TYPE_DATA:
+	    data_len += iov[i].buffer.length;
+	    break;
+	case GSS_IOV_BUFFER_TYPE_HEADER:
+	    if (header != NULL) {
+		*minor_status = EINVAL;
+		return GSS_S_FAILURE;
+	    }
+	    header = &iov[i];
+	    break;
+	case GSS_IOV_BUFFER_TYPE_TRAILER:
+	    if (trailer != NULL) {
+		*minor_status = EINVAL;
+		return GSS_S_FAILURE;
+	    }
+	    trailer = &iov[i];
+	    break;
+	case GSS_IOV_BUFFER_TYPE_PADDING:
+	    if (padding != NULL) {
+		*minor_status = EINVAL;
+		return GSS_S_FAILURE;
+	    }
+	    padding = &iov[i];
+	    break;
+	case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
+	    break;
+	default:
+	    *minor_status = EINVAL;
+	    return GSS_S_FAILURE;
+	}
+    }
+
+    major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
+    if (major_status != GSS_S_COMPLETE) {
+	    return major_status;
+    }
+
+    if (IS_DCE_STYLE(ctx)) {
+	size_t len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+	size_t total_len;
+	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
+	header->buffer.length = total_len;
+    } else {
+	size_t len;
+	size_t total_len;
+	if (padding) {
+	    data_len += 1; /* padding */
+	}
+	len = data_len + GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+	_gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
+	header->buffer.length = total_len - data_len;
+    }
+
+    if (trailer) {
+	trailer->buffer.length = 0;
+    }
+
+    if (padding) {
+	padding->buffer.length = 1;
+    }
+
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+_gssapi_wrap_iov_arcfour(OM_uint32 *minor_status,
+			 gsskrb5_ctx ctx,
+			 krb5_context context,
+			 int conf_req_flag,
+			 int *conf_state,
+			 gss_iov_buffer_desc *iov,
+			 int iov_count,
+			 krb5_keyblock *key)
+{
+    OM_uint32 major_status, junk;
+    gss_iov_buffer_desc *header, *padding, *trailer;
+    krb5_error_code kret;
+    int32_t seq_number;
+    u_char Klocaldata[16], k6_data[16], *p, *p0;
+    size_t make_len = 0;
+    size_t header_len = 0;
+    size_t data_len = 0;
+    krb5_keyblock Klocal;
+    int i;
+
+    header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+    trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+    major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
+    if (major_status != GSS_S_COMPLETE) {
+	return major_status;
+    }
+
+    for (i = 0; i < iov_count; i++) {
+	switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+	case GSS_IOV_BUFFER_TYPE_DATA:
+	    break;
+	default:
+	    continue;
+	}
+
+	data_len += iov[i].buffer.length;
+    }
+
+    if (padding) {
+	data_len += 1;
+    }
+
+    if (IS_DCE_STYLE(ctx)) {
+	size_t unwrapped_len;
+	unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+	_gssapi_encap_length(unwrapped_len,
+			     &make_len,
+			     &header_len,
+			     GSS_KRB5_MECHANISM);
+    } else {
+	size_t unwrapped_len;
+	unwrapped_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + data_len;
+	_gssapi_encap_length(unwrapped_len,
+			     &make_len,
+			     &header_len,
+			     GSS_KRB5_MECHANISM);
+	header_len -= data_len;
+    }
+
+    if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) {
+	major_status = _gk_allocate_buffer(minor_status, header,
+					   header_len);
+	if (major_status != GSS_S_COMPLETE)
+	    goto failure;
+    } else if (header->buffer.length < header_len) {
+	*minor_status = KRB5_BAD_MSIZE;
+	major_status = GSS_S_FAILURE;
+	goto failure;
+    } else {
+	header->buffer.length = header_len;
+    }
+
+    if (padding) {
+	if (GSS_IOV_BUFFER_FLAGS(padding->type) & GSS_IOV_BUFFER_TYPE_FLAG_ALLOCATE) {
+	    major_status = _gk_allocate_buffer(minor_status, padding, 1);
+	    if (major_status != GSS_S_COMPLETE)
+		goto failure;
+	} else if (padding->buffer.length < 1) {
+	    *minor_status = KRB5_BAD_MSIZE;
+	    major_status = GSS_S_FAILURE;
+	    goto failure;
+	} else {
+	    padding->buffer.length = 1;
+	}
+	memset(padding->buffer.value, 1, 1);
+    }
+
+    if (trailer) {
+	trailer->buffer.length = 0;
+	trailer->buffer.value = NULL;
+    }
+
+    p0 = _gssapi_make_mech_header(header->buffer.value,
+				  make_len,
+				  GSS_KRB5_MECHANISM);
+    p = p0;
+
+    *p++ = 0x02; /* TOK_ID */
+    *p++ = 0x01;
+    *p++ = 0x11; /* SGN_ALG */
+    *p++ = 0x00;
+    if (conf_req_flag) {
+	*p++ = 0x10; /* SEAL_ALG */
+	*p++ = 0x00;
+    } else {
+	*p++ = 0xff; /* SEAL_ALG */
+	*p++ = 0xff;
+    }
+    *p++ = 0xff; /* Filler */
+    *p++ = 0xff;
+
+    p = NULL;
+
+    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+    krb5_auth_con_getlocalseqnumber(context,
+				    ctx->auth_context,
+				    &seq_number);
+    _gsskrb5_encode_be_om_uint32(seq_number, p0 + 8);
+
+    krb5_auth_con_setlocalseqnumber(context,
+				    ctx->auth_context,
+				    ++seq_number);
+    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+
+    memset(p0 + 8 + 4,
+           (ctx->more_flags & LOCAL) ? 0 : 0xff,
+           4);
+
+    krb5_generate_random_block(p0 + 24, 8); /* fill in Confounder */
+
+    /* Sign Data */
+    kret = arcfour_mic_cksum_iov(context,
+				 key, KRB5_KU_USAGE_SEAL,
+				 p0 + 16, 8, /* SGN_CKSUM */
+				 p0, 8, /* TOK_ID, SGN_ALG, SEAL_ALG, Filler */
+				 p0 + 24, 8, /* Confounder */
+				 iov, iov_count, /* Data + SignOnly */
+				 padding); /* padding */
+    if (kret) {
+	*minor_status = kret;
+	major_status = GSS_S_FAILURE;
+	goto failure;
+    }
+
+    Klocal.keytype = key->keytype;
+    Klocal.keyvalue.data = Klocaldata;
+    Klocal.keyvalue.length = sizeof(Klocaldata);
+
+    for (i = 0; i < 16; i++) {
+	Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
+    }
+    kret = arcfour_mic_key(context, &Klocal,
+			   p0 + 8, 4, /* SND_SEQ */
+			   k6_data, sizeof(k6_data));
+    memset(Klocaldata, 0, sizeof(Klocaldata));
+    if (kret) {
+	*minor_status = kret;
+	major_status = GSS_S_FAILURE;
+	goto failure;
+    }
+
+    if (conf_req_flag) {
+	EVP_CIPHER_CTX rc4_key;
+
+	EVP_CIPHER_CTX_init(&rc4_key);
+	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
+
+	/* Confounder */
+	EVP_Cipher(&rc4_key, p0 + 24, p0 + 24, 8);
+
+	/* Seal Data */
+	for (i=0; i < iov_count; i++) {
+	    switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+	    case GSS_IOV_BUFFER_TYPE_DATA:
+		break;
+	    default:
+		continue;
+	    }
+
+	    EVP_Cipher(&rc4_key, iov[i].buffer.value,
+		       iov[i].buffer.value, iov[i].buffer.length);
+	}
+
+	/* Padding */
+	if (padding) {
+	    EVP_Cipher(&rc4_key, padding->buffer.value,
+		       padding->buffer.value, padding->buffer.length);
+	}
+
+	EVP_CIPHER_CTX_cleanup(&rc4_key);
+    }
+    memset(k6_data, 0, sizeof(k6_data));
+
+    kret = arcfour_mic_key(context, key,
+			   p0 + 16, 8, /* SGN_CKSUM */
+			   k6_data, sizeof(k6_data));
+    if (kret) {
+	*minor_status = kret;
+	major_status = GSS_S_FAILURE;
+    }
+
+    {
+	EVP_CIPHER_CTX rc4_key;
+
+	EVP_CIPHER_CTX_init(&rc4_key);
+	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
+	EVP_Cipher(&rc4_key, p0 + 8, p0 + 8, 8); /* SND_SEQ */
+	EVP_CIPHER_CTX_cleanup(&rc4_key);
+
+	memset(k6_data, 0, sizeof(k6_data));
+    }
+
+    if (conf_state)
+	*conf_state = conf_req_flag;
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+
+failure:
+
+    gss_release_iov_buffer(&junk, iov, iov_count);
+
+    return major_status;
+}
+
+OM_uint32
+_gssapi_unwrap_iov_arcfour(OM_uint32 *minor_status,
+			   gsskrb5_ctx ctx,
+			   krb5_context context,
+			   int *pconf_state,
+			   gss_qop_t *pqop_state,
+			   gss_iov_buffer_desc *iov,
+			   int iov_count,
+			   krb5_keyblock *key)
+{
+    OM_uint32 major_status;
+    gss_iov_buffer_desc *header, *padding, *trailer;
+    krb5_keyblock Klocal;
+    uint8_t Klocaldata[16];
+    uint8_t k6_data[16], snd_seq[8], Confounder[8];
+    uint8_t cksum_data[8];
+    uint8_t *_p = NULL;
+    const uint8_t *p, *p0;
+    size_t verify_len = 0;
+    uint32_t seq_number;
+    size_t hlen = 0;
+    int conf_state;
+    int cmp;
+    size_t i;
+    krb5_error_code kret;
+    OM_uint32 ret;
+
+    if (pconf_state != NULL) {
+	*pconf_state = 0;
+    }
+    if (pqop_state != NULL) {
+	*pqop_state = 0;
+    }
+
+    header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
+    padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
+    trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
+
+    /* Check if the packet is correct */
+    major_status = _gk_verify_buffers(minor_status,
+				  ctx,
+				  header,
+				  padding,
+				  trailer);
+    if (major_status != GSS_S_COMPLETE) {
+	return major_status;
+    }
+
+    if (padding != NULL && padding->buffer.length != 1) {
+	*minor_status = EINVAL;
+	return GSS_S_FAILURE;
+    }
+
+    if (IS_DCE_STYLE(context)) {
+	verify_len = GSS_ARCFOUR_WRAP_TOKEN_SIZE +
+		     GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE;
+	if (header->buffer.length > verify_len) {
+	    return GSS_S_BAD_MECH;
+	}
+    } else {
+	verify_len = header->buffer.length;
+    }
+    _p = header->buffer.value;
+
+    ret = _gssapi_verify_mech_header(&_p,
+				     verify_len,
+				     GSS_KRB5_MECHANISM);
+    if (ret) {
+	return ret;
+    }
+    p0 = _p;
+
+    /* length of mech header */
+    hlen = (p0 - (uint8_t *)header->buffer.value);
+    hlen += GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+
+    if (hlen > header->buffer.length) {
+	return GSS_S_BAD_MECH;
+    }
+
+    p = p0;
+
+    if (memcmp(p, "\x02\x01", 2) != 0)
+	return GSS_S_BAD_SIG;
+    p += 2;
+    if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */
+	return GSS_S_BAD_SIG;
+    p += 2;
+
+    if (memcmp (p, "\x10\x00", 2) == 0)
+	conf_state = 1;
+    else if (memcmp (p, "\xff\xff", 2) == 0)
+	conf_state = 0;
+    else
+	return GSS_S_BAD_SIG;
+
+    p += 2;
+    if (memcmp (p, "\xff\xff", 2) != 0)
+	return GSS_S_BAD_MIC;
+    p = NULL;
+
+    kret = arcfour_mic_key(context,
+			   key,
+			   p0 + 16, /* SGN_CKSUM */
+			   8,       /* SGN_CKSUM_LEN */
+			   k6_data,
+			   sizeof(k6_data));
+    if (kret) {
+	*minor_status = kret;
+	return GSS_S_FAILURE;
+    }
+
+    {
+	EVP_CIPHER_CTX rc4_key;
+
+	EVP_CIPHER_CTX_init(&rc4_key);
+	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
+	EVP_Cipher(&rc4_key, snd_seq, p0 + 8, 8); /* SND_SEQ */
+	EVP_CIPHER_CTX_cleanup(&rc4_key);
+
+	memset(k6_data, 0, sizeof(k6_data));
+    }
+
+    _gsskrb5_decode_be_om_uint32(snd_seq, &seq_number);
+
+    if (ctx->more_flags & LOCAL) {
+	cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4);
+    } else {
+	cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4);
+    }
+    if (cmp != 0) {
+	*minor_status = 0;
+	return GSS_S_BAD_MIC;
+    }
+
+    if (ctx->more_flags & LOCAL) {
+	cmp = memcmp(&snd_seq[4], "\xff\xff\xff\xff", 4);
+    } else {
+	cmp = memcmp(&snd_seq[4], "\x00\x00\x00\x00", 4);
+    }
+    if (cmp != 0) {
+	*minor_status = 0;
+	return GSS_S_BAD_MIC;
+    }
+
+    /* keyblock */
+    Klocal.keytype = key->keytype;
+    Klocal.keyvalue.data = Klocaldata;
+    Klocal.keyvalue.length = sizeof(Klocaldata);
+
+    for (i = 0; i < 16; i++) {
+	Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0;
+    }
+
+    kret = arcfour_mic_key(context,
+			   &Klocal,
+			   snd_seq,
+			   4,
+			   k6_data, sizeof(k6_data));
+    memset(Klocaldata, 0, sizeof(Klocaldata));
+    if (kret) {
+	*minor_status = kret;
+	return GSS_S_FAILURE;
+    }
+
+    if (conf_state == 1) {
+	EVP_CIPHER_CTX rc4_key;
+
+	EVP_CIPHER_CTX_init(&rc4_key);
+	EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1);
+
+	/* Confounder */
+	EVP_Cipher(&rc4_key, Confounder, p0 + 24, 8);
+
+	/* Data */
+	for (i = 0; i < iov_count; i++) {
+	    switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
+	    case GSS_IOV_BUFFER_TYPE_DATA:
+		break;
+	    default:
+		continue;
+	    }
+
+	    EVP_Cipher(&rc4_key, iov[i].buffer.value,
+		       iov[i].buffer.value, iov[i].buffer.length);
+	}
+
+	/* Padding */
+	if (padding) {
+	    EVP_Cipher(&rc4_key, padding->buffer.value,
+		       padding->buffer.value, padding->buffer.length);
+	}
+
+	EVP_CIPHER_CTX_cleanup(&rc4_key);
+    } else {
+	/* Confounder */
+	memcpy(Confounder, p0 + 24, 8);
+    }
+    memset(k6_data, 0, sizeof(k6_data));
+
+    /* Prepare the buffer for signing */
+    kret = arcfour_mic_cksum_iov(context,
+				 key, KRB5_KU_USAGE_SEAL,
+				 cksum_data, sizeof(cksum_data),
+				 p0, 8,
+				 Confounder, sizeof(Confounder),
+				 iov, iov_count,
+				 padding);
+    if (kret) {
+	*minor_status = kret;
+	return GSS_S_FAILURE;
+    }
+
+    cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */
+    if (cmp != 0) {
+	*minor_status = 0;
+	return GSS_S_BAD_MIC;
+    }
+
+    if (padding) {
+	size_t plen;
+
+	ret = _gssapi_verify_pad(&padding->buffer, 1, &plen);
+	if (ret) {
+	    *minor_status = 0;
+	    return ret;
+	}
+    }
+
+    HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
+    ret = _gssapi_msg_order_check(ctx->order, seq_number);
+    HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
+    if (ret != 0) {
+	return ret;
+    }
+
+    if (pconf_state) {
+	*pconf_state = conf_state;
+    }
+
+    *minor_status = 0;
+    return GSS_S_COMPLETE;
+}
-- 
1.9.1


From b49ad7b65b01eb6fff779e450d3c75f2b46f9315 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Thu, 25 Sep 2008 08:34:48 +0200
Subject: [PATCH 7/9] auth/kerberos: add gssapi_get_sig_size() and
 gssapi_{seal,unseal,sign,check}_packet() helper functions

These make use of gss_[un]wrap_iov[_length]() where required and support
header signing.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 auth/kerberos/gssapi_helper.c | 395 ++++++++++++++++++++++++++++++++++++++++++
 auth/kerberos/gssapi_helper.h |  55 ++++++
 auth/kerberos/wscript_build   |   2 +-
 3 files changed, 451 insertions(+), 1 deletion(-)
 create mode 100644 auth/kerberos/gssapi_helper.c
 create mode 100644 auth/kerberos/gssapi_helper.h

diff --git a/auth/kerberos/gssapi_helper.c b/auth/kerberos/gssapi_helper.c
new file mode 100644
index 0000000..b7ffb6c
--- /dev/null
+++ b/auth/kerberos/gssapi_helper.c
@@ -0,0 +1,395 @@
+/*
+   Unix SMB/CIFS implementation.
+   GSSAPI helper functions
+
+   Copyright (C) Stefan Metzmacher 2008,2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/gssapi.h"
+#include "auth/kerberos/pac_utils.h"
+#include "auth/kerberos/gssapi_helper.h"
+
+size_t gssapi_get_sig_size(gss_ctx_id_t gssapi_context,
+			   const gss_OID mech,
+			   uint32_t gss_want_flags,
+			   size_t data_size)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	size_t sig_size = 0;
+
+	if (gss_want_flags & GSS_C_CONF_FLAG) {
+		OM_uint32 min_stat, maj_stat;
+		bool want_sealing = true;
+		int sealed = 0;
+		gss_iov_buffer_desc iov[2];
+
+		if (!(gss_want_flags & GSS_C_DCE_STYLE)) {
+			TALLOC_FREE(frame);
+			return 0;
+		}
+
+		/*
+		 * gss_wrap_iov_length() only needs the type and length
+		 */
+		iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
+		iov[0].buffer.value = NULL;
+		iov[0].buffer.length = 0;
+		iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
+		iov[1].buffer.value = NULL;
+		iov[1].buffer.length = data_size;
+
+		maj_stat = gss_wrap_iov_length(&min_stat,
+					       gssapi_context,
+					       want_sealing,
+					       GSS_C_QOP_DEFAULT,
+					       &sealed,
+					       iov, ARRAY_SIZE(iov));
+		if (maj_stat) {
+			DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
+				  gssapi_error_string(frame,
+						      maj_stat,
+						      min_stat,
+						      mech)));
+			TALLOC_FREE(frame);
+			return 0;
+		}
+
+		sig_size = iov[0].buffer.length;
+	} else if (gss_want_flags & GSS_C_INTEG_FLAG) {
+		NTSTATUS status;
+		uint32_t keytype;
+
+		status = gssapi_get_session_key(frame,
+						gssapi_context,
+						NULL, &keytype);
+		if (!NT_STATUS_IS_OK(status)) {
+			TALLOC_FREE(frame);
+			return 0;
+		}
+
+		switch (keytype) {
+		case ENCTYPE_DES_CBC_MD5:
+		case ENCTYPE_DES_CBC_CRC:
+		case ENCTYPE_ARCFOUR_HMAC:
+		case ENCTYPE_ARCFOUR_HMAC_EXP:
+			sig_size = 37;
+			break;
+		default:
+			sig_size = 28;
+			break;
+		}
+	}
+
+	TALLOC_FREE(frame);
+	return sig_size;
+}
+
+NTSTATUS gssapi_seal_packet(gss_ctx_id_t gssapi_context,
+			    const gss_OID mech,
+			    bool hdr_signing, size_t sig_size,
+			    uint8_t *data, size_t length,
+			    const uint8_t *whole_pdu, size_t pdu_length,
+			    TALLOC_CTX *mem_ctx,
+			    DATA_BLOB *sig)
+{
+	OM_uint32 maj_stat, min_stat;
+	gss_iov_buffer_desc iov[4];
+	int req_seal = 1;
+	int sealed = 0;
+	const uint8_t *pre_sign_ptr = NULL;
+	size_t pre_sign_len = 0;
+	const uint8_t *post_sign_ptr = NULL;
+	size_t post_sign_len = 0;
+
+	if (hdr_signing) {
+		const uint8_t *de = data + length;
+		const uint8_t *we = whole_pdu + pdu_length;
+
+		if (data < whole_pdu) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		if (de > we) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		pre_sign_len = data - whole_pdu;
+		if (pre_sign_len > 0) {
+			pre_sign_ptr = whole_pdu;
+		}
+		post_sign_len = we - de;
+		if (post_sign_len > 0) {
+			post_sign_ptr = de;
+		}
+	}
+
+	sig->length = sig_size;
+	if (sig->length == 0) {
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	sig->data = talloc_zero_array(mem_ctx, uint8_t, sig->length);
+	if (sig->data == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	iov[0].type          = GSS_IOV_BUFFER_TYPE_HEADER;
+	iov[0].buffer.length = sig->length;
+	iov[0].buffer.value  = sig->data;
+
+	if (pre_sign_ptr != NULL) {
+		iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+		iov[1].buffer.length = pre_sign_len;
+		iov[1].buffer.value = discard_const(pre_sign_ptr);
+	} else {
+		iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+		iov[1].buffer.length = 0;
+		iov[1].buffer.value = NULL;
+	}
+
+	/* data is encrypted in place, which is ok */
+	iov[2].type          = GSS_IOV_BUFFER_TYPE_DATA;
+	iov[2].buffer.length = length;
+	iov[2].buffer.value  = data;
+
+	if (post_sign_ptr != NULL) {
+		iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+		iov[3].buffer.length = post_sign_len;
+		iov[3].buffer.value = discard_const(post_sign_ptr);
+	} else {
+		iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+		iov[3].buffer.length = 0;
+		iov[3].buffer.value = NULL;
+	}
+
+	maj_stat = gss_wrap_iov(&min_stat,
+				gssapi_context,
+				req_seal,
+				GSS_C_QOP_DEFAULT,
+				&sealed,
+				iov, ARRAY_SIZE(iov));
+	if (GSS_ERROR(maj_stat)) {
+		char *error_string = gssapi_error_string(mem_ctx,
+							 maj_stat,
+							 min_stat,
+							 mech);
+		DEBUG(1, ("gss_wrap_iov failed: %s\n", error_string));
+		talloc_free(error_string);
+		data_blob_free(sig);
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	if (req_seal == 1 && sealed == 0) {
+		DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
+		data_blob_free(sig);
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	dump_data_pw("gssapi_seal_packet: sig\n", sig->data, sig->length);
+	dump_data_pw("gssapi_seal_packet: sealed\n", data, length);
+
+	DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
+		   (int)iov[2].buffer.length, (int)iov[0].buffer.length));
+
+	return NT_STATUS_OK;
+}
+
+NTSTATUS gssapi_unseal_packet(gss_ctx_id_t gssapi_context,
+			      const gss_OID mech,
+			      bool hdr_signing,
+			      uint8_t *data, size_t length,
+			      const uint8_t *whole_pdu, size_t pdu_length,
+			      const DATA_BLOB *sig)
+{
+	OM_uint32 maj_stat, min_stat;
+	gss_iov_buffer_desc iov[4];
+	gss_qop_t qop_state;
+	int sealed = 0;
+	const uint8_t *pre_sign_ptr = NULL;
+	size_t pre_sign_len = 0;
+	const uint8_t *post_sign_ptr = NULL;
+	size_t post_sign_len = 0;
+
+	if (hdr_signing) {
+		const uint8_t *de = data + length;
+		const uint8_t *we = whole_pdu + pdu_length;
+
+		if (data < whole_pdu) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		if (de > we) {
+			return NT_STATUS_INVALID_PARAMETER;
+		}
+
+		pre_sign_len = data - whole_pdu;
+		if (pre_sign_len > 0) {
+			pre_sign_ptr = whole_pdu;
+		}
+		post_sign_len = we - de;
+		if (post_sign_len > 0) {
+			post_sign_ptr = de;
+		}
+	}
+
+	dump_data_pw("gssapi_unseal_packet: sig\n", sig->data, sig->length);
+	dump_data_pw("gssapi_unseal_packet: sealed\n", data, length);
+
+	iov[0].type          = GSS_IOV_BUFFER_TYPE_HEADER;
+	iov[0].buffer.length = sig->length;
+	iov[0].buffer.value  = sig->data;
+
+	if (pre_sign_ptr != NULL) {
+		iov[1].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+		iov[1].buffer.length = pre_sign_len;
+		iov[1].buffer.value = discard_const(pre_sign_ptr);
+	} else {
+		iov[1].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+		iov[1].buffer.length = 0;
+		iov[1].buffer.value = NULL;
+	}
+
+	/* data is encrypted in place, which is ok */
+	iov[2].type          = GSS_IOV_BUFFER_TYPE_DATA;
+	iov[2].buffer.length = length;
+	iov[2].buffer.value  = data;
+
+	if (post_sign_ptr != NULL) {
+		iov[3].type = GSS_IOV_BUFFER_TYPE_SIGN_ONLY;
+		iov[3].buffer.length = post_sign_len;
+		iov[3].buffer.value = discard_const(post_sign_ptr);
+	} else {
+		iov[3].type = GSS_IOV_BUFFER_TYPE_EMPTY;
+		iov[3].buffer.length = 0;
+		iov[3].buffer.value = NULL;
+	}
+
+	maj_stat = gss_unwrap_iov(&min_stat,
+				  gssapi_context,
+				  &sealed,
+				  &qop_state,
+				  iov, ARRAY_SIZE(iov));
+	if (GSS_ERROR(maj_stat)) {
+		char *error_string = gssapi_error_string(NULL,
+							 maj_stat,
+							 min_stat,
+							 mech);
+		DEBUG(1, ("gss_unwrap_iov failed: %s\n", error_string));
+		talloc_free(error_string);
+
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	if (sealed == 0) {
+		DEBUG(0, ("gss_unwrap_iov says data was not sealed!\n"));
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
+		   (int)iov[2].buffer.length, (int)iov[0].buffer.length));
+
+	return NT_STATUS_OK;
+}
+
+NTSTATUS gssapi_sign_packet(gss_ctx_id_t gssapi_context,
+			    const gss_OID mech,
+			    bool hdr_signing,
+			    const uint8_t *data, size_t length,
+			    const uint8_t *whole_pdu, size_t pdu_length,
+			    TALLOC_CTX *mem_ctx,
+			    DATA_BLOB *sig)
+{
+	OM_uint32 maj_stat, min_stat;
+	gss_buffer_desc input_token, output_token;
+
+	if (hdr_signing) {
+		input_token.length = pdu_length;
+		input_token.value = discard_const_p(uint8_t *, whole_pdu);
+	} else {
+		input_token.length = length;
+		input_token.value = discard_const_p(uint8_t *, data);
+	}
+
+	maj_stat = gss_get_mic(&min_stat,
+			       gssapi_context,
+			       GSS_C_QOP_DEFAULT,
+			       &input_token,
+			       &output_token);
+	if (GSS_ERROR(maj_stat)) {
+		char *error_string = gssapi_error_string(mem_ctx,
+							 maj_stat,
+							 min_stat,
+							 mech);
+		DEBUG(1, ("GSS GetMic failed: %s\n", error_string));
+		talloc_free(error_string);
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	*sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length);
+	gss_release_buffer(&min_stat, &output_token);
+	if (sig->data == NULL) {
+		return NT_STATUS_NO_MEMORY;
+	}
+
+	dump_data_pw("gssapi_sign_packet: sig\n", sig->data, sig->length);
+
+	return NT_STATUS_OK;
+}
+
+NTSTATUS gssapi_check_packet(gss_ctx_id_t gssapi_context,
+			     const gss_OID mech,
+			     bool hdr_signing,
+			     const uint8_t *data, size_t length,
+			     const uint8_t *whole_pdu, size_t pdu_length,
+			     const DATA_BLOB *sig)
+{
+	OM_uint32 maj_stat, min_stat;
+	gss_buffer_desc input_token;
+	gss_buffer_desc input_message;
+	gss_qop_t qop_state;
+
+	dump_data_pw("gssapi_check_packet: sig\n", sig->data, sig->length);
+
+	if (hdr_signing) {
+		input_message.length = pdu_length;
+		input_message.value = discard_const(whole_pdu);
+	} else {
+		input_message.length = length;
+		input_message.value = discard_const(data);
+	}
+
+	input_token.length = sig->length;
+	input_token.value = sig->data;
+
+	maj_stat = gss_verify_mic(&min_stat,
+				  gssapi_context,
+				  &input_message,
+				  &input_token,
+				  &qop_state);
+	if (GSS_ERROR(maj_stat)) {
+		char *error_string = gssapi_error_string(NULL,
+							 maj_stat,
+							 min_stat,
+							 mech);
+		DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string));
+		talloc_free(error_string);
+
+		return NT_STATUS_ACCESS_DENIED;
+	}
+
+	return NT_STATUS_OK;
+}
diff --git a/auth/kerberos/gssapi_helper.h b/auth/kerberos/gssapi_helper.h
new file mode 100644
index 0000000..f40adf1
--- /dev/null
+++ b/auth/kerberos/gssapi_helper.h
@@ -0,0 +1,55 @@
+/*
+   Unix SMB/CIFS implementation.
+   GSSAPI helper functions
+
+   Copyright (C) Stefan Metzmacher 2008,2015
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef AUTH_KERBEROS_GSSAPI_HELPER_H
+#define AUTH_KERBEROS_GSSAPI_HELPER_H 1
+
+size_t gssapi_get_sig_size(gss_ctx_id_t gssapi_context,
+			   const gss_OID mech,
+			   uint32_t gss_want_flags,
+			   size_t data_size);
+NTSTATUS gssapi_seal_packet(gss_ctx_id_t gssapi_context,
+			    const gss_OID mech,
+			    bool hdr_signing, size_t sig_size,
+			    uint8_t *data, size_t length,
+			    const uint8_t *whole_pdu, size_t pdu_length,
+			    TALLOC_CTX *mem_ctx,
+			    DATA_BLOB *sig);
+NTSTATUS gssapi_unseal_packet(gss_ctx_id_t gssapi_context,
+			      const gss_OID mech,
+			      bool hdr_signing,
+			      uint8_t *data, size_t length,
+			      const uint8_t *whole_pdu, size_t pdu_length,
+			      const DATA_BLOB *sig);
+NTSTATUS gssapi_sign_packet(gss_ctx_id_t gssapi_context,
+			    const gss_OID mech,
+			    bool hdr_signing,
+			    const uint8_t *data, size_t length,
+			    const uint8_t *whole_pdu, size_t pdu_length,
+			    TALLOC_CTX *mem_ctx,
+			    DATA_BLOB *sig);
+NTSTATUS gssapi_check_packet(gss_ctx_id_t gssapi_context,
+			     const gss_OID mech,
+			     bool hdr_signing,
+			     const uint8_t *data, size_t length,
+			     const uint8_t *whole_pdu, size_t pdu_length,
+			     const DATA_BLOB *sig);
+
+#endif /* AUTH_KERBEROS_GSSAPI_HELPER_H */
diff --git a/auth/kerberos/wscript_build b/auth/kerberos/wscript_build
index 97b8879..1fa1b51 100755
--- a/auth/kerberos/wscript_build
+++ b/auth/kerberos/wscript_build
@@ -1,4 +1,4 @@
 #!/usr/bin/env python
 bld.SAMBA_SUBSYSTEM('KRB5_PAC',
-                    source='gssapi_pac.c kerberos_pac.c',
+                    source='gssapi_pac.c kerberos_pac.c gssapi_helper.c',
                     deps='gssapi_krb5 ndr-krb5pac krb5samba')
-- 
1.9.1


From fa7d52fc77b09487ee925ed37ceb5b7f2f0c68ca Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Mon, 22 Jun 2015 01:23:16 +0200
Subject: [PATCH 8/9] s3:librpc/gse: make use of add gssapi_get_sig_size() and
 gssapi_{seal,unseal,sign,check}_packet() helper functions

This way are able to support GENSEC_FEATURE_SIGN_PKT_HEADER.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/librpc/crypto/gse.c         | 312 +++++++++++++-----------------------
 source4/auth/gensec/gensec_gssapi.c |   1 +
 2 files changed, 115 insertions(+), 198 deletions(-)

diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index c0928ce..d70a575 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -36,12 +36,15 @@
 #include "gse_krb5.h"
 
 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
+static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
+				  size_t data_size);
 
 struct gse_context {
 	gss_ctx_id_t gssapi_context;
 	gss_name_t server_name;
 	gss_name_t client_name;
 	OM_uint32 gss_want_flags, gss_got_flags;
+	size_t sig_size;
 
 	gss_cred_id_t delegated_cred_handle;
 
@@ -557,193 +560,6 @@ done:
 	return errstr;
 }
 
-static size_t gse_get_signature_length(struct gse_context *gse_ctx,
-				       bool seal, size_t payload_size)
-{
-	OM_uint32 gss_min, gss_maj;
-	gss_iov_buffer_desc iov[2];
-	int sealed;
-
-	/*
-	 * gss_wrap_iov_length() only needs the type and length
-	 */
-	iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
-	iov[0].buffer.value = NULL;
-	iov[0].buffer.length = 0;
-	iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
-	iov[1].buffer.value = NULL;
-	iov[1].buffer.length = payload_size;
-
-	gss_maj = gss_wrap_iov_length(&gss_min, gse_ctx->gssapi_context,
-					seal, GSS_C_QOP_DEFAULT,
-					&sealed, iov, 2);
-	if (gss_maj) {
-		DEBUG(0, ("gss_wrap_iov_length failed with [%s]\n",
-			  gse_errstr(talloc_tos(), gss_maj, gss_min)));
-		return 0;
-	}
-
-	return iov[0].buffer.length;
-}
-
-static NTSTATUS gse_seal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
-			 DATA_BLOB *data, DATA_BLOB *signature)
-{
-	OM_uint32 gss_min, gss_maj;
-	gss_iov_buffer_desc iov[2];
-	int req_seal = 1; /* setting to 1 means we request sign+seal */
-	int sealed = 1;
-	NTSTATUS status;
-
-	/* allocate the memory ourselves so we do not need to talloc_memdup */
-	signature->length = gse_get_signature_length(gse_ctx, true, data->length);
-	if (!signature->length) {
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-	signature->data = (uint8_t *)talloc_size(mem_ctx, signature->length);
-	if (!signature->data) {
-		return NT_STATUS_NO_MEMORY;
-	}
-	iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
-	iov[0].buffer.value = signature->data;
-	iov[0].buffer.length = signature->length;
-
-	/* data is encrypted in place, which is ok */
-	iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
-	iov[1].buffer.value = data->data;
-	iov[1].buffer.length = data->length;
-
-	gss_maj = gss_wrap_iov(&gss_min, gse_ctx->gssapi_context,
-				req_seal, GSS_C_QOP_DEFAULT,
-				&sealed, iov, 2);
-	if (gss_maj) {
-		DEBUG(0, ("gss_wrap_iov failed with [%s]\n",
-			  gse_errstr(talloc_tos(), gss_maj, gss_min)));
-		status = NT_STATUS_ACCESS_DENIED;
-		goto done;
-	}
-
-	if (!sealed) {
-		DEBUG(0, ("gss_wrap_iov says data was not sealed!\n"));
-		status = NT_STATUS_ACCESS_DENIED;
-		goto done;
-	}
-
-	status = NT_STATUS_OK;
-
-	DEBUG(10, ("Sealed %d bytes, and got %d bytes header/signature.\n",
-		   (int)iov[1].buffer.length, (int)iov[0].buffer.length));
-
-done:
-	return status;
-}
-
-static NTSTATUS gse_unseal(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
-			   DATA_BLOB *data, const DATA_BLOB *signature)
-{
-	OM_uint32 gss_min, gss_maj;
-	gss_iov_buffer_desc iov[2];
-	int sealed;
-	NTSTATUS status;
-
-	iov[0].type = GSS_IOV_BUFFER_TYPE_HEADER;
-	iov[0].buffer.value = signature->data;
-	iov[0].buffer.length = signature->length;
-
-	/* data is decrypted in place, which is ok */
-	iov[1].type = GSS_IOV_BUFFER_TYPE_DATA;
-	iov[1].buffer.value = data->data;
-	iov[1].buffer.length = data->length;
-
-	gss_maj = gss_unwrap_iov(&gss_min, gse_ctx->gssapi_context,
-				 &sealed, NULL, iov, 2);
-	if (gss_maj) {
-		DEBUG(0, ("gss_unwrap_iov failed with [%s]\n",
-			  gse_errstr(talloc_tos(), gss_maj, gss_min)));
-		status = NT_STATUS_ACCESS_DENIED;
-		goto done;
-	}
-
-	if (!sealed) {
-		DEBUG(0, ("gss_unwrap_iov says data is not sealed!\n"));
-		status = NT_STATUS_ACCESS_DENIED;
-		goto done;
-	}
-
-	status = NT_STATUS_OK;
-
-	DEBUG(10, ("Unsealed %d bytes, with %d bytes header/signature.\n",
-		   (int)iov[1].buffer.length, (int)iov[0].buffer.length));
-
-done:
-	return status;
-}
-
-static NTSTATUS gse_sign(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
-			 DATA_BLOB *data, DATA_BLOB *signature)
-{
-	OM_uint32 gss_min, gss_maj;
-	gss_buffer_desc in_data = { 0, NULL };
-	gss_buffer_desc out_data = { 0, NULL};
-	NTSTATUS status;
-
-	in_data.value = data->data;
-	in_data.length = data->length;
-
-	gss_maj = gss_get_mic(&gss_min, gse_ctx->gssapi_context,
-			      GSS_C_QOP_DEFAULT,
-			      &in_data, &out_data);
-	if (gss_maj) {
-		DEBUG(0, ("gss_get_mic failed with [%s]\n",
-			  gse_errstr(talloc_tos(), gss_maj, gss_min)));
-		status = NT_STATUS_ACCESS_DENIED;
-		goto done;
-	}
-
-	*signature = data_blob_talloc(mem_ctx,
-					out_data.value, out_data.length);
-	if (!signature->data) {
-		status = NT_STATUS_NO_MEMORY;
-		goto done;
-	}
-
-	status = NT_STATUS_OK;
-
-done:
-	if (out_data.value) {
-		gss_maj = gss_release_buffer(&gss_min, &out_data);
-	}
-	return status;
-}
-
-static NTSTATUS gse_sigcheck(TALLOC_CTX *mem_ctx, struct gse_context *gse_ctx,
-			     const DATA_BLOB *data, const DATA_BLOB *signature)
-{
-	OM_uint32 gss_min, gss_maj;
-	gss_buffer_desc in_data = { 0, NULL };
-	gss_buffer_desc in_token = { 0, NULL};
-	NTSTATUS status;
-
-	in_data.value = data->data;
-	in_data.length = data->length;
-	in_token.value = signature->data;
-	in_token.length = signature->length;
-
-	gss_maj = gss_verify_mic(&gss_min, gse_ctx->gssapi_context,
-				 &in_data, &in_token, NULL);
-	if (gss_maj) {
-		DEBUG(0, ("gss_verify_mic failed with [%s]\n",
-			  gse_errstr(talloc_tos(), gss_maj, gss_min)));
-		status = NT_STATUS_ACCESS_DENIED;
-		goto done;
-	}
-
-	status = NT_STATUS_OK;
-
-done:
-	return status;
-}
-
 static NTSTATUS gensec_gse_client_start(struct gensec_security *gensec_security)
 {
 	struct gse_context *gse_ctx;
@@ -937,8 +753,31 @@ static NTSTATUS gensec_gse_seal_packet(struct gensec_security *gensec_security,
 	struct gse_context *gse_ctx =
 		talloc_get_type_abort(gensec_security->private_data,
 		struct gse_context);
-	DATA_BLOB payload = data_blob_const(data, length);
-	return gse_seal(mem_ctx, gse_ctx, &payload, sig);
+	bool hdr_signing = false;
+	size_t sig_size = 0;
+	NTSTATUS status;
+
+	if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+		hdr_signing = true;
+	}
+
+	sig_size = gensec_gse_sig_size(gensec_security, length);
+
+	status = gssapi_seal_packet(gse_ctx->gssapi_context,
+				    &gse_ctx->gss_mech,
+				    hdr_signing, sig_size,
+				    data, length,
+				    whole_pdu, pdu_length,
+				    mem_ctx, sig);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%ju,"
+			  "data=%ju,pdu=%ju) failed: %s\n",
+			  hdr_signing, sig_size, length, pdu_length,
+			  nt_errstr(status)));
+		return status;
+	}
+
+	return NT_STATUS_OK;
 }
 
 static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security,
@@ -949,8 +788,28 @@ static NTSTATUS gensec_gse_unseal_packet(struct gensec_security *gensec_security
 	struct gse_context *gse_ctx =
 		talloc_get_type_abort(gensec_security->private_data,
 		struct gse_context);
-	DATA_BLOB payload = data_blob_const(data, length);
-	return gse_unseal(talloc_tos() /* unused */, gse_ctx, &payload, sig);
+	bool hdr_signing = false;
+	NTSTATUS status;
+
+	if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+		hdr_signing = true;
+	}
+
+	status = gssapi_unseal_packet(gse_ctx->gssapi_context,
+				      &gse_ctx->gss_mech,
+				      hdr_signing,
+				      data, length,
+				      whole_pdu, pdu_length,
+				      sig);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%ju,"
+			  "data=%ju,pdu=%ju) failed: %s\n",
+			  hdr_signing, sig->length, length, pdu_length,
+			  nt_errstr(status)));
+		return status;
+	}
+
+	return NT_STATUS_OK;
 }
 
 static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
@@ -962,8 +821,28 @@ static NTSTATUS gensec_gse_sign_packet(struct gensec_security *gensec_security,
 	struct gse_context *gse_ctx =
 		talloc_get_type_abort(gensec_security->private_data,
 		struct gse_context);
-	DATA_BLOB payload = data_blob_const(data, length);
-	return gse_sign(mem_ctx, gse_ctx, &payload, sig);
+	bool hdr_signing = false;
+	NTSTATUS status;
+
+	if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+		hdr_signing = true;
+	}
+
+	status = gssapi_sign_packet(gse_ctx->gssapi_context,
+				    &gse_ctx->gss_mech,
+				    hdr_signing,
+				    data, length,
+				    whole_pdu, pdu_length,
+				    mem_ctx, sig);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
+			  "data=%ju,pdu=%ju) failed: %s\n",
+			  hdr_signing, length, pdu_length,
+			  nt_errstr(status)));
+		return status;
+	}
+
+	return NT_STATUS_OK;
 }
 
 static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
@@ -974,8 +853,28 @@ static NTSTATUS gensec_gse_check_packet(struct gensec_security *gensec_security,
 	struct gse_context *gse_ctx =
 		talloc_get_type_abort(gensec_security->private_data,
 		struct gse_context);
-	DATA_BLOB payload = data_blob_const(data, length);
-	return gse_sigcheck(NULL, gse_ctx, &payload, sig);
+	bool hdr_signing = false;
+	NTSTATUS status;
+
+	if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+		hdr_signing = true;
+	}
+
+	status = gssapi_check_packet(gse_ctx->gssapi_context,
+				     &gse_ctx->gss_mech,
+				     hdr_signing,
+				     data, length,
+				     whole_pdu, pdu_length,
+				     sig);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%ju"
+			  "data=%ju,pdu=%ju) failed: %s\n",
+			  hdr_signing, sig->length, length, pdu_length,
+			  nt_errstr(status)));
+		return status;
+	}
+
+	return NT_STATUS_OK;
 }
 
 /* Try to figure out what features we actually got on the connection */
@@ -1035,6 +934,17 @@ static bool gensec_gse_have_feature(struct gensec_security *gensec_security,
 	if (feature & GENSEC_FEATURE_ASYNC_REPLIES) {
 		return true;
 	}
+	if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
+		if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
+			return true;
+		}
+
+		if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
+			return true;
+		}
+
+		return false;
+	}
 	return false;
 }
 
@@ -1149,9 +1059,15 @@ static size_t gensec_gse_sig_size(struct gensec_security *gensec_security,
 		talloc_get_type_abort(gensec_security->private_data,
 		struct gse_context);
 
-	return gse_get_signature_length(gse_ctx,
-					gensec_security->want_features & GENSEC_FEATURE_SEAL,
-					data_size);
+	if (gse_ctx->sig_size > 0) {
+		return gse_ctx->sig_size;
+	}
+
+	gse_ctx->sig_size = gssapi_get_sig_size(gse_ctx->gssapi_context,
+					        &gse_ctx->gss_mech,
+					        gse_ctx->gss_want_flags,
+					        data_size);
+	return gse_ctx->sig_size;
 }
 
 static const char *gensec_gse_krb5_oids[] = {
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index b3a4697..c010f7c 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -42,6 +42,7 @@
 #include "gensec_gssapi.h"
 #include "lib/util/util_net.h"
 #include "auth/kerberos/pac_utils.h"
+#include "auth/kerberos/gssapi_helper.h"
 
 #ifndef gss_mech_spnego
 gss_OID_desc spnego_mech_oid_desc =
-- 
1.9.1


From bd66c27195fedf4bc0402acd22bbb8d04b3da938 Mon Sep 17 00:00:00 2001
From: Stefan Metzmacher <metze at samba.org>
Date: Tue, 23 Jun 2015 12:32:34 +0200
Subject: [PATCH 9/9] s4:gensec/gssapi: make use of add gssapi_get_sig_size()
 and gssapi_{seal,unseal,sign,check}_packet() helper functions

This way are able to support GENSEC_FEATURE_SIGN_PKT_HEADER also together with
GENSEC_FEATURE_SEAL.

Signed-off-by: Stefan Metzmacher <metze at samba.org>
---
 source3/librpc/crypto/gse.c         |   1 +
 source4/auth/gensec/gensec_gssapi.c | 284 +++++++++---------------------------
 source4/auth/gensec/gensec_gssapi.h |   1 -
 3 files changed, 72 insertions(+), 214 deletions(-)

diff --git a/source3/librpc/crypto/gse.c b/source3/librpc/crypto/gse.c
index d70a575..349e927 100644
--- a/source3/librpc/crypto/gse.c
+++ b/source3/librpc/crypto/gse.c
@@ -33,6 +33,7 @@
 #if defined(HAVE_KRB5)
 
 #include "auth/kerberos/pac_utils.h"
+#include "auth/kerberos/gssapi_helper.h"
 #include "gse_krb5.h"
 
 static char *gse_errstr(TALLOC_CTX *mem_ctx, OM_uint32 maj, OM_uint32 min);
diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c
index c010f7c..899dcfd 100644
--- a/source4/auth/gensec/gensec_gssapi.c
+++ b/source4/auth/gensec/gensec_gssapi.c
@@ -54,6 +54,7 @@ _PUBLIC_ NTSTATUS gensec_gssapi_init(void);
 
 static size_t gensec_gssapi_max_input_size(struct gensec_security *gensec_security);
 static size_t gensec_gssapi_max_wrapped_size(struct gensec_security *gensec_security);
+static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size);
 
 static int gensec_gssapi_destructor(struct gensec_gssapi_state *gensec_gssapi_state)
 {
@@ -79,44 +80,9 @@ static int gensec_gssapi_destructor(struct gensec_gssapi_state *gensec_gssapi_st
 				 &gensec_gssapi_state->client_name);
 	}
 
-	if (gensec_gssapi_state->lucid) {
-		gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
-	}
-
 	return 0;
 }
 
-static NTSTATUS gensec_gssapi_init_lucid(struct gensec_gssapi_state *gensec_gssapi_state)
-{
-	OM_uint32 maj_stat, min_stat;
-
-	if (gensec_gssapi_state->lucid) {
-		return NT_STATUS_OK;
-	}
-
-	maj_stat = gss_krb5_export_lucid_sec_context(&min_stat,
-						     &gensec_gssapi_state->gssapi_context,
-						     1,
-						     (void **)&gensec_gssapi_state->lucid);
-	if (maj_stat != GSS_S_COMPLETE) {
-		DEBUG(0,("gensec_gssapi_init_lucid: %s\n",
-			gssapi_error_string(gensec_gssapi_state,
-					    maj_stat, min_stat,
-					    gensec_gssapi_state->gss_oid)));
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	if (gensec_gssapi_state->lucid->version != 1) {
-		DEBUG(0,("gensec_gssapi_init_lucid: lucid version[%d] != 1\n",
-			gensec_gssapi_state->lucid->version));
-		gss_krb5_free_lucid_sec_context(&min_stat, gensec_gssapi_state->lucid);
-		gensec_gssapi_state->lucid = NULL;
-		return NT_STATUS_INTERNAL_ERROR;
-	}
-
-	return NT_STATUS_OK;
-}
-
 static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 {
 	struct gensec_gssapi_state *gensec_gssapi_state;
@@ -194,8 +160,6 @@ static NTSTATUS gensec_gssapi_start(struct gensec_security *gensec_security)
 	gensec_gssapi_state->client_cred = NULL;
 	gensec_gssapi_state->server_cred = NULL;
 
-	gensec_gssapi_state->lucid = NULL;
-
 	gensec_gssapi_state->delegated_cred_handle = GSS_C_NO_CREDENTIAL;
 
 	gensec_gssapi_state->sasl = false;
@@ -1033,53 +997,30 @@ static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_securit
 {
 	struct gensec_gssapi_state *gensec_gssapi_state
 		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-	OM_uint32 maj_stat, min_stat;
-	gss_buffer_desc input_token, output_token;
-	int conf_state;
-	ssize_t sig_length;
+	bool hdr_signing = false;
+	size_t sig_size = 0;
+	NTSTATUS status;
 
 	if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
-		DEBUG(1, ("gensec_gssapi_seal_packet: "
-			  "GENSEC_FEATURE_SIGN_PKT_HEADER not supported\n"));
-		return NT_STATUS_ACCESS_DENIED;
+		hdr_signing = true;
 	}
 
-	input_token.length = length;
-	input_token.value = data;
-	
-	maj_stat = gss_wrap(&min_stat, 
-			    gensec_gssapi_state->gssapi_context,
-			    gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
-			    GSS_C_QOP_DEFAULT,
-			    &input_token,
-			    &conf_state,
-			    &output_token);
-	if (GSS_ERROR(maj_stat)) {
-		DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap failed: %s\n", 
-			  gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
-		return NT_STATUS_ACCESS_DENIED;
-	}
+	sig_size = gensec_gssapi_sig_size(gensec_security, length);
 
-	if (output_token.length < input_token.length) {
-		DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%ld] *less* than caller length [%ld]\n", 
-			  (long)output_token.length, (long)length));
-		return NT_STATUS_INTERNAL_ERROR;
+	status = gssapi_seal_packet(gensec_gssapi_state->gssapi_context,
+				    gensec_gssapi_state->gss_oid,
+				    hdr_signing, sig_size,
+				    data, length,
+				    whole_pdu, pdu_length,
+				    mem_ctx, sig);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("gssapi_seal_packet(hdr_signing=%u,sig_size=%ju,"
+			  "data=%ju,pdu=%ju) failed: %s\n",
+			  hdr_signing, sig_size, length, pdu_length,
+			  nt_errstr(status)));
+		return status;
 	}
-	sig_length = output_token.length - input_token.length;
-
-	memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
-	*sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
-
-	dump_data_pw("gensec_gssapi_seal_packet: sig\n", sig->data, sig->length);
-	dump_data_pw("gensec_gssapi_seal_packet: clear\n", data, length);
-	dump_data_pw("gensec_gssapi_seal_packet: sealed\n", ((uint8_t *)output_token.value) + sig_length, output_token.length - sig_length);
-
-	gss_release_buffer(&min_stat, &output_token);
 
-	if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
-	    && !conf_state) {
-		return NT_STATUS_ACCESS_DENIED;
-	}
 	return NT_STATUS_OK;
 }
 
@@ -1090,55 +1031,27 @@ static NTSTATUS gensec_gssapi_unseal_packet(struct gensec_security *gensec_secur
 {
 	struct gensec_gssapi_state *gensec_gssapi_state
 		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-	OM_uint32 maj_stat, min_stat;
-	gss_buffer_desc input_token, output_token;
-	int conf_state;
-	gss_qop_t qop_state;
-	DATA_BLOB in;
-
-	dump_data_pw("gensec_gssapi_unseal_packet: sig\n", sig->data, sig->length);
+	bool hdr_signing = false;
+	NTSTATUS status;
 
 	if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
-		DEBUG(1, ("gensec_gssapi_unseal_packet: "
-			  "GENSEC_FEATURE_SIGN_PKT_HEADER not supported\n"));
-		return NT_STATUS_ACCESS_DENIED;
-	}
-
-	in = data_blob_talloc(gensec_security, NULL, sig->length + length);
-
-	memcpy(in.data, sig->data, sig->length);
-	memcpy(in.data + sig->length, data, length);
-
-	input_token.length = in.length;
-	input_token.value = in.data;
-	
-	maj_stat = gss_unwrap(&min_stat, 
-			      gensec_gssapi_state->gssapi_context, 
-			      &input_token,
-			      &output_token, 
-			      &conf_state,
-			      &qop_state);
-	talloc_free(in.data);
-	if (GSS_ERROR(maj_stat)) {
-		char *error_string = gssapi_error_string(NULL, maj_stat, min_stat, gensec_gssapi_state->gss_oid);
-		DEBUG(1, ("gensec_gssapi_unseal_packet: GSS UnWrap failed: %s\n", 
-			  error_string));
-		talloc_free(error_string);
-		return NT_STATUS_ACCESS_DENIED;
+		hdr_signing = true;
 	}
 
-	if (output_token.length != length) {
-		return NT_STATUS_INTERNAL_ERROR;
+	status = gssapi_unseal_packet(gensec_gssapi_state->gssapi_context,
+				      gensec_gssapi_state->gss_oid,
+				      hdr_signing,
+				      data, length,
+				      whole_pdu, pdu_length,
+				      sig);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("gssapi_unseal_packet(hdr_signing=%u,sig_size=%ju,"
+			  "data=%ju,pdu=%ju) failed: %s\n",
+			  hdr_signing, sig->length, length, pdu_length,
+			  nt_errstr(status)));
+		return status;
 	}
 
-	memcpy(data, output_token.value, length);
-
-	gss_release_buffer(&min_stat, &output_token);
-	
-	if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)
-	    && !conf_state) {
-		return NT_STATUS_ACCESS_DENIED;
-	}
 	return NT_STATUS_OK;
 }
 
@@ -1150,34 +1063,27 @@ static NTSTATUS gensec_gssapi_sign_packet(struct gensec_security *gensec_securit
 {
 	struct gensec_gssapi_state *gensec_gssapi_state
 		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-	OM_uint32 maj_stat, min_stat;
-	gss_buffer_desc input_token, output_token;
+	bool hdr_signing = false;
+	NTSTATUS status;
 
 	if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
-		input_token.length = pdu_length;
-		input_token.value = discard_const_p(uint8_t *, whole_pdu);
-	} else {
-		input_token.length = length;
-		input_token.value = discard_const_p(uint8_t *, data);
+		hdr_signing = true;
 	}
 
-	maj_stat = gss_get_mic(&min_stat,
-			    gensec_gssapi_state->gssapi_context,
-			    GSS_C_QOP_DEFAULT,
-			    &input_token,
-			    &output_token);
-	if (GSS_ERROR(maj_stat)) {
-		DEBUG(1, ("GSS GetMic failed: %s\n",
-			  gssapi_error_string(mem_ctx, maj_stat, min_stat, gensec_gssapi_state->gss_oid)));
-		return NT_STATUS_ACCESS_DENIED;
+	status = gssapi_sign_packet(gensec_gssapi_state->gssapi_context,
+				    gensec_gssapi_state->gss_oid,
+				    hdr_signing,
+				    data, length,
+				    whole_pdu, pdu_length,
+				    mem_ctx, sig);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("gssapi_sign_packet(hdr_signing=%u,"
+			  "data=%ju,pdu=%ju) failed: %s\n",
+			  hdr_signing, length, pdu_length,
+			  nt_errstr(status)));
+		return status;
 	}
 
-	*sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, output_token.length);
-
-	dump_data_pw("gensec_gssapi_sign_packet: sig\n", sig->data, sig->length);
-
-	gss_release_buffer(&min_stat, &output_token);
-
 	return NT_STATUS_OK;
 }
 
@@ -1188,35 +1094,25 @@ static NTSTATUS gensec_gssapi_check_packet(struct gensec_security *gensec_securi
 {
 	struct gensec_gssapi_state *gensec_gssapi_state
 		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-	OM_uint32 maj_stat, min_stat;
-	gss_buffer_desc input_token;
-	gss_buffer_desc input_message;
-	gss_qop_t qop_state;
-
-	dump_data_pw("gensec_gssapi_check_packet: sig\n", sig->data, sig->length);
+	bool hdr_signing = false;
+	NTSTATUS status;
 
 	if (gensec_security->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
-		input_message.length = pdu_length;
-		input_message.value = discard_const(whole_pdu);
-	} else {
-		input_message.length = length;
-		input_message.value = discard_const(data);
+		hdr_signing = true;
 	}
 
-	input_token.length = sig->length;
-	input_token.value = sig->data;
-
-	maj_stat = gss_verify_mic(&min_stat,
-			      gensec_gssapi_state->gssapi_context, 
-			      &input_message,
-			      &input_token,
-			      &qop_state);
-	if (GSS_ERROR(maj_stat)) {
-		char *error_string = gssapi_error_string(NULL, maj_stat, min_stat, gensec_gssapi_state->gss_oid);
-		DEBUG(1, ("GSS VerifyMic failed: %s\n", error_string));
-		talloc_free(error_string);
-
-		return NT_STATUS_ACCESS_DENIED;
+	status = gssapi_check_packet(gensec_gssapi_state->gssapi_context,
+				     gensec_gssapi_state->gss_oid,
+				     hdr_signing,
+				     data, length,
+				     whole_pdu, pdu_length,
+				     sig);
+	if (!NT_STATUS_IS_OK(status)) {
+		DEBUG(0, ("gssapi_check_packet(hdr_signing=%u,sig_size=%ju,"
+			  "data=%ju,pdu=%ju) failed: %s\n",
+			  hdr_signing, sig->length, length, pdu_length,
+			  nt_errstr(status)));
+		return status;
 	}
 
 	return NT_STATUS_OK;
@@ -1299,8 +1195,7 @@ static bool gensec_gssapi_have_feature(struct gensec_security *gensec_security,
 	}
 	if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
 		if (gensec_security->want_features & GENSEC_FEATURE_SEAL) {
-			/* TODO: implement this using gss_wrap_iov() */
-			return false;
+			return true;
 		}
 
 		if (gensec_security->want_features & GENSEC_FEATURE_SIGN) {
@@ -1452,55 +1347,18 @@ static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, si
 {
 	struct gensec_gssapi_state *gensec_gssapi_state
 		= talloc_get_type(gensec_security->private_data, struct gensec_gssapi_state);
-	NTSTATUS status;
+	size_t sig_size;
 
-	if (gensec_gssapi_state->sig_size) {
+	if (gensec_gssapi_state->sig_size > 0) {
 		return gensec_gssapi_state->sig_size;
 	}
 
-	if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) {
-		gensec_gssapi_state->sig_size = 45;
-	} else {
-		gensec_gssapi_state->sig_size = 37;
-	}
-
-	status = gensec_gssapi_init_lucid(gensec_gssapi_state);
-	if (!NT_STATUS_IS_OK(status)) {
-		return gensec_gssapi_state->sig_size;
-	}
-
-	if (gensec_gssapi_state->lucid->protocol == 1) {
-		if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) {
-			gensec_gssapi_state->sig_size = 60;
-			if (gensec_gssapi_state->gss_got_flags & GSS_C_DCE_STYLE) {
-				gensec_gssapi_state->sig_size += 16;
-			}
-		} else {
-			gensec_gssapi_state->sig_size = 28;
-		}
-	} else if (gensec_gssapi_state->lucid->protocol == 0) {
-		switch (gensec_gssapi_state->lucid->rfc1964_kd.ctx_key.type) {
-		case ENCTYPE_DES_CBC_CRC:
-		case ENCTYPE_ARCFOUR_HMAC:
-		case ENCTYPE_ARCFOUR_HMAC_EXP:
-			if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) {
-				gensec_gssapi_state->sig_size = 45;
-			} else {
-				gensec_gssapi_state->sig_size = 37;
-			}
-			break;
-#ifdef SAMBA4_USES_HEIMDAL
-		case ENCTYPE_OLD_DES3_CBC_SHA1:
-			if (gensec_gssapi_state->gss_got_flags & GSS_C_CONF_FLAG) {
-				gensec_gssapi_state->sig_size = 57;
-			} else {
-				gensec_gssapi_state->sig_size = 49;
-			}
-			break;
-#endif
-		}
-	}
+	sig_size = gssapi_get_sig_size(gensec_gssapi_state->gssapi_context,
+				       gensec_gssapi_state->gss_oid,
+				       gensec_gssapi_state->gss_want_flags,
+				       data_size);
 
+	gensec_gssapi_state->sig_size = sig_size;
 	return gensec_gssapi_state->sig_size;
 }
 
diff --git a/source4/auth/gensec/gensec_gssapi.h b/source4/auth/gensec/gensec_gssapi.h
index b7429b5..cf0e3a8 100644
--- a/source4/auth/gensec/gensec_gssapi.h
+++ b/source4/auth/gensec/gensec_gssapi.h
@@ -46,7 +46,6 @@ struct gensec_gssapi_state {
 	NTTIME expire_time;
 
 	/* gensec_gssapi only */
-	gss_krb5_lucid_context_v1_t *lucid;
 	gss_OID gss_oid;
 
 	struct gss_channel_bindings_struct *input_chan_bindings;
-- 
1.9.1
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: OpenPGP digital signature
URL: <http://lists.samba.org/pipermail/samba-technical/attachments/20150623/bd6bc331/attachment.pgp>


More information about the samba-technical mailing list