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-INFO2-ENTRY        ::= SEQUENCE {
45   *            etype           [0] Int32,
46   *            salt            [1] KerberosString OPTIONAL,
47   *            s2kparams       [2] OCTET STRING OPTIONAL
48   *    }
49   * </pre>
50   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
51   */
52  public class ETypeInfo2Entry implements Asn1Object
53  {
54      /** The logger */
55      private static final Logger LOG = LoggerFactory.getLogger( ETypeInfo2Entry.class );
56  
57      /** Speedup for logs */
58      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
59  
60      /** The encryption type */
61      private EncryptionType etype;
62  
63      /** The salt */
64      private String salt;
65      private byte[] saltBytes;
66  
67      /** The s2k params */
68      private byte[] s2kparams;
69  
70      // Storage for computed lengths
71      private int etypeTagLength;
72      private int saltTagLength;
73      private int s2kparamsTagLength;
74      private int etypeInfo2EntrySeqLength;
75  
76  
77      /**
78       * Creates a new instance of ETypeInfo2Entry.
79       */
80      public ETypeInfo2Entry()
81      {
82      }
83  
84  
85      public ETypeInfo2Entry( EncryptionType etype )
86      {
87          this.etype = etype;
88      }
89  
90  
91      /**
92       * Returns the salt.
93       *
94       * @return The salt.
95       */
96      public String getSalt()
97      {
98          return salt;
99      }
100 
101 
102     /**
103      * @param salt the salt to set
104      */
105     public void setSalt( String salt )
106     {
107         this.salt = salt;
108     }
109 
110 
111     /**
112      * Returns the s2kparams.
113      *
114      * @return The s2kparams.
115      */
116     public byte[] getS2kparams()
117     {
118         return s2kparams;
119     }
120 
121 
122     /**
123      * @param s2kparams the s2kparams to set
124      */
125     public void setS2kparams( byte[] s2kparams )
126     {
127         this.s2kparams = s2kparams;
128     }
129 
130 
131     /**
132      * Returns the {@link EncryptionType}.
133      *
134      * @return The {@link EncryptionType}.
135      */
136     public EncryptionType getEType()
137     {
138         return etype;
139     }
140 
141 
142     /**
143      * @param etype the encryptionType to set
144      */
145     public void setEType( EncryptionType etype )
146     {
147         this.etype = etype;
148     }
149 
150 
151     /**
152      * Compute the ETYPE-INFO2-ENTRY length
153      * <pre>
154      * ETYPE-INFO-ENTRY :
155      * 
156      * 0x30 L1 ETYPE-INFO2-ENTRY sequence
157      *  |
158      *  +--&gt; 0xA0 L2 etype tag
159      *  |     |
160      *  |     +--&gt; 0x02 L2-1etype (int)
161      *  |
162      *  +--&gt; 0xA1 L3 salt tag
163      *  |     |
164      *  |     +--&gt; 0x1B L3-1 salt (KerberosString)
165      *  |
166      *  +--&gt; 0xA2 L4 s2kparams tag
167      *        |
168      *        +--&gt; 0x04 L4-1 salt (OCTET STRING)
169      *        
170      *  where L1 = L2 + length(0xA0) + length(L2) +
171      *             L3 + length(0xA1) + length(L3) +
172      *             L4 + length(0xA2) + length( L4)
173      *  and
174      *  L2 = L2-1 + length(0x02) + length( L2-1) 
175      *  L3 = L3-1 + length(0x1B) + length( L3-1) 
176      *  L4 = L4-1 + length(0x04) + length( L4-1) 
177      *  </pre>
178      */
179     public int computeLength()
180     {
181         // Compute the etype. The Length will always be contained in 1 byte
182         int etypeLength = BerValue.getNbBytes( etype.getValue() );
183         etypeTagLength = 1 + TLV.getNbBytes( etypeLength ) + etypeLength;
184         etypeInfo2EntrySeqLength = 1 + TLV.getNbBytes( etypeTagLength ) + etypeTagLength;
185 
186         // Compute the salt
187         if ( salt != null )
188         {
189             saltBytes = Strings.getBytesUtf8( salt );
190             saltTagLength = 1 + TLV.getNbBytes( saltBytes.length ) + saltBytes.length;
191             etypeInfo2EntrySeqLength += 1 + TLV.getNbBytes( saltTagLength ) + saltTagLength;
192         }
193 
194         // Compute the s2kparams
195         if ( s2kparams != null )
196         {
197             s2kparamsTagLength = 1 + TLV.getNbBytes( s2kparams.length ) + s2kparams.length;
198             etypeInfo2EntrySeqLength += 1 + TLV.getNbBytes( s2kparamsTagLength ) + s2kparamsTagLength;
199         }
200 
201         return 1 + TLV.getNbBytes( etypeInfo2EntrySeqLength ) + etypeInfo2EntrySeqLength;
202     }
203 
204 
205     /**
206      * Encode the ETYPE-INFO2-ENTRY message to a PDU. 
207      * <pre>
208      * ETYPE-INFO2-ENTRY :
209      * 
210      * 0x30 LL
211      *   0xA0 LL 
212      *     0x02 0x01 etype
213      *   0xA1 LL 
214      *     0x1B LL salt
215      *   0xA2 LL 
216      *     0x04 LL s2kparams
217      * </pre>
218      * @param buffer The buffer where to put the PDU. It should have been allocated
219      * before, with the right size.
220      * @return The constructed PDU.
221      */
222     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
223     {
224         if ( buffer == null )
225         {
226             throw new EncoderException( I18n.err( I18n.ERR_148 ) );
227         }
228 
229         try
230         {
231             // The ETYPE-INFO2-ENTRY SEQ Tag
232             buffer.put( UniversalTag.SEQUENCE.getValue() );
233             buffer.put( TLV.getBytes( etypeInfo2EntrySeqLength ) );
234 
235             // The etype, first the tag, then the value
236             buffer.put( ( byte ) KerberosConstants.ETYPE_INFO2_ENTRY_ETYPE_TAG );
237             buffer.put( TLV.getBytes( etypeTagLength ) );
238             BerValue.encode( buffer, etype.getValue() );
239 
240             // The salt, first the tag, then the value, if salt is not null
241             if ( salt != null )
242             {
243                 // The tag
244                 buffer.put( ( byte ) KerberosConstants.ETYPE_INFO2_ENTRY_SALT_TAG );
245                 buffer.put( TLV.getBytes( saltTagLength ) );
246 
247                 // The value
248                 buffer.put( UniversalTag.GENERAL_STRING.getValue() );
249                 buffer.put( TLV.getBytes( saltBytes.length ) );
250                 buffer.put( saltBytes );
251             }
252 
253             // The s2kparams, first the tag, then the value, if s2kparams is not null
254             if ( s2kparams != null )
255             {
256                 buffer.put( ( byte ) KerberosConstants.ETYPE_INFO2_ENTRY_S2KPARAMS_TAG );
257                 buffer.put( TLV.getBytes( saltTagLength ) );
258                 BerValue.encode( buffer, s2kparams );
259             }
260         }
261         catch ( BufferOverflowException boe )
262         {
263             LOG.error( I18n.err( I18n.ERR_145, 1 + TLV.getNbBytes( etypeInfo2EntrySeqLength )
264                 + etypeInfo2EntrySeqLength, buffer.capacity() ) );
265             throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
266         }
267 
268         if ( IS_DEBUG )
269         {
270             LOG.debug( "ETYPE-INFO2-ENTRY encoding : {}", Strings.dumpBytes( buffer.array() ) );
271             LOG.debug( "ETYPE-INFO2-ENTRY initial value : {}", this );
272         }
273 
274         return buffer;
275     }
276 
277 
278     /**
279      * @see Object#toString()
280      */
281     public String toString()
282     {
283         StringBuilder sb = new StringBuilder();
284 
285         sb.append( "ETYPE-INFO2-ENTRY : {\n" );
286         sb.append( "    etype: " ).append( etype ).append( '\n' );
287 
288         if ( salt != null )
289         {
290             sb.append( "    salt: " ).append( salt ).append( '\n' );
291         }
292 
293         if ( salt != null )
294         {
295             sb.append( "    s2kparams: " ).append( Strings.dumpBytes( s2kparams ) ).append( '\n' );
296         }
297 
298         sb.append( "}\n" );
299 
300         return sb.toString();
301     }
302 }