OM_uint32 tmpMinor;
gss_ctx_id_t ctx;
- assert(*pCtx == GSS_C_NO_CONTEXT);
+ GSSEAP_ASSERT(*pCtx == GSS_C_NO_CONTEXT);
ctx = (gss_ctx_id_t)GSSEAP_CALLOC(1, sizeof(*ctx));
if (ctx == NULL) {
}
if (GSSEAP_MUTEX_INIT(&ctx->mutex) != 0) {
- *minor = errno;
+ *minor = GSSEAP_GET_LAST_ERROR();
gssEapReleaseContext(&tmpMinor, &ctx);
return GSS_S_FAILURE;
}
ctx->state = GSSEAP_STATE_INITIAL;
+ ctx->mechanismUsed = GSS_C_NO_OID;
/*
* Integrity, confidentiality, sequencing and replay detection are
eap_peer_sm_deinit(ctx->eap);
}
+#ifdef GSSEAP_ENABLE_ACCEPTOR
static void
releaseAcceptorContext(struct gss_eap_acceptor_ctx *ctx)
{
if (ctx->vps != NULL)
gssEapRadiusFreeAvps(&tmpMinor, &ctx->vps);
}
+#endif /* GSSEAP_ENABLE_ACCEPTOR */
OM_uint32
gssEapReleaseContext(OM_uint32 *minor,
if (ctx->flags & CTX_FLAG_KRB_REAUTH) {
gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
} else
-#endif
+#endif /* GSSEAP_ENABLE_REAUTH */
if (CTX_IS_INITIATOR(ctx)) {
releaseInitiatorContext(&ctx->initiatorCtx);
- } else {
+ }
+#ifdef GSSEAP_ENABLE_ACCEPTOR
+ else {
releaseAcceptorContext(&ctx->acceptorCtx);
}
+#endif /* GSSEAP_ENABLE_ACCEPTOR */
krb5_free_keyblock_contents(krbContext, &ctx->rfc3961Key);
gssEapReleaseName(&tmpMinor, &ctx->initiatorName);
gssEapReleaseName(&tmpMinor, &ctx->acceptorName);
gssEapReleaseOid(&tmpMinor, &ctx->mechanismUsed);
sequenceFree(&tmpMinor, &ctx->seqState);
- gssEapReleaseCred(&tmpMinor, &ctx->defaultCred);
+ gssEapReleaseCred(&tmpMinor, &ctx->cred);
GSSEAP_MUTEX_DESTROY(&ctx->mutex);
{
unsigned char *p;
+ GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID);
+
outputToken->length = tokenSize(ctx->mechanismUsed, innerToken->length);
outputToken->value = GSSEAP_MALLOC(outputToken->length);
if (outputToken->value == NULL) {
return GSS_S_COMPLETE;
}
+
+static OM_uint32
+gssEapMakeOrVerifyTokenMIC(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t tokenMIC,
+ int verifyMIC)
+{
+ OM_uint32 major;
+ size_t i = 0, j;
+ enum gss_eap_token_type tokType;
+ OM_uint32 micTokType;
+ unsigned char wireTokType[2];
+ unsigned char *innerTokTypes = NULL, *innerTokLengths = NULL;
+ const struct gss_eap_token_buffer_set *tokens;
+ ssize_t checksumIndex = -1;
+
+ krb5_keyusage usage;
+ krb5_error_code code = 0;
+ krb5_context krbContext;
+ krb5_crypto_iov *kiov = NULL;
+#ifdef HAVE_HEIMDAL_VERSION
+ krb5_crypto krbCrypto = NULL;
+ krb5_cksumtype cksumType;
+#endif
+ size_t kiovCount;
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ tokens = verifyMIC ? ctx->inputTokens : ctx->outputTokens;
+
+ GSSEAP_ASSERT(tokens != NULL);
+
+#ifdef HAVE_HEIMDAL_VERSION
+ code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
+ if (code != 0)
+ goto cleanup;
+#endif
+
+ kiovCount = 2 + (3 * tokens->buffers.count) + 1;
+
+ if (verifyMIC) {
+ assert(tokens->buffers.count != 0);
+ kiovCount -= 3;
+ }
+
+ kiov = GSSEAP_CALLOC(kiovCount, sizeof(*kiov));
+ if (kiov == NULL) {
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+
+ innerTokTypes = GSSEAP_MALLOC(4 * tokens->buffers.count);
+ if (innerTokTypes == NULL) {
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+
+ innerTokLengths = GSSEAP_MALLOC(4 * tokens->buffers.count);
+ if (innerTokLengths == NULL) {
+ *minor = ENOMEM;
+ goto cleanup;
+ }
+
+ /* Mechanism OID */
+ GSSEAP_ASSERT(ctx->mechanismUsed != GSS_C_NO_OID);
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = ctx->mechanismUsed->length;
+ kiov[i].data.data = ctx->mechanismUsed->elements;
+ i++;
+
+ /* Token type */
+ if (CTX_IS_INITIATOR(ctx) ^ verifyMIC) {
+ tokType = TOK_TYPE_INITIATOR_CONTEXT;
+ micTokType = ITOK_TYPE_INITIATOR_MIC;
+ usage = KEY_USAGE_GSSEAP_INITOKEN_MIC;
+ } else {
+ tokType = TOK_TYPE_ACCEPTOR_CONTEXT;
+ micTokType = ITOK_TYPE_ACCEPTOR_MIC;
+ usage = KEY_USAGE_GSSEAP_ACCTOKEN_MIC;
+ }
+ store_uint16_be(tokType, wireTokType);
+
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = sizeof(wireTokType);
+ kiov[i].data.data = (char *)wireTokType;
+ i++;
+
+ for (j = 0; j < tokens->buffers.count; j++) {
+ if (verifyMIC &&
+ (tokens->types[j] & ITOK_TYPE_MASK) == micTokType) {
+ continue;
+ }
+
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = 4;
+ kiov[i].data.data = (char *)&innerTokTypes[j * 4];
+ store_uint32_be(tokens->types[j] & ~(ITOK_FLAG_VERIFIED),
+ kiov[i].data.data);
+ i++;
+
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ kiov[i].data.length = 4;
+ kiov[i].data.data = (char *)&innerTokLengths[j * 4];
+ store_uint32_be(tokens->buffers.elements[j].length,
+ kiov[i].data.data);
+ i++;
+
+ kiov[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
+ gssBufferToKrbData(&tokens->buffers.elements[j], &kiov[i].data);
+ i++;
+ }
+
+ kiov[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
+ if (verifyMIC) {
+ gssBufferToKrbData(tokenMIC, &kiov[i].data);
+ } else {
+ size_t checksumSize;
+
+ code = krb5_c_checksum_length(krbContext, ctx->checksumType,
+ &checksumSize);
+ if (code != 0)
+ goto cleanup;
+
+ kiov[i].data.data = GSSEAP_MALLOC(checksumSize);
+ if (kiov[i].data.data == NULL) {
+ code = ENOMEM;
+ goto cleanup;
+ }
+ kiov[i].data.length = checksumSize;
+ checksumIndex = i;
+ }
+ i++;
+ GSSEAP_ASSERT(i == kiovCount);
+
+#ifdef HAVE_HEIMDAL_VERSION
+ cksumType = ctx->checksumType;
+
+ if (verifyMIC) {
+ code = krb5_verify_checksum_iov(krbContext, krbCrypto, usage,
+ kiov, i, &cksumType);
+ } else {
+ code = krb5_create_checksum_iov(krbContext, krbCrypto, usage,
+ kiov, i, &cksumType);
+ }
+#else
+ if (verifyMIC) {
+ krb5_boolean kvalid = FALSE;
+
+ code = krb5_c_verify_checksum_iov(krbContext, ctx->checksumType,
+ &ctx->rfc3961Key,
+ usage, kiov, i, &kvalid);
+ if (code == 0 && !kvalid) {
+ code = KRB5KRB_AP_ERR_BAD_INTEGRITY;
+ }
+ } else {
+ code = krb5_c_make_checksum_iov(krbContext, ctx->checksumType,
+ &ctx->rfc3961Key,
+ usage, kiov, i);
+ }
+#endif /* HAVE_HEIMDAL_VERSION */
+
+ if (code == 0 && !verifyMIC) {
+ krbDataToGssBuffer(&kiov[checksumIndex].data, tokenMIC);
+ checksumIndex = -1;
+ }
+
+cleanup:
+ if (checksumIndex != -1)
+ GSSEAP_FREE(kiov[checksumIndex].data.data);
+ if (kiov != NULL)
+ GSSEAP_FREE(kiov);
+ if (innerTokTypes != NULL)
+ GSSEAP_FREE(innerTokTypes);
+ if (innerTokLengths != NULL)
+ GSSEAP_FREE(innerTokLengths);
+#ifdef HAVE_HEIMDAL_VERSION
+ if (krbCrypto != NULL)
+ krb5_crypto_destroy(krbContext, krbCrypto);
+#endif
+
+ *minor = code;
+
+ switch (code) {
+ case KRB5KRB_AP_ERR_BAD_INTEGRITY:
+ major = GSS_S_BAD_SIG;
+ break;
+ case 0:
+ major = GSS_S_COMPLETE;
+ break;
+ default:
+ major = GSS_S_FAILURE;
+ break;
+ }
+
+ return major;
+}
+
+OM_uint32
+gssEapMakeTokenMIC(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ gss_buffer_t tokenMIC)
+{
+ tokenMIC->length = 0;
+ tokenMIC->value = NULL;
+
+ return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, FALSE);
+}
+
+OM_uint32
+gssEapVerifyTokenMIC(OM_uint32 *minor,
+ gss_ctx_id_t ctx,
+ const gss_buffer_t tokenMIC)
+{
+ return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, TRUE);
+}