7040151: SPNEGO GSS code does not parse tokens in accordance to RFC 2478
authorweijun
Tue, 03 May 2011 02:48:59 +0800
changeset 9549 24b7de36d243
parent 9548 225dbdc1cb74
child 9551 1ca07a2f000f
7040151: SPNEGO GSS code does not parse tokens in accordance to RFC 2478 Reviewed-by: valeriep
jdk/src/share/classes/sun/security/jgss/spnego/NegTokenInit.java
jdk/src/share/classes/sun/security/jgss/spnego/NegTokenTarg.java
jdk/src/share/classes/sun/security/jgss/spnego/SpNegoToken.java
jdk/test/sun/security/jgss/spnego/NegTokenTargFields.java
jdk/test/sun/security/krb5/auto/SPNEGO.java
--- a/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenInit.java	Mon May 02 11:39:46 2011 -0700
+++ b/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenInit.java	Tue May 03 02:48:59 2011 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -152,75 +152,50 @@
                                 "did not have the Sequence tag");
             }
 
-            // parse SEQUENCE of mechTypes, if present
-            if (tmp1.data.available() > 0) {
+            // parse various fields if present
+            int lastField = -1;
+            while (tmp1.data.available() > 0) {
                 DerValue tmp2 = tmp1.data.getDerValue();
-                if (!tmp2.isContextSpecific((byte)0x00)) {
-                    throw new IOException("SPNEGO NegoTokenInit : " +
-                        "did not have the right context tag for mechTypes");
-                }
-                // get the DER-encoded sequence of mechTypes
-                DerInputStream mValue = tmp2.data;
-                mechTypes = mValue.toByteArray();
+                if (tmp2.isContextSpecific((byte)0x00)) {
+                    // get the DER-encoded sequence of mechTypes
+                    lastField = checkNextField(lastField, 0);
+                    DerInputStream mValue = tmp2.data;
+                    mechTypes = mValue.toByteArray();
 
-                // read all the mechTypes
-                DerValue[] mList = mValue.getSequence(0);
-                mechTypeList = new Oid[mList.length];
-                ObjectIdentifier mech = null;
-                for (int i = 0; i < mList.length; i++) {
-                    mech = mList[i].getOID();
+                    // read all the mechTypes
+                    DerValue[] mList = mValue.getSequence(0);
+                    mechTypeList = new Oid[mList.length];
+                    ObjectIdentifier mech = null;
+                    for (int i = 0; i < mList.length; i++) {
+                        mech = mList[i].getOID();
+                        if (DEBUG) {
+                            System.out.println("SpNegoToken NegTokenInit: " +
+                                    "reading Mechanism Oid = " + mech);
+                        }
+                        mechTypeList[i] = new Oid(mech.toString());
+                    }
+                } else if (tmp2.isContextSpecific((byte)0x01)) {
+                    lastField = checkNextField(lastField, 1);
+                    // received reqFlags, skip it
+                } else if (tmp2.isContextSpecific((byte)0x02)) {
+                    lastField = checkNextField(lastField, 2);
                     if (DEBUG) {
                         System.out.println("SpNegoToken NegTokenInit: " +
-                                "reading Mechanism Oid = " + mech);
+                                            "reading Mech Token");
                     }
-                    mechTypeList[i] = new Oid(mech.toString());
-                }
-            }
-
-            // parse mechToken, if present (skip reqFlags)
-            if (tmp1.data.available() > 0) {
-                DerValue tmp3 = tmp1.data.getDerValue();
-                if (tmp3.isContextSpecific((byte)0x01)) {
-                    // received reqFlags, skip it
-                    // now parse next field mechToken
-                    if (tmp1.data.available() > 0) {
-                        tmp3 = tmp1.data.getDerValue();
+                    mechToken = tmp2.data.getOctetString();
+                } else if (tmp2.isContextSpecific((byte)0x03)) {
+                    lastField = checkNextField(lastField, 3);
+                    if (!GSSUtil.useMSInterop()) {
+                        mechListMIC = tmp2.data.getOctetString();
+                        if (DEBUG) {
+                            System.out.println("SpNegoToken NegTokenInit: " +
+                                    "MechListMIC Token = " +
+                                    getHexBytes(mechListMIC));
+                        }
                     }
                 }
-                if (!tmp3.isContextSpecific((byte)0x02)) {
-                    throw new IOException("SPNEGO NegoTokenInit : " +
-                        "did not have the right context tag for mechToken");
-                }
-                if (DEBUG) {
-                    System.out.println("SpNegoToken NegTokenInit: " +
-                                        "reading Mech Token");
-                }
-                mechToken = tmp3.data.getOctetString();
             }
-
-            // parse mechListMIC, if present and not in MS interop mode
-            if (!GSSUtil.useMSInterop() && (tmp1.data.available() > 0)) {
-                if (DEBUG) {
-                    System.out.println("SpNegoToken NegTokenInit: " +
-                                        "receiving MechListMIC");
-                }
-                DerValue tmp6 = tmp1.data.getDerValue();
-                if (!tmp6.isContextSpecific((byte)0x03)) {
-                    throw new IOException("SPNEGO NegoTokenInit : " +
-                        "did not have the right context tag for MICToken");
-                }
-                mechListMIC = tmp6.data.getOctetString();
-                if (DEBUG) {
-                    System.out.println("SpNegoToken NegTokenInit: " +
-                        "MechListMIC Token = " + getHexBytes(mechListMIC));
-                }
-            } else {
-                if (DEBUG) {
-                    System.out.println("SpNegoToken NegTokenInit : " +
-                                        "no MIC token included");
-                }
-            }
-
         } catch (IOException e) {
             throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
                 "Invalid SPNEGO NegTokenInit token : " + e.getMessage());
--- a/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenTarg.java	Mon May 02 11:39:46 2011 -0700
+++ b/jdk/src/share/classes/sun/security/jgss/spnego/NegTokenTarg.java	Tue May 03 02:48:59 2011 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -153,69 +153,40 @@
                         "did not have the Sequence tag");
             }
 
