From 26a69856f624b2d5e375ce348d1f559e0d404a7b Mon Sep 17 00:00:00 2001 From: Luke Howard Date: Tue, 14 Apr 2020 12:36:09 +1000 Subject: [PATCH] gss: GSS_KRB5_IMPORT_RFC4121_CONTEXT_X / _gss_mg_import_rfc4121_context() Add a new private interface (accessed through _gss_mg_import_rfc4121_context()) through which a skeletal krb5 mechanism context can be created, suitable for RFC4121 message protection and PRF services. --- lib/gssapi/Makefile.am | 1 + lib/gssapi/NTMakefile | 2 + lib/gssapi/gssapi/gssapi_oid.h | 3 + lib/gssapi/krb5/set_sec_context_option.c | 115 +++++++++++++++++++++++ lib/gssapi/mech/gss_oid.c | 4 + lib/gssapi/mech/gss_rfc4121.c | 111 ++++++++++++++++++++++ lib/gssapi/mech/utils.h | 8 ++ lib/gssapi/oid.txt | 1 + 8 files changed, 245 insertions(+) create mode 100644 lib/gssapi/mech/gss_rfc4121.c diff --git a/lib/gssapi/Makefile.am b/lib/gssapi/Makefile.am index ee59266f6..8239ef106 100644 --- a/lib/gssapi/Makefile.am +++ b/lib/gssapi/Makefile.am @@ -139,6 +139,7 @@ mechsrc = \ mech/gss_release_name.c \ mech/gss_release_oid.c \ mech/gss_release_oid_set.c \ + mech/gss_rfc4121.c \ mech/gss_seal.c \ mech/gss_set_cred_option.c \ mech/gss_set_name_attribute.c \ diff --git a/lib/gssapi/NTMakefile b/lib/gssapi/NTMakefile index 5093b9867..61dc7e5d8 100644 --- a/lib/gssapi/NTMakefile +++ b/lib/gssapi/NTMakefile @@ -156,6 +156,7 @@ mechsrc = \ mech/gss_release_name.c \ mech/gss_release_oid.c \ mech/gss_release_oid_set.c \ + mech/gss_rfc4121.c \ mech/gss_seal.c \ mech/gss_set_cred_option.c \ mech/gss_set_name_attribute.c \ @@ -404,6 +405,7 @@ libgssapi_OBJs = \ $(OBJ)\mech/gss_release_name.obj \ $(OBJ)\mech/gss_release_oid.obj \ $(OBJ)\mech/gss_release_oid_set.obj \ + $(OBJ)\mech/gss_rfc4121.obj \ $(OBJ)\mech/gss_seal.obj \ $(OBJ)\mech/gss_set_cred_option.obj \ $(OBJ)\mech/gss_set_name_attribute.obj \ diff --git a/lib/gssapi/gssapi/gssapi_oid.h b/lib/gssapi/gssapi/gssapi_oid.h index 751fa491a..55054858d 100644 --- a/lib/gssapi/gssapi/gssapi_oid.h +++ b/lib/gssapi/gssapi/gssapi_oid.h @@ -99,6 +99,9 @@ extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_cred_no_ci_flags_x_oid_desc; extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_import_cred_x_oid_desc; #define GSS_KRB5_IMPORT_CRED_X (&__gss_krb5_import_cred_x_oid_desc) +extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_krb5_import_rfc4121_context_x_oid_desc; +#define GSS_KRB5_IMPORT_RFC4121_CONTEXT_X (&__gss_krb5_import_rfc4121_context_x_oid_desc) + /* glue for gss_inquire_saslname_for_mech */ extern GSSAPI_LIB_VARIABLE gss_OID_desc __gss_c_ma_sasl_mech_name_oid_desc; #define GSS_C_MA_SASL_MECH_NAME (&__gss_c_ma_sasl_mech_name_oid_desc) diff --git a/lib/gssapi/krb5/set_sec_context_option.c b/lib/gssapi/krb5/set_sec_context_option.c index a0e6fd02c..56a30cd07 100644 --- a/lib/gssapi/krb5/set_sec_context_option.c +++ b/lib/gssapi/krb5/set_sec_context_option.c @@ -98,6 +98,119 @@ set_int32(OM_uint32 *minor_status, return GSS_S_COMPLETE; } +/* + * GSS_KRB5_IMPORT_RFC4121_CONTEXT_X is an internal, private interface + * to allow SAnon to create a skeletal context for using RFC4121 message + * protection services. + * + * rfc4121_args ::= initiator_flag || flags || enctype || session key + */ +static OM_uint32 +make_rfc4121_context(OM_uint32 *minor, + krb5_context context, + gss_ctx_id_t *context_handle, + gss_const_buffer_t rfc4121_args) +{ + OM_uint32 major = GSS_S_FAILURE, tmp; + krb5_error_code ret; + krb5_storage *sp = NULL; + gsskrb5_ctx ctx = NULL; + uint8_t initiator_flag; + int32_t enctype; + size_t keysize; + krb5_keyblock *key; + + *minor = 0; + + sp = krb5_storage_from_readonly_mem(rfc4121_args->value, rfc4121_args->length); + if (sp == NULL) { + ret = ENOMEM; + goto out; + } + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST); + + ctx = calloc(1, sizeof(*ctx)); + if (ctx == NULL) { + ret = ENOMEM; + goto out; + } + + ret = krb5_ret_uint8(sp, &initiator_flag); + if (ret != 0) + goto out; + + ret = krb5_ret_uint32(sp, &ctx->flags); + if (ret != 0) + goto out; + + ctx->more_flags = IS_CFX | ACCEPTOR_SUBKEY | OPEN; + if (initiator_flag) + ctx->more_flags |= LOCAL; + + ctx->state = initiator_flag ? INITIATOR_READY : ACCEPTOR_READY; + + ret = krb5_ret_int32(sp, &enctype); + if (ret != 0) + goto out; + + ret = krb5_enctype_keysize(context, enctype, &keysize); + if (ret != 0) + goto out; + + ctx->auth_context = calloc(1, sizeof(*ctx->auth_context)); + if (ctx->auth_context == NULL) { + ret = ENOMEM; + goto out; + } + + key = calloc(1, sizeof(*key)); + if (key == NULL) { + ret = ENOMEM; + goto out; + } + if (initiator_flag) + ctx->auth_context->remote_subkey = key; + else + ctx->auth_context->local_subkey = key; + + key->keytype = enctype; + key->keyvalue.data = malloc(keysize); + if (key->keyvalue.data == NULL) { + ret = ENOMEM; + goto out; + } + + if (krb5_storage_read(sp, key->keyvalue.data, keysize) != keysize) { + ret = EINVAL; + goto out; + } + key->keyvalue.length = keysize; + + ret = krb5_crypto_init(context, key, 0, &ctx->crypto); + if (ret != 0) + goto out; + + major = _gssapi_msg_order_create(minor, &ctx->order, + _gssapi_msg_order_f(ctx->flags), + 0, 0, 1); + if (major != GSS_S_COMPLETE) + goto out; + +out: + krb5_storage_free(sp); + + if (major != GSS_S_COMPLETE) { + if (*minor == 0) + *minor = ret; + _gsskrb5_delete_sec_context(&tmp, (gss_ctx_id_t *)&ctx, GSS_C_NO_BUFFER); + } else { + *context_handle = (gss_ctx_id_t)ctx; + } + + return major; +} + OM_uint32 GSSAPI_CALLCONV _gsskrb5_set_sec_context_option (OM_uint32 *minor_status, @@ -239,6 +352,8 @@ _gsskrb5_set_sec_context_option *minor_status = 0; return GSS_S_COMPLETE; + } else if (gss_oid_equal(desired_object, GSS_KRB5_IMPORT_RFC4121_CONTEXT_X)) { + return make_rfc4121_context(minor_status, context, context_handle, value); } *minor_status = EINVAL; diff --git a/lib/gssapi/mech/gss_oid.c b/lib/gssapi/mech/gss_oid.c index 99eacf4ef..69ff9868c 100644 --- a/lib/gssapi/mech/gss_oid.c +++ b/lib/gssapi/mech/gss_oid.c @@ -94,6 +94,9 @@ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_cred_no_ci_flags_x_oid_desc = { 6, r /* GSS_KRB5_IMPORT_CRED_X - 1.2.752.43.13.30 */ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_import_cred_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x1e") }; +/* GSS_KRB5_IMPORT_RFC4121_CONTEXT_X - 1.2.752.43.13.31 */ +gss_OID_desc GSSAPI_LIB_VARIABLE __gss_krb5_import_rfc4121_context_x_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x1f") }; + /* GSS_C_MA_SASL_MECH_NAME - 1.2.752.43.13.100 */ gss_OID_desc GSSAPI_LIB_VARIABLE __gss_c_ma_sasl_mech_name_oid_desc = { 6, rk_UNCONST("\x2a\x85\x70\x2b\x0d\x64") }; @@ -309,6 +312,7 @@ gss_OID _gss_ot_internal[] = { &__gss_c_ntlm_force_v1_oid_desc, &__gss_krb5_cred_no_ci_flags_x_oid_desc, &__gss_krb5_import_cred_x_oid_desc, + &__gss_krb5_import_rfc4121_context_x_oid_desc, &__gss_c_ma_sasl_mech_name_oid_desc, &__gss_c_ma_mech_name_oid_desc, &__gss_c_ma_mech_description_oid_desc, diff --git a/lib/gssapi/mech/gss_rfc4121.c b/lib/gssapi/mech/gss_rfc4121.c new file mode 100644 index 000000000..97a0833d5 --- /dev/null +++ b/lib/gssapi/mech/gss_rfc4121.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2019-2020, AuriStor, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "mech_locl.h" + +/* + * An internal API (for now) to return a mechglue context handle given + * a session key that can provide RFC 4121 compatible message protection + * and PRF services. Used by SAnon. The implementation of those services + * is currently provided by the krb5 GSS mechanism but that is opaque to + * the caller (minor status codes notwithstanding). + */ +OM_uint32 +_gss_mg_import_rfc4121_context(OM_uint32 *minor, + uint8_t initiator_flag, + OM_uint32 gss_flags, + int32_t rfc3961_enctype, + gss_const_buffer_t session_key, + gss_ctx_id_t *rfc4121_context_handle) +{ + OM_uint32 major = GSS_S_FAILURE, tmpMinor; + krb5_storage *sp; + krb5_error_code ret; + krb5_data d; + gss_buffer_desc rfc4121_args = GSS_C_EMPTY_BUFFER; + + krb5_data_zero(&d); + + *minor = 0; + *rfc4121_context_handle = GSS_C_NO_CONTEXT; + + sp = krb5_storage_emem(); + if (sp == NULL) { + ret = ENOMEM; + goto out; + } + + krb5_storage_set_byteorder(sp, KRB5_STORAGE_BYTEORDER_HOST); + + /* + * The arguments GSS_KRB5_IMPORT_RFC4121_CONTEXT_X are the serialized + * form of initiator_flag || flags || keytype || session_key. The session + * key length is inferred from the keytype. + */ + ret = krb5_store_uint8(sp, initiator_flag); + if (ret != 0) + goto out; + + ret = krb5_store_uint32(sp, gss_flags); + if (ret != 0) + goto out; + + ret = krb5_store_int32(sp, rfc3961_enctype); + if (ret != 0) + goto out; + + if (krb5_storage_write(sp, session_key->value, session_key->length) + != session_key->length) { + ret = ENOMEM; + goto out; + } + + ret = krb5_storage_to_data(sp, &d); + if (ret != 0) + goto out; + + rfc4121_args.length = d.length; + rfc4121_args.value = d.data; + + major = gss_set_sec_context_option(minor, rfc4121_context_handle, + GSS_KRB5_IMPORT_RFC4121_CONTEXT_X, + &rfc4121_args); + +out: + _gss_secure_release_buffer(&tmpMinor, &rfc4121_args); + krb5_storage_free(sp); + + if (major == GSS_S_FAILURE && *minor == 0) + *minor = ret; + + return major; +} + diff --git a/lib/gssapi/mech/utils.h b/lib/gssapi/mech/utils.h index 17fca284a..31104f2e3 100644 --- a/lib/gssapi/mech/utils.h +++ b/lib/gssapi/mech/utils.h @@ -45,3 +45,11 @@ void _gss_mg_encode_le_uint16(uint16_t n, uint8_t *p); void _gss_mg_decode_le_uint16(const void *ptr, uint16_t *n); void _gss_mg_encode_be_uint16(uint16_t n, uint8_t *p); void _gss_mg_decode_be_uint16(const void *ptr, uint16_t *n); + +OM_uint32 +_gss_mg_import_rfc4121_context(OM_uint32 *minor, + uint8_t initiator_flag, + OM_uint32 gss_flags, + int32_t rfc3961_enctype, + gss_const_buffer_t session_key, + gss_ctx_id_t *rfc4121_context_handle); diff --git a/lib/gssapi/oid.txt b/lib/gssapi/oid.txt index 7d56b639a..93bcf443a 100644 --- a/lib/gssapi/oid.txt +++ b/lib/gssapi/oid.txt @@ -35,6 +35,7 @@ oid base GSS_C_NTLM_SESSION_KEY 1.2.752.43.13.27 oid base GSS_C_NTLM_FORCE_V1 1.2.752.43.13.28 oid base GSS_KRB5_CRED_NO_CI_FLAGS_X 1.2.752.43.13.29 oid base GSS_KRB5_IMPORT_CRED_X 1.2.752.43.13.30 +oid base GSS_KRB5_IMPORT_RFC4121_CONTEXT_X 1.2.752.43.13.31 # /* glue for gss_inquire_saslname_for_mech */ oid base GSS_C_MA_SASL_MECH_NAME 1.2.752.43.13.100