util_cksum.c \
util_cred.c \
util_crypt.c \
+ util_krb.c \
util_mech.c \
util_name.c \
util_oid.c \
gss_name_t name2,
int *name_equal)
{
- GSSEAP_NOT_IMPLEMENTED;
+ OM_uint32 major;
+ krb5_context context;
+
+ GSSEAP_KRB_INIT(&context);
}
enum eap_gss_state state;
OM_uint32 flags;
OM_uint32 gssFlags;
- krb5_context kerberosCtx;
gss_OID mechanismUsed;
krb5_enctype encryptionType;
krb5_cksumtype checksumType;
- krb5_keyblock *rfc3961Key;
+ krb5_keyblock rfc3961Key;
gss_name_t initiatorName;
gss_name_t acceptorName;
time_t expiryTime;
#define TOK_FLAG_WRAP_CONFIDENTIAL 0x02
#define TOK_FLAG_ACCEPTOR_SUBKEY 0x04
-#define KEY_USAGE_ACCEPTOR_SEAL 512
-#define KEY_USAGE_ACCEPTOR_SIGN 513
-#define KEY_USAGE_INITIATOR_SEAL 514
-#define KEY_USAGE_INITIATOR_SIGN 515
+#define KEY_USAGE_ACCEPTOR_SEAL 22
+#define KEY_USAGE_ACCEPTOR_SIGN 23
+#define KEY_USAGE_INITIATOR_SEAL 24
+#define KEY_USAGE_INITIATOR_SIGN 25
/* wrap_iov.c */
OM_uint32
size_t prflen;
krb5_data t, ns;
unsigned char *p;
+ krb5_context krbContext;
prf_out->length = 0;
prf_out->value = NULL;
if (!CTX_IS_ESTABLISHED(ctx))
return GSS_S_NO_CONTEXT;
+ GSSEAP_KRB_INIT(&krbContext);
+
t.length = 0;
t.data = NULL;
}
prf_out->length = desired_output_len;
- code = krb5_c_prf_length(ctx->kerberosCtx,
+ code = krb5_c_prf_length(krbContext,
ctx->encryptionType,
&prflen);
if (code != 0)
while (desired_output_len > 0) {
store_uint32_be(i, ns.data);
- code = krb5_c_prf(ctx->kerberosCtx, ctx->rfc3961Key, &ns, &t);
+ code = krb5_c_prf(krbContext, &ctx->rfc3961Key, &ns, &t);
if (code != 0)
goto cleanup;
cleanup:
if (code != 0)
gss_release_buffer(&tmpMinor, prf_out);
- krb5_free_data_contents(ctx->kerberosCtx, &ns);
- krb5_free_data_contents(ctx->kerberosCtx, &t);
+ krb5_free_data_contents(krbContext, &ns);
+ krb5_free_data_contents(krbContext, &t);
*minor = code;
return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
int valid = 0;
krb5_cksumtype cksumtype;
int conf_flag = 0;
+ krb5_context krbContext;
+
+ GSSEAP_KRB_INIT(&krbContext);
*minor = 0;
rrc = load_uint16_be(ptr + 6);
seqnum = load_uint64_be(ptr + 8);
- code = krb5_c_crypto_length(ctx->kerberosCtx,
+ code = krb5_c_crypto_length(krbContext,
ctx->encryptionType,
conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
KRB5_CRYPTO_TYPE_CHECKSUM,
unsigned char *althdr;
/* Decrypt */
- code = gssEapDecrypt(ctx->kerberosCtx,
+ code = gssEapDecrypt(krbContext,
((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
- ec, rrc, ctx->rfc3961Key,
+ ec, rrc, &ctx->rfc3961Key,
keyUsage, 0, iov, iov_count);
if (code != 0) {
*minor = code;
store_uint16_be(0, ptr + 4);
store_uint16_be(0, ptr + 6);
- code = gssEapVerify(ctx->kerberosCtx, cksumtype, rrc,
- ctx->rfc3961Key, keyUsage,
+ code = gssEapVerify(krbContext, cksumtype, rrc,
+ &ctx->rfc3961Key, keyUsage,
iov, iov_count, &valid);
if (code != 0 || valid == FALSE) {
*minor = code;
goto defective;
seqnum = load_uint64_be(ptr + 8);
- code = gssEapVerify(ctx->kerberosCtx, cksumtype, 0,
- ctx->rfc3961Key, keyUsage,
+ code = gssEapVerify(krbContext, cksumtype, 0,
+ &ctx->rfc3961Key, keyUsage,
iov, iov_count, &valid);
if (code != 0 || valid == FALSE) {
*minor = code;
{
unsigned char *ptr;
OM_uint32 code = 0, major = GSS_S_FAILURE;
- krb5_context context = ctx->kerberosCtx;
+ krb5_context krbContext;
int conf_req_flag, toktype2;
int i = 0, j;
gss_iov_buffer_desc *tiov = NULL;
gss_iov_buffer_t stream, data = NULL;
gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer;
+ GSSEAP_KRB_INIT(&krbContext);
+
assert(toktype == TOK_TYPE_WRAP);
if (toktype != TOK_TYPE_WRAP || (ctx->gssFlags & GSS_C_DCE_STYLE)) {
}
if (conf_req_flag) {
- code = krb5_c_crypto_length(context, ctx->encryptionType,
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
if (code != 0)
goto cleanup;
}
/* no PADDING for CFX, EC is used instead */
- code = krb5_c_crypto_length(context, ctx->encryptionType,
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
conf_req_flag
? KRB5_CRYPTO_TYPE_TRAILER
: KRB5_CRYPTO_TYPE_CHECKSUM,
int
gssEapAllocIov(gss_iov_buffer_t iov, size_t size);
+OM_uint32
+gssEapDeriveRFC3961Key(OM_uint32 *minor,
+ gss_buffer_t msk,
+ krb5_enctype enctype,
+ krb5_keyblock *pKey);
+
+/* util_krb.c */
+OM_uint32
+gssEapKerberosInit(OM_uint32 *minor, krb5_context *context);
+
+#define GSSEAP_KRB_INIT(ctx) do { \
+ OM_uint32 tmpMajor; \
+ tmpMajor = gssEapKerberosInit(minor, ctx); \
+ if (GSS_ERROR(tmpMajor)) { \
+ return tmpMajor; \
+ } \
+ } while (0)
+
/* util_mech.c */
void
gssEapInternalizeOid(const gss_OID oid,
#include <pthread.h>
#define GSSEAP_MUTEX pthread_mutex_t
+#define GSSEAP_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
+
#define GSSEAP_MUTEX_INIT(m) pthread_mutex_init((m), NULL)
#define GSSEAP_MUTEX_DESTROY(m) pthread_mutex_destroy((m))
#define GSSEAP_MUTEX_LOCK(m) pthread_mutex_lock((m))
#define GSSEAP_MUTEX_UNLOCK(m) pthread_mutex_unlock((m))
+#define GSSEAP_THREAD_KEY pthread_key_t
+#define GSSEAP_KEY_CREATE(k, d) pthread_key_create((k), (d))
+#define GSSEAP_GETSPECIFIC(k) pthread_getspecific((k))
+#define GSSEAP_SETSPECIFIC(k, d) pthread_setspecific((k), (d))
+
+#define GSSEAP_THREAD_ONCE pthread_once_t
+#define GSSEAP_ONCE(o, i) pthread_once((o), (i))
+#define GSSEAP_ONCE_INITIALIZER PTHREAD_ONCE_INIT
+
/* Helper functions */
static inline void
store_uint16_be(uint16_t val, void *vp)
return GSS_S_FAILURE;
}
- *minor = krb5_init_context(&ctx->kerberosCtx);
- if (*minor != 0) {
- gssEapReleaseContext(&tmpMinor, &ctx);
- return GSS_S_FAILURE;
- }
-
*pCtx = ctx;
return GSS_S_COMPLETE;
{
OM_uint32 major, tmpMinor;
gss_ctx_id_t ctx = *pCtx;
+ krb5_context krbContext = NULL;
if (ctx == GSS_C_NO_CONTEXT) {
return GSS_S_COMPLETE;
}
+ gssEapKerberosInit(&tmpMinor, &krbContext);
+
if (CTX_IS_INITIATOR(ctx)) {
releaseInitiatorContext(&ctx->initiatorCtx);
} else {
releaseAcceptorContext(&ctx->acceptorCtx);
}
- if (ctx->rfc3961Key != NULL) {
- krb5_free_keyblock(ctx->kerberosCtx, ctx->rfc3961Key);
- }
-
- if (ctx->kerberosCtx != NULL) {
- krb5_free_context(ctx->kerberosCtx);
- }
-
+ krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key);
gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
gssEapReleaseName(&tmpMinor, &ctx->acceptorName);
gss_release_oid(&tmpMinor, &ctx->mechanismUsed);
return 0;
}
+
+static char
+keyDerivationConstant[] = "rfc4121-gss-eap";
+
+OM_uint32
+gssEapDeriveRFC3961Key(OM_uint32 *minor,
+ gss_buffer_t msk,
+ krb5_enctype enctype,
+ krb5_keyblock *pKey)
+{
+ krb5_context context;
+ krb5_data data, prf;
+ krb5_keyblock kd;
+ krb5_error_code code;
+ size_t keybytes, keylength, prflength;
+
+ memset(pKey, 0, sizeof(*pKey));
+
+ GSSEAP_KRB_INIT(&context);
+
+ kd.contents = NULL;
+ prf.data = NULL;
+ KRB_KEYTYPE(&kd) = enctype;
+
+ code = krb5_c_keylengths(context, enctype, &keybytes, &keylength);
+ if (code != 0)
+ goto cleanup;
+
+ data.length = msk->length;
+ data.data = (char *)msk->value;
+
+ kd.contents = GSSEAP_MALLOC(keylength);
+ if (kd.contents == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ kd.length = keylength;
+
+ code = krb5_c_random_to_key(context, enctype, &data, &kd);
+ if (code != 0)
+ goto cleanup;
+
+ data.length = sizeof(keyDerivationConstant) - 1;
+ data.data = keyDerivationConstant;
+
+ code = krb5_c_prf_length(context, enctype, &prflength);
+ if (code != 0)
+ goto cleanup;
+
+ prf.length = prflength;
+ prf.data = GSSEAP_MALLOC(prflength);
+ if (data.data == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+
+ code = krb5_c_prf(context, &kd, &data, &prf);
+ if (code != 0)
+ goto cleanup;
+
+ code = krb5_c_random_to_key(context, enctype, &prf, &kd);
+ if (code != 0)
+ goto cleanup;
+
+ *pKey = kd;
+
+cleanup:
+ if (code != 0) {
+ GSSEAP_FREE(kd.contents);
+ }
+
+ GSSEAP_FREE(prf.data);
+
+ *minor = code;
+ return (*minor == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. 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.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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 "gssapiP_eap.h"
+
+static GSSEAP_THREAD_ONCE krbContextKeyOnce = GSSEAP_ONCE_INITIALIZER;
+static GSSEAP_THREAD_KEY krbContextKey;
+
+static void
+destroyKrbContext(void *arg)
+{
+ krb5_context context = (krb5_context)arg;
+
+ if (context != NULL)
+ krb5_free_context(context);
+}
+
+static void
+createKrbContextKey(void)
+{
+ GSSEAP_KEY_CREATE(&krbContextKey, destroyKrbContext);
+}
+
+OM_uint32
+gssEapKerberosInit(OM_uint32 *minor, krb5_context *context)
+{
+ *minor = 0;
+
+ GSSEAP_ONCE(&krbContextKeyOnce, createKrbContextKey);
+
+ *context = GSSEAP_GETSPECIFIC(krbContextKey);
+ if (*context == NULL) {
+ *minor = krb5_init_context(context);
+ if (*minor == 0) {
+ if (GSSEAP_SETSPECIFIC(krbContextKey, *context) != 0) {
+ *minor = errno;
+ krb5_free_context(*context);
+ *context = NULL;
+ }
+ }
+ }
+
+ return *minor == 0 ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
return GSS_S_COMPLETE;
}
-OM_uint32
-gssEapDuplicateName(krb5_context context,
- const gss_name_t src,
- gss_name_t *dst)
-{
-}
-
-krb5_boolean
-gssEapCompareName(krb5_context context,
- gss_name_t name1,
- gss_name_t name2)
-{
-}
size_t rrc = 0;
unsigned int gssHeaderLen, gssTrailerLen;
size_t dataLen, assocDataLen;
+ krb5_context krbContext;
if (!CTX_IS_ESTABLISHED(ctx))
return GSS_S_NO_CONTEXT;
+ GSSEAP_KRB_INIT(&krbContext);
+
acceptorFlag = CTX_IS_INITIATOR(ctx) ? 0 : TOK_FLAG_SENDER_IS_ACCEPTOR;
keyUsage = ((toktype == TOK_TYPE_WRAP)
? (CTX_IS_INITIATOR(ctx)
size_t ec = 0;
size_t confDataLen = dataLen - assocDataLen;
- code = krb5_c_crypto_length(ctx->kerberosCtx, ctx->encryptionType,
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
if (code != 0)
goto cleanup;
- code = krb5_c_padding_length(ctx->kerberosCtx, ctx->encryptionType,
+ code = krb5_c_padding_length(krbContext, ctx->encryptionType,
confDataLen + 16 /* E(Header) */,
&krbPadLen);
if (code != 0)
if (krbPadLen == 0 && (ctx->gssFlags & GSS_C_DCE_STYLE)) {
/* Windows rejects AEAD tokens with non-zero EC */
- code = krb5_c_block_size(ctx->kerberosCtx, ctx->encryptionType, &ec);
+ code = krb5_c_block_size(krbContext, ctx->encryptionType, &ec);
if (code != 0)
goto cleanup;
} else
ec = krbPadLen;
- code = krb5_c_crypto_length(ctx->kerberosCtx, ctx->encryptionType,
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
KRB5_CRYPTO_TYPE_TRAILER, &krbTrailerLen);
if (code != 0)
goto cleanup;
memset(tbuf, 0xFF, ec);
memcpy(tbuf + ec, header->buffer.value, 16);
- code = gssEapEncrypt(ctx->kerberosCtx,
+ code = gssEapEncrypt(krbContext,
((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
- ec, rrc, ctx->rfc3961Key,
+ ec, rrc, &ctx->rfc3961Key,
keyUsage, 0, iov, iov_count);
if (code != 0)
goto cleanup;
gssHeaderLen = 16;
- code = krb5_c_crypto_length(ctx->kerberosCtx, ctx->encryptionType,
+ code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
KRB5_CRYPTO_TYPE_CHECKSUM,
&gssTrailerLen);
if (code != 0)
}
store_64_be(ctx->sendSeq, outbuf + 8);
- code = gssEapSign(ctx->kerberosCtx, ctx->checksumType,
- rrc, ctx->rfc3961Key, keyUsage,
+ code = gssEapSign(krbContext, ctx->checksumType,
+ rrc, &ctx->rfc3961Key, keyUsage,
iov, iov_count);
if (code != 0)
goto cleanup;