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.ByteBuffer;
24  import java.util.ArrayList;
25  import java.util.List;
26  
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.server.i18n.I18n;
32  import org.apache.directory.shared.kerberos.KerberosConstants;
33  import org.apache.directory.shared.kerberos.KerberosMessageType;
34  import org.apache.directory.shared.kerberos.messages.KerberosMessage;
35  
36  
37  /**
38   * The KDC-REQ data structure. It will store the object described by the ASN.1 grammar :
39   * <pre>
40   * KDC-REQ    ::= SEQUENCE {
41   *      -- NOTE: first tag is [1], not [0]
42   *      pvno            [1] INTEGER (5) ,
43   *      msg-type        [2] INTEGER (10 -- AS -- | 12 -- TGS --),
44   *      padata          [3] SEQUENCE OF &lt;PA-DATA&gt; OPTIONAL
45                              -- NOTE: not empty --,
46   *      req-body        [4] &lt;KDC-REQ-BODY&gt;
47   * }
48   * </pre>
49   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
50   */
51  public abstract class KdcReq extends KerberosMessage
52  {
53      /** The PA-DATAs */
54      private List<PaData> paData;
55  
56      /** The KDC-REQ-BODY */
57      private KdcReqBody kdcReqBody;
58  
59      // Storage for computed lengths
60      private int pvnoLength;
61      private int msgTypeLength;
62      private int paDataLength;
63      private int paDataSeqLength;
64      private int[] paDataLengths;
65      private int kdcReqBodyLength;
66      private int kdcReqSeqLength;
67      private int kdcReqLength;
68  
69  
70      /**
71       * Creates a new instance of KDC-REQ.
72       */
73      public KdcReq( KerberosMessageType msgType )
74      {
75          super( msgType );
76          paData = new ArrayList<>();
77      }
78  
79  
80      /**
81       * @return the pvno
82       */
83      public int getPvno()
84      {
85          return getProtocolVersionNumber();
86      }
87  
88  
89      /**
90       * @param pvno the pvno to set
91       */
92      public void setPvno( int pvno )
93      {
94          setProtocolVersionNumber( pvno );
95      }
96  
97  
98      /**
99       * @return the paData
100      */
101     public List<PaData> getPaData()
102     {
103         return paData;
104     }
105 
106 
107     /**
108      * @param paData the paData to set
109      */
110     public void addPaData( PaData paData )
111     {
112         this.paData.add( paData );
113     }
114 
115 
116     /**
117      * @return the kdcReqBody
118      */
119     public KdcReqBody getKdcReqBody()
120     {
121         return kdcReqBody;
122     }
123 
124 
125     /**
126      * @param kdcReqBody the kdcReqBody to set
127      */
128     public void setKdcReqBody( KdcReqBody kdcReqBody )
129     {
130         this.kdcReqBody = kdcReqBody;
131     }
132 
133 
134     /**
135      * Compute the KDC-REQ length
136      * <pre>
137      * KDC-REQ :
138      * 
139      * 0x30 L1 KDC-REQ sequence
140      *  |
141      *  +--&gt; 0xA1 0x03 pvno tag
142      *  |     |
143      *  |     +--&gt; 0x02 0x01 0x05 pvno (5)
144      *  |
145      *  +--&gt; 0xA2 0x03 msg-type tag
146      *  |     |
147      *  |     +--&gt; 0x02 0x01 0x0A/0x0C msg-type : either AS-REQ (0x0A) or TGS-REQ (0x0C)
148      *  |     
149      *  +--&gt; 0xA3 L2 pa-data tag
150      *  |     |
151      *  |     +--&gt; 0x30 L2-1 pa-data SEQ
152      *  |           |
153      *  |           +--&gt; 0x30 L2-1-1 pa-data
154      *  |           |
155      *  |           +--&gt; 0x30 L2-1-2 pa-data
156      *  |           :
157      *  |     
158      *  +--&gt; 0xA4 L3 req-body tag
159      *  |     |
160      *  |     +--&gt; 0x30 L3-1 req-body (KDC-REQ-BODY)
161      * </pre>       
162      */
163     public int computeLength()
164     {
165         // The pvno length
166         pvnoLength = 1 + 1 + 1;
167         kdcReqSeqLength = 1 + TLV.getNbBytes( pvnoLength ) + pvnoLength;
168 
169         // The msg-type length
170         msgTypeLength = 1 + 1 + 1;
171         kdcReqSeqLength += 1 + TLV.getNbBytes( msgTypeLength ) + msgTypeLength;
172 
173         // Compute the pa-data length.
174         if ( !paData.isEmpty() )
175         {
176             paDataLengths = new int[paData.size()];
177             int pos = 0;
178             paDataSeqLength = 0;
179 
180             for ( PaData paDataElem : paData )
181             {
182                 paDataLengths[pos] = paDataElem.computeLength();
183                 paDataSeqLength += paDataLengths[pos];
184                 pos++;
185             }
186 
187             paDataLength = 1 + TLV.getNbBytes( paDataSeqLength ) + paDataSeqLength;
188             kdcReqSeqLength += 1 + TLV.getNbBytes( paDataLength ) + paDataLength;
189         }
190 
191         // The KDC-REQ-BODY length
192         kdcReqBodyLength = kdcReqBody.computeLength();
193         kdcReqSeqLength += 1 + TLV.getNbBytes( kdcReqBodyLength ) + kdcReqBodyLength;
194 
195         // compute the global size
196         kdcReqLength = 1 + TLV.getNbBytes( kdcReqSeqLength ) + kdcReqSeqLength;
197 
198         return kdcReqLength;
199     }
200 
201 
202     /**
203      * Encode the KDC-REQ component
204      * 
205      * @param buffer The buffer containing the encoded result
206      * @return The encoded component
207      * @throws EncoderException If the encoding failed
208      */
209     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
210     {
211         if ( buffer == null )
212         {
213             throw new EncoderException( I18n.err( I18n.ERR_148 ) );
214         }
215 
216         // The KDC-REQ SEQ Tag
217         buffer.put( UniversalTag.SEQUENCE.getValue() );
218         buffer.put( TLV.getBytes( kdcReqSeqLength ) );
219 
220         // The PVNO -----------------------------------------------------------
221         // The tag
222         buffer.put( ( byte ) KerberosConstants.KDC_REQ_PVNO_TAG );
223         buffer.put( TLV.getBytes( pvnoLength ) );
224 
225         // The value
226         BerValue.encode( buffer, getProtocolVersionNumber() );
227 
228         // The msg-type if any ------------------------------------------------
229         // The tag
230         buffer.put( ( byte ) KerberosConstants.KDC_REQ_MSG_TYPE_TAG );
231         buffer.put( TLV.getBytes( msgTypeLength ) );
232 
233         // The value
234         BerValue.encode( buffer, getMessageType().getValue() );
235 
236         // The PD-DATA if any -------------------------------------------------
237         if ( !paData.isEmpty() )
238         {
239             // The tag
240             buffer.put( ( byte ) KerberosConstants.KDC_REQ_PA_DATA_TAG );
241             buffer.put( TLV.getBytes( paDataLength ) );
242 
243             // The sequence
244             buffer.put( UniversalTag.SEQUENCE.getValue() );
245             buffer.put( TLV.getBytes( paDataSeqLength ) );
246 
247             // The values
248             for ( PaData paDataElem : paData )
249             {
250                 paDataElem.encode( buffer );
251             }
252         }
253 
254         // The KDC-REQ-BODY ---------------------------------------------------
255         // The tag
256         buffer.put( ( byte ) KerberosConstants.KDC_REQ_KDC_REQ_BODY_TAG );
257         buffer.put( TLV.getBytes( kdcReqBodyLength ) );
258 
259         // The value
260         kdcReqBody.encode( buffer );
261 
262         return buffer;
263     }
264 
265 
266     /**
267      * Pretty print the instance
268      */
269     public String toString( String tabs )
270     {
271         StringBuilder sb = new StringBuilder();
272 
273         sb.append( tabs ).append(
274             "\n>-------------------------------------------------------------------------------\n" );
275         if ( getMessageType() == KerberosMessageType.AS_REQ )
276         {
277             sb.append( tabs ).append( "AS-REQ" ).append( '\n' );
278         }
279         else if ( getMessageType() == KerberosMessageType.TGS_REQ )
280         {
281             sb.append( tabs ).append( "TGS-REQ" ).append( '\n' );
282         }
283         else
284         {
285             sb.append( tabs ).append( "Unknown" ).append( '\n' );
286         }
287 
288         sb.append( tabs ).append( "pvno : " ).append( getProtocolVersionNumber() ).append( '\n' );
289 
290         sb.append( tabs ).append( "msg-type : " ).append( getMessageType() ).append( "\n" );
291 
292         for ( PaData paDataElem : paData )
293         {
294             sb.append( tabs ).append( "padata :\n" );
295             sb.append( paDataElem.toString( tabs + "    " ) ).append( '\n' );
296         }
297 
298         sb.append( tabs ).append( "kdc-req-body : \n" );
299         sb.append( kdcReqBody.toString( tabs + "    " ) ).append( '\n' );
300         sb.append( tabs ).append( "\n-------------------------------------------------------------------------------<\n" );
301 
302         return sb.toString();
303     }
304 
305 
306     /**
307      * @see Object#toString()
308      */
309     public String toString()
310     {
311         return toString( "" );
312     }
313 }