mirror of
https://github.com/samba-team/samba.git
synced 2025-01-08 21:18:16 +03:00
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@samba.org> Reviewed-by: Andrew Bartlett <abartlet@samba.org>
This commit is contained in:
parent
c245d4f33e
commit
8a4c0abb3e
395
auth/kerberos/gssapi_helper.c
Normal file
395
auth/kerberos/gssapi_helper.c
Normal file
@ -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;
|
||||
}
|
55
auth/kerberos/gssapi_helper.h
Normal file
55
auth/kerberos/gssapi_helper.h
Normal file
@ -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 */
|
@ -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')
|
||||
|
Loading…
Reference in New Issue
Block a user