From: Luke Howard Date: Mon, 27 Apr 2020 04:52:10 +0000 (+1000) Subject: gss: update SAnon for draft-howard-gss-sanon-13 X-Git-Url: http://git.samba.org/?p=metze%2Fheimdal%2Fwip.git;a=commitdiff_plain;h=c785af8b62cc2e4e709645d2824917bb2410a5f5 gss: update SAnon for draft-howard-gss-sanon-13 draft-howard-gss-sanon-13 will move extended (RFC4757) flags from the NegoEx metadata to an optional component of the initial context token --- diff --git a/lib/gssapi/sanon/accept_sec_context.c b/lib/gssapi/sanon/accept_sec_context.c index bcaa3316d..51ba51a0a 100644 --- a/lib/gssapi/sanon/accept_sec_context.c +++ b/lib/gssapi/sanon/accept_sec_context.c @@ -48,8 +48,10 @@ _gss_sanon_accept_sec_context(OM_uint32 *minor, OM_uint32 major, tmp; sanon_ctx sc = (sanon_ctx)*context_handle; gss_buffer_desc mech_input_token = GSS_C_EMPTY_BUFFER; + gss_buffer_desc initiator_pk = GSS_C_EMPTY_BUFFER; gss_buffer_desc hok_mic = GSS_C_EMPTY_BUFFER; gss_buffer_desc session_key = GSS_C_EMPTY_BUFFER; + OM_uint32 req_flags = 0; if (output_token == GSS_C_NO_BUFFER) { *minor = EINVAL; @@ -62,7 +64,7 @@ _gss_sanon_accept_sec_context(OM_uint32 *minor, if (input_token == GSS_C_NO_BUFFER) { major = GSS_S_DEFECTIVE_TOKEN; goto out; - } else if (sc != NULL && sc->rfc4121 != GSS_C_NO_CONTEXT) { + } else if (sc != NULL) { major = GSS_S_BAD_STATUS; goto out; } @@ -73,30 +75,50 @@ _gss_sanon_accept_sec_context(OM_uint32 *minor, if (major != GSS_S_COMPLETE) goto out; + sc = calloc(1, sizeof(*sc)); if (sc == NULL) { - sc = calloc(1, sizeof(*sc)); - if (sc == NULL) { - *minor = ENOMEM; - major = GSS_S_FAILURE; - goto out; - } + *minor = ENOMEM; + major = GSS_S_FAILURE; + goto out; + } + + /* initiator token can include optional 64-bit flags */ + if (mech_input_token.length != crypto_scalarmult_curve25519_BYTES && + mech_input_token.length != crypto_scalarmult_curve25519_BYTES + 8) { + *minor = 0; + major = GSS_S_DEFECTIVE_TOKEN; + goto out; } + initiator_pk = mech_input_token; + initiator_pk.length = crypto_scalarmult_curve25519_BYTES; + /* compute public and secret keys */ major = _gss_sanon_curve25519_base(minor, sc); if (major != GSS_S_COMPLETE) goto out; + if (mech_input_token.length > crypto_scalarmult_curve25519_BYTES) { + /* extra flags */ + uint8_t *p = (uint8_t *)mech_input_token.value + crypto_scalarmult_curve25519_BYTES; + uint32_t dummy; + + _gss_mg_decode_be_uint32(p, &dummy); /* upper 32 bits presently unused */ + _gss_mg_decode_be_uint32(&p[4], &req_flags); + } + + req_flags &= SANON_PROTOCOL_FLAG_MASK; /* do not let initiator set any other flags */ + /* compute shared secret */ - major = _gss_sanon_curve25519(minor, sc, &mech_input_token, + major = _gss_sanon_curve25519(minor, sc, &initiator_pk, req_flags, input_chan_bindings, &session_key); if (major != GSS_S_COMPLETE) goto out; - sc->flags |= GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | + req_flags |= GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG | GSS_C_ANON_FLAG | GSS_C_TRANS_FLAG; - major = _gss_sanon_import_rfc4121_context(minor, sc, &session_key); + major = _gss_sanon_import_rfc4121_context(minor, sc, req_flags, &session_key); if (major != GSS_S_COMPLETE) goto out; @@ -124,7 +146,7 @@ _gss_sanon_accept_sec_context(OM_uint32 *minor, if (src_name) *src_name = _gss_sanon_anonymous_identity; if (ret_flags) - *ret_flags = sc->flags; + *ret_flags = req_flags; if (time_rec) *time_rec = GSS_C_INDEFINITE; diff --git a/lib/gssapi/sanon/crypto.c b/lib/gssapi/sanon/crypto.c index 69d175476..0c7a67f70 100644 --- a/lib/gssapi/sanon/crypto.c +++ b/lib/gssapi/sanon/crypto.c @@ -239,6 +239,7 @@ OM_uint32 _gss_sanon_curve25519(OM_uint32 *minor, sanon_ctx sc, gss_buffer_t pk, + OM_uint32 gss_flags, const gss_channel_bindings_t input_chan_bindings, gss_buffer_t session_key) { @@ -268,7 +269,7 @@ _gss_sanon_curve25519(OM_uint32 *minor, kdf_label.length = sizeof("sanon-x25519") - 1; ret = krb5_data_alloc(&kdf_context, - 2 * crypto_scalarmult_curve25519_BYTES + + 2 * crypto_scalarmult_curve25519_BYTES + 8 + (input_chan_bindings ? input_chan_bindings->application_data.length : 0)); if (ret != 0) { krb5_free_context(context); @@ -285,11 +286,15 @@ _gss_sanon_curve25519(OM_uint32 *minor, memcpy(p, pk->value, pk->length); memcpy(&p[sizeof(sc->pk)], sc->pk, sizeof(sc->pk)); } + p += 2 * crypto_scalarmult_curve25519_BYTES; + _gss_mg_encode_be_uint32(0, p); /* upper 32 bits presently unused */ + p += 4; + _gss_mg_encode_be_uint32(gss_flags, p); + p += 4; if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS && input_chan_bindings->application_data.value != NULL) { - memcpy(&p[2 * crypto_scalarmult_curve25519_BYTES], - input_chan_bindings->application_data.value, + memcpy(p, input_chan_bindings->application_data.value, input_chan_bindings->application_data.length); } @@ -318,9 +323,10 @@ _gss_sanon_curve25519(OM_uint32 *minor, OM_uint32 _gss_sanon_import_rfc4121_context(OM_uint32 *minor, sanon_ctx sc, + OM_uint32 gss_flags, gss_const_buffer_t session_key) { - return _gss_mg_import_rfc4121_context(minor, sc->is_initiator, sc->flags, + return _gss_mg_import_rfc4121_context(minor, sc->is_initiator, gss_flags, KRB5_ENCTYPE_AES128_CTS_HMAC_SHA256_128, session_key, &sc->rfc4121); } diff --git a/lib/gssapi/sanon/init_sec_context.c b/lib/gssapi/sanon/init_sec_context.c index c553bbdb4..be61aba9b 100644 --- a/lib/gssapi/sanon/init_sec_context.c +++ b/lib/gssapi/sanon/init_sec_context.c @@ -99,12 +99,13 @@ _gss_sanon_init_sec_context(OM_uint32 *minor, } flags |= GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | GSS_C_CONF_FLAG | - GSS_C_INTEG_FLAG | GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG | - GSS_C_EXTENDED_ERROR_FLAG; /* supported flags */ + GSS_C_INTEG_FLAG | SANON_PROTOCOL_FLAG_MASK; /* supported flags */ flags &= req_flags; flags |= GSS_C_ANON_FLAG; /* always set this flag */ if (sc == NULL) { + uint8_t pk_and_flags[crypto_scalarmult_curve25519_BYTES + 8]; + if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) { major = GSS_S_DEFECTIVE_TOKEN; goto out; @@ -118,15 +119,23 @@ _gss_sanon_init_sec_context(OM_uint32 *minor, } sc->is_initiator = 1; - sc->flags = req_flags; /* compute public and secret keys */ major = _gss_sanon_curve25519_base(minor, sc); if (major != GSS_S_COMPLETE) goto out; - mech_token.length = sizeof(sc->pk); - mech_token.value = sc->pk; + if (req_flags & SANON_PROTOCOL_FLAG_MASK) { + memcpy(pk_and_flags, sc->pk, sizeof(sc->pk)); + _gss_mg_encode_be_uint32(0, &pk_and_flags[sizeof(sc->pk)]); + _gss_mg_encode_be_uint32(req_flags & SANON_PROTOCOL_FLAG_MASK, + &pk_and_flags[sizeof(sc->pk) + 4]); + mech_token.length = sizeof(pk_and_flags); + mech_token.value = pk_and_flags; + } else { + mech_token.length = sizeof(sc->pk); + mech_token.value = sc->pk; + } /* send public key to acceptor */ major = gss_encapsulate_token(&mech_token, @@ -154,14 +163,14 @@ _gss_sanon_init_sec_context(OM_uint32 *minor, pk.value = input_token->value; /* compute shared secret */ - major = _gss_sanon_curve25519(minor, sc, &pk, input_chan_bindings, &session_key); + major = _gss_sanon_curve25519(minor, sc, &pk, flags & SANON_PROTOCOL_FLAG_MASK, + input_chan_bindings, &session_key); if (major != GSS_S_COMPLETE) goto out; flags |= GSS_C_TRANS_FLAG; - sc->flags |= GSS_C_TRANS_FLAG; - major = _gss_sanon_import_rfc4121_context(minor, sc, &session_key); + major = _gss_sanon_import_rfc4121_context(minor, sc, flags, &session_key); if (major != GSS_S_COMPLETE) goto out; diff --git a/lib/gssapi/sanon/inquire_context.c b/lib/gssapi/sanon/inquire_context.c index bec1d5088..f5aa727b5 100644 --- a/lib/gssapi/sanon/inquire_context.c +++ b/lib/gssapi/sanon/inquire_context.c @@ -64,7 +64,8 @@ _gss_sanon_inquire_context(OM_uint32 *minor, if (open_context) *open_context = 0; if (ctx_flags) - *ctx_flags = sc->flags; + *ctx_flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG | + GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG | GSS_C_ANON_FLAG; } else { major = gss_inquire_context(minor, sc->rfc4121, NULL, NULL, NULL, NULL, ctx_flags, locally_initiated, diff --git a/lib/gssapi/sanon/negoex.c b/lib/gssapi/sanon/negoex.c index 86df155aa..c6a21dd2b 100644 --- a/lib/gssapi/sanon/negoex.c +++ b/lib/gssapi/sanon/negoex.c @@ -97,19 +97,6 @@ _gss_sanon_inquire_negoex_key(OM_uint32 *minor, return major; } -static OM_uint32 -make_flags_meta_data(OM_uint32 *minor, - OM_uint32 flags, - gss_buffer_t meta_data) -{ - uint8_t data[4]; - gss_buffer_desc buffer = { sizeof(data), data }; - - _gss_mg_encode_le_uint32(flags, data); - - return _gss_copy_buffer(minor, &buffer, meta_data); -} - OM_uint32 GSSAPI_CALLCONV _gssspi_sanon_query_meta_data(OM_uint32 *minor, gss_const_OID mech_oid, @@ -119,45 +106,13 @@ _gssspi_sanon_query_meta_data(OM_uint32 *minor, OM_uint32 req_flags, gss_buffer_t meta_data) { - OM_uint32 major; - int local = (targ_name != GSS_C_NO_NAME); + int is_initiator = (targ_name != GSS_C_NO_NAME); *minor = 0; - if (local) { - if (!_gss_sanon_available_p(cred_handle, targ_name, req_flags)) - return GSS_S_UNAVAILABLE; - - /* - * Obscure Windows interoperability hack: use metadata to convey - * RFC4757 extended flags from initiator to acceptor. - */ - req_flags &= (GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG); - if (req_flags) { - major = make_flags_meta_data(minor, req_flags, meta_data); - if (major != GSS_S_COMPLETE) - return major; - } - } - - return GSS_S_COMPLETE; -} - -static OM_uint32 -parse_flags_meta_data(OM_uint32 *minor, - gss_const_buffer_t meta_data, - OM_uint32 *flags) -{ - *minor = 0; - *flags = 0; - - if (meta_data->length == 0) - return GSS_S_COMPLETE; - - if (meta_data->length < 4) - return GSS_S_DEFECTIVE_TOKEN; - - _gss_mg_decode_le_uint32(meta_data->value, flags); + if (is_initiator && + !_gss_sanon_available_p(cred_handle, targ_name, req_flags)) + return GSS_S_UNAVAILABLE; return GSS_S_COMPLETE; } @@ -171,30 +126,6 @@ _gssspi_sanon_exchange_meta_data(OM_uint32 *minor, OM_uint32 req_flags, gss_const_buffer_t meta_data) { - sanon_ctx sc = (sanon_ctx)*context_handle; - int local = (targ_name != GSS_C_NO_NAME); - OM_uint32 major, init_flags; - *minor = 0; - - if (local) - return GSS_S_COMPLETE; - - if (sc == NULL) { - sc = calloc(1, sizeof(*sc)); - if (sc == NULL) { - *minor = ENOMEM; - return GSS_S_FAILURE; - } - *context_handle = (gss_ctx_id_t)sc; - } - - major = parse_flags_meta_data(minor, meta_data, &init_flags); - if (major != GSS_S_COMPLETE) - return major; - - init_flags &= ~(GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG); - sc->flags |= init_flags | req_flags; - return GSS_S_COMPLETE; } diff --git a/lib/gssapi/sanon/sanon_locl.h b/lib/gssapi/sanon/sanon_locl.h index 9d853b6fc..7b3c4780a 100644 --- a/lib/gssapi/sanon/sanon_locl.h +++ b/lib/gssapi/sanon/sanon_locl.h @@ -48,11 +48,9 @@ typedef struct sanon_ctx_desc { uint8_t sk[crypto_scalarmult_curve25519_BYTES]; /* X25519 ECDH public key */ uint8_t pk[crypto_scalarmult_curve25519_BYTES]; - /* GSS_C_*_FLAG */ - uint32_t flags; /* krb5 context for message protection/PRF */ gss_ctx_id_t rfc4121; - int is_initiator; + int is_initiator : 1; } *sanon_ctx; extern gss_name_t _gss_sanon_anonymous_identity; @@ -80,4 +78,7 @@ buffer_equal_p(gss_const_buffer_t b1, gss_const_buffer_t b2) memcmp(b1->value, b2->value, b2->length) == 0; } +/* flags that are valid to be sent from a SAnon initiator in the flags field */ +#define SANON_PROTOCOL_FLAG_MASK ( GSS_C_DCE_STYLE | GSS_C_IDENTIFY_FLAG | GSS_C_EXTENDED_ERROR_FLAG ) + #endif /* SANON_LOCL_H */