On Sat, 2005-09-10 at 14:29 +1000, Andrew Bartlett wrote: > On Sat, 2005-09-10 at 10:57 +1000, Andrew Bartlett wrote: > > This patch, inspired by the lukeh's heimdal-mechglue branch appears to > > fix up gesnec_gssapi for sign/seal, samba->samba when using AES. It > > also works Samba->Windows and Windows->Samba. > > > > However, I'm not sure if I've broken the original intent of this > > function, and it might make more sense to have a direct > > gss_sig_length(conext, data_len, &length) function. I'm going to have a > > look at that approach now. > > This patch adds a new function: > OM_uint32 > gss_wrap_size ( > OM_uint32 * /*minor_status*/, > const gss_ctx_id_t /*context_handle*/, > int /*conf_req_flag*/, > gss_qop_t /*qop_req*/, > OM_uint32 /*req_input_size*/, > OM_uint32 * /*output_size*/ > ); > > This tells the caller what the wrapped size would be, given an input > size. From there, I can tell what the 'signature' portion would be. > > My testing so far has been on AES and ARCFOUR, where this seems to match > up with the results of the actual sealing. I'm looking for comments on > this patch. (as well as any hints towards any testing setup that may > already exist for the size_limit function). And this patch should compile (missed a couple of callers to the sig_size code). Andrew Bartlett -- Andrew Bartlett http://samba.org/~abartlet/ Samba Developer, SuSE Labs, Novell Inc. http://suse.de Authentication Developer, Samba Team http://samba.org Student Network Administrator, Hawker College http://hawkerc.net
Index: auth/gensec/gensec.c
===================================================================
--- auth/gensec/gensec.c (revision 10115)
+++ auth/gensec/gensec.c (working copy)
@@ -559,7 +559,7 @@
return gensec_security->ops->sign_packet(gensec_security, mem_ctx, data, length, whole_pdu, pdu_length, sig);
}
-size_t gensec_sig_size(struct gensec_security *gensec_security)
+size_t gensec_sig_size(struct gensec_security *gensec_security, size_t data_size)
{
if (!gensec_security->ops->sig_size) {
return 0;
@@ -568,7 +568,7 @@
return 0;
}
- return gensec_security->ops->sig_size(gensec_security);
+ return gensec_security->ops->sig_size(gensec_security, data_size);
}
NTSTATUS gensec_wrap(struct gensec_security *gensec_security,
Index: auth/gensec/gensec.h
===================================================================
--- auth/gensec/gensec.h (revision 10115)
+++ auth/gensec/gensec.h (working copy)
@@ -73,7 +73,7 @@
const uint8_t *data, size_t length,
const uint8_t *whole_pdu, size_t pdu_length,
DATA_BLOB *sig);
- size_t (*sig_size)(struct gensec_security *gensec_security);
+ size_t (*sig_size)(struct gensec_security *gensec_security, size_t data_size);
NTSTATUS (*check_packet)(struct gensec_security *gensec_security, TALLOC_CTX *sig_mem_ctx,
const uint8_t *data, size_t length,
const uint8_t *whole_pdu, size_t pdu_length,
Index: auth/gensec/gensec_gssapi.c
===================================================================
--- auth/gensec/gensec_gssapi.c (revision 10115)
+++ auth/gensec/gensec_gssapi.c (working copy)
@@ -480,10 +480,31 @@
return NT_STATUS_OK;
}
-static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security)
+static size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t data_size)
{
- /* not const but work for DCERPC packets and arcfour */
- return 45;
+ struct gensec_gssapi_state *gensec_gssapi_state = gensec_security->private_data;
+ OM_uint32 maj_stat, min_stat;
+ OM_uint32 output_size;
+ maj_stat = gss_wrap_size(&min_stat,
+ gensec_gssapi_state->gssapi_context,
+ gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL),
+ GSS_C_QOP_DEFAULT,
+ data_size,
+ &output_size);
+ if (GSS_ERROR(maj_stat)) {
+ TALLOC_CTX *mem_ctx = talloc_new(NULL);
+ DEBUG(1, ("gensec_gssapi_seal_packet: determinaing signature size with gss_wrap_size_limit failed: %s\n",
+ gssapi_error_string(mem_ctx, maj_stat, min_stat)));
+ talloc_free(mem_ctx);
+ return 0;
+ }
+
+ if (output_size < data_size) {
+ return 0;
+ }
+
+ /* The difference between the max output and the max input must be the signature */
+ return output_size - data_size;
}
static NTSTATUS gensec_gssapi_seal_packet(struct gensec_security *gensec_security,
@@ -496,7 +517,7 @@
OM_uint32 maj_stat, min_stat;
gss_buffer_desc input_token, output_token;
int conf_state;
- ssize_t sig_length = 0;
+ ssize_t sig_length;
input_token.length = length;
input_token.value = data;
@@ -514,12 +535,15 @@
return NT_STATUS_ACCESS_DENIED;
}
- if (output_token.length < length) {
+ sig_length = gensec_gssapi_sig_size(gensec_security, length);
+
+ /* Caller must pad to right boundary */
+ if (output_token.length != (length + sig_length)) {
+ DEBUG(1, ("gensec_gssapi_seal_packet: GSS Wrap length [%d] does not match caller length [%d] plus sig size [%d] = [%d]\n",
+ output_token.length, length, sig_length, length + sig_length));
return NT_STATUS_INTERNAL_ERROR;
}
- sig_length = 45;
-
memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);
*sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
@@ -618,7 +642,7 @@
return NT_STATUS_INTERNAL_ERROR;
}
- sig_length = 45;
+ sig_length = gensec_gssapi_sig_size(gensec_security, length);
/*memcpy(data, ((uint8_t *)output_token.value) + sig_length, length);*/
*sig = data_blob_talloc(mem_ctx, (uint8_t *)output_token.value, sig_length);
Index: auth/gensec/schannel.c
===================================================================
--- auth/gensec/schannel.c (revision 10115)
+++ auth/gensec/schannel.c (working copy)
@@ -26,7 +26,7 @@
#include "auth/auth.h"
#include "auth/gensec/schannel.h"
-static size_t schannel_sig_size(struct gensec_security *gensec_security)
+static size_t schannel_sig_size(struct gensec_security *gensec_security, size_t data_size)
{
return 32;
}
Index: auth/gensec/spnego.c
===================================================================
--- auth/gensec/spnego.c (revision 10115)
+++ auth/gensec/spnego.c (working copy)
@@ -198,7 +198,7 @@
mem_ctx, in, out);
}
-static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security)
+static size_t gensec_spnego_sig_size(struct gensec_security *gensec_security, size_t data_size)
{
struct spnego_state *spnego_state = gensec_security->private_data;
@@ -207,7 +207,7 @@
return 0;
}
- return gensec_sig_size(spnego_state->sub_sec_security);
+ return gensec_sig_size(spnego_state->sub_sec_security, data_size);
}
static NTSTATUS gensec_spnego_session_key(struct gensec_security *gensec_security,
Index: heimdal/lib/gssapi/wrap.c
===================================================================
--- heimdal/lib/gssapi/wrap.c (revision 10115)
+++ heimdal/lib/gssapi/wrap.c (working copy)
@@ -120,7 +120,7 @@
}
static OM_uint32
-sub_wrap_size (
+sub_wrap_size_limit (
OM_uint32 req_output_size,
OM_uint32 * max_input_size,
int blocksize,
@@ -156,6 +156,8 @@
krb5_keyblock *key;
OM_uint32 ret;
krb5_keytype keytype;
+ OM_uint32 output_size;
+ OM_uint32 blocksize;
ret = gss_krb5_get_subkey(context_handle, &key);
if (ret) {
@@ -167,17 +169,102 @@
switch (keytype) {
case KEYTYPE_DES :
+ ret = sub_wrap_size_limit(req_output_size, max_input_size, 8, 22);
+ break;
+ case KEYTYPE_DES3 :
+ ret = sub_wrap_size_limit(req_output_size, max_input_size, 8, 34);
+ break;
case KEYTYPE_ARCFOUR:
case KEYTYPE_ARCFOUR_56:
- ret = sub_wrap_size(req_output_size, max_input_size, 8, 22);
+ ret = _gssapi_wrap_size_arcfour(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ req_output_size, &output_size,
+ &blocksize, key);
+
+ if (output_size > req_output_size) {
+ *max_input_size = req_output_size - (output_size - req_output_size);
+ (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
+ } else {
+ *max_input_size = 0;
+ }
break;
+ default :
+ ret = _gssapi_wrap_size_cfx(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ req_output_size, &output_size,
+ &blocksize, key);
+ if (output_size > req_output_size) {
+ *max_input_size = req_output_size - (output_size - req_output_size);
+ (*max_input_size) &= (~(OM_uint32)(blocksize - 1));
+ } else {
+ *max_input_size = 0;
+ }
+ break;
+ }
+ krb5_free_keyblock (gssapi_krb5_context, key);
+ *minor_status = 0;
+ return ret;
+}
+
+static OM_uint32
+sub_wrap_size (
+ OM_uint32 req_input_size,
+ OM_uint32 * output_size,
+ int blocksize,
+ int extrasize
+ )
+{
+ size_t len, total_len, padlength, datalen;
+
+ padlength = blocksize - (req_input_size % blocksize);
+ datalen = req_input_size + padlength + 8;
+ len = datalen + extrasize;
+ gssapi_krb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM);
+
+ *output_size = total_len;
+
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
+gss_wrap_size (
+ OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_input_size,
+ OM_uint32 * output_size
+ )
+{
+ krb5_keyblock *key;
+ OM_uint32 ret, padlen;
+ krb5_keytype keytype;
+
+ ret = gss_krb5_get_subkey(context_handle, &key);
+ if (ret) {
+ gssapi_krb5_set_error_string ();
+ *minor_status = ret;
+ return GSS_S_FAILURE;
+ }
+ krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype);
+
+ switch (keytype) {
+ case KEYTYPE_DES :
+ ret = sub_wrap_size(req_input_size, output_size, 8, 22);
+ break;
case KEYTYPE_DES3 :
- ret = sub_wrap_size(req_output_size, max_input_size, 8, 34);
+ ret = sub_wrap_size(req_input_size, output_size, 8, 34);
break;
+ case KEYTYPE_ARCFOUR:
+ case KEYTYPE_ARCFOUR_56:
+ ret = _gssapi_wrap_size_arcfour(minor_status, context_handle,
+ conf_req_flag, qop_req,
+ req_input_size, output_size, &padlen, key);
+ break;
default :
ret = _gssapi_wrap_size_cfx(minor_status, context_handle,
conf_req_flag, qop_req,
- req_output_size, max_input_size, key);
+ req_input_size, output_size, &padlen, key);
break;
}
krb5_free_keyblock (gssapi_krb5_context, key);
Index: heimdal/lib/gssapi/cfx.c
===================================================================
--- heimdal/lib/gssapi/cfx.c (revision 10115)
+++ heimdal/lib/gssapi/cfx.c (working copy)
@@ -48,7 +48,8 @@
size_t input_length,
size_t *output_length,
size_t *cksumsize,
- u_int16_t *padlength)
+ u_int16_t *padlength,
+ size_t *padsize)
{
krb5_error_code ret;
krb5_cksumtype type;
@@ -68,18 +69,17 @@
}
if (conf_req_flag) {
- size_t padsize;
/* Header is concatenated with data before encryption */
input_length += sizeof(gss_cfx_wrap_token_desc);
- ret = krb5_crypto_getpadsize(gssapi_krb5_context, crypto, &padsize);
+ ret = krb5_crypto_getpadsize(gssapi_krb5_context, crypto, padsize);
if (ret) {
return ret;
}
if (padsize > 1) {
/* XXX check this */
- *padlength = padsize - (input_length % padsize);
+ *padlength = *padsize - (input_length % *padsize);
}
/* We add the pad ourselves (noted here for completeness only) */
@@ -90,6 +90,7 @@
} else {
/* Checksum is concatenated with data */
*output_length += input_length + *cksumsize;
+ *padsize = 0;
}
assert(*output_length > input_length);
@@ -101,13 +102,15 @@
const gss_ctx_id_t context_handle,
int conf_req_flag,
gss_qop_t qop_req,
- OM_uint32 req_output_size,
- OM_uint32 *max_input_size,
+ OM_uint32 req_input_size,
+ OM_uint32 *output_len,
+ OM_uint32 *padsize,
krb5_keyblock *key)
{
krb5_error_code ret;
krb5_crypto crypto;
- u_int16_t padlength;
+ u_int16_t pad_length;
+ size_t pad_size;
size_t output_length, cksumsize;
ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
@@ -118,8 +121,8 @@
}
ret = wrap_length_cfx(crypto, conf_req_flag,
- req_output_size,
- &output_length, &cksumsize, &padlength);
+ req_input_size,
+ &output_length, &cksumsize, &pad_length, &pad_size);
if (ret != 0) {
gssapi_krb5_set_error_string();
*minor_status = ret;
@@ -127,13 +130,8 @@
return GSS_S_FAILURE;
}
- if (output_length < req_output_size) {
- *max_input_size = (req_output_size - output_length);
- *max_input_size -= padlength;
- } else {
- /* Should this return an error? */
- *max_input_size = 0;
- }
+ *output_len = output_length;
+ *padsize = pad_size;
krb5_crypto_destroy(gssapi_krb5_context, crypto);
@@ -201,7 +199,7 @@
krb5_data cipher;
size_t wrapped_len, cksumsize;
u_int16_t padlength, rrc = 0;
- OM_uint32 seq_number;
+ OM_uint32 seq_number, padsize;
u_char *p;
ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto);
@@ -213,7 +211,7 @@
ret = wrap_length_cfx(crypto, conf_req_flag,
input_message_buffer->length,
- &wrapped_len, &cksumsize, &padlength);
+ &wrapped_len, &cksumsize, &padlength, &padsize);
if (ret != 0) {
gssapi_krb5_set_error_string();
*minor_status = ret;
Index: heimdal/lib/gssapi/cfx.h
===================================================================
--- heimdal/lib/gssapi/cfx.h (revision 10115)
+++ heimdal/lib/gssapi/cfx.h (working copy)
@@ -66,8 +66,9 @@
const gss_ctx_id_t context_handle,
int conf_req_flag,
gss_qop_t qop_req,
- OM_uint32 req_output_size,
- OM_uint32 *max_input_size,
+ OM_uint32 req_input_size,
+ OM_uint32 *output_len,
+ OM_uint32 *padlen,
krb5_keyblock *key);
OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
Index: heimdal/lib/gssapi/gssapi.h
===================================================================
--- heimdal/lib/gssapi/gssapi.h (revision 10115)
+++ heimdal/lib/gssapi/gssapi.h (working copy)
@@ -628,6 +628,16 @@
int * /*open_context*/
);
+OM_uint32
+gss_wrap_size (
+ OM_uint32 * /*minor_status*/,
+ const gss_ctx_id_t /*context_handle*/,
+ int /*conf_req_flag*/,
+ gss_qop_t /*qop_req*/,
+ OM_uint32 /*req_input_size*/,
+ OM_uint32 * /*output_size*/
+ );
+
OM_uint32 gss_wrap_size_limit (
OM_uint32 * /*minor_status*/,
const gss_ctx_id_t /*context_handle*/,
Index: heimdal/lib/gssapi/arcfour.c
===================================================================
--- heimdal/lib/gssapi/arcfour.c (revision 10115)
+++ heimdal/lib/gssapi/arcfour.c (working copy)
@@ -326,6 +326,37 @@
}
OM_uint32
+_gssapi_wrap_size_arcfour(OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_input_size,
+ OM_uint32 * output_size,
+ OM_uint32 * padlen,
+ krb5_keyblock *key)
+{
+ size_t len, total_len, datalen;
+ *padlen = 0;
+ datalen = req_input_size;
+ len = GSS_ARCFOUR_WRAP_TOKEN_SIZE;
+ /* if GSS_C_DCE_STYLE is in use:
+ * - we only need to encapsulate the WRAP token
+ * - we should not add padding
+ */
+ if (!(context_handle->flags & GSS_C_DCE_STYLE)) {
+ datalen += 1 /* padding */;
+ len += datalen;
+ }
+ _gssapi_encap_length(len, &len, &total_len, GSS_KRB5_MECHANISM);
+ if (context_handle->flags & GSS_C_DCE_STYLE) {
+ total_len += datalen;
+ }
+
+ *output_size = total_len;
+ return GSS_S_COMPLETE;
+}
+
+OM_uint32
_gssapi_wrap_arcfour(OM_uint32 * minor_status,
const gss_ctx_id_t context_handle,
int conf_req_flag,
Index: heimdal/lib/gssapi/arcfour.h
===================================================================
--- heimdal/lib/gssapi/arcfour.h (revision 10115)
+++ heimdal/lib/gssapi/arcfour.h (working copy)
@@ -70,5 +70,14 @@
gss_qop_t *qop_state,
krb5_keyblock *key,
char *type);
+OM_uint32
+_gssapi_wrap_size_arcfour(OM_uint32 * minor_status,
+ const gss_ctx_id_t context_handle,
+ int conf_req_flag,
+ gss_qop_t qop_req,
+ OM_uint32 req_input_size,
+ OM_uint32 * output_size,
+ OM_uint32 * padlen,
+ krb5_keyblock *key);
#endif /* GSSAPI_ARCFOUR_H_ */
This is a digitally signed message part