gss: GSS_KRB5_IMPORT_RFC4121_CONTEXT_X / _gss_mg_import_rfc4121_context()
authorLuke Howard <lukeh@padl.com>
Tue, 14 Apr 2020 02:36:09 +0000 (12:36 +1000)
committerLuke Howard <lukeh@padl.com>
Fri, 17 Apr 2020 01:04:33 +0000 (11:04 +1000)
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
lib/gssapi/NTMakefile
lib/gssapi/gssapi/gssapi_oid.h
lib/gssapi/krb5/set_sec_context_option.c
lib/gssapi/mech/gss_oid.c
lib/gssapi/mech/gss_rfc4121.c [new file with mode: 0644]
lib/gssapi/mech/utils.h
lib/gssapi/oid.txt

index ee59266f604e11a3e32c59a9cef7e1f73f9bca41..8239ef106d49d97cc148eac0b02c12c6c9380703 100644 (file)
@@ -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 \
index 5093b986752ef4d4f82ae169521cc375d962ce9e..61dc7e5d8458c48410519347245a9c00f7ffb3a0 100644 (file)
@@ -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 \
index 751fa491acc444f90f179405ba9a32f0d61df600..55054858d0d202b171328b514973c4c1afc1607c 100644 (file)
@@ -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)
index a0e6fd02c59a1494dd298523ac66874194705006..56a30cd07cb449b6f0ba8a11c7f54b4aafe0a9e4 100644 (file)
@@ -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;
index 99eacf4efbb7c56e80dba0dc1492324ad1d9b1d3..69ff9868ccfb9df19587e561d5dda062a1f08ea2 100644 (file)
@@ -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 (file)
index 0000000..97a0833
--- /dev/null
@@ -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;
+}
+
index 17fca284a420cf4f0d26816107d549005d7ddd00..31104f2e38526ae71bcdb1248fc99b7ea53721b1 100644 (file)
@@ -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);
index 7d56b639ab23acc1178093aad84b2f23e589d0e7..93bcf443ad2c69eafa31f3c90ed74d82acf61229 100644 (file)
@@ -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