You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by el...@apache.org on 2005/05/06 00:18:28 UTC

svn commit: r168447 - /directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/spnego/codec/grammars/SpnegoGrammar.java

Author: elecharny
Date: Thu May  5 15:18:26 2005
New Revision: 168447

URL: http://svn.apache.org/viewcvs?rev=168447&view=rev
Log:
The grammar has been completed to handle all SPNEGO PDUs. 

Modified:
    directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/spnego/codec/grammars/SpnegoGrammar.java

Modified: directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/spnego/codec/grammars/SpnegoGrammar.java
URL: http://svn.apache.org/viewcvs/directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/spnego/codec/grammars/SpnegoGrammar.java?rev=168447&r1=168446&r2=168447&view=diff
==============================================================================
--- directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/spnego/codec/grammars/SpnegoGrammar.java (original)
+++ directory/sandbox/trunk/asn1-new-codec/src/java/org/apache/asn1/spnego/codec/grammars/SpnegoGrammar.java Thu May  5 15:18:26 2005
@@ -26,9 +26,11 @@
 import org.apache.asn1.primitives.BitString;
 import org.apache.asn1.primitives.OID;
 import org.apache.asn1.primitives.OctetString;
+import org.apache.asn1.spnego.SpnegoConstants;
 import org.apache.asn1.spnego.codec.SpnegoContainer;
 import org.apache.asn1.spnego.codec.SpnegoPoolEnum;
 import org.apache.asn1.spnego.pojo.SpnegoNegTokenInitPOJO;
+import org.apache.asn1.spnego.pojo.SpnegoNegTokenTargPOJO;
 import org.apache.asn1.spnego.pojo.SpnegoPOJO;
 import org.apache.asn1.util.pools.PoolEnum;
 import org.apache.asn1.util.pools.PoolException;
@@ -81,8 +83,8 @@
         //      negTokenInit  [0]  NegTokenInit, (Tag)
         // We have a negTokenInit, and the tag must be 0xA0. We will create the Spnego POJO
         // here, and store it in the container.
-        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_TOKEN_INIT_TAG][0xA0] =
-            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_TOKEN_INIT_TAG,
+        super.transitions[SpnegoStatesEnum.SPNEGO_START_STATE][0xA0] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_START_STATE,
                 SpnegoStatesEnum.SPNEGO_NEG_TOKEN_INIT_LENGTH,
                 new GrammarAction( "Spnego neg token init tag" )
                 {
@@ -192,7 +194,7 @@
         //    mechToken     [2]  OCTET STRING  OPTIONAL,
         //    mechListMIC   [3]  OCTET STRING  OPTIONAL }
         // The next token will be either 0xA0, 0xA1, 0xA2, 0xA3 or the grammar end, depending on the
-        // element : mechType, reqFlages, mechToken or mechListMIC.
+        // element : mechType, reqFlags, mechToken or mechListMIC.
         // This transition does nothing.
         super.transitions[SpnegoStatesEnum.SPNEGO_NEG_TOKEN_INIT_SEQUENCE_VALUE][0x30] =
             new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_TOKEN_INIT_SEQUENCE_VALUE,
@@ -302,7 +304,8 @@
                 SpnegoStatesEnum.SPNEGO_MECH_TYPE_LENGTH, null );
 
         // MechType ::= OBJECT IDENTIFIER (Length)
-        // We have to check the length.
+        // We have to check the length. We also have to handle the special case of a zero
+        // length OID, which is an error.
         super.transitions[SpnegoStatesEnum.SPNEGO_MECH_TYPE_LENGTH][0x06] = new GrammarTransition(
                 SpnegoStatesEnum.SPNEGO_MECH_TYPE_LENGTH, SpnegoStatesEnum.SPNEGO_MECH_TYPE_VALUE,
                 new GrammarAction( "Mech Type Length" )
@@ -325,6 +328,12 @@
                             throw new DecoderException(
                                 "The current length is longer than the expected length" );
                         }