-            // parse negResult, if present
-            if (tmp1.data.available() > 0) {
+            // parse various fields if present
+            int lastField = -1;
+            while (tmp1.data.available() > 0) {
                 DerValue tmp2 = tmp1.data.getDerValue();
-                if (!tmp2.isContextSpecific((byte)0x00)) {
-                        throw new IOException("SPNEGO NegoTokenTarg : " +
-                        "did not have the right context tag for negResult");
-                }
-                negResult = tmp2.data.getEnumerated();
-                if (DEBUG) {
-                    System.out.println("SpNegoToken NegTokenTarg: negotiated" +
-                                " result = " + getNegoResultString(negResult));
-                }
-            }
-
-            // parse supportedMech, if present
-            if (tmp1.data.available() > 0) {
-                DerValue tmp3 = tmp1.data.getDerValue();
-                if (!tmp3.isContextSpecific((byte)0x01)) {
-                    throw new IOException("SPNEGO NegoTokenTarg : " +
-                        "did not have the right context tag for supportedMech");
-                }
-                ObjectIdentifier mech = tmp3.data.getOID();
-                supportedMech = new Oid(mech.toString());
-                if (DEBUG) {
-                    System.out.println("SpNegoToken NegTokenTarg: " +
-                                "supported mechanism = " + supportedMech);
+                if (tmp2.isContextSpecific((byte)0x00)) {
+                    lastField = checkNextField(lastField, 0);
+                    negResult = tmp2.data.getEnumerated();
+                    if (DEBUG) {
+                        System.out.println("SpNegoToken NegTokenTarg: negotiated" +
+                                    " result = " + getNegoResultString(negResult));
+                    }
+                } else if (tmp2.isContextSpecific((byte)0x01)) {
+                    lastField = checkNextField(lastField, 1);
+                    ObjectIdentifier mech = tmp2.data.getOID();
+                    supportedMech = new Oid(mech.toString());
+                    if (DEBUG) {
+                        System.out.println("SpNegoToken NegTokenTarg: " +
+                                    "supported mechanism = " + supportedMech);
+                    }
+                } else if (tmp2.isContextSpecific((byte)0x02)) {
+                    lastField = checkNextField(lastField, 2);
+                    responseToken = tmp2.data.getOctetString();
+                } else if (tmp2.isContextSpecific((byte)0x03)) {
+                    lastField = checkNextField(lastField, 3);
+                    if (!GSSUtil.useMSInterop()) {
+                        mechListMIC = tmp2.data.getOctetString();
+                        if (DEBUG) {
+                            System.out.println("SpNegoToken NegTokenTarg: " +
+                                                "MechListMIC Token = " +
+                                                getHexBytes(mechListMIC));
+                        }
+                    }
                 }
             }
-
-            // parse ResponseToken, if present
-            if (tmp1.data.available() > 0) {
-                DerValue tmp4 = tmp1.data.getDerValue();
-                if (!tmp4.isContextSpecific((byte)0x02)) {
-                    throw new IOException("SPNEGO NegoTokenTarg : did not" +
-                        " have the right context tag for response token");
-                }
-                responseToken = tmp4.data.getOctetString();
-            }
-
-            // parse mechListMIC if present and not in MS interop
-            if (!GSSUtil.useMSInterop() && (tmp1.data.available() > 0)) {
-                if (DEBUG) {
-                    System.out.println("SpNegoToken NegTokenTarg: " +
-                                                "receiving MechListMIC");
-                }
-                DerValue tmp5 = tmp1.data.getDerValue();
-                if (!tmp5.isContextSpecific((byte)0x03)) {
-                    throw new IOException("SPNEGO NegoTokenTarg : " +
-                        "did not have the right context tag for mechListMIC");
-                }
-                mechListMIC = tmp5.data.getOctetString();
-                if (DEBUG) {
-                    System.out.println("SpNegoToken NegTokenTarg: " +
-                                        "MechListMIC Token = " +
-                                        getHexBytes(mechListMIC));
-                }
-            } else {
-                if (DEBUG) {
-                    System.out.println("SpNegoToken NegTokenTarg : " +
-                                        "no MIC token included");
-                }
-            }
-
         } catch (IOException e) {
             throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
                 "Invalid SPNEGO NegTokenTarg token : " + e.getMessage());
--- a/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoToken.java	Mon May 02 11:39:46 2011 -0700
+++ b/jdk/src/share/classes/sun/security/jgss/spnego/SpNegoToken.java	Tue May 03 02:48:59 2011 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -187,4 +187,21 @@
                 return ("Unknown Negotiated Result: " + result);
         }
     }
