Merge branch 'windows'
[moonshot.git] / moonshot / mech_eap / util_context.c
index 8ff6c50..78c3636 100644 (file)
@@ -52,12 +52,13 @@ gssEapAllocContext(OM_uint32 *minor,
     }
 
     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
@@ -70,8 +71,7 @@ gssEapAllocContext(OM_uint32 *minor,
                     GSS_C_INTEG_FLAG    |   /* integrity */
                     GSS_C_CONF_FLAG     |   /* confidentiality */
                     GSS_C_SEQUENCE_FLAG |   /* sequencing */
-                    GSS_C_REPLAY_FLAG|      /* replay detection */
-      GSS_C_MUTUAL_FLAG; /*xxx big hack */
+                    GSS_C_REPLAY_FLAG;      /* replay detection */
 
     *pCtx = ctx;
 
@@ -120,21 +120,22 @@ 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
     }
+#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);
 
@@ -155,6 +156,8 @@ gssEapMakeToken(OM_uint32 *minor,
 {
     unsigned char *p;
 
+    assert(ctx->mechanismUsed != GSS_C_NO_OID);
+
     outputToken->length = tokenSize(ctx->mechanismUsed, innerToken->length);
     outputToken->value = GSSEAP_MALLOC(outputToken->length);
     if (outputToken->value == NULL) {
@@ -232,3 +235,149 @@ gssEapContextTime(OM_uint32 *minor,
 
     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;
+    gss_iov_buffer_desc *iov = NULL;
+    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;
+
+    tokens = verifyMIC ? ctx->inputTokens : ctx->outputTokens;
+
+    assert(tokens != NULL);
+
+    iov = GSSEAP_CALLOC(2 + (3 * tokens->buffers.count) + 1, sizeof(*iov));
+    if (iov == NULL) {
+        major = GSS_S_FAILURE;
+        *minor = ENOMEM;
+        goto cleanup;
+    }
+
+    innerTokTypes = GSSEAP_MALLOC(4 * tokens->buffers.count);
+    if (innerTokTypes == NULL) {
+        *minor = ENOMEM;
+        major = GSS_S_FAILURE;
+        goto cleanup;
+    }
+
+    innerTokLengths = GSSEAP_MALLOC(4 * tokens->buffers.count);
+    if (innerTokLengths == NULL) {
+        major = GSS_S_FAILURE;
+        *minor = ENOMEM;
+        goto cleanup;
+    }
+
+    /* Mechanism OID */
+    assert(ctx->mechanismUsed != GSS_C_NO_OID);
+    iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
+    iov[i].buffer.length = ctx->mechanismUsed->length;
+    iov[i].buffer.value = ctx->mechanismUsed->elements;
+    i++;
+
+    /* Token type */
+    if (CTX_IS_INITIATOR(ctx) ^ verifyMIC) {
+        tokType = TOK_TYPE_INITIATOR_CONTEXT;
+        micTokType = ITOK_TYPE_INITIATOR_MIC;
+    } else {
+        tokType = TOK_TYPE_ACCEPTOR_CONTEXT;
+        micTokType = ITOK_TYPE_ACCEPTOR_MIC;
+    }
+    store_uint16_be(tokType, wireTokType);
+
+    iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
+    iov[i].buffer.length = sizeof(wireTokType);
+    iov[i].buffer.value = wireTokType;
+    i++;
+
+    for (j = 0; j < tokens->buffers.count; j++) {
+        if (verifyMIC &&
+            (tokens->types[j] & ITOK_TYPE_MASK) == micTokType)
+            continue; /* will use this slot for trailer */
+
+        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
+        iov[i].buffer.length = 4;
+        iov[i].buffer.value = &innerTokTypes[j * 4];
+        store_uint32_be(tokens->types[j] & ~(ITOK_FLAG_VERIFIED),
+                        iov[i].buffer.value);
+        i++;
+
+        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
+        iov[i].buffer.length = 4;
+        iov[i].buffer.value = &innerTokLengths[j * 4];
+        store_uint32_be(tokens->buffers.elements[j].length,
+                        iov[i].buffer.value);
+        i++;
+
+        iov[i].type = GSS_IOV_BUFFER_TYPE_DATA;
+        iov[i].buffer = tokens->buffers.elements[j];
+        i++;
+    }
+
+    if (verifyMIC) {
+        assert(tokenMIC->length >= 16);
+
+        assert(i < 2 + (3 * tokens->buffers.count));
+
+        iov[i].type = GSS_IOV_BUFFER_TYPE_HEADER;
+        iov[i].buffer.length = 16;
+        iov[i].buffer.value = tokenMIC->value;
+        i++;
+
+        iov[i].type = GSS_IOV_BUFFER_TYPE_TRAILER;
+        iov[i].buffer.length = tokenMIC->length - 16;
+        iov[i].buffer.value = (unsigned char *)tokenMIC->value + 16;
+        i++;
+
+        major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
+                                        iov, i, TOK_TYPE_MIC);
+    } else {
+        iov[i++].type = GSS_IOV_BUFFER_TYPE_HEADER | GSS_IOV_BUFFER_FLAG_ALLOCATE;
+        major = gssEapWrapOrGetMIC(minor, ctx, FALSE, NULL,
+                                   iov, i, TOK_TYPE_MIC);
+        if (!GSS_ERROR(major))
+            *tokenMIC = iov[i - 1].buffer;
+    }
+
+cleanup:
+    if (iov != NULL)
+        gssEapReleaseIov(iov, tokens->buffers.count);
+    if (innerTokTypes != NULL)
+        GSSEAP_FREE(innerTokTypes);
+    if (innerTokLengths != NULL)
+        GSSEAP_FREE(innerTokLengths);
+
+    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)
+{
+    if (tokenMIC->length < 16) {
+        *minor = GSSEAP_TOK_TRUNC;
+        return GSS_S_BAD_SIG;
+    }
+
+    return gssEapMakeOrVerifyTokenMIC(minor, ctx, tokenMIC, TRUE);
+}