major = gssEapRadiusAddAvp(minor, req,
PW_GSS_ACCEPTOR_SERVICE_NAME,
- VENDORPEC_UKERNA,
+ 0,
&nameBuf);
if (GSS_ERROR(major))
return major;
major = gssEapRadiusAddAvp(minor, req,
PW_GSS_ACCEPTOR_HOST_NAME,
- VENDORPEC_UKERNA,
+ 0,
&nameBuf);
if (GSS_ERROR(major))
return major;
if (KRB_PRINC_LENGTH(krbPrinc) > 2) {
/* Acceptor-Service-Specific */
- krb5_principal_data ssiPrinc = *krbPrinc;
- char *ssi;
-
- KRB_PRINC_LENGTH(&ssiPrinc) -= 2;
- KRB_PRINC_NAME(&ssiPrinc) += 2;
-
- *minor = krb5_unparse_name_flags(krbContext, &ssiPrinc,
- KRB5_PRINCIPAL_UNPARSE_NO_REALM, &ssi);
+ *minor = krbPrincUnparseServiceSpecifics(krbContext,
+ krbPrinc, &nameBuf);
if (*minor != 0)
return GSS_S_FAILURE;
- nameBuf.value = ssi;
- nameBuf.length = strlen(ssi);
-
major = gssEapRadiusAddAvp(minor, req,
- PW_GSS_ACCEPTOR_SERVICE_SPECIFIC,
- VENDORPEC_UKERNA,
+ PW_GSS_ACCEPTOR_SERVICE_SPECIFICS,
+ 0,
&nameBuf);
-
- if (GSS_ERROR(major)) {
- krb5_free_unparsed_name(krbContext, ssi);
+ krbFreeUnparsedName(krbContext, &nameBuf);
+ if (GSS_ERROR(major))
return major;
- }
- krb5_free_unparsed_name(krbContext, ssi);
}
krbPrincRealmToGssBuffer(krbPrinc, &nameBuf);
/* Acceptor-Realm-Name */
major = gssEapRadiusAddAvp(minor, req,
PW_GSS_ACCEPTOR_REALM_NAME,
- VENDORPEC_UKERNA,
+ 0,
&nameBuf);
if (GSS_ERROR(major))
return major;
gss_buffer_t outputToken GSSEAP_UNUSED,
OM_uint32 *smFlags GSSEAP_UNUSED)
{
- OM_uint32 major;
- gss_iov_buffer_desc iov[2];
+ krb5_error_code code;
+ krb5_context krbContext;
+ krb5_data data;
+ krb5_checksum cksum;
+ krb5_boolean valid = FALSE;
- iov[0].type = GSS_IOV_BUFFER_TYPE_DATA | GSS_IOV_BUFFER_FLAG_ALLOCATE;
- iov[0].buffer.length = 0;
- iov[0].buffer.value = NULL;
+ if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS ||
+ chanBindings->application_data.length == 0)
+ return GSS_S_CONTINUE_NEEDED;
- iov[1].type = GSS_IOV_BUFFER_TYPE_STREAM | GSS_IOV_BUFFER_FLAG_ALLOCATED;
+ GSSEAP_KRB_INIT(&krbContext);
- /* XXX necessary because decrypted in place and we verify it later */
- major = duplicateBuffer(minor, inputToken, &iov[1].buffer);
- if (GSS_ERROR(major))
- return major;
+ KRB_DATA_INIT(&data);
- major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
- iov, 2, TOK_TYPE_WRAP);
- if (GSS_ERROR(major)) {
- gssEapReleaseIov(iov, 2);
- return major;
+ gssBufferToKrbData(&chanBindings->application_data, &data);
+
+ KRB_CHECKSUM_INIT(&cksum, ctx->checksumType, inputToken);
+
+ code = krb5_c_verify_checksum(krbContext, &ctx->rfc3961Key,
+ KEY_USAGE_GSSEAP_CHBIND_MIC,
+ &data, &cksum, &valid);
+ if (code != 0) {
+ *minor = code;
+ return GSS_S_FAILURE;
}
- if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS &&
- !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
- major = GSS_S_BAD_BINDINGS;
+ if (valid == FALSE) {
*minor = GSSEAP_BINDINGS_MISMATCH;
- } else {
- major = GSS_S_CONTINUE_NEEDED;
- *minor = 0;
+ return GSS_S_BAD_BINDINGS;
}
- gssEapReleaseIov(iov, 2);
+ ctx->flags |= CTX_FLAG_CHANNEL_BINDINGS_VERIFIED;
- return major;
+ *minor = 0;
+ return GSS_S_CONTINUE_NEEDED;
}
static OM_uint32
gss_OID mech GSSEAP_UNUSED,
OM_uint32 reqFlags GSSEAP_UNUSED,
OM_uint32 timeReq GSSEAP_UNUSED,
- gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings,
gss_buffer_t inputToken,
gss_buffer_t outputToken GSSEAP_UNUSED,
OM_uint32 *smFlags GSSEAP_UNUSED)
{
OM_uint32 major;
+ /*
+ * The channel binding token is optional, however if the caller indicated
+ * bindings we must raise an error if it was absent.
+ *
+ * In the future, we might use a context option to allow the caller to
+ * indicate that missing bindings are acceptable.
+ */
+ if (chanBindings != NULL &&
+ chanBindings->application_data.length != 0 &&
+ (ctx->flags & CTX_FLAG_CHANNEL_BINDINGS_VERIFIED) == 0) {
+ *minor = GSSEAP_MISSING_BINDINGS;
+ return GSS_S_BAD_BINDINGS;
+ }
+
major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
if (GSS_ERROR(major))
return major;
ITOK_TYPE_GSS_CHANNEL_BINDINGS,
ITOK_TYPE_NONE,
GSSEAP_STATE_INITIATOR_EXTS,
- SM_ITOK_FLAG_REQUIRED,
+ 0,
eapGssSmAcceptGssChannelBindings,
},
{
#endif
{
ITOK_TYPE_NONE,
+ ITOK_TYPE_ACCEPTOR_NAME_RESP,
+ GSSEAP_STATE_ACCEPTOR_EXTS,
+ 0,
+ eapGssSmAcceptAcceptorName
+ },
+ {
+ ITOK_TYPE_NONE,
ITOK_TYPE_ACCEPTOR_MIC,
GSSEAP_STATE_ACCEPTOR_EXTS,
0,
* credential handle.
*/
- /*
- * Calling gssEapInquireCred() forces the default acceptor credential name
- * to be resolved.
- */
- major = gssEapInquireCred(minor, cred, &ctx->acceptorName, NULL, NULL, NULL);
- if (GSS_ERROR(major))
- goto cleanup;
+ if (cred->name != GSS_C_NO_NAME) {
+ major = gssEapDuplicateName(minor, cred->name, &ctx->acceptorName);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
major = gssEapSmStep(minor,
cred,