+
+    /**
+     * Checks if the context tag in a sequence is in correct order. The "last"
+     * value must be smaller than "current".
+     * @param last the last tag seen
+     * @param current the current tag
+     * @return the current tag, used as the next value for last
+     * @throws GSSException if there's a wrong order
+     */
+    static int checkNextField(int last, int current) throws GSSException {
+        if (last < current) {
+            return current;
+        } else {
+            throw new GSSException(GSSException.DEFECTIVE_TOKEN, -1,
+                "Invalid SpNegoToken token : wrong order");
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/jgss/spnego/NegTokenTargFields.java	Tue May 03 02:48:59 2011 +0800
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7040151
+ * @summary SPNEGO GSS code does not parse tokens in accordance to RFC 2478
+ * @compile -XDignore.symbol.file NegTokenTargFields.java
+ * @run main NegTokenTargFields nomech
+ * @run main/fail NegTokenTargFields badorder
+ */
+
+import sun.security.jgss.spnego.NegTokenTarg;
+
+public class NegTokenTargFields {
+
+    // A hand-crafted NegTokenTarg with negResult and responseToken only
+    public static byte[] nomech = {
+        (byte)0xA1, (byte)0x0F, (byte)0x30, (byte)0x0D,
+        (byte)0xA0, (byte)0x03, (byte)0x0A, (byte)0x01,
+        (byte)0x02, (byte)0xA2, (byte)0x02, (byte)0x04,
+        (byte)0x00, (byte)0xA3, (byte)0x02, (byte)0x04,
+        (byte)0x00,
+    };
+
+    // A hand-crafted NegTokenTarg with negResult and supportedMech in wrong order
+    public static byte[] badorder = {
+        (byte)0xA1, (byte)0x1E, (byte)0x30, (byte)0x1C,
+        (byte)0xA1, (byte)0x0B, (byte)0x06, (byte)0x09,
+        (byte)0x2A, (byte)0x86, (byte)0x48, (byte)0x86,
+        (byte)0xF7, (byte)0x12, (byte)0x01, (byte)0x02,
+        (byte)0x02, (byte)0xA0, (byte)0x03, (byte)0x0A,
+        (byte)0x01, (byte)0x00, (byte)0xA2, (byte)0x03,
+        (byte)0x04, (byte)0x01, (byte)0x00, (byte)0xA3,
+        (byte)0x03, (byte)0x04, (byte)0x01, (byte)0x00,
+    };
+
+    public static void main(String[] args) throws Exception {
+        byte[] buf = (byte[])NegTokenTargFields.class.getField(args[0]).get(null);
+        new NegTokenTarg(buf);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/krb5/auto/SPNEGO.java	Tue May 03 02:48:59 2011 +0800
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 7040151
+ * @summary SPNEGO GSS code does not parse tokens in accordance to RFC 2478
+ * @compile -XDignore.symbol.file SPNEGO.java
+ * @run main/othervm SPNEGO
+ */
+
+import sun.security.jgss.GSSUtil;
+
+// The basic krb5 test skeleton you can copy from
+public class SPNEGO {
+
+    public static void main(String[] args) throws Exception {
+
+        new OneKDC(null).writeJAASConf();
+
+        Context c, s;
+        c = Context.fromJAAS("client");
+        s = Context.fromJAAS("server");
+
+        c.startAsClient(OneKDC.SERVER, GSSUtil.GSS_SPNEGO_MECH_OID);
+        s.startAsServer(GSSUtil.GSS_SPNEGO_MECH_OID);
+
+        Context.handshake(c, s);
+
+        Context.transmit("i say high --", c, s);
+        Context.transmit("   you say low", s, c);
+
+        s.dispose();
+        c.dispose();
+    }
+}