001/*
002 *   Licensed to the Apache Software Foundation (ASF) under one
003 *   or more contributor license agreements.  See the NOTICE file
004 *   distributed with this work for additional information
005 *   regarding copyright ownership.  The ASF licenses this file
006 *   to you under the Apache License, Version 2.0 (the
007 *   "License"); you may not use this file except in compliance
008 *   with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *   Unless required by applicable law or agreed to in writing,
013 *   software distributed under the License is distributed on an
014 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *   KIND, either express or implied.  See the License for the
016 *   specific language governing permissions and limitations
017 *   under the License.
018 *
019 */
020
021package org.apache.directory.shared.kerberos.components;
022
023
024import java.nio.BufferOverflowException;
025import java.nio.ByteBuffer;
026
027import org.apache.directory.api.asn1.Asn1Object;
028import org.apache.directory.api.asn1.EncoderException;
029import org.apache.directory.api.asn1.ber.tlv.BerValue;
030import org.apache.directory.api.asn1.ber.tlv.TLV;
031import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
032import org.apache.directory.api.util.Strings;
033import org.apache.directory.server.i18n.I18n;
034import org.apache.directory.shared.kerberos.KerberosConstants;
035import org.apache.directory.shared.kerberos.KerberosTime;
036import org.slf4j.Logger;
037import org.slf4j.LoggerFactory;
038
039
040/**
041 * Class representing KRB-SAFE-BODY message
042 * 
043 * <pre>
044 * KRB-SAFE-BODY   ::= SEQUENCE {
045 *         user-data       [0] OCTET STRING,
046 *         timestamp       [1] KerberosTime OPTIONAL,
047 *         usec            [2] Microseconds OPTIONAL,
048 *         seq-number      [3] UInt32 OPTIONAL,
049 *         s-address       [4] HostAddress,
050 *         r-address       [5] HostAddress OPTIONAL
051 * }
052 *</pre>
053 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
054 */
055public class KrbSafeBody implements Asn1Object
056{
057    /** The logger */
058    private static final Logger log = LoggerFactory.getLogger( KrbSafeBody.class );
059
060    /** Speedup for logs */
061    private static final boolean IS_DEBUG = log.isDebugEnabled();
062
063    /** the user data */
064    private byte[] userData;
065
066    /** the current time of the sender */
067    private KerberosTime timestamp;
068
069    /** the microsecond part of the timestamp */
070    private Integer usec;
071
072    /** the sequence number */
073    private Integer seqNumber;
074
075    /** the sender's address */
076    private HostAddress senderAddress;
077
078    /** the recipient's address */
079    private HostAddress recipientAddress;
080
081    // Storage for computed lengths
082    private int userDataLen;
083    private int timestampLen;
084    private int usecLen;
085    private int seqNumberLen;
086    private int senderAddressLen;
087    private int recipientAddressLen;
088    private int krbSafeBodySeqLen;
089
090
091    /**
092     * Creates a new instance of KrbSafeBody.
093     */
094    public KrbSafeBody()
095    {
096    }
097
098
099    /**
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}