src/java.security.jgss/share/classes/sun/security/jgss/krb5/InitSecContextToken.java
changeset 50187 261d0ac3b09d
parent 47216 71c04702a3d5
--- a/src/java.security.jgss/share/classes/sun/security/jgss/krb5/InitSecContextToken.java	Fri May 18 18:31:28 2018 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/jgss/krb5/InitSecContextToken.java	Sat May 19 22:06:47 2018 +0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, 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
@@ -28,6 +28,8 @@
 import org.ietf.jgss.*;
 import java.io.InputStream;
 import java.io.IOException;
+
+import sun.security.action.GetPropertyAction;
 import sun.security.krb5.*;
 import java.net.InetAddress;
 import sun.security.krb5.internal.AuthorizationData;
@@ -35,6 +37,33 @@
 
 class InitSecContextToken extends InitialToken {
 
+    // If non-mutual authentication is requested, there is no AP-REP message.
+    // The acceptor thus has no chance to send the seq-number field to the
+    // initiator. In this case, the initiator and acceptor should has an
+    // agreement to derive acceptor's initial seq-number if the acceptor wishes
+    // to send messages to the initiator.
+
+    // If this flag is true, it will the same as the initiator's initial
+    // seq-number (as MIT krb5 and Windows SSPI do). Otherwise, it will be zero
+    // (as Heimdal does). The default value is true.
+    private static final boolean ACCEPTOR_USE_INITIATOR_SEQNUM;
+
+    static {
+        // The ACCEPTOR_USE_INITIATOR_SEQNUM value is determined by the system
+        // property "sun.security.krb5.acceptor.sequence.number.nonmutual",
+        // which can be set to "initiator", "zero" or "0".
+        String propName = "sun.security.krb5.acceptor.sequence.number.nonmutual";
+        String s = GetPropertyAction.privilegedGetProperty(propName, "initiator");
+        if (s.equals("initiator")) {
+            ACCEPTOR_USE_INITIATOR_SEQNUM = true;
+        } else if (s.equals("zero") || s.equals("0")) {
+            ACCEPTOR_USE_INITIATOR_SEQNUM = false;
+        } else {
+            throw new AssertionError("Unrecognized value for " + propName
+                    + ": " + s);
+        }
+    }
+
     private KrbApReq apReq = null;
 
     /**
@@ -78,7 +107,10 @@
             context.setKey(Krb5Context.SESSION_KEY, serviceTicket.getSessionKey());
 
         if (!mutualRequired)
-            context.resetPeerSequenceNumber(0);
+            context.resetPeerSequenceNumber(
+                    ACCEPTOR_USE_INITIATOR_SEQNUM
+                    ? apReq.getSeqNumber().intValue()
+                    : 0);
     }
 
     /**
@@ -143,10 +175,12 @@
                              apReqSeqNumber.intValue() :
                              0);
         context.resetPeerSequenceNumber(peerSeqNumber);
-        if (!context.getMutualAuthState())
-            // Use the same sequence number as the peer
-            // (Behaviour exhibited by the Windows SSPI server)
-            context.resetMySequenceNumber(peerSeqNumber);
+        if (!context.getMutualAuthState()) {
+            context.resetMySequenceNumber(
+                    ACCEPTOR_USE_INITIATOR_SEQNUM
+                            ? peerSeqNumber
+                            : 0);
+        }
         context.setAuthTime(
                 new KerberosTime(apReq.getCreds().getAuthTime()).toString());
         context.setTktFlags(apReq.getCreds().getFlags());