+                        
+                        if (currentLength == 0)
+                        {
+                            throw new DecoderException(
+                            "The length of an OID cannot be null" );
+                        }
 
                         // Updates the current length.
                         spnego.setMechTypeListExpectedLength( expectedLength - currentLength );
@@ -855,6 +864,748 @@
                     }
                 } );
 
+        //********************************************************************************************
+        //============================================================================================
+        // NegTokenTarg State
+        //--------------------------------------------------------------------------------------------
+        // SPNEGO --> CHOICE {
+        //      negTokenTarg  [1]  NegTokenTarg, (Tag)
+        // We have a negTokenTarg, and the tag must be 0xA1. We will create the Spnego POJO
+        // here, and store it in the container.
+        super.transitions[SpnegoStatesEnum.SPNEGO_START_STATE][0xA1] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_START_STATE,
+                SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_LENGTH,
+                new GrammarAction( "Spnego neg token targ tag" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        try
+                        {
+
+                            SpnegoContainer spnegoContainer = ( SpnegoContainer ) container;
+
+                            // First, create a empty Spnego POJO
+                            SpnegoPOJO spnegoPOJO = ( SpnegoPOJO )
+                                spnegoContainer.getPoolManager().allocate(
+                                    SpnegoPoolEnum.SPNEGO_NEG_TOKEN_TARG_POJO_POOL );
+
+                            // Then stores it into the container
+                            spnegoContainer.setSpnego( spnegoPOJO );
+
+                            return;
+                        }
+                        catch ( PoolException pe )
+                        {
+                            throw new DecoderException(
+                                "Cannot allocate a spnego Pojo : " + pe.getMessage() );
+                        }
+                    }
+                } );
+
+        // SPNEGO --> CHOICE { ...
+        //      negTokenTarg  [1]  NegTokenTarg, (Length)
+        // We get the negTokenTarg length, and store it in the Spnego POJO
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_LENGTH][0xA1] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_LENGTH,
+                SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_VALUE,
+                new GrammarAction( "Spnego neg token targ Length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        // We have to store the expected Length of the PDU
+                        SpnegoContainer spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoPOJO      spnego          = spnegoContainer.getSpnego();
+
+                        spnego.setExpectedLength( spnegoContainer.getCurrentTLV().getLength()
+                            .getLength() );
+                        spnego.setCurrentLength( 0 );
+
+                        return;
+                    }
+                } );
+
+        // SPNEGO --> CHOICE { ...
+        //      negTokenTarg  [1]  NegTokenTarg, (Value)
+        // We will have a SEQUENCE. There is no value, so this is just a phantom transition.
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_VALUE][0xA1] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_VALUE,
+                SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_TAG, null );
+
+        //============================================================================================
+        // NegTokenTargSequence State
+        //--------------------------------------------------------------------------------------------
+        // NegTokenTarg ::= SEQUENCE { (Tag)
+        //    negResult      [0]  ENUMERATED {
+        //            accept_completed (0),
+        //            accept_incomplete (1),
+        //            rejected (2) }           OPTIONAL,
+        //    supportedMech  [1]  MechType     OPTIONAL,
+        //    responseToken  [2]  OCTET STRING OPTIONAL,
+        //    mechListMIC    [3]  OCTET STRING OPTIONAL
+        // }
+        // Nothing to do here, it's just a tag...
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_TAG][0x30] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_TAG,
+                SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_LENGTH, null );
+
+        // NegTokenTarg ::= SEQUENCE { (Tag)
+        //    negResult      [0]  ENUMERATED {
+        //            accept_completed (0),
+        //            accept_incomplete (1),
+        //            rejected (2) }           OPTIONAL,
+        //    supportedMech  [1]  MechType     OPTIONAL,
+        //    responseToken  [2]  OCTET STRING OPTIONAL,
+        //    mechListMIC    [3]  OCTET STRING OPTIONAL
+        // }
+        // We have to check the length, and set the new expected length.
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_LENGTH][0x30] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_LENGTH,
+                SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_VALUE,
+                new GrammarAction( "Spnego neg token targ sequence Length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        // first, we check that the length is OK
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+                        checkLength( spnego, tlv );
+
+                        // Second, we store the new expected length into the global
+                        // expected length, as it won't be usefull any more (this is
+                        // an optimisation, we could have declared another class
+                        // member to do this.) We also reset the current length to 0.
+                        spnego.setExpectedLength( tlv.getLength().getLength() );
+                        spnego.setCurrentLength( 0 );
+                        return;
+                    }
+                } );
+
+        // NegTokenTarg ::= SEQUENCE { (Tag)
+        //    negResult      [0]  ENUMERATED {
+        //            accept_completed (0),
+        //            accept_incomplete (1),
+        //            rejected (2) }           OPTIONAL,
+        //    supportedMech  [1]  MechType     OPTIONAL,
+        //    responseToken  [2]  OCTET STRING OPTIONAL,
+        //    mechListMIC    [3]  OCTET STRING OPTIONAL
+        // }
+        // The next token will be either 0xA0, 0xA1, 0xA2, 0xA3 or the grammar end, depending on the
+        // element : negResult, supportedMech, responseToken or mechListMIC.
+        // This transition does nothing.
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_VALUE][0x30] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_VALUE,
+                SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_FOLLOWING_TAG, null );
+
+        //============================================================================================
+        // negResult State
+        //--------------------------------------------------------------------------------------------
+        // negResult      [0]  ENUMERATED {
+        //        accept_completed (0),
+        //        accept_incomplete (1),
+        //        rejected (2) 
+        // } OPTIONAL,
+        // ...
+        // We are coming from a NegtTokenTargSequence state
+        // We have to switch to the Length transition of a negResult state
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_FOLLOWING_TAG][0xA0] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_FOLLOWING_TAG,
+                SpnegoStatesEnum.SPNEGO_NEG_RESULT_LENGTH, null );
+
+        // negResult      [0]  ENUMERATED {
+        //        accept_completed (0),
+        //        accept_incomplete (1),
+        //        rejected (2) 
+        // } OPTIONAL,
+        // ...
+        // We have to check the length
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_RESULT_LENGTH][0xA0] = new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_NEG_RESULT_LENGTH, SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE,
+                new GrammarAction( "neg result Length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+
+                        // Checks the length.
+                        checkLength( spnego, tlv );
+
+                        // Store the length in the Neg Result expected length
+                        spnego.setNegResultExpectedLength( tlv.getLength().getLength() );
+                        return;
+                    }
+                } );
+
+        // negResult      [0]  ENUMERATED {
+        //        accept_completed (0),
+        //        accept_incomplete (1),
+        //        rejected (2) 
+        // } OPTIONAL,
+        // ...
+        // Nothing to do. We just switch to the ENUMERATED
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE][0xA0] = new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE,
+                SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE_TAG, null );
+
+        //============================================================================================
+        // NegResult enumerated
+        //--------------------------------------------------------------------------------------------
+        // negResult      [0]  ENUMERATED { (Tag)
+        //        accept_completed (0),
+        //        accept_incomplete (1),
+        //        rejected (2) 
+        // } 
+        //
+        // Nothing to do. We have to deal with the enumeration
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE_TAG][0x0A] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE_TAG,
+                SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE_LENGTH, null );
+
+        // negResult      [0]  ENUMERATED { (Tag)
+        //        accept_completed (0),
+        //        accept_incomplete (1),
+        //        rejected (2) 
+        // } 
+        //
+        // We have to check the length, and handle the special case of an empty length, which
+        /// is an error. The length MUST be 1, nothing else.
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE_LENGTH][0x0A] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE_LENGTH,
+                SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE_VALUE,
+                new GrammarAction( "neg result value Length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+                        int valueLength = tlv.getLength().getLength();
+
+                        int                    expectedLength  = spnego.getNegResultExpectedLength();
+                        
+                        int                    currentLength   =
+                            tlv.getLength().getSize() + tlv.getTag().getSize() +
+                            valueLength;
+
+                        // The length must be 1, as the result is a value in [0..2]
+                        if (valueLength != 1)
+                        {
+                            throw new DecoderException(
+                            "The negResult length must be 1, not " + valueLength );
+                        }
+                        
+                        if ( expectedLength != currentLength )
+                        {
+                            throw new DecoderException(
+                                "The NegResult length is different than the expected length" );
+                        }
+
+                        return;
+                    }
+                } );
+
+        // negResult      [0]  ENUMERATED { (Tag)
+        //        accept_completed (0),
+        //        accept_incomplete (1),
+        //        rejected (2) 
+        // } 
+        //
+        // Controls the result, it should be 0, 1 or 2.
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE_VALUE][0x0A] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_NEG_RESULT_VALUE_VALUE,
+                SpnegoStatesEnum.SPNEGO_NEG_RESULT_FOLLOWING_TAG,
+                new GrammarAction( "neg result value" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+
+                        // Get the result and stores it in the POJO
+                        byte result = tlv.getValue().getData()[0];
+                        
+                        if (	(result == SpnegoConstants.SPNEGO_ACCEPT_COMPLETED) || 
+                                (result == SpnegoConstants.SPNEGO_ACCEPT_INCOMPLETE) ||
+                                (result == SpnegoConstants.SPNEGO_ACCEPT_REJECTED) )
+                        {
+                            spnego.setNegResult(result);
+                        }
+                        else
+                        {
+                            throw new DecoderException(
+                            "The NegResult value must be 0, 1 or 2, not " + result );
+                        }
+
+                        return;
+                    }
+                } );
+
+        //============================================================================================
+        // supportedMech State
+        //--------------------------------------------------------------------------------------------
+        // supportedMech  [1]  MechType OPTIONAL, (Tag)
+        // ...
+        // We are coming from a NegTokenTargSequence state
+        // We have to switch to the Length transition of a supportedMech State
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_FOLLOWING_TAG][0xA1] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_FOLLOWING_TAG,
+                SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_LENGTH, null );
+
+        // supportedMech  [1]  MechType OPTIONAL, (Tag)
+        // ...
+        // We are coming from a NegResult state
+        // We have to switch to the Length transition of a supportedMech State
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_RESULT_FOLLOWING_TAG][0xA1] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_RESULT_FOLLOWING_TAG,
+                SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_LENGTH, null );
+
+        // supportedMech  [1]  MechType OPTIONAL, (Length)
+        // ...
+        // Just check the length.
+        super.transitions[SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_LENGTH][0xA1] = new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_LENGTH, SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_VALUE,
+                new GrammarAction( "supported Mech Length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+
+                        // Checks the length.
+                        checkLength( spnego, tlv );
+
+                        // Store the length in the supported Mech expected length
+                        spnego.setSupportedMechExpectedLength( tlv.getLength().getLength() );
+                        return;
+                    }
+                } );
+
+        // supportedMech  [1]  MechType OPTIONAL, (Value)
+        // ...
+        // Nothing to do. 
+        super.transitions[SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_VALUE][0xA1] = new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_VALUE,
+                SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_OID_TAG, null );
+
+        //============================================================================================
+        // supportedMech OID State
+        //--------------------------------------------------------------------------------------------
+        // supportedMech  [1]  MechType OPTIONAL,
+        // ...
+        // MechType ::= OBJECT IDENTIFIER (Tag)
+        //
+        // Nothing to do. 
+        super.transitions[SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_OID_TAG][0x06] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_OID_TAG,
+                SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_OID_LENGTH, null );
+
+        // supportedMech  [1]  MechType OPTIONAL,
+        // ...
+        // MechType ::= OBJECT IDENTIFIER (Length)
+        //
+        // We have to check the length, and handle the special case of an empty length,
+        // which is an error.
+        super.transitions[SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_OID_LENGTH][0x06] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_OID_LENGTH,
+                SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_OID_VALUE,
+                new GrammarAction( "supported mech OID Length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+
+                        // Checks the length.
+                        int expectedLength = spnego.getSupportedMechExpectedLength();
+
+                        int currentLength  = tlv.getLength().getLength() + tlv.getSize();
+
+                        if ( expectedLength < currentLength )
+                        {
+                            throw new DecoderException(
+                                "The current length is longer than the expected length" );
+                        }
+                        
+                        if (currentLength == 0)
+                        {
+                            throw new DecoderException(
+                            "The length of an OID cannot be null" );
+                        }
+
+                        return;
+                    }
+                } );
+
+        // supportedMech  [1]  MechType OPTIONAL,
+        // ...
+        // MechType ::= OBJECT IDENTIFIER (Value)
+        //
+        // Get the OID and store it into the Spnego POJO
+        super.transitions[SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_OID_VALUE][0x06] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_OID_VALUE,
+                SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_FOLLOWING_TAG,
+                new GrammarAction( "supported Meth OID value" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+
+                        // Creates a new OID, and add it to the supported meth
+                        try
+                        {
+
+                            OID oid = ( OID ) ( spnegoContainer.getPoolManager().allocate(
+                                        PoolEnum.OID_POOL ) );
+
+                            oid.setOID( tlv.getValue().getData() );
+                            spnego.setSupportedMech( oid );
+                        }
+                        catch ( PoolException pe )
+                        {
+                            throw new DecoderException( "Cannot allocate an OID" );
+                        }
+
+                        return;
+                    }
+                } );
+
+        //============================================================================================
+        // responseToken State
+        //--------------------------------------------------------------------------------------------
+        // responseToken [2] OCTET STRING OPTIONAL, (Tag)
+        // ...
+        // We are coming from a NegTokenTargSequence state
+        // We have to switch to the Length transition of a responseToken State
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_FOLLOWING_TAG][0xA2] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_FOLLOWING_TAG,
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_LENGTH, null );
+
+        // responseToken [2] OCTET STRING OPTIONAL, (Tag)
+        // ...
+        // We are coming from a NegResult state
+        // We have to switch to the Length transition of a responseToken State
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_RESULT_FOLLOWING_TAG][0xA2] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_RESULT_FOLLOWING_TAG,
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_LENGTH, null );
+
+        // responseToken [2] OCTET STRING OPTIONAL, (Tag)
+        // ...
+        // We are coming from a supportedMech state
+        // We have to switch to the Length transition of a responseToken State
+        super.transitions[SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_FOLLOWING_TAG][0xA2] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_FOLLOWING_TAG,
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_LENGTH, null );
+
+        // responseToken [2] OCTET STRING OPTIONAL, (Length)
+        // ...
+        // Just check the length.
+        super.transitions[SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_LENGTH][0xA2] = new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_LENGTH, SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_VALUE,
+                new GrammarAction( "response Token Length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+
+                        // Checks the length.
+                        checkLength( spnego, tlv );
+
+                        // Store the length in the supported Mech expected length
+                        spnego.setResponseTokenExpectedLength( tlv.getLength().getLength() );
+                        return;
+                    }
+                } );
+
+        // responseToken [2] OCTET STRING OPTIONAL, (Value)
+        // ...
+        // Nothing to do. 
+        super.transitions[SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_VALUE][0xA2] = new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_VALUE,
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_OCTET_STRING_TAG, null );
+
+        //============================================================================================
+        // responseToken OID State
+        //--------------------------------------------------------------------------------------------
+        // response token OCTET STRING (Tag)
+        //
+        // Nothing to do. 
+        super.transitions[SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_OCTET_STRING_TAG][0x04] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_OCTET_STRING_TAG,
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_OCTET_STRING_LENGTH, null );
+
+        // response token OCTET STRING (Length)
+        //
+        // We have to check the length, and handle the special case of an empty length.
+        super.transitions[SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_OCTET_STRING_LENGTH][0x04] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_OCTET_STRING_LENGTH,
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_OCTET_STRING_VALUE,
+                new GrammarAction( "response token octet string Length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+
+                        // Checks the length.
+                        int expectedLength = spnego.getResponseTokenExpectedLength();
+
+                        int currentLength  = tlv.getLength().getLength() + tlv.getSize();
+
+                        if ( expectedLength < currentLength )
+                        {
+                            throw new DecoderException(
+                                "The current length is longer than the expected length" );
+                        }
+                        
+                        // Deal with a zero-length octet string
+                        if (currentLength == 0)
+                        {
+                            spnego.setResponseToken(OctetString.EMPTY_STRING);
+                        }
+                        else
+                        {
+                            // Create a responseToken
+                            // TODO: use the length to allocate the best
+                            // OctetString possible.
+                            try
+                            {
+                                OctetString responseToken = ( OctetString )
+                                    ( spnegoContainer.getPoolManager().allocate(
+                                            PoolEnum.OCTET_STRING_POOL ) );
+
+                                spnego.setResponseToken( responseToken );
+                            }
+                            catch ( PoolException pe )
+                            {
+                                throw new DecoderException( "Cannot allocate a responseToken" );
+                            }
+                        }
+
+                        return;
+                    }
+                } );
+
+        // response token OCTET STRING (Value)
+        //
+        // Get the response token and store it into the Spnego POJO
+        super.transitions[SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_OCTET_STRING_VALUE][0x04] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_OCTET_STRING_VALUE,
+                SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_FOLLOWING_TAG,
+                new GrammarAction( "response token octet string value" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+
+                        // Stores the response token
+                        OctetString responseToken = spnego.getResponseToken();
+                        responseToken.setData( tlv.getValue().getData() );
+
+                        return;
+                    }
+                } );
+
+        //============================================================================================
+        // mechListMIC State
+        //--------------------------------------------------------------------------------------------
+        // mechListMIC [3] OCTET STRING OPTIONAL (Tag)
+        // ...
+        // We are coming from a NegTokenTargSequence state
+        // We have to switch to the Length transition of a mechListMIC State
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_FOLLOWING_TAG][0xA3] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_TOKEN_TARG_SEQUENCE_FOLLOWING_TAG,
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_LENGTH, null );
+
+        // mechListMIC [3] OCTET STRING OPTIONAL (Tag)
+        // ...
+        // We are coming from a NegResult state
+        // We have to switch to the Length transition of a mechListMIC State
+        super.transitions[SpnegoStatesEnum.SPNEGO_NEG_RESULT_FOLLOWING_TAG][0xA3] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_NEG_RESULT_FOLLOWING_TAG,
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_LENGTH, null );
+
+        // mechListMIC [3] OCTET STRING OPTIONAL (Tag)
+        // ...
+        // We are coming from a supportedMech state
+        // We have to switch to the Length transition of a mechListMIC State
+        super.transitions[SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_FOLLOWING_TAG][0xA3] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_SUPPORTED_METH_FOLLOWING_TAG,
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_LENGTH, null );
+
+        // mechListMIC [3] OCTET STRING OPTIONAL (Tag)
+        // ...
+        // We are coming from a responseToken state
+        // We have to switch to the Length transition of a mechListMIC State
+        super.transitions[SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_FOLLOWING_TAG][0xA3] =
+            new GrammarTransition( SpnegoStatesEnum.SPNEGO_RESPONSE_TOKEN_FOLLOWING_TAG,
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_LENGTH, null );
+
+        // mechListMIC [3] OCTET STRING OPTIONAL (Length)
+        // ...
+        // Just check the length.
+        super.transitions[SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_LENGTH][0xA3] = new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_LENGTH, SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_VALUE,
+                new GrammarAction( "mech List MIC Length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+
+                        // Checks the length.
+                        checkLength( spnego, tlv );
+
+                        // Store the length in the supported Mech expected length
+                        spnego.setMechListMICExpectedLength( tlv.getLength().getLength() );
+                        return;
+                    }
+                } );
+
+        // mechListMIC [3] OCTET STRING OPTIONAL (Value)
+        // ...
+        // Nothing to do. 
+        super.transitions[SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_VALUE][0xA3] = new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_VALUE,
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_OCTET_STRING_TAG, null );
+
+        //============================================================================================
+        // Targ mech list MIC Octet String State
+        //--------------------------------------------------------------------------------------------
+        // mech list MIC OCTET STRING (Tag)
+        //
+        // Nothing to do. 
+        super.transitions[SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_OCTET_STRING_TAG][0x04] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_OCTET_STRING_TAG,
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_OCTET_STRING_LENGTH, null );
+
+        // mech list MIC OCTET STRING (Length)
+        //
+        // We have to check the length, and handle the special case of an empty length.
+        super.transitions[SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_OCTET_STRING_LENGTH][0x04] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_OCTET_STRING_LENGTH,
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_OCTET_STRING_VALUE,
+                new GrammarAction( "mech list MIC octet string Length" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+
+                        // Checks the length.
+                        int expectedLength = spnego.getMechListMICExpectedLength();
+
+                        int currentLength  = tlv.getLength().getLength() + tlv.getSize();
+
+                        if ( expectedLength < currentLength )
+                        {
+                            throw new DecoderException(
+                                "The current length is longer than the expected length" );
+                        }
+                        
+                        // Deal with a zero-length octet string
+                        if (currentLength == 0)
+                        {
+                            spnego.setMechListMIC(OctetString.EMPTY_STRING);
+                        }
+                        else
+                        {
+                            // Create a responseToken
+                            // TODO: use the length to allocate the best
+                            // OctetString possible.
+                            try
+                            {
+                                OctetString mechListMIC = ( OctetString )
+                                    ( spnegoContainer.getPoolManager().allocate(
+                                            PoolEnum.OCTET_STRING_POOL ) );
+
+                                spnego.setMechListMIC( mechListMIC );
+                            }
+                            catch ( PoolException pe )
+                            {
+                                throw new DecoderException( "Cannot allocate a mechListMIC" );
+                            }
+                        }
+
+                        return;
+                    }
+                } );
+
+        // mech list MIC OCTET STRING (Value)
+        //
+        // Get the mech list MIC and store it into the Spnego POJO.
+        // This is the last state of this grammar.
+        super.transitions[SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_OCTET_STRING_VALUE][0x04] =
+            new GrammarTransition(
+                SpnegoStatesEnum.SPNEGO_TARG_MECH_LIST_MIC_OCTET_STRING_VALUE,
+                -1,
+                new GrammarAction( "mech list MIC octet string value" )
+                {
+                    public void action( IAsn1Container container ) throws DecoderException
+                    {
+
+                        SpnegoContainer        spnegoContainer = ( SpnegoContainer ) container;
+                        SpnegoNegTokenTargPOJO spnego          = ( SpnegoNegTokenTargPOJO )
+                            spnegoContainer.getSpnego();
+                        TLV                    tlv             = spnegoContainer.getCurrentTLV();
+
+                        // Stores the response token
+                        OctetString mechListMIC = spnego.getMechListMIC();
+                        mechListMIC.setData( tlv.getValue().getData() );
+
+                        return;
+                    }
+                } );
     }
 
     //~ Methods ------------------------------------------------------------------------------------