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  
21  package org.apache.directory.shared.kerberos.components;
22  
23  
24  import java.nio.BufferOverflowException;
25  import java.nio.ByteBuffer;
26  import java.util.ArrayList;
27  import java.util.List;
28  
29  import org.apache.directory.api.asn1.Asn1Object;
30  import org.apache.directory.api.asn1.EncoderException;
31  import org.apache.directory.api.asn1.ber.tlv.BerValue;
32  import org.apache.directory.api.asn1.ber.tlv.TLV;
33  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
34  import org.apache.directory.api.util.Strings;
35  import org.apache.directory.server.i18n.I18n;
36  import org.apache.directory.shared.kerberos.KerberosConstants;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  
41  /**
42   * TYPED-DATA      ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
43   *         data-type       [0] Int32,
44   *         data-value      [1] OCTET STRING OPTIONAL
45   * }
46   *
47   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
48   */
49  public class TypedData implements Asn1Object
50  {
51  
52      // The inner class storing the individual TDs
53      public class TD
54      {
55          /** the type of TypedData */
56          private int dataType;
57  
58          /** the TypedData data */
59          private byte[] dataValue;
60  
61  
62          /**
63           * @return the TD type
64           */
65          public int getDataType()
66          {
67              return dataType;
68          }
69  
70  
71          /**
72           * @return the TD data
73           */
74          public byte[] getDataValue()
75          {
76              return dataValue;
77          }
78      }
79  
80      /** The list of TypedData elements */
81      private List<TD> typedDataList = new ArrayList<>();
82  
83      /** The current TD being processed */
84      private TD currentTD;
85  
86      /** The logger */
87      private static final Logger LOG = LoggerFactory.getLogger( TypedData.class );
88  
89      /** Speedup for logs */
90      private static final boolean IS_DEBUG = LOG.isDebugEnabled();
91  
92      // Storage for computed lengths
93      private int dataTypeTagLength[];
94      private int dataValueTagLength[];
95      private int typedDataSeqLength[];
96      private int typedDataSeqSeqLength;
97  
98  
99      /**
100      * @return the currentTD type
101      */
102     public int getCurrentDataType()
103     {
104         return currentTD.dataType;
105     }
106 
107 
108     /**
109      * Set the current TD type
110      */
111     public void setCurrentDataType( int tdType )
112     {
113         currentTD.dataType = tdType;
114     }
115 
116 
117     /**
118      * @return the currentTD data
119      */
120     public byte[] getCurrentDataValue()
121     {
122         return currentTD.dataValue;
123     }
124 
125 
126     /**
127      * Set the current TD data
128      */
129     public void setCurrentDataValue( byte[] tdData )
130     {
131         currentTD.dataValue = tdData;
132     }
133 
134 
135     /**
136      * @return the currentTD
137      */
138     public TD getCurrentTD()
139     {
140         return currentTD;
141     }
142 
143 
144     /**
145      * Create a new currentTD
146      */
147     public void createNewTD()
148     {
149         currentTD = new TD();
150         typedDataList.add( currentTD );
151     }
152 
153 
154     /**
155      * @return the TypedData
156      */
157     public List<TD> getTypedData()
158     {
159         return typedDataList;
160     }
161 
162 
163     /**
164      * Compute the TypedData length
165      * <pre>
166      * 0x30 L1 TypedData sequence
167      *  |
168      *  +-- 0x30 L2 The TD sequence
169      *       |
170      *       +--&gt; 0xA0 L3 tdType tag
171      *       |     |
172      *       |     +--&gt; 0x02 L3-2 tdType (int)
173      *       |
174      *       +--&gt; [0xA1 L4 tdData tag
175      *             |
176      *             +--&gt; 0x04 L4-2 tdData (OCTET STRING)]
177      * </pre>
178      */
179     @Override
180     public int computeLength()
181     {
182         int i = 0;
183         typedDataSeqLength = new int[typedDataList.size()];
184         dataTypeTagLength = new int[typedDataList.size()];
185         dataValueTagLength = new int[typedDataList.size()];
186         typedDataSeqSeqLength = 0;
187 
188         for ( TD td : typedDataList )
189         {
190             int adTypeLen = BerValue.getNbBytes( td.dataType );
191             dataTypeTagLength[i] = 1 + TLV.getNbBytes( adTypeLen ) + adTypeLen;
192             typedDataSeqLength[i] = 1 + TLV.getNbBytes( dataTypeTagLength[i] ) + dataTypeTagLength[i];
193 
194             if ( td.dataValue != null )
195             {
196                 dataValueTagLength[i] = 1 + TLV.getNbBytes( td.dataValue.length ) + td.dataValue.length;
197                 typedDataSeqLength[i] += 1 + TLV.getNbBytes( dataValueTagLength[i] ) + dataValueTagLength[i];
198             }
199 
200             typedDataSeqSeqLength += 1 + TLV.getNbBytes( typedDataSeqLength[i] ) + typedDataSeqLength[i];
201             i++;
202         }
203 
204         return 1 + TLV.getNbBytes( typedDataSeqSeqLength ) + typedDataSeqSeqLength;
205     }
206 
207 
208     /**
209      * {@inheritDoc}
210      */
211     @Override
212     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
213     {
214         if ( buffer == null )
215         {
216             throw new EncoderException( I18n.err( I18n.ERR_148 ) );
217         }
218 
219         try
220         {
221             // The AuthorizationData SEQ OF Tag
222             buffer.put( UniversalTag.SEQUENCE.getValue() );
223             buffer.put( TLV.getBytes( typedDataSeqSeqLength ) );
224 
225             int i = 0;
226             for ( TD td : typedDataList )
227             {
228                 buffer.put( UniversalTag.SEQUENCE.getValue() );
229                 buffer.put( TLV.getBytes( typedDataSeqLength[i] ) );
230 
231                 // the tdType
232                 buffer.put( ( byte ) KerberosConstants.TYPED_DATA_TDTYPE_TAG );
233                 buffer.put( TLV.getBytes( dataTypeTagLength[i] ) );
234                 BerValue.encode( buffer, td.dataType );
235 
236                 if ( td.dataValue != null )
237                 {
238                     // the tdData
239                     buffer.put( ( byte ) KerberosConstants.TYPED_DATA_TDDATA_TAG );
240                     buffer.put( TLV.getBytes( dataValueTagLength[i] ) );
241                     BerValue.encode( buffer, td.dataValue );
242                 }
243 
244                 i++;
245             }
246         }
247         catch ( BufferOverflowException boe )
248         {
249             LOG.error( I18n.err( I18n.ERR_743_CANNOT_ENCODE_TYPED_DATA, 1 + TLV.getNbBytes( typedDataSeqSeqLength )
250                 + typedDataSeqSeqLength, buffer.capacity() ) );
251             throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
252         }
253 
254         if ( IS_DEBUG )
255         {
256             LOG.debug( "TypedData encoding : {}", Strings.dumpBytes( buffer.array() ) );
257             LOG.debug( "TypedData initial value : {}", this );
258         }
259 
260         return buffer;
261     }
262 
263 
264     /**
265      * @see Object#toString()
266      */
267     public String toString()
268     {
269         return toString( "" );
270     }
271 
272 
273     /**
274      * @see Object#toString()
275      */
276     public String toString( String tabs )
277     {
278         StringBuilder sb = new StringBuilder();
279 
280         sb.append( tabs ).append( "TypedData : \n" );
281 
282         for ( TD td : typedDataList )
283         {
284             sb.append( tabs ).append( "    {\n" );
285             sb.append( tabs ).append( "        tdType: " ).append( td.dataType ).append( '\n' );
286             if ( td.dataValue != null )
287             {
288                 sb.append( tabs ).append( "        tdData: " ).append( Strings.dumpBytes( td.dataValue ) )
289                     .append( '\n' );
290             }
291             sb.append( tabs ).append( "    }\n" );
292         }
293 
294         return sb.toString();
295     }
296 }