krb5 commit: Rewrite wrong-krb5-mech SPNEGO test

Greg Hudson ghudson at mit.edu
Fri Jul 17 23:37:28 EDT 2015


https://github.com/krb5/krb5/commit/90544415b37e4755daf9c2c548532e1ebbcbd7a9
commit 90544415b37e4755daf9c2c548532e1ebbcbd7a9
Author: Greg Hudson <ghudson at mit.edu>
Date:   Tue Jul 14 00:01:02 2015 -0400

    Rewrite wrong-krb5-mech SPNEGO test
    
    t_spnego.c contains a test for properly reflecting the erroneous
    Microsoft krb5 OID.  Currently this test produces its input token by
    acquiring a SPNEGO cred and using gss_set_neg_mechs() to offer only
    the wrong krb5 OID.  This method will not work when SPNEGO is changed
    not to acquire multiple krb5 creds in the next commit, so rewrite it
    to manually produce the SPNEGO initiator token.

 src/tests/gssapi/t_spnego.c |  130 +++++++++++++++++++++++++++++++++++-------
 1 files changed, 108 insertions(+), 22 deletions(-)

diff --git a/src/tests/gssapi/t_spnego.c b/src/tests/gssapi/t_spnego.c
index 0d19908..8ab6e25 100644
--- a/src/tests/gssapi/t_spnego.c
+++ b/src/tests/gssapi/t_spnego.c
@@ -45,6 +45,96 @@ gss_OID_set_desc mechset_krb5_wrong = { 1, &mech_krb5_wrong };
  * ./t_spnego host/test.host at REALM testhost.keytab
  */
 
