/*
- * Copyright (c) 2010, JANET(UK)
+ * Copyright (c) 2011, JANET(UK)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* or implied warranty.
*/
+/*
+ * Message protection services: unwrap with scatter-gather API.
+ */
+
#include "gssapiP_eap.h"
/*
OM_uint32
unwrapToken(OM_uint32 *minor,
gss_ctx_id_t ctx,
+#ifdef HAVE_HEIMDAL_VERSION
+ krb5_crypto krbCrypto,
+#else
+ krb5_keyblock *unused GSSEAP_UNUSED,
+#endif
int *conf_state,
gss_qop_t *qop_state,
gss_iov_buffer_desc *iov,
int iov_count,
enum gss_eap_token_type toktype)
{
- OM_uint32 code;
+ OM_uint32 major = GSS_S_FAILURE, code;
gss_iov_buffer_t header;
gss_iov_buffer_t padding;
gss_iov_buffer_t trailer;
int valid = 0;
int conf_flag = 0;
krb5_context krbContext;
+#ifdef HAVE_HEIMDAL_VERSION
+ int freeCrypto = (krbCrypto == NULL);
+#endif
GSSEAP_KRB_INIT(&krbContext);
assert(header != NULL);
padding = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
- if (padding != NULL && padding->buffer.length != 0)
- return GSS_S_DEFECTIVE_TOKEN;
+ if (padding != NULL && padding->buffer.length != 0) {
+ code = GSSEAP_BAD_PADDING_IOV;
+ major = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
trailer = gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
ptr = (unsigned char *)header->buffer.value;
- if (header->buffer.length < 16)
- return GSS_S_DEFECTIVE_TOKEN;
+ if (header->buffer.length < 16) {
+ code = GSSEAP_TOK_TRUNC;
+ major = GSS_S_DEFECTIVE_TOKEN;
+ goto cleanup;
+ }
- if ((ptr[2] & flags) != flags)
- return GSS_S_BAD_SIG;
+ if ((ptr[2] & flags) != flags) {
+ code = GSSEAP_BAD_DIRECTION;
+ major = GSS_S_BAD_SIG;
+ goto cleanup;
+ }
+
+#ifdef HAVE_HEIMDAL_VERSION
+ if (krbCrypto == NULL) {
+ code = krb5_crypto_init(krbContext, &ctx->rfc3961Key,
+ ETYPE_NULL, &krbCrypto);
+ if (code != 0)
+ goto cleanup;
+ }
+#endif
if (toktype == TOK_TYPE_WRAP) {
- unsigned int krbTrailerLen;
+ size_t krbTrailerLen;
if (load_uint16_be(ptr) != TOK_TYPE_WRAP)
goto defective;
rrc = load_uint16_be(ptr + 6);
seqnum = load_uint64_be(ptr + 8);
- code = krb5_c_crypto_length(krbContext,
- ctx->encryptionType,
- conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
- KRB5_CRYPTO_TYPE_CHECKSUM,
- &krbTrailerLen);
- if (code != 0) {
- *minor = code;
- return GSS_S_FAILURE;
- }
+ code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
+ conf_flag ? KRB5_CRYPTO_TYPE_TRAILER :
+ KRB5_CRYPTO_TYPE_CHECKSUM,
+ &krbTrailerLen);
+ if (code != 0)
+ goto cleanup;
/* Deal with RRC */
if (trailer == NULL) {
/* Decrypt */
code = gssEapDecrypt(krbContext,
((ctx->gssFlags & GSS_C_DCE_STYLE) != 0),
- ec, rrc, &ctx->rfc3961Key,
- keyUsage, 0, iov, iov_count);
+ ec, rrc, KRB_CRYPTO_CONTEXT(ctx), keyUsage,
+ iov, iov_count);
if (code != 0) {
- *minor = code;
- return GSS_S_BAD_SIG;
+ major = GSS_S_BAD_SIG;
+ goto cleanup;
}
/* Validate header integrity */
|| althdr[2] != ptr[2]
|| althdr[3] != ptr[3]
|| memcmp(althdr + 8, ptr + 8, 8) != 0) {
- *minor = 0;
- return GSS_S_BAD_SIG;
+ code = GSSEAP_BAD_WRAP_TOKEN;
+ major = GSS_S_BAD_SIG;
+ goto cleanup;
}
} else {
/* Verify checksum: note EC is checksum size here, not padding */
store_uint16_be(0, ptr + 6);
code = gssEapVerify(krbContext, ctx->checksumType, rrc,
- &ctx->rfc3961Key, keyUsage,
+ KRB_CRYPTO_CONTEXT(ctx), keyUsage,
iov, iov_count, &valid);
if (code != 0 || valid == FALSE) {
- *minor = code;
- return GSS_S_BAD_SIG;
+ major = GSS_S_BAD_SIG;
+ goto cleanup;
}
}
seqnum = load_uint64_be(ptr + 8);
code = gssEapVerify(krbContext, ctx->checksumType, 0,
- &ctx->rfc3961Key, keyUsage,
+ KRB_CRYPTO_CONTEXT(ctx), keyUsage,
iov, iov_count, &valid);
if (code != 0 || valid == FALSE) {
- *minor = code;
- return GSS_S_BAD_SIG;
+ major = GSS_S_BAD_SIG;
+ goto cleanup;
}
code = sequenceCheck(minor, &ctx->seqState, seqnum);
} else if (toktype == TOK_TYPE_DELETE_CONTEXT) {
goto defective;
}
- *minor = 0;
-
if (conf_state != NULL)
*conf_state = conf_flag;
- return code;
+ code = 0;
+ major = GSS_S_COMPLETE;
+ goto cleanup;
defective:
- *minor = 0;
+ code = GSSEAP_BAD_WRAP_TOKEN;
+ major = GSS_S_DEFECTIVE_TOKEN;
- return GSS_S_DEFECTIVE_TOKEN;
+cleanup:
+ *minor = code;
+#ifdef HAVE_HEIMDAL_VERSION
+ if (freeCrypto && krbCrypto != NULL)
+ krb5_crypto_destroy(krbContext, krbCrypto);
+#endif
+
+ return major;
}
int
gss_iov_buffer_desc *tiov = NULL;
gss_iov_buffer_t stream, data = NULL;
gss_iov_buffer_t theader, tdata = NULL, tpadding, ttrailer;
+#ifdef HAVE_HEIMDAL_VERSION
+ krb5_crypto krbCrypto = NULL;
+#endif
GSSEAP_KRB_INIT(&krbContext);
ttrailer = &tiov[i++];
ttrailer->type = GSS_IOV_BUFFER_TYPE_TRAILER;
+#ifdef HAVE_HEIMDAL_VERSION
+ code = krb5_crypto_init(krbContext, &ctx->rfc3961Key, ETYPE_NULL, &krbCrypto);
+ if (code != 0)
+ goto cleanup;
+#endif
+
{
size_t ec, rrc;
- unsigned int krbHeaderLen = 0;
- unsigned int krbTrailerLen = 0;
+ size_t krbHeaderLen = 0;
+ size_t krbTrailerLen = 0;
conf_req_flag = ((ptr[0] & TOK_FLAG_WRAP_CONFIDENTIAL) != 0);
ec = conf_req_flag ? load_uint16_be(ptr + 2) : 0;
}
if (conf_req_flag) {
- code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
- KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
+ code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
+ KRB5_CRYPTO_TYPE_HEADER, &krbHeaderLen);
if (code != 0)
goto cleanup;
theader->buffer.length += krbHeaderLen; /* length validated later */
}
/* no PADDING for CFX, EC is used instead */
- code = krb5_c_crypto_length(krbContext, ctx->encryptionType,
- conf_req_flag
- ? KRB5_CRYPTO_TYPE_TRAILER
- : KRB5_CRYPTO_TYPE_CHECKSUM,
- &krbTrailerLen);
+ code = krbCryptoLength(krbContext, KRB_CRYPTO_CONTEXT(ctx),
+ conf_req_flag
+ ? KRB5_CRYPTO_TYPE_TRAILER
+ : KRB5_CRYPTO_TYPE_CHECKSUM,
+ &krbTrailerLen);
if (code != 0)
goto cleanup;
if (stream->buffer.length < theader->buffer.length +
tpadding->buffer.length +
ttrailer->buffer.length) {
- code = GSSEAP_WRONG_SIZE;
major = GSS_S_DEFECTIVE_TOKEN;
+ code = GSSEAP_TOK_TRUNC;
goto cleanup;
}
assert(i <= iov_count + 2);
- major = unwrapToken(&code, ctx, conf_state, qop_state,
- tiov, i, toktype);
+ major = unwrapToken(&code, ctx, KRB_CRYPTO_CONTEXT(ctx),
+ conf_state, qop_state, tiov, i, toktype);
if (major == GSS_S_COMPLETE) {
*data = *tdata;
} else if (tdata->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
cleanup:
if (tiov != NULL)
GSSEAP_FREE(tiov);
+#ifdef HAVE_HEIMDAL_VERSION
+ if (krbCrypto != NULL)
+ krb5_crypto_destroy(krbContext, krbCrypto);
+#endif
*minor = code;
{
OM_uint32 major;
- if (ctx->encryptionType == ENCTYPE_NULL)
+ if (ctx->encryptionType == ENCTYPE_NULL) {
+ *minor = GSSEAP_KEY_UNAVAILABLE;
return GSS_S_UNAVAILABLE;
+ }
if (gssEapLocateIov(iov, iov_count, GSS_IOV_BUFFER_TYPE_STREAM) != NULL) {
major = unwrapStream(minor, ctx, conf_state, qop_state,
iov, iov_count, toktype);
} else {
- major = unwrapToken(minor, ctx, conf_state, qop_state,
+ major = unwrapToken(minor, ctx,
+ NULL, /* krbCrypto */
+ conf_state, qop_state,
iov, iov_count, toktype);
}
if (ctx == GSS_C_NO_CONTEXT) {
*minor = EINVAL;
- return GSS_S_NO_CONTEXT;
+ return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
}
*minor = 0;
GSSEAP_MUTEX_LOCK(&ctx->mutex);
if (!CTX_IS_ESTABLISHED(ctx)) {
- *minor = GSSEAP_CONTEXT_INCOMPLETE;
major = GSS_S_NO_CONTEXT;
+ *minor = GSSEAP_CONTEXT_INCOMPLETE;
goto cleanup;
}