static OM_uint32 importKerberosKey(OM_uint32 *minor, unsigned char **pBuf, size_t *pRemain, krb5_cksumtype *checksumType, krb5_enctype *pEncryptionType, krb5_keyblock *pKey) { unsigned char *p = *pBuf; size_t remain = *pRemain; OM_uint32 encryptionType; OM_uint32 length; krb5_context krbContext; krb5_keyblock key; krb5_error_code code; GSSEAP_KRB_INIT(&krbContext); KRB_KEY_INIT(pKey); if (remain < 12) { *minor = GSSEAP_TOK_TRUNC; return GSS_S_DEFECTIVE_TOKEN; } *checksumType = load_uint32_be(&p[0]); encryptionType = load_uint32_be(&p[4]); length = load_uint32_be(&p[8]); if ((length != 0) != (encryptionType != ENCTYPE_NULL)) { *minor = GSSEAP_BAD_CONTEXT_TOKEN; return GSS_S_DEFECTIVE_TOKEN; } if (remain - 12 < length) { *minor = GSSEAP_TOK_TRUNC; return GSS_S_DEFECTIVE_TOKEN; } if (encryptionType != ENCTYPE_NULL) { KRB_KEY_INIT(&key); KRB_KEY_TYPE(&key) = encryptionType; KRB_KEY_LENGTH(&key) = length; KRB_KEY_DATA(&key) = &p[12]; code = krb5_copy_keyblock_contents(krbContext, &key, pKey); if (code != 0) { *minor = code; return GSS_S_FAILURE; } } *pBuf += 12 + length; *pRemain -= 12 + length; *pEncryptionType = encryptionType; *minor = 0; return GSS_S_COMPLETE; }
static OM_uint32 importMechanismOid(OM_uint32 *minor, unsigned char **pBuf, size_t *pRemain, gss_OID *pOid) { OM_uint32 major; unsigned char *p = *pBuf; size_t remain = *pRemain; gss_OID_desc oidBuf; oidBuf.length = load_uint32_be(p); if (remain < 4 + oidBuf.length || oidBuf.length == 0) { *minor = GSSEAP_TOK_TRUNC; return GSS_S_DEFECTIVE_TOKEN; } oidBuf.elements = &p[4]; major = gssEapCanonicalizeOid(minor, &oidBuf, 0, pOid); if (GSS_ERROR(major)) return major; *pBuf += 4 + oidBuf.length; *pRemain -= 4 + oidBuf.length; *minor = 0; return GSS_S_COMPLETE; }
static OM_uint32 importName(OM_uint32 *minor, gss_OID mech, unsigned char **pBuf, size_t *pRemain, gss_name_t *pName) { OM_uint32 major, tmpMinor, flags; unsigned char *p = *pBuf; size_t remain = *pRemain; gss_buffer_desc tmp; if (remain < 4) { *minor = GSSEAP_TOK_TRUNC; return GSS_S_DEFECTIVE_TOKEN; } tmp.length = load_uint32_be(p); if (tmp.length != 0) { if (remain - 4 < tmp.length) { *minor = GSSEAP_TOK_TRUNC; return GSS_S_DEFECTIVE_TOKEN; } tmp.value = p + 4; flags = EXPORT_NAME_FLAG_COMPOSITE; if (mech == GSS_C_NO_OID) flags |= EXPORT_NAME_FLAG_OID; major = gssEapImportNameInternal(minor, &tmp, pName, flags); if (GSS_ERROR(major)) return major; if ((flags & EXPORT_NAME_FLAG_OID) == 0) { major = gssEapCanonicalizeOid(minor, mech, 0, &(*pName)->mechanismUsed); if (GSS_ERROR(major)) { gssEapReleaseName(&tmpMinor, pName); return major; } } } *pBuf += 4 + tmp.length; *pRemain -= 4 + tmp.length; *minor = 0; return GSS_S_COMPLETE; }
OM_uint32 gssEapDecodeInnerTokens(OM_uint32 *minor, const gss_buffer_t buffer, struct gss_eap_token_buffer_set *tokens) { OM_uint32 major, tmpMinor; unsigned char *p; size_t count = 0; size_t remain; tokens->buffers.count = 0; tokens->buffers.elements = NULL; tokens->types = NULL; if (buffer->length == 0) { major = GSS_S_COMPLETE; goto cleanup; } p = (unsigned char *)buffer->value; remain = buffer->length; do { OM_uint32 *ntypes; gss_buffer_desc tokenBuffer, *newTokenBuffers; if (remain < 8) { major = GSS_S_DEFECTIVE_TOKEN; *minor = GSSEAP_TOK_TRUNC; goto cleanup; } if (tokens->buffers.count <= count) { if (count == 0) count = 1; else count *= 2; ntypes = GSSEAP_MALLOC(count * sizeof(OM_uint32)); if (ntypes == NULL) { major = GSS_S_FAILURE; *minor = ENOMEM; goto cleanup; } if (tokens->types != NULL) { memcpy(ntypes, tokens->types, tokens->buffers.count * sizeof(OM_uint32)); GSSEAP_FREE(tokens->types); } tokens->types = ntypes; newTokenBuffers = GSSEAP_MALLOC(count * sizeof(gss_buffer_desc)); if (newTokenBuffers == NULL) { major = GSS_S_FAILURE; *minor = ENOMEM; goto cleanup; } if (tokens->buffers.elements != NULL) { memcpy(newTokenBuffers, tokens->buffers.elements, tokens->buffers.count * sizeof(gss_buffer_desc)); GSSEAP_FREE(tokens->buffers.elements); } tokens->buffers.elements = newTokenBuffers; } tokens->types[tokens->buffers.count] = load_uint32_be(&p[0]); tokenBuffer.length = load_uint32_be(&p[4]); if (remain < 8 + tokenBuffer.length) { major = GSS_S_DEFECTIVE_TOKEN; *minor = GSSEAP_TOK_TRUNC; goto cleanup; } tokenBuffer.value = &p[8]; tokens->buffers.elements[tokens->buffers.count] = tokenBuffer; tokens->buffers.count++; p += 8 + tokenBuffer.length; remain -= 8 + tokenBuffer.length; } while (remain != 0); major = GSS_S_COMPLETE; *minor = 0; cleanup: if (GSS_ERROR(major)) gssEapReleaseInnerTokens(&tmpMinor, tokens, 0); return major; }
static OM_uint32 gssEapImportPartialContext(OM_uint32 *minor, unsigned char **pBuf, size_t *pRemain, gss_ctx_id_t ctx) { OM_uint32 major; unsigned char *p = *pBuf; size_t remain = *pRemain; gss_buffer_desc buf; size_t ctxLength, serverLen; /* Length of partial RADIUS context */ CHECK_REMAIN(4); ctxLength = load_uint32_be(p); UPDATE_REMAIN(4); CHECK_REMAIN(ctxLength); remain = ctxLength; /* check against partial context length */ /* Selected RADIUS server */ CHECK_REMAIN(4); serverLen = load_uint32_be(p); UPDATE_REMAIN(4); if (serverLen != 0) { CHECK_REMAIN(serverLen); ctx->acceptorCtx.radServer = GSSEAP_MALLOC(serverLen + 1); if (ctx->acceptorCtx.radServer == NULL) { *minor = ENOMEM; return GSS_S_FAILURE; } memcpy(ctx->acceptorCtx.radServer, p, serverLen); ctx->acceptorCtx.radServer[serverLen] = '\0'; UPDATE_REMAIN(serverLen); } /* RADIUS state blob */ CHECK_REMAIN(4); buf.length = load_uint32_be(p); UPDATE_REMAIN(4); if (buf.length != 0) { CHECK_REMAIN(buf.length); buf.value = p; major = duplicateBuffer(minor, &buf, &ctx->acceptorCtx.state); if (GSS_ERROR(major)) return major; UPDATE_REMAIN(buf.length); } #ifdef GSSEAP_DEBUG GSSEAP_ASSERT(remain == 0); #endif *pBuf = p; *pRemain -= 4 + ctxLength; return GSS_S_COMPLETE; }
OM_uint32 gssEapImportContext(OM_uint32 *minor, gss_buffer_t token, gss_ctx_id_t ctx) { OM_uint32 major; unsigned char *p = (unsigned char *)token->value; size_t remain = token->length; if (remain < 16) { *minor = GSSEAP_TOK_TRUNC; return GSS_S_DEFECTIVE_TOKEN; } if (load_uint32_be(&p[0]) != EAP_EXPORT_CONTEXT_V1) { *minor = GSSEAP_BAD_CONTEXT_TOKEN; return GSS_S_DEFECTIVE_TOKEN; } ctx->state = load_uint32_be(&p[4]); ctx->flags = load_uint32_be(&p[8]); ctx->gssFlags = load_uint32_be(&p[12]); p += 16; remain -= 16; /* Validate state */ if (GSSEAP_SM_STATE(ctx) < GSSEAP_STATE_INITIAL || GSSEAP_SM_STATE(ctx) > GSSEAP_STATE_ESTABLISHED) return GSS_S_DEFECTIVE_TOKEN; /* Only acceptor can export partial context tokens */ if (CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx)) return GSS_S_DEFECTIVE_TOKEN; major = importMechanismOid(minor, &p, &remain, &ctx->mechanismUsed); if (GSS_ERROR(major)) return major; major = importKerberosKey(minor, &p, &remain, &ctx->checksumType, &ctx->encryptionType, &ctx->rfc3961Key); if (GSS_ERROR(major)) return major; /* Initiator name OID matches the context mechanism, so it's not encoded */ major = importName(minor, ctx->mechanismUsed, &p, &remain, &ctx->initiatorName); if (GSS_ERROR(major)) return major; major = importName(minor, GSS_C_NO_OID, &p, &remain, &ctx->acceptorName); if (GSS_ERROR(major)) return major; /* Check that, if context is established, names are valid */ if (CTX_IS_ESTABLISHED(ctx) && (CTX_IS_INITIATOR(ctx) ? ctx->acceptorName == GSS_C_NO_NAME : ctx->initiatorName == GSS_C_NO_NAME)) { return GSS_S_DEFECTIVE_TOKEN; } if (remain < 24 + sequenceSize(ctx->seqState)) { *minor = GSSEAP_TOK_TRUNC; return GSS_S_DEFECTIVE_TOKEN; } ctx->expiryTime = (time_t)load_uint64_be(&p[0]); ctx->sendSeq = load_uint64_be(&p[8]); ctx->recvSeq = load_uint64_be(&p[16]); p += 24; remain -= 24; major = sequenceInternalize(minor, &ctx->seqState, &p, &remain); if (GSS_ERROR(major)) return major; #ifdef GSSEAP_ENABLE_ACCEPTOR /* * The partial context should only be expected for unestablished * acceptor contexts. */ if (!CTX_IS_INITIATOR(ctx) && !CTX_IS_ESTABLISHED(ctx) && (ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) { major = gssEapImportPartialContext(minor, &p, &remain, ctx); if (GSS_ERROR(major)) return major; } #ifdef GSSEAP_DEBUG GSSEAP_ASSERT(remain == 0); #endif #endif /* GSSEAP_ENABLE_ACCEPTOR */ major = GSS_S_COMPLETE; *minor = 0; return major; }