View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *  
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *  
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License. 
18   *  
19   */
20  package org.apache.directory.shared.kerberos.components;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  
26  import org.apache.directory.api.asn1.Asn1Object;
27  import org.apache.directory.api.asn1.EncoderException;
28  import org.apache.directory.api.asn1.ber.tlv.BerValue;
29  import org.apache.directory.api.asn1.ber.tlv.TLV;
30  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
31  import org.apache.directory.api.util.Strings;
32  import org.apache.directory.server.i18n.I18n;
33  import org.apache.directory.shared.kerberos.KerberosConstants;
34  import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
35  import org.slf4j.Logger;
36  import org.slf4j.LoggerFactory;
37  
38  
39  /**
40   * Provides encryption info information sent to the client.
41   * 
42   * The ASN.1 grammar for this structure is :
43   * <pre>
44   * ETYPE-INFO-ENTRY        ::= SEQUENCE {
45   *            etype           [0] Int32,
46   *            salt            [1] OCTET STRING OPTIONAL
47   *    }
48   * </pre>
49   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
50   */
51  public class ETypeInfoEntry implements Asn1Object
52  {
53      /** The logger */
54      private static final Logger LOG = LoggerFactory.getLogger( ETypeInfoEntry.class );
55  
56      /** Speedup for logs */
57      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
58  
59      /** The encryption type */
60      private EncryptionType etype;
61  
62      /** The salt */
63      private byte[] salt;
64  
65      // Storage for computed lengths
66      private int etypeTagLength;
67      private int saltTagLength;
68      private int etypeInfoEntrySeqLength;
69  
70  
71      /**
72       * Creates a new instance of ETypeInfoEntry.
73       * 
74       * @param etype the Encryption type
75       * @param salt the salt
76       */
77      public ETypeInfoEntry( EncryptionType etype, byte[] salt )
78      {
79          this.etype = etype;
80          this.salt = salt;
81      }
82  
83  
84      /**
85       * Creates a new instance of ETypeInfoEntry.
86       */
87      public ETypeInfoEntry()
88      {
89      }
90  
91  
92      /**
93       * Returns the salt.
94       *
95       * @return The salt.
96       */
97      public byte[] getSalt()
98      {
99          return salt;
100     }
101 
102 
103     /**
104      * @param salt the salt to set
105      */
106     public void setSalt( byte[] salt )
107     {
108         this.salt = salt;
109     }
110 
111 
112     /**
113      * Returns the {@link EncryptionType}.
114      *
115      * @return The {@link EncryptionType}.
116      */
117     public EncryptionType getEType()
118     {
119         return etype;
120     }
121 
122 
123     /**
124      * @param etype the encryptionType to set
125      */
126     public void setEType( EncryptionType etype )
127     {
128         this.etype = etype;
129     }
130 
131 
132     /**
133      * Compute the ETYPE-INFO-ENTRY length
134      * <pre>
135      * ETYPE-INFO-ENTRY :
136      * 
137      * 0x30 L1 ETYPE-INFO-ENTRY sequence
138      *  |
139      *  +--&gt; 0xA0 L2 etype tag
140      *  |     |
141      *  |     +--&gt; 0x02 L2-1etype (int)
142      *  |
143      *  +--&gt; 0xA1 L3 salt tag
144      *        |
145      *        +--&gt; 0x04 L3-1 salt (OCTET STRING)
146      *        
147      *  where L1 = L2 + lenght(0xA0) + length(L2) +
148      *             L3 + lenght(0xA1) + length(L3) 
149      *  and
150      *  L2 = L2-1 + length(0x02) + length( L2-1) 
151      *  L3 = L3-1 + length(0x04) + length( L3-1) 
152      *  </pre>
153      */
154     public int computeLength()
155     {
156         // Compute the etype. The Length will always be contained in 1 byte
157         int etypeLength = BerValue.getNbBytes( etype.getValue() );
158         etypeTagLength = 1 + TLV.getNbBytes( etypeLength ) + etypeLength;
159         etypeInfoEntrySeqLength = 1 + TLV.getNbBytes( etypeTagLength ) + etypeTagLength;
160 
161         // Compute the salt
162         if ( salt != null )
163         {
164             saltTagLength = 1 + TLV.getNbBytes( salt.length ) + salt.length;
165             etypeInfoEntrySeqLength += 1 + TLV.getNbBytes( saltTagLength ) + saltTagLength;
166         }
167 
168         return 1 + TLV.getNbBytes( etypeInfoEntrySeqLength ) + etypeInfoEntrySeqLength;
169     }
170 
171 
172     /**
173      * Encode the ETYPE-INFO-ENTRY message to a PDU. 
174      * <pre>
175      * ETYPE-INFO-ENTRY :
176      * 
177      * 0x30 LL
178      *   0xA1 LL 
179      *     0x02 0x01 etype
180      *   0xA2 LL 
181      *     0x04 LL salt
182      * </pre>
183      * @param buffer The buffer where to put the PDU. It should have been allocated
184      * before, with the right size.
185      * @return The constructed PDU.
186      */
187     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
188     {
189         if ( buffer == null )
190         {
191             throw new EncoderException( I18n.err( I18n.ERR_148 ) );
192         }
193 
194         try
195         {
196             // The ETYPE-INFO-ENTRY SEQ Tag
197             buffer.put( UniversalTag.SEQUENCE.getValue() );
198             buffer.put( TLV.getBytes( etypeInfoEntrySeqLength ) );
199 
200             // The etype, first the tag, then the value
201             buffer.put( ( byte ) KerberosConstants.ETYPE_INFO_ENTRY_ETYPE_TAG );
202             buffer.put( TLV.getBytes( etypeTagLength ) );
203             BerValue.encode( buffer, etype.getValue() );
204 
205             // The salt, first the tag, then the value, if salt is not null
206             if ( salt != null )
207             {
208                 buffer.put( ( byte ) KerberosConstants.ETYPE_INFO_ENTRY_SALT_TAG );
209                 buffer.put( TLV.getBytes( saltTagLength ) );
210                 BerValue.encode( buffer, salt );
211             }
212         }
213         catch ( BufferOverflowException boe )
214         {
215             LOG.error( I18n.err( I18n.ERR_145, 1 + TLV.getNbBytes( etypeInfoEntrySeqLength )
216                 + etypeInfoEntrySeqLength, buffer.capacity() ) );
217             throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
218         }
219 
220         if ( IS_DEBUG )
221         {
222             LOG.debug( "ETYPE-INFO-ENTRY encoding : {}", Strings.dumpBytes( buffer.array() ) );
223             LOG.debug( "ETYPE-INFO-ENTRY initial value : {}", this );
224         }
225 
226         return buffer;
227     }
228 
229 
230     /**
231      * @see Object#toString()
232      */
233     public String toString()
234     {
235         StringBuilder sb = new StringBuilder();
236 
237         sb.append( "ETYPE-INFO-ENTRY : {\n" );
238         sb.append( "    etype: " ).append( etype ).append( '\n' );
239 
240         if ( salt != null )
241         {
242             sb.append( "    salt: " ).append( Strings.dumpBytes( salt ) ).append( '\n' );
243         }
244 
245         sb.append( "}\n" );
246 
247         return sb.toString();
248     }
249 }