Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8202953

Deprecate stream-based GSSContext methods

    XMLWordPrintable

Details

    • CSR
    • Resolution: Approved
    • P3
    • 11
    • security-libs
    • None
    • behavioral
    • minimal
    • New warnings on using deprecated methods will be shown at build time.
    • Java API
    • SE

    Description

      Summary

      Deprecate the stream-based GSSContext methods. This includes initSecContext, acceptSecContext, wrap, unwrap, getMIC, and verifyMIC that have an InputStream argument. (For each name, there is an overloaded method that has a byte[] argument).

      Problem

      In RFC 2743, a GSS-API message is defined as an opaque token which does not necessarily contain self-framing information. However, besides token-based methods which use byte arrays as input and output, the Java GSS-API also defines some GSSContext methods that take an InputStream argument. These methods intend to read a GSS-API token from a possibly infinite stream which means the implementation needs to find out where the token ends in the stream. On the other hand, the C bindings of GSS-API defined in RFC 2744 can only work on tokens, i.e. a char buffer with a definitive length.

      RFC 7546 (Structure of the Generic Security Service (GSS) Negotiation Loop), an informational RFC that intends to clarify certain behaviors of GSS-API, explicitly points out that the library does not have this obligation:

      the application protocol must specify
      the necessary framing for the application to determine what octet
      strings constitute GSS security context tokens and pass them into the
      GSS-API implementation as appropriate.

      In fact, these Java stream-based GSSContext methods are aware of this problem and contain the following words in their specifications:

      * The format of the input token that this method
      * reads is defined in the specification for the underlying mechanism that
      * will be used. This method will attempt to read one of these tokens per
      * invocation. If the mechanism token contains a definitive start and
      * end this method may block on the <code>InputStream</code> if only
      * part of the token is available. If the start and end of the token
      * are not definitive then the method will attempt to treat all
      * available bytes as part of the token.

      But in the real world, as every good application has already defined its framing protocol, there is no need for these methods to be so smart (which is also difficult to implement) and the usage becomes awkward. For example, suppose an application always prepends an int16 length before every token, with the stream-based methods, it looks like a Java application should be written this way:

      void receiveAndSend(GSSContext ctxt, DataInputStream ins, DataOutputStream out)
              throws Exception {
          ins.skip(2);
          // ignore it, the stream-based method is smart enough to find out the length
          ctxt.initSecContext(ins, out);
          // Oops, when should I write out the length of the output token? The
          // token has already been sent out to the stream!
      }

      but in fact, the "correct" way (if one insists on using a stream-based method) is

      void receiveAndSend(GSSContext ctxt, DataInputStream ins, DataOutputStream out)
              throws Exception {
          int n = ins.readShort();
          ByteArrayOutputStream buffer = new ByteArrayOutputStream();
          ctxt.initSecContext(new ByteArrayInputStream(ins.readNBytes(n)), buffer);
          out.writeShort(buffer.size());
          buffer.writeTo(out);
      }

      This is awkward because the original input and output streams here are NOT used by the GSSContext method at all, and we have to create new ByteArrayInputStream and ByteArrayOutputStream objects to pretend we are using streams. Why not just use token-based methods like this?

      void receiveAndSend(GSSContext ctxt, DataInputStream ins, DataOutputStream out)
              throws Exception {
          int n = ins.readShort();
          byte[] output = ctxt.initSecContext(ins.readNBytes(n)), 0, n);
          out.writeShort(output.length());
          out.write(output);
      }

      We are not aware of any bad application out there that does not define an external framing and rely on the GSS-API library implementation it uses to automatically find the correct end of a token. But if there is one, it must be designed by a Java programmer who believes they have these stream-based methods that are able to read the exact token from a stream (a C programmer does not have these smart functions). As we know, the specification of these methods has not guaranteed so.

      In summary, we think these stream-based methods are both unreliable and misleading. We would like to deprecate these methods for these reasons:

      1. GSS-API is defined on tokens, not streams.

      2. It gives a false sense that the wire protocol has already been defined inside GSS-API and the application does not need to define one. A Java developer might thus design an application-level wire protocol that does not include framing information at all and call initSecContext (and other stream-based methods) directly on raw streams. This is not reliable and does not match the requirement of RFC 7546. It is also impossible to write a native GSS-API application to use this protocol.

      3. It is difficult to implement.

      4. Its usage is not reliable and users end up not relying on its assumptions.

      5. The "correct" usage of these methods does not save any memory allocation or simplify the code.

      Solution

      Deprecate these methods. The methods are already removed from the latest version of Java GSS-API defined by RFC 8353.

      We don't intend to remove these methods in the next release at this moment. They might be still used by customers, and as demonstrated by the code above, they can be used "correctly".

      Specification

      diff --git a/src/java.security.jgss/share/classes/org/ietf/jgss/GSSContext.java b/src/java.security.jgss/share/classes/org/ietf/jgss/GSSContext.java
      --- a/src/java.security.jgss/share/classes/org/ietf/jgss/GSSContext.java
      +++ b/src/java.security.jgss/share/classes/org/ietf/jgss/GSSContext.java
      @@ -99,6 +99,25 @@
        * mechanism provider. The application will need to ensure that it has the
        * appropriate permissions if such checks are made in the mechanism layer.<p>
        *
      + * The stream-based methods of {@code GSSContext} have been deprecated in
      + * Java SE 11. These methods have also been removed from
      + * <a href="http://tools.ietf.org/html/rfc8353">
      + * RFC 8353: Generic Security Service API Version 2: Java Bindings Update</a>
      + * for the following reasons (see section 11): "The overloaded methods of
      + * GSSContext that use input and output streams as the means to convey
      + * authentication and per-message GSS-API tokens as described in Section 5.15
      + * of RFC 5653 are removed in this update as the wire protocol
      + * should be defined by an application and not a library. It's also impossible
      + * to implement these methods correctly when the token has no self-framing
      + * (where the end cannot be determined), or the library has no knowledge of
      + * the token format (for example, as a bridge talking to another GSS library)".
      + * These methods include {@link #initSecContext(InputStream, OutputStream)},
      + * {@link #acceptSecContext(InputStream, OutputStream)},
      + * {@link #wrap(InputStream, OutputStream, MessageProp)},
      + * {@link #unwrap(InputStream, OutputStream, MessageProp)},
      + * {@link #getMIC(InputStream, OutputStream, MessageProp)},
      + * and {@link #verifyMIC(InputStream, InputStream, MessageProp)}.<p>
      + *
        * The example code presented below demonstrates the usage of the
        * <code>GSSContext</code> interface for the initiating peer.  Different
        * operations on the <code>GSSContext</code> object are presented,
      @@ -316,7 +332,10 @@
            *   {@link GSSException#BAD_NAMETYPE GSSException.BAD_NAMETYPE},
            *   {@link GSSException#BAD_MECH GSSException.BAD_MECH},
            *   {@link GSSException#FAILURE GSSException.FAILURE}
      +     * @deprecated The stream-based methods have been removed from RFC 8353.
      +     * Use {@link #initSecContext(byte[], int, int)} instead.
            */
      +    @Deprecated(since="11")
           public int initSecContext(InputStream inStream,
                                     OutputStream outStream) throws GSSException;
      
      @@ -459,6 +478,9 @@
            *   {@link GSSException#DUPLICATE_TOKEN GSSException.DUPLICATE_TOKEN},
            *   {@link GSSException#BAD_MECH GSSException.BAD_MECH},
            *   {@link GSSException#FAILURE GSSException.FAILURE}
      +     *
      +     * @deprecated The stream-based methods have been removed from RFC 8353.
      +     * Use {@link #acceptSecContext(byte[], int, int)} instead.
            */
           /* Missing return value in RFC. int should have been returned.
            * -----------------------------------------------------------
      @@ -472,6 +494,7 @@
            * 0 indicates that no token  needs to be
            * sent.</strong>
            */
      +    @Deprecated(since="11")
           public void acceptSecContext(InputStream inStream,
                                        OutputStream outStream) throws GSSException;
      
      @@ -613,7 +636,11 @@
            *   {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED},
            *   {@link GSSException#BAD_QOP GSSException.BAD_QOP},
            *   {@link GSSException#FAILURE GSSException.FAILURE}
      +     *
      +     * @deprecated The stream-based methods have been removed from RFC 8353.
      +     * Use {@link #wrap(byte[], int, int, MessageProp)} instead.
            */
      +    @Deprecated(since="11")
           public void wrap(InputStream inStream, OutputStream outStream,
                            MessageProp msgProp) throws GSSException;
      
      @@ -696,7 +723,11 @@
            *   {@link GSSException#BAD_MIC GSSException.BAD_MIC},
            *   {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED},
            *   {@link GSSException#FAILURE GSSException.FAILURE}
      +     *
      +     * @deprecated The stream-based methods have been removed from RFC 8353.
      +     * Use {@link #unwrap(byte[], int, int, MessageProp)} instead.
            */
      +    @Deprecated(since="11")
           public void unwrap(InputStream inStream, OutputStream outStream,
                              MessageProp msgProp) throws GSSException;
      
      @@ -761,7 +792,11 @@
            *   {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED},
            *   {@link GSSException#BAD_QOP GSSException.BAD_QOP},
            *   {@link GSSException#FAILURE GSSException.FAILURE}
      +     *
      +     * @deprecated The stream-based methods have been removed from RFC 8353.
      +     * Use {@link #getMIC(byte[], int, int, MessageProp)} instead.
            */
      +    @Deprecated(since="11")
           public void getMIC(InputStream inStream, OutputStream outStream,
                              MessageProp msgProp) throws GSSException;
      
      @@ -844,7 +879,12 @@
            *   {@link GSSException#BAD_MIC GSSException.BAD_MIC}
            *   {@link GSSException#CONTEXT_EXPIRED GSSException.CONTEXT_EXPIRED}
            *   {@link GSSException#FAILURE GSSException.FAILURE}
      +     *
      +     * @deprecated The stream-based methods have been removed from RFC 8353.
      +     * Use {@link #verifyMIC(byte[], int, int, byte[], int, int, MessageProp)}
      +     * instead.
            */
      +    @Deprecated(since="11")
           public void verifyMIC(InputStream tokStream, InputStream msgStream,
                                 MessageProp msgProp) throws GSSException;

      Attachments

        Issue Links

          Activity

            People

              weijun Weijun Wang
              weijun Weijun Wang
              Sean Mullan
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: