From 4ad02f51857322b3d63b435f1e3ea60ead2e1993 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 25 Jul 2008 13:11:46 +0200 Subject: gsskrb5: add support for DCE_STYLE and des and des3 keys Only the des keys are tested as windows doesn't support des3 metze (This used to be commit 86848dd0f217774faed81af8fbf68618013e20a1) --- source4/heimdal/lib/gssapi/krb5/unwrap.c | 52 +++++++++++++++++++++++--------- source4/heimdal/lib/gssapi/krb5/wrap.c | 34 ++++++++++++++++----- 2 files changed, 64 insertions(+), 22 deletions(-) diff --git a/source4/heimdal/lib/gssapi/krb5/unwrap.c b/source4/heimdal/lib/gssapi/krb5/unwrap.c index eec4078a70..c287469e96 100644 --- a/source4/heimdal/lib/gssapi/krb5/unwrap.c +++ b/source4/heimdal/lib/gssapi/krb5/unwrap.c @@ -59,10 +59,17 @@ unwrap_des OM_uint32 ret; int cstate; int cmp; + int token_len; + + if (IS_DCE_STYLE(context_handle)) { + token_len = 22 + 8 + 15; /* 45 */ + } else { + token_len = input_message_buffer->length; + } p = input_message_buffer->value; ret = _gsskrb5_verify_header (&p, - input_message_buffer->length, + token_len, "\x02\x01", GSS_KRB5_MECHANISM); if (ret) @@ -105,12 +112,17 @@ unwrap_des memset (deskey, 0, sizeof(deskey)); memset (&schedule, 0, sizeof(schedule)); } - /* check pad */ - ret = _gssapi_verify_pad(input_message_buffer, - input_message_buffer->length - len, - &padlength); - if (ret) - return ret; + + if (IS_DCE_STYLE(context_handle)) { + padlength = 0; + } else { + /* check pad */ + ret = _gssapi_verify_pad(input_message_buffer, + input_message_buffer->length - len, + &padlength); + if (ret) + return ret; + } MD5_Init (&md5); MD5_Update (&md5, p - 24, 8); @@ -195,10 +207,17 @@ unwrap_des3 krb5_crypto crypto; Checksum csum; int cmp; + int token_len; + + if (IS_DCE_STYLE(context_handle)) { + token_len = 34 + 8 + 15; /* 57 */ + } else { + token_len = input_message_buffer->length; + } p = input_message_buffer->value; ret = _gsskrb5_verify_header (&p, - input_message_buffer->length, + token_len, "\x02\x01", GSS_KRB5_MECHANISM); if (ret) @@ -245,12 +264,17 @@ unwrap_des3 memcpy (p, tmp.data, tmp.length); krb5_data_free(&tmp); } - /* check pad */ - ret = _gssapi_verify_pad(input_message_buffer, - input_message_buffer->length - len, - &padlength); - if (ret) - return ret; + + if (IS_DCE_STYLE(context_handle)) { + padlength = 0; + } else { + /* check pad */ + ret = _gssapi_verify_pad(input_message_buffer, + input_message_buffer->length - len, + &padlength); + if (ret) + return ret; + } /* verify sequence number */ diff --git a/source4/heimdal/lib/gssapi/krb5/wrap.c b/source4/heimdal/lib/gssapi/krb5/wrap.c index 6d00f2adcf..bedeace4dd 100644 --- a/source4/heimdal/lib/gssapi/krb5/wrap.c +++ b/source4/heimdal/lib/gssapi/krb5/wrap.c @@ -210,10 +210,19 @@ wrap_des int32_t seq_number; size_t len, total_len, padlength, datalen; - padlength = 8 - (input_message_buffer->length % 8); - datalen = input_message_buffer->length + padlength + 8; - len = datalen + 22; - _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + if (IS_DCE_STYLE(ctx)) { + padlength = 0; + datalen = input_message_buffer->length; + len = 22 + 8; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + total_len += datalen; + datalen += 8; + } else { + padlength = 8 - (input_message_buffer->length % 8); + datalen = input_message_buffer->length + padlength + 8; + len = datalen + 22; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + } output_message_buffer->length = total_len; output_message_buffer->value = malloc (total_len); @@ -336,10 +345,19 @@ wrap_des3 Checksum cksum; krb5_data encdata; - padlength = 8 - (input_message_buffer->length % 8); - datalen = input_message_buffer->length + padlength + 8; - len = datalen + 34; - _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + if (IS_DCE_STYLE(ctx)) { + padlength = 0; + datalen = input_message_buffer->length; + len = 34 + 8; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + total_len += datalen; + datalen += 8; + } else { + padlength = 8 - (input_message_buffer->length % 8); + datalen = input_message_buffer->length + padlength + 8; + len = datalen + 34; + _gsskrb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); + } output_message_buffer->length = total_len; output_message_buffer->value = malloc (total_len); -- cgit From 610b1ada1535b2ae1b38adde4de112ee6dc23a2c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2008 15:22:39 +0200 Subject: krb5: always generate the acceptor subkey as the same enctype as the used service key With this patch samba4 can use gsskrb5_get_subkey() to get the session key. metze (This used to be commit dbb94133e0313cae933d261af0bf1210807a6d11) --- source4/heimdal/lib/krb5/rd_req.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source4/heimdal/lib/krb5/rd_req.c b/source4/heimdal/lib/krb5/rd_req.c index ddf1f69ae4..e80aaa6789 100644 --- a/source4/heimdal/lib/krb5/rd_req.c +++ b/source4/heimdal/lib/krb5/rd_req.c @@ -463,6 +463,8 @@ krb5_verify_ap_req2(krb5_context context, ac->keytype = ETYPE_NULL; +#if 0 +/* it's bad to use a different enctype as the client */ if (etypes.val) { int i; @@ -473,6 +475,7 @@ krb5_verify_ap_req2(krb5_context context, } } } +#endif /* save key */ ret = krb5_copy_keyblock(context, &t->ticket.key, &ac->keyblock); -- cgit From dd35840d9be4acff6fe2ff4f268039adf828d871 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2008 15:27:40 +0200 Subject: gensec_gssapi: use gsskrb5_get_subkey() to get the session key This is needed to get the correct key, when aes keys are used. metze (This used to be commit 7587a7d8b65f27a5865d6873f63a450488da02c9) --- source4/auth/gensec/gensec_gssapi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index 1541c88e07..0b1b9d851c 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -1165,9 +1165,9 @@ static NTSTATUS gensec_gssapi_session_key(struct gensec_security *gensec_securit return NT_STATUS_OK; } - maj_stat = gsskrb5_get_initiator_subkey(&min_stat, - gensec_gssapi_state->gssapi_context, - &subkey); + maj_stat = gsskrb5_get_subkey(&min_stat, + gensec_gssapi_state->gssapi_context, + &subkey); if (maj_stat != 0) { DEBUG(1, ("NO session key for this mech\n")); return NT_STATUS_NO_USER_SESSION_KEY; -- cgit From 5569132f45e12011697d2f465be9f33f34a5ea60 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2008 15:01:15 +0200 Subject: gsskrb5: try to be compatible with windows for gss_wrap* and cfx The good thing is that windows and heimdal both use EC=0 in the non DCE_STYLE case, so we need the windows compat hack only in DCE_STYLE mode. metze (This used to be commit 0fa41a94e466d5e11bcf362ccd8ff41b72733d1a) --- source4/heimdal/lib/gssapi/krb5/cfx.c | 49 ++++++++++++++++++----- source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h | 1 + 2 files changed, 39 insertions(+), 11 deletions(-) diff --git a/source4/heimdal/lib/gssapi/krb5/cfx.c b/source4/heimdal/lib/gssapi/krb5/cfx.c index 6452f802ab..bc0d736e81 100755 --- a/source4/heimdal/lib/gssapi/krb5/cfx.c +++ b/source4/heimdal/lib/gssapi/krb5/cfx.c @@ -43,7 +43,8 @@ RCSID("$Id: cfx.c 19031 2006-11-13 18:02:57Z lha $"); #define CFXAcceptorSubkey (1 << 2) krb5_error_code -_gsskrb5cfx_wrap_length_cfx(krb5_context context, +_gsskrb5cfx_wrap_length_cfx(const gsskrb5_ctx context_handle, + krb5_context context, krb5_crypto crypto, int conf_req_flag, size_t input_length, @@ -72,7 +73,11 @@ _gsskrb5cfx_wrap_length_cfx(krb5_context context, /* Header is concatenated with data before encryption */ input_length += sizeof(gss_cfx_wrap_token_desc); - ret = krb5_crypto_getpadsize(context, crypto, &padsize); + if (IS_DCE_STYLE(context_handle)) { + ret = krb5_crypto_getblocksize(context, crypto, &padsize); + } else { + ret = krb5_crypto_getpadsize(context, crypto, &padsize); + } if (ret) { return ret; } @@ -258,7 +263,7 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, return GSS_S_FAILURE; } - ret = _gsskrb5cfx_wrap_length_cfx(context, + ret = _gsskrb5cfx_wrap_length_cfx(context_handle, context, crypto, conf_req_flag, input_message_buffer->length, &wrapped_len, &cksumsize, &padlength); @@ -380,7 +385,15 @@ OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status, token->RRC[0] = (rrc >> 8) & 0xFF; token->RRC[1] = (rrc >> 0) & 0xFF; - ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE); + /* + * this is really ugly, but needed against windows + * for DCERPC, as windows rotates by EC+RRC. + */ + if (IS_DCE_STYLE(context_handle)) { + ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE); + } else { + ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE); + } if (ret != 0) { *minor_status = ret; krb5_crypto_destroy(context, crypto); @@ -553,14 +566,21 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, len = input_message_buffer->length; len -= (p - (u_char *)input_message_buffer->value); - /* Rotate by RRC; bogus to do this in-place XXX */ - *minor_status = rrc_rotate(p, len, rrc, TRUE); - if (*minor_status != 0) { - krb5_crypto_destroy(context, crypto); - return GSS_S_FAILURE; - } - if (token_flags & CFXSealed) { + /* + * this is really ugly, but needed against windows + * for DCERPC, as windows rotates by EC+RRC. + */ + if (IS_DCE_STYLE(context_handle)) { + *minor_status = rrc_rotate(p, len, rrc+ec, TRUE); + } else { + *minor_status = rrc_rotate(p, len, rrc, TRUE); + } + if (*minor_status != 0) { + krb5_crypto_destroy(context, crypto); + return GSS_S_FAILURE; + } + ret = krb5_decrypt(context, crypto, usage, p, len, &data); if (ret != 0) { @@ -594,6 +614,13 @@ OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status, } else { Checksum cksum; + /* Rotate by RRC; bogus to do this in-place XXX */ + *minor_status = rrc_rotate(p, len, rrc, TRUE); + if (*minor_status != 0) { + krb5_crypto_destroy(context, crypto); + return GSS_S_FAILURE; + } + /* Determine checksum type */ ret = krb5_crypto_get_checksum_type(context, crypto, &cksum.cksumtype); diff --git a/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h b/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h index 64a0dd36b1..f6edb8b247 100644 --- a/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h +++ b/source4/heimdal/lib/gssapi/krb5/gsskrb5-private.h @@ -661,6 +661,7 @@ _gsskrb5cfx_max_wrap_length_cfx ( krb5_error_code _gsskrb5cfx_wrap_length_cfx ( + const gsskrb5_ctx /*context_handle*/, krb5_context /*context*/, krb5_crypto /*crypto*/, int /*conf_req_flag*/, -- cgit From 50fb2059c023600259e21051a29d1613ef19459f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Fri, 8 Aug 2008 12:39:11 +0200 Subject: gensec_gssapi: use the correct signature size for cfx/rfc4121 style signatures metze (This used to be commit fcabe24f96c9677146ca754a502f336c23050339) --- source4/auth/gensec/gensec_gssapi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source4/auth/gensec/gensec_gssapi.c b/source4/auth/gensec/gensec_gssapi.c index 0b1b9d851c..ff4a23e7fc 100644 --- a/source4/auth/gensec/gensec_gssapi.c +++ b/source4/auth/gensec/gensec_gssapi.c @@ -1416,7 +1416,7 @@ size_t gensec_gssapi_sig_size(struct gensec_security *gensec_security, size_t da * TODO: windows uses 76 here, but we don't know * gss_wrap works with aes keys yet */ - gensec_gssapi_state->sig_size = 60; + gensec_gssapi_state->sig_size = 76; } else { gensec_gssapi_state->sig_size = 28; } -- cgit From 802b4596feabb454a3d573ac9db34a72bc3ca0f9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2008 17:59:38 +0200 Subject: dcerpc.idl: add DCERPC_AUTH_TRAILER_LENGTH metze (This used to be commit ce36448d74b0c6cdf8928e10c088bf0248a95cf7) --- source4/librpc/idl/dcerpc.idl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl index e54bc2c29f..0fb94e9672 100644 --- a/source4/librpc/idl/dcerpc.idl +++ b/source4/librpc/idl/dcerpc.idl @@ -154,6 +154,8 @@ interface dcerpc [flag(NDR_REMAINING)] DATA_BLOB credentials; } dcerpc_auth; + const uint8 DCERPC_AUTH_TRAILER_LENGTH = 8; + typedef [public] struct { uint32 _pad; [flag(NDR_REMAINING)] DATA_BLOB auth_info; -- cgit From eb81a62d142883f3cef3da4ba29675b70b515883 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2008 18:00:11 +0200 Subject: librpc/rpc: correct the chunk_size depending on the signature size metze (This used to be commit 50eb0e726405580dc5ca3a8a3b15f3bd674f722a) --- source4/librpc/rpc/dcerpc.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/source4/librpc/rpc/dcerpc.c b/source4/librpc/rpc/dcerpc.c index a6c7e0020d..28b5cd65a9 100644 --- a/source4/librpc/rpc/dcerpc.c +++ b/source4/librpc/rpc/dcerpc.c @@ -334,6 +334,7 @@ static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX */ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx, + size_t sig_size, struct ncacn_packet *pkt) { NTSTATUS status; @@ -384,8 +385,7 @@ static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c, * GENSEC mech does AEAD signing of the packet * headers */ c->security_state.auth_info->credentials - = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state, - payload_length)); + = data_blob_talloc(mem_ctx, NULL, sig_size); data_blob_clear(&c->security_state.auth_info->credentials); break; @@ -1042,6 +1042,7 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c) DATA_BLOB blob; uint32_t remaining, chunk_size; bool first_packet = true; + size_t sig_size = 0; req = c->request_queue; if (req == NULL) { @@ -1065,7 +1066,15 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c) /* we can write a full max_recv_frag size, minus the dcerpc request header size */ - chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH); + chunk_size = p->conn->srv_max_recv_frag; + chunk_size -= DCERPC_REQUEST_LENGTH; + if (c->security_state.generic_state) { + chunk_size -= DCERPC_AUTH_TRAILER_LENGTH; + sig_size = gensec_sig_size(c->security_state.generic_state, + p->conn->srv_max_recv_frag); + chunk_size -= sig_size; + chunk_size -= (chunk_size % 16); + } pkt.ptype = DCERPC_PKT_REQUEST; pkt.call_id = req->call_id; @@ -1101,7 +1110,7 @@ static void dcerpc_ship_next_request(struct dcerpc_connection *c) (stub_data->length - remaining); pkt.u.request.stub_and_verifier.length = chunk; - req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt); + req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt); if (!NT_STATUS_IS_OK(req->status)) { req->state = RPC_REQUEST_DONE; DLIST_REMOVE(p->conn->pending, req); -- cgit From 97f59cb1902eec0fba610da6c13d7089ea7d7576 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2008 18:12:54 +0200 Subject: rpc_server: correct the chunk_size depending on the signature size metze (This used to be commit 20fc0d7bfdaa60d6a8ac939dc64733a91652587e) --- source4/rpc_server/dcerpc_server.c | 13 +++++++++++-- source4/rpc_server/dcesrv_auth.c | 7 +++---- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index a336ddb339..fa7b8d26f5 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -917,6 +917,7 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call) DATA_BLOB stub; uint32_t total_length, chunk_size; struct dcesrv_connection_context *context = call->context; + size_t sig_size = 0; /* call the reply function */ status = context->iface->reply(call, call, call->r); @@ -948,7 +949,15 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call) /* we can write a full max_recv_frag size, minus the dcerpc request header size */ - chunk_size = call->conn->cli_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH); + chunk_size = call->conn->cli_max_recv_frag; + chunk_size -= DCERPC_REQUEST_LENGTH; + if (call->conn->auth_state.gensec_security) { + chunk_size -= DCERPC_AUTH_TRAILER_LENGTH; + sig_size = gensec_sig_size(call->conn->auth_state.gensec_security, + call->conn->cli_max_recv_frag); + chunk_size -= sig_size; + chunk_size -= (chunk_size % 16); + } do { uint32_t length; @@ -978,7 +987,7 @@ _PUBLIC_ NTSTATUS dcesrv_reply(struct dcesrv_call_state *call) pkt.u.response.stub_and_verifier.data = stub.data; pkt.u.response.stub_and_verifier.length = length; - if (!dcesrv_auth_response(call, &rep->blob, &pkt)) { + if (!dcesrv_auth_response(call, &rep->blob, sig_size, &pkt)) { return dcesrv_fault(call, DCERPC_FAULT_OTHER); } diff --git a/source4/rpc_server/dcesrv_auth.c b/source4/rpc_server/dcesrv_auth.c index 64f42eea25..0aad3775d0 100644 --- a/source4/rpc_server/dcesrv_auth.c +++ b/source4/rpc_server/dcesrv_auth.c @@ -398,7 +398,8 @@ bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet) push a signed or sealed dcerpc request packet into a blob */ bool dcesrv_auth_response(struct dcesrv_call_state *call, - DATA_BLOB *blob, struct ncacn_packet *pkt) + DATA_BLOB *blob, size_t sig_size, + struct ncacn_packet *pkt) { struct dcesrv_connection *dce_conn = call->conn; NTSTATUS status; @@ -445,9 +446,7 @@ bool dcesrv_auth_response(struct dcesrv_call_state *call, * GENSEC mech does AEAD signing of the packet * headers */ dce_conn->auth_state.auth_info->credentials - = data_blob_talloc(call, NULL, - gensec_sig_size(dce_conn->auth_state.gensec_security, - payload_length)); + = data_blob_talloc(call, NULL, sig_size); data_blob_clear(&dce_conn->auth_state.auth_info->credentials); } -- cgit From 0965b22ec561588201a3a79f1f1e316834c8ce0b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 11 Aug 2008 18:14:51 +0200 Subject: dcerpc.idl: remove used DCERPC_MAX_SIGN_SIZE metze (This used to be commit 54b873e49ff363609632fa2862208bf6b4c1b6ed) --- source4/librpc/idl/dcerpc.idl | 1 - 1 file changed, 1 deletion(-) diff --git a/source4/librpc/idl/dcerpc.idl b/source4/librpc/idl/dcerpc.idl index 0fb94e9672..1c6574b11b 100644 --- a/source4/librpc/idl/dcerpc.idl +++ b/source4/librpc/idl/dcerpc.idl @@ -30,7 +30,6 @@ interface dcerpc } dcerpc_bind; const uint8 DCERPC_REQUEST_LENGTH = 24; - const uint8 DCERPC_MAX_SIGN_SIZE = 64; typedef struct { } dcerpc_empty; -- cgit