+/* Replace *tok and *len with the concatenation of prefix and *tok. */
+static void
+prepend(const void *prefix, size_t plen, uint8_t **tok, size_t *len)
+{
+    uint8_t *newtok;
+
+    newtok = malloc(plen + *len);
+    assert(newtok != NULL);
+    memcpy(newtok, prefix, plen);
+    memcpy(newtok + plen, *tok, *len);
+    free(*tok);
+    *tok = newtok;
+    *len = plen + *len;
+}
+
+/* Replace *tok and *len with *tok wrapped in a DER tag with the given tag
+ * byte.  *len must be less than 2^16. */
+static void
+der_wrap(uint8_t tag, uint8_t **tok, size_t *len)
+{
+    char lenbuf[3];
+    uint8_t *wrapped;
+    size_t llen;
+
+    if (*len < 128) {
+        lenbuf[0] = *len;
+        llen = 1;
+    } else if (*len < 256) {
+        lenbuf[0] = 0x81;
+        lenbuf[1] = *len;
+        llen = 2;
+    } else {
+        assert(*len >> 16 == 0);
+        lenbuf[0] = 0x82;
+        lenbuf[1] = *len >> 8;
+        lenbuf[2] = *len & 0xFF;
+        llen = 3;
+    }
+    wrapped = malloc(1 + llen + *len);
+    assert(wrapped != NULL);
+    *wrapped = tag;
+    memcpy(wrapped + 1, lenbuf, llen);
+    memcpy(wrapped + 1 + llen, *tok, *len);
+    free(*tok);
+    *tok = wrapped;
+    *len = 1 + llen + *len;
+}
+
+/*
+ * Create a SPNEGO initiator token for the erroneous Microsoft krb5 mech OID,
+ * wrapping a krb5 token ktok.  The token should look like:
+ *
+ * 60 <len> (GSS framing sequence)
+ *   06 06 2B 06 01 05 05 02 (SPNEGO OID)
+ *   A0 <len> (NegotiationToken choice 0, negTokenInit)
+ *     30 <len> (sequence)
+ *       A0 0D (context tag 0, mechTypes)
+ *         30 0B (sequence of)
+ *           06 09 2A 86 48 82 F7 12 01 02 02 (wrong krb5 OID)
+ *       A2 <len> (context tag 2, mechToken)
+ *         04 <len> (octet string)
+ *           <mech token octets>
+ */
+static void
+create_mskrb5_spnego_token(gss_buffer_t ktok, gss_buffer_desc *tok_out)
+{
+    uint8_t *tok;
+    size_t len;
+
+    len = ktok->length;
+    tok = malloc(len);
+    assert(tok != NULL);
+    memcpy(tok, ktok->value, len);
+    /* Wrap the krb5 token in OCTET STRING and [2] tags. */
+    der_wrap(0x04, &tok, &len);
+    der_wrap(0xA2, &tok, &len);
+    /* Prepend the wrong krb5 OID inside OBJECT IDENTIFIER and [0] tags. */
+    prepend("\xA0\x0D\x30\x0B\x06\x09\x2A\x86\x48\x82\xF7\x12\x01\x02\x02", 15,
+            &tok, &len);
+    /* Wrap the previous two things in SEQUENCE and [0] tags. */
+    der_wrap(0x30, &tok, &len);
+    der_wrap(0xA0, &tok, &len);
+    /* Prepend the SPNEGO OID in an OBJECT IDENTIFIER tag. */
+    prepend("\x06\x06\x2B\x06\x01\x05\x05\x02", 8, &tok, &len);
+    /* Wrap the whole thing in an [APPLICATION 0] tag. */
+    der_wrap(0x60, &tok, &len);
+    tok_out->value = tok;
+    tok_out->length = len;
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -52,7 +142,7 @@ main(int argc, char *argv[])
     gss_cred_id_t verifier_cred_handle = GSS_C_NO_CREDENTIAL;
     gss_cred_id_t initiator_cred_handle = GSS_C_NO_CREDENTIAL;
     gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
-    gss_buffer_desc itok = GSS_C_EMPTY_BUFFER, atok = GSS_C_EMPTY_BUFFER;
+    gss_buffer_desc atok = GSS_C_EMPTY_BUFFER, ktok = GSS_C_EMPTY_BUFFER, stok;
     gss_ctx_id_t initiator_context, acceptor_context;
     gss_name_t target_name, source_name = GSS_C_NO_NAME;
     gss_OID mech = GSS_C_NO_OID;
@@ -115,12 +205,12 @@ main(int argc, char *argv[])
     /*
      * Test that the SPNEGO acceptor code properly reflects back the erroneous
      * Microsoft mech OID in the supportedMech field of the NegTokenResp
-     * message.  Our initiator code doesn't care (it treats all variants of the
-     * krb5 mech as equivalent when comparing the supportedMech response to its
-     * first-choice mech), so we have to look directly at the DER encoding of
-     * the response token.  If we don't request mutual authentication, the
-     * SPNEGO reply will contain no underlying mech token, so the encoding of
-     * the correct NegotiationToken response is completely predictable:
+     * message.  Our SPNEGO mech no longer acquires creds for the wrong mech
+     * OID, so we have to construct a SPNEGO token ourselves, and then look
+     * look directly at the DER encoding of the response token.  If we don't
+     * request mutual authentication, the SPNEGO reply will contain no
+     * underlying mech token, so the encoding of the correct NegotiationToken
+     * response is completely predictable:
      *
      *   A1 14 (choice 1, length 20, meaning negTokenResp)
      *     30 12 (sequence, length 18)
@@ -133,22 +223,17 @@ main(int argc, char *argv[])
      * So we can just compare the length to 22 and the nine bytes at offset 13
      * to the expected OID.
      */
-    major = gss_acquire_cred(&minor, GSS_C_NO_NAME, GSS_C_INDEFINITE,
-                             &mechset_spnego, GSS_C_INITIATE,
-                             &initiator_cred_handle, NULL, NULL);
-    check_gsserr("gss_acquire_cred(2)", major, minor);
-    major = gss_set_neg_mechs(&minor, initiator_cred_handle,
-                              &mechset_krb5_wrong);
-    check_gsserr("gss_set_neg_mechs(2)", major, minor);
-    major = gss_init_sec_context(&minor, initiator_cred_handle,
-                                 &initiator_context, target_name, &mech_spnego,
-                                 flags, GSS_C_INDEFINITE,
-                                 GSS_C_NO_CHANNEL_BINDINGS, &atok, NULL, &itok,
-                                 NULL, NULL);
+    major = gss_init_sec_context(&minor, GSS_C_NO_CREDENTIAL,
+                                 &initiator_context, target_name,
+                                 (gss_OID)gss_mech_krb5_wrong, flags,
+                                 GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS,
+                                 &atok, NULL, &ktok, NULL, NULL);
     check_gsserr("gss_init_sec_context", major, minor);
-    assert(major == GSS_S_CONTINUE_NEEDED);
+    assert(major == GSS_S_COMPLETE);
+    create_mskrb5_spnego_token(&ktok, &stok);
+
     major = gss_accept_sec_context(&minor, &acceptor_context,
-                                   GSS_C_NO_CREDENTIAL, &itok,
+                                   GSS_C_NO_CREDENTIAL, &stok,
                                    GSS_C_NO_CHANNEL_BINDINGS, NULL,
                                    NULL, &atok, NULL, NULL, NULL);
     assert(atok.length == 22);
@@ -160,7 +245,8 @@ main(int argc, char *argv[])
     (void)gss_delete_sec_context(&minor, &acceptor_context, NULL);
     (void)gss_release_cred(&minor, &initiator_cred_handle);
     (void)gss_release_name(&minor, &target_name);
-    (void)gss_release_buffer(&minor, &itok);
+    (void)gss_release_buffer(&minor, &ktok);
     (void)gss_release_buffer(&minor, &atok);
+    free(stok.value);
     return 0;
 }


More information about the cvs-krb5 mailing list