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  
27  import org.apache.directory.api.asn1.Asn1Object;
28  import org.apache.directory.api.asn1.EncoderException;
29  import org.apache.directory.api.asn1.ber.tlv.BerValue;
30  import org.apache.directory.api.asn1.ber.tlv.TLV;
31  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
32  import org.apache.directory.api.util.Strings;
33  import org.apache.directory.server.i18n.I18n;
34  import org.apache.directory.shared.kerberos.KerberosConstants;
35  import org.apache.directory.shared.kerberos.KerberosTime;
36  import org.slf4j.Logger;
37  import org.slf4j.LoggerFactory;
38  
39  
40  /**
41   * Class representing KRB-SAFE-BODY message
42   * 
43   * <pre>
44   * KRB-SAFE-BODY   ::= SEQUENCE {
45   *         user-data       [0] OCTET STRING,
46   *         timestamp       [1] KerberosTime OPTIONAL,
47   *         usec            [2] Microseconds OPTIONAL,
48   *         seq-number      [3] UInt32 OPTIONAL,
49   *         s-address       [4] HostAddress,
50   *         r-address       [5] HostAddress OPTIONAL
51   * }
52   *</pre>
53   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
54   */
55  public class KrbSafeBody implements Asn1Object
56  {
57      /** The logger */
58      private static final Logger log = LoggerFactory.getLogger( KrbSafeBody.class );
59  
60      /** Speedup for logs */
61      private static final boolean IS_DEBUG = log.isDebugEnabled();
62  
63      /** the user data */
64      private byte[] userData;
65  
66      /** the current time of the sender */
67      private KerberosTime timestamp;
68  
69      /** the microsecond part of the timestamp */
70      private Integer usec;
71  
72      /** the sequence number */
73      private Integer seqNumber;
74  
75      /** the sender's address */
76      private HostAddress senderAddress;
77  
78      /** the recipient's address */
79      private HostAddress recipientAddress;
80  
81      // Storage for computed lengths
82      private int userDataLen;
83      private int timestampLen;
84      private int usecLen;
85      private int seqNumberLen;
86      private int senderAddressLen;
87      private int recipientAddressLen;
88      private int krbSafeBodySeqLen;
89  
90  
91      /**
92       * Creates a new instance of KrbSafeBody.
93       */
94      public KrbSafeBody()
95      {
96      }
97  
98  
99      /**
100      * @return the userData
101      */
102     public byte[] getUserData()
103     {
104         return userData;
105     }
106 
107 
108     /**
109      * @param userData the userData to set
110      */
111     public void setUserData( byte[] userData )
112     {
113         this.userData = userData;
114     }
115 
116 
117     /**
118      * @return the timestamp
119      */
120     public KerberosTime getTimestamp()
121     {
122         return timestamp;
123     }
124 
125 
126     /**
127      * @param timestamp the timestamp to set
128      */
129     public void setTimestamp( KerberosTime timestamp )
130     {
131         this.timestamp = timestamp;
132     }
133 
134 
135     /**
136      * @return the usec
137      */
138     public int getUsec()
139     {
140         if ( usec == null )
141         {
142             return 0;
143         }
144 
145         return usec;
146     }
147 
148 
149     /**
150      * @param usec the usec to set
151      */
152     public void setUsec( int usec )
153     {
154         this.usec = usec;
155     }
156 
157 
158     /**
159      * @return the seqNumber
160      */
161     public int getSeqNumber()
162     {
163         if ( seqNumber == null )
164         {
165             return 0;
166         }
167 
168         return seqNumber;
169     }
170 
171 
172     /**
173      * @param seqNumber the seqNumber to set
174      */
175     public void setSeqNumber( int seqNumber )
176     {
177         this.seqNumber = seqNumber;
178     }
179 
180 
181     /**
182      * @return the senderAddress
183      */
184     public HostAddress getSenderAddress()
185     {
186         return senderAddress;
187     }
188 
189 
190     /**
191      * @param senderAddress the senderAddress to set
192      */
193     public void setSenderAddress( HostAddress senderAddress )
194     {
195         this.senderAddress = senderAddress;
196     }
197 
198 
199     /**
200      * @return the recipientAddress
201      */
202     public HostAddress getRecipientAddress()
203     {
204         return recipientAddress;
205     }
206 
207 
208     /**
209      * @param recipientAddress the recipientAddress to set
210      */
211     public void setRecipientAddress( HostAddress recipientAddress )
212     {
213         this.recipientAddress = recipientAddress;
214     }
215 
216 
217     /**
218      * Compute the KRB-SAFE-BODY length:
219      * 
220      * <pre>
221      * 0x30 L1 KRB-SAFE-BODY SEQ
222      *  |
223      *  +--&gt; 0xA0 L2 user-data tag
224      *  |     |
225      *  |     +--&gt; 0x04 L2-1 user-data (Octet String)
226      *  |
227      *  +--&gt; 0xA1 0x11 timestamp tag
228      *  |     |
229      *  |     +--&gt; 0x18 0x0F timestamp (KerberosTime)
230      *  |
231      *  +--&gt; 0xA2 L3 usec tag
232      *  |     |
233      *  |     +--&gt; 0x02 L3-1 usec (Microseconds)
234      *  |
235      *  +--&gt; 0xA3 L4 seq-number tag
236      *  |     |
237      *  |     +--&gt; 0x02 L4-1 seqnumber (UInt32)
238      *  |
239      *  +--&gt; 0xA4 L5 s-address tag
240      *  |     |
241      *  |     +--&gt; 0x30 L5-1 s-address (HostAddress)
242      *  |
243      *  +--&gt; 0xA5 L6 r-address tag
244      *        |
245      *        +--&gt; 0x30 L6-1 r-address (HostAddress)
246      * </pre>       
247      */
248     @Override
249     public int computeLength()
250     {
251         userDataLen = 1 + TLV.getNbBytes( userData.length ) + userData.length;
252         krbSafeBodySeqLen = 1 + TLV.getNbBytes( userDataLen ) + userDataLen;
253 
254         senderAddressLen = senderAddress.computeLength();
255         krbSafeBodySeqLen += 1 + TLV.getNbBytes( senderAddressLen ) + senderAddressLen;
256 
257         if ( timestamp != null )
258         {
259             timestampLen = timestamp.getBytes().length;
260             timestampLen = 1 + TLV.getNbBytes( timestampLen ) + timestampLen;
261             krbSafeBodySeqLen += 1 + TLV.getNbBytes( timestampLen ) + timestampLen;
262         }
263 
264         if ( usec != null )
265         {
266             usecLen = BerValue.getNbBytes( usec );
267             usecLen = 1 + TLV.getNbBytes( usecLen ) + usecLen;
268             krbSafeBodySeqLen += 1 + TLV.getNbBytes( usecLen ) + usecLen;
269         }
270 
271         if ( seqNumber != null )
272         {
273             seqNumberLen = BerValue.getNbBytes( seqNumber );
274             seqNumberLen = 1 + TLV.getNbBytes( seqNumberLen ) + seqNumberLen;
275             krbSafeBodySeqLen += 1 + TLV.getNbBytes( seqNumberLen ) + seqNumberLen;
276         }
277 
278         if ( recipientAddress != null )
279         {
280             recipientAddressLen = recipientAddress.computeLength();
281             krbSafeBodySeqLen += 1 + TLV.getNbBytes( recipientAddressLen ) + recipientAddressLen;
282         }
283 
284         return 1 + TLV.getNbBytes( krbSafeBodySeqLen ) + krbSafeBodySeqLen;
285     }
286 
287 
288     /**
289      * {@inheritDoc}
290      */
291     @Override
292     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
293     {
294         if ( buffer == null )
295         {
296             throw new EncoderException( I18n.err( I18n.ERR_148 ) );
297         }
298 
299         try
300         {
301             buffer.put( UniversalTag.SEQUENCE.getValue() );
302             buffer.put( TLV.getBytes( krbSafeBodySeqLen ) );
303 
304             // user-data
305             buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_USER_DATA_TAG );
306             buffer.put( TLV.getBytes( userDataLen ) );
307             BerValue.encode( buffer, userData );
308 
309             if ( timestamp != null )
310             {
311                 // timestamp tag
312                 buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_TIMESTAMP_TAG );
313                 buffer.put( TLV.getBytes( timestampLen ) );
314 
315                 // timestamp value
316                 buffer.put( UniversalTag.GENERALIZED_TIME.getValue() );
317                 buffer.put( ( byte ) 0x0F );
318                 buffer.put( timestamp.getBytes() );
319             }
320 
321             if ( usec != null )
322             {
323                 // usec
324                 buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_USEC_TAG );
325                 buffer.put( TLV.getBytes( usecLen ) );
326                 BerValue.encode( buffer, usec );
327             }
328 
329             if ( seqNumber != null )
330             {
331                 // seq-number
332                 buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_SEQ_NUMBER_TAG );
333                 buffer.put( TLV.getBytes( seqNumberLen ) );
334                 BerValue.encode( buffer, seqNumber );
335             }
336 
337             // s-address
338             buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_SENDER_ADDRESS_TAG );
339             buffer.put( TLV.getBytes( senderAddressLen ) );
340             senderAddress.encode( buffer );
341 
342             if ( recipientAddress != null )
343             {
344                 // s-address
345                 buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_RECIPIENT_ADDRESS_TAG );
346                 buffer.put( TLV.getBytes( recipientAddressLen ) );
347                 recipientAddress.encode( buffer );
348             }
349         }
350         catch ( BufferOverflowException boe )
351         {
352             log.error( I18n.err( I18n.ERR_735_CANNOT_ENCODE_KRBSAFEBODY, 1 + TLV.getNbBytes( krbSafeBodySeqLen )
353                 + krbSafeBodySeqLen, buffer.capacity() ) );
354             throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
355         }
356 
357         if ( IS_DEBUG )
358         {
359             log.debug( "KrbSafeBody encoding : {}", Strings.dumpBytes( buffer.array() ) );
360             log.debug( "KrbSafeBody initial value : {}", this );
361         }
362 
363         return buffer;
364     }
365 
366 
367     /**
368      * @see Object#toString()
369      */
370     public String toString()
371     {
372         StringBuilder sb = new StringBuilder();
373 
374         sb.append( "KRB-SAFE-BODY : {\n" );
375         sb.append( "    user-data: " ).append( Strings.dumpBytes( userData ) ).append( '\n' );
376 
377         if ( timestamp != null )
378         {
379             sb.append( "    timestamp: " ).append( timestamp.getDate() ).append( '\n' );
380         }
381 
382         if ( usec != null )
383         {
384             sb.append( "    usec: " ).append( usec ).append( '\n' );
385         }
386 
387         if ( seqNumber != null )
388         {
389             sb.append( "    seq-number: " ).append( seqNumber ).append( '\n' );
390         }
391 
392         sb.append( "    s-address: " ).append( senderAddress ).append( '\n' );
393 
394         if ( recipientAddress != null )
395         {
396             sb.append( "    r-address: " ).append( recipientAddress ).append( '\n' );
397         }
398 
399         sb.append( "}\n" );
400 
401         return sb.toString();
402     }
403 }