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.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.KerberosMessageType;
35  import org.apache.directory.shared.kerberos.messages.KerberosMessage;
36  import org.apache.directory.shared.kerberos.messages.Ticket;
37  
38  
39  /**
40   * The KDC-REP data structure. It will store the object described by the ASN.1 grammar :
41   * <pre>
42   * KDC-REP         ::= SEQUENCE {
43   *         pvno            [0] INTEGER (5),
44   *         msg-type        [1] INTEGER (11 -- AS -- | 13 -- TGS --),
45   *         padata          [2] SEQUENCE OF PA-DATA OPTIONAL
46   *                                 -- NOTE: not empty --,
47   *         crealm          [3] Realm,
48   *         cname           [4] &lt;PrincipalName&gt;,
49   *         ticket          [5] &lt;Ticket@gt;,
50   *         enc-part        [6] &lt;EncryptedData&gt;
51   *                                 -- EncASRepPart or EncTGSRepPart,
52   *                                 -- as appropriate
53   * }
54   * </pre>
55   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
56   */
57  public class KdcRep extends KerberosMessage
58  {
59      /** The PA-DATAs */
60      private List<PaData> paData;
61  
62      /** The client realm */
63      private String crealm;
64  
65      /** A storage for a byte array representation of the realm */
66      private byte[] crealmBytes;
67  
68      /** The client principal name */
69      private PrincipalName cname;
70  
71      /** The ticket tickets */
72      private Ticket ticket;
73  
74      /** Encoded part */
75      private EncryptedData encPart;
76  
77      /** The decoded KDC-REP part */
78      protected EncKdcRepPart encKdcRepPart;
79  
80      // Storage for computed lengths
81      private int pvnoLength;
82      private int msgTypeLength;
83      private int paDataLength;
84      private int paDataSeqLength;
85      private int[] paDataLengths;
86      private int cnameLength;
87      private int crealmLength;
88      private int ticketLength;
89      private int encPartLength;
90      private int kdcRepSeqLength;
91      private int kdcRepLength;
92  
93  
94      /**
95       * Creates a new instance of KDC-REP.
96       */
97      public KdcRep( KerberosMessageType msgType )
98      {
99          super( msgType );
100         paData = new ArrayList<>();
101     }
102 
103 
104     /**
105      * @return the pvno
106      */
107     public int getPvno()
108     {
109         return getProtocolVersionNumber();
110     }
111 
112 
113     /**
114      * @param pvno the pvno to set
115      */
116     public void setPvno( int pvno )
117     {
118         setProtocolVersionNumber( pvno );
119     }
120 
121 
122     /**
123      * @return the paData
124      */
125     public List<PaData> getPaData()
126     {
127         return paData;
128     }
129 
130 
131     /**
132      * @param paData the paData to set
133      */
134     public void addPaData( PaData paData )
135     {
136         this.paData.add( paData );
137     }
138 
139 
140     /**
141      * Returns the client realm.
142      *
143      * @return The client realm.
144      */
145     public String getCRealm()
146     {
147         return crealm;
148     }
149 
150 
151     /**
152      * Set the client realm
153      * @param crealm the client realm
154      */
155     public void setCRealm( String crealm )
156     {
157         this.crealm = crealm;
158     }
159 
160 
161     /**
162      * Returns the client {@link PrincipalName}.
163      *
164      * @return The client {@link PrincipalName}.
165      */
166     public PrincipalName getCName()
167     {
168         return cname;
169     }
170 
171 
172     /**
173      * Set the client principalName
174      * @param cname the client principalName
175      */
176     public void setCName( PrincipalName cname )
177     {
178         this.cname = cname;
179     }
180 
181 
182     /**
183      * Returns the {@link Ticket}
184      *
185      * @return The {@link Ticket}
186      */
187     public Ticket getTicket()
188     {
189         return ticket;
190     }
191 
192 
193     /**
194      * Set the Ticket
195      * @param ticket the ticket to set
196      */
197     public void setTicket( Ticket ticket )
198     {
199         this.ticket = ticket;
200     }
201 
202 
203     /**
204      * Returns the encrypted part as {@link EncryptedData}.
205      *
206      * @return The encrypted part as {@link EncryptedData}.
207      */
208     public EncryptedData getEncPart()
209     {
210         return encPart;
211     }
212 
213 
214     /**
215      * @param encPart the encPart to set
216      */
217     public void setEncPart( EncryptedData encPart )
218     {
219         this.encPart = encPart;
220     }
221 
222 
223     /**
224      * @return the encKdcRepPart
225      */
226     public EncKdcRepPart getEncKdcRepPart()
227     {
228         return encKdcRepPart;
229     }
230 
231 
232     /**
233      * @param encKdcRepPart the encKdcRepPart to set
234      */
235     public void setEncKdcRepPart( EncKdcRepPart encKdcRepPart )
236     {
237         this.encKdcRepPart = encKdcRepPart;
238     }
239 
240 
241     /**
242      * Compute the KDC-REP length
243      * <pre>
244      * KDC-REP :
245      * 
246      * 0x30 L1 KDC-REP sequence
247      *  |
248      *  +--&gt; 0xA0 0x03 pvno tag
249      *  |     |
250      *  |     +--&gt; 0x02 0x01 0x05 pvno (5)
251      *  |
252      *  +--&gt; 0xA1 0x03 msg-type tag
253      *  |     |
254      *  |     +--&gt; 0x02 0x01 0x0B/0x0D msg-type : either AS-REP (0x0B) or TGS-REP (0x0D)
255      *  |     
256      *  +--&gt; 0xA2 L2 pa-data tag
257      *  |     |
258      *  |     +--&gt; 0x30 L2-1 pa-data SEQ
259      *  |           |
260      *  |           +--&gt; 0x30 L2-1-1 pa-data
261      *  |           |
262      *  |           +--&gt; 0x30 L2-1-2 pa-data
263      *  |           :
264      *  |     
265      *  +--&gt; 0xA3 L3 crealm tag
266      *  |     |
267      *  |     +--&gt; 0x1B L3-1 crealm
268      *  |
269      *  +--&gt; 0xA4 L4 cname tag
270      *  |     |
271      *  |     +--&gt; 0x30 L4-1 cname
272      *  |
273      *  +--&gt; 0xA5 L5 ticket tag
274      *  |     |
275      *  |     +--&gt; 0x61 L5-1 ticket
276      *  |
277      *  +--&gt; 0xA6 L6 enc-part tag
278      *        |
279      *        +--&gt; 0x30 L6-1 enc-part
280      *  
281      * </pre>       
282      */
283     public int computeLength()
284     {
285         // The pvno length
286         pvnoLength = 1 + 1 + 1;
287         kdcRepSeqLength = 1 + TLV.getNbBytes( pvnoLength ) + pvnoLength;
288 
289         // The msg-type length
290         msgTypeLength = 1 + 1 + 1;
291         kdcRepSeqLength += 1 + TLV.getNbBytes( msgTypeLength ) + msgTypeLength;
292 
293         // Compute the pa-data length.
294         if ( !paData.isEmpty() )
295         {
296             paDataLengths = new int[paData.size()];
297             int pos = 0;
298             paDataSeqLength = 0;
299 
300             for ( PaData paDataElem : paData )
301             {
302                 paDataLengths[pos] = paDataElem.computeLength();
303                 paDataSeqLength += paDataLengths[pos];
304                 pos++;
305             }
306 
307             paDataLength = 1 + TLV.getNbBytes( paDataSeqLength ) + paDataSeqLength;
308             kdcRepSeqLength += 1 + TLV.getNbBytes( paDataLength ) + paDataLength;
309         }
310 
311         // The crealm length
312         crealmBytes = Strings.getBytesUtf8( crealm );
313         crealmLength = 1 + TLV.getNbBytes( crealmBytes.length ) + crealmBytes.length;
314         kdcRepSeqLength += 1 + TLV.getNbBytes( crealmLength ) + crealmLength;
315 
316         // Compute the client principalName length
317         cnameLength = cname.computeLength();
318         kdcRepSeqLength += 1 + TLV.getNbBytes( cnameLength ) + cnameLength;
319 
320         // Compute the ticket length
321         ticketLength = ticket.computeLength();
322         kdcRepSeqLength += 1 + TLV.getNbBytes( ticketLength ) + ticketLength;
323 
324         // Compute the encrypted part
325         encPartLength = encPart.computeLength();
326         kdcRepSeqLength += 1 + TLV.getNbBytes( encPartLength ) + encPartLength;
327 
328         // compute the global size
329         kdcRepLength = 1 + TLV.getNbBytes( kdcRepSeqLength ) + kdcRepSeqLength;
330 
331         return kdcRepLength;
332     }
333 
334 
335     /**
336      * Encode the KDC-REP component
337      * 
338      * @param buffer The buffer containing the encoded result
339      * @return The encoded component
340      * @throws EncoderException If the encoding failed
341      */
342     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
343     {
344         if ( buffer == null )
345         {
346             throw new EncoderException( I18n.err( I18n.ERR_148 ) );
347         }
348 
349         // The KDC-REP SEQ Tag
350         buffer.put( UniversalTag.SEQUENCE.getValue() );
351         buffer.put( TLV.getBytes( kdcRepSeqLength ) );
352 
353         // The PVNO -----------------------------------------------------------
354         // The tag
355         buffer.put( ( byte ) KerberosConstants.KDC_REP_PVNO_TAG );
356         buffer.put( TLV.getBytes( pvnoLength ) );
357 
358         // The value
359         BerValue.encode( buffer, getProtocolVersionNumber() );
360 
361         // The MSG-TYPE if any ------------------------------------------------
362         // The tag
363         buffer.put( ( byte ) KerberosConstants.KDC_REP_MSG_TYPE_TAG );
364         buffer.put( TLV.getBytes( msgTypeLength ) );
365 
366         // The value
367         BerValue.encode( buffer, getMessageType().getValue() );
368 
369         // The PD-DATA if any -------------------------------------------------
370         if ( !paData.isEmpty() )
371         {
372             // The tag
373             buffer.put( ( byte ) KerberosConstants.KDC_REP_PA_DATA_TAG );
374             buffer.put( TLV.getBytes( paDataLength ) );
375 
376             // The sequence
377             buffer.put( UniversalTag.SEQUENCE.getValue() );
378             buffer.put( TLV.getBytes( paDataSeqLength ) );
379 
380             // The values
381             for ( PaData paDataElem : paData )
382             {
383                 paDataElem.encode( buffer );
384             }
385         }
386 
387         // The CREALM ---------------------------------------------------------
388         // The tag
389         buffer.put( ( byte ) KerberosConstants.KDC_REP_CREALM_TAG );
390         buffer.put( TLV.getBytes( crealmLength ) );
391 
392         // The value
393         buffer.put( UniversalTag.GENERAL_STRING.getValue() );
394         buffer.put( TLV.getBytes( crealmBytes.length ) );
395         buffer.put( crealmBytes );
396 
397         // The CNAME ----------------------------------------------------------
398         // The tag
399         buffer.put( ( byte ) KerberosConstants.KDC_REP_CNAME_TAG );
400         buffer.put( TLV.getBytes( cnameLength ) );
401 
402         // The value
403         cname.encode( buffer );
404 
405         // The TICKET ---------------------------------------------------------
406         // The tag
407         buffer.put( ( byte ) KerberosConstants.KDC_REP_TICKET_TAG );
408         buffer.put( TLV.getBytes( ticketLength ) );
409 
410         // The value
411         ticket.encode( buffer );
412 
413         // The ENC-PART -------------------------------------------------------
414         // The tag
415         buffer.put( ( byte ) KerberosConstants.KDC_REP_ENC_PART_TAG );
416         buffer.put( TLV.getBytes( encPartLength ) );
417 
418         // The value
419         encPart.encode( buffer );
420 
421         return buffer;
422     }
423 
424 
425     /**
426      * Pretty print the instance
427      */
428     public String toString( String tabs )
429     {
430         StringBuilder sb = new StringBuilder();
431 
432         sb.append( tabs ).append(
433             "\n>-------------------------------------------------------------------------------\n" );
434         sb.append( tabs ).append( "KdcRep : " );
435 
436         if ( getMessageType() == KerberosMessageType.AS_REP )
437         {
438             sb.append( "AS-REP" ).append( '\n' );
439         }
440         else if ( getMessageType() == KerberosMessageType.TGS_REP )
441         {
442             sb.append( "TGS-REP" ).append( '\n' );
443         }
444         else
445         {
446             sb.append( "Unknown" ).append( '\n' );
447         }
448 
449         sb.append( tabs ).append( "pvno : " ).append( getProtocolVersionNumber() ).append( '\n' );
450 
451         sb.append( tabs ).append( "msg-type : " ).append( getMessageType() ).append( '\n' );
452 
453         for ( PaData paDataElem : paData )
454         {
455             sb.append( tabs ).append( "padata : " ).append( paDataElem.toString( tabs + "    " ) ).append( '\n' );
456         }
457 
458         sb.append( tabs ).append( "crealm : " ).append( crealm ).append( '\n' );
459         sb.append( tabs ).append( "cname : " ).append( cname ).append( '\n' );
460         sb.append( ticket.toString( tabs ) );
461         sb.append( encPart.toString( tabs ) );
462         sb.append( tabs ).append(
463             "\n-------------------------------------------------------------------------------<\n" );
464 
465         return sb.toString();
466     }
467 
468 
469     /**
470      * @see Object#toString()
471      */
472     public String toString()
473     {
474         return toString( "" );
475     }
476 }