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