s3:librpc/gse: make use of add gssapi_get_sig_size() and gssapi_{seal,unseal,sign...
authorStefan Metzmacher <metze@samba.org>
Sun, 21 Jun 2015 23:23:16 +0000 (01:23 +0200)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 23 Jun 2015 23:03:17 +0000 (01:03 +0200)
This way are able to support GENSEC_FEATURE_SIGN_PKT_HEADER.

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source3/librpc/crypto/gse.c
source4/auth/gensec/gensec_gssapi.c

index 8db3cdd227aa442fbaec84e7741d83736cfa0775..beebd14a7664e3e79d0c122079cfd1281c3bb90c 100644 (file)
 #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;
 
@@ -541,193 +544,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;
@@ -921,8 +737,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,
@@ -933,8 +772,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,
@@ -946,8 +805,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,
@@ -958,8 +837,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 */
@@ -1019,6 +918,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;
 }
 
@@ -1133,9 +1043,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[] = {
index b3a469770d6c75f3ccb09311ce9bb0fcd3405f7c..c010f7c1c32b7e42a04c116997dcd52c76bab4f6 100644 (file)
@@ -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 =