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 * The EncKrbPrivPart structure is used to store a EncKrbPrivPart associated to a type.
042 * 
043 * The ASN.1 grammar is :
044 * <pre>
045 * EncKrbPrivPart  ::= [APPLICATION 28] SEQUENCE {
046 *      user-data       [0] OCTET STRING,
047 *      timestamp       [1] KerberosTime OPTIONAL,
048 *      usec            [2] Microseconds OPTIONAL,
049 *      seq-number      [3] UInt32 OPTIONAL,
050 *      s-address       [4] HostAddress -- sender's addr --,
051 *      r-address       [5] HostAddress OPTIONAL -- recip's addr
052 * }
053 * </pre>
054 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
055 */
056//NOTE: this ASN.1 structure is quite identical to KrbSafeBody
057public class EncKrbPrivPart implements Asn1Object
058{
059    /** The logger */
060    private static final Logger log = LoggerFactory.getLogger( EncKrbPrivPart.class );
061
062    /** Speedup for logs */
063    private static final boolean IS_DEBUG = log.isDebugEnabled();
064
065    /** the user data */
066    private byte[] userData;
067
068    /** the current time of the sender */
069    private KerberosTime timestamp;
070
071    /** the microsecond part of the timestamp */
072    private Integer usec;
073
074    /** the sequence number */
075    private Integer seqNumber;
076
077    /** the sender's address */
078    private HostAddress senderAddress;
079
080    /** the recipient's address */
081    private HostAddress recipientAddress;
082
083    // Storage for computed lengths
084    private int userDataLen;
085    private int timestampLen;
086    private int usecLen;
087    private int seqNumberLen;
088    private int senderAddressLen;
089    private int recipientAddressLen;
090    private int encKrbPrivPartSeqLen;
091    private int encKrbPrivPartLen;
092
093
094    /**
095     * @return the userData
096     */
097    public byte[] getUserData()
098    {
099        return userData;
100    }
101
102
103    /**
104     * @param userData the userData to set
105     */
106    public void setUserData( byte[] userData )
107    {
108        this.userData = userData;
109    }
110
111
112    /**
113     * @return the timestamp
114     */
115    public KerberosTime getTimestamp()
116    {
117        return timestamp;
118    }
119
120
121    /**
122     * @param timestamp the timestamp to set
123     */
124    public void setTimestamp( KerberosTime timestamp )
125    {
126        this.timestamp = timestamp;
127    }
128
129
130    /**
131     * @return the usec
132     */
133    public int getUsec()
134    {
135        if ( usec == null )
136        {
137            return 0;
138        }
139
140        return usec;
141    }
142
143
144    /**
145     * @param usec the usec to set
146     */
147    public void setUsec( int usec )
148    {
149        this.usec = usec;
150    }
151
152
153    /**
154     * @return the seqNumber
155     */
156    public int getSeqNumber()
157    {
158        if ( seqNumber == null )
159        {
160            return 0;
161        }
162
163        return seqNumber;
164    }
165
166
167    /**
168     * @param seqNumber the seqNumber to set
169     */
170    public void setSeqNumber( int seqNumber )
171    {
172        this.seqNumber = seqNumber;
173    }
174
175
176    /**
177     * @return the senderAddress
178     */
179    public HostAddress getSenderAddress()
180    {
181        return senderAddress;
182    }
183
184
185    /**
186     * @param senderAddress the senderAddress to set
187     */
188    public void setSenderAddress( HostAddress senderAddress )
189    {
190        this.senderAddress = senderAddress;
191    }
192
193
194    /**
195     * @return the recipientAddress
196     */
197    public HostAddress getRecipientAddress()
198    {
199        return recipientAddress;
200    }
201
202
203    /**
204     * @param recipientAddress the recipientAddress to set
205     */
206    public void setRecipientAddress( HostAddress recipientAddress )
207    {
208        this.recipientAddress = recipientAddress;
209    }
210
211
212    /**
213     * Compute the EncKrbPrivPart length:
214     * 
215     * <pre>
216     * 0x7C L0 EncKrbPrivPart
217     *  |
218     *  |
219     * 0x30 L1 EncKrbPrivPart SEQ
220     *  |
221     *  +--&gt; 0xA0 L2 user-data tag
222     *  |     |
223     *  |     +--&gt; 0x04 L2-1 user-data (Octet String)
224     *  |
225     *  +--&gt; 0xA1 0x11 timestamp tag
226     *  |     |
227     *  |     +--&gt; 0x18 0x0F timestamp (KerberosTime)
228     *  |
229     *  +--&gt; 0xA2 L3 usec tag
230     *  |     |
231     *  |     +--&gt; 0x02 L3-1 usec (Microseconds)
232     *  |
233     *  +--&gt; 0xA3 L4 seq-number tag
234     *  |     |
235     *  |     +--&gt; 0x02 L4-1 seqnumber (UInt32)
236     *  |
237     *  +--&gt; 0xA4 L5 s-address tag
238     *  |     |
239     *  |     +--&gt; 0x30 L5-1 s-address (HostAddress)
240     *  |
241     *  +--&gt; 0xA5 L6 r-address tag
242     *        |
243     *        +--&gt; 0x30 L6-1 r-address (HostAddress)
244     * </pre>       
245     */
246    @Override
247    public int computeLength()
248    {
249        userDataLen = 1 + TLV.getNbBytes( userData.length ) + userData.length;
250        encKrbPrivPartSeqLen = 1 + TLV.getNbBytes( userDataLen ) + userDataLen;
251
252        senderAddressLen = senderAddress.computeLength();
253        encKrbPrivPartSeqLen += 1 + TLV.getNbBytes( senderAddressLen ) + senderAddressLen;
254
255        if ( timestamp != null )
256        {
257            timestampLen = timestamp.getBytes().length;
258            timestampLen = 1 + TLV.getNbBytes( timestampLen ) + timestampLen;
259            encKrbPrivPartSeqLen += 1 + TLV.getNbBytes( timestampLen ) + timestampLen;
260        }
261
262        if ( usec != null )
263        {
264            usecLen = BerValue.getNbBytes( usec );
265            usecLen = 1 + TLV.getNbBytes( usecLen ) + usecLen;
266            encKrbPrivPartSeqLen += 1 + TLV.getNbBytes( usecLen ) + usecLen;
267        }
268
269        if ( seqNumber != null )
270        {
271            seqNumberLen = BerValue.getNbBytes( seqNumber );
272            seqNumberLen = 1 + TLV.getNbBytes( seqNumberLen ) + seqNumberLen;
273            encKrbPrivPartSeqLen += 1 + TLV.getNbBytes( seqNumberLen ) + seqNumberLen;
274        }
275
276        if ( recipientAddress != null )
277        {
278            recipientAddressLen = recipientAddress.computeLength();
279            encKrbPrivPartSeqLen += 1 + TLV.getNbBytes( recipientAddressLen ) + recipientAddressLen;
280        }
281
282        encKrbPrivPartLen = 1 + TLV.getNbBytes( encKrbPrivPartSeqLen ) + encKrbPrivPartSeqLen;
283
284        return 1 + TLV.getNbBytes( encKrbPrivPartLen ) + encKrbPrivPartLen;
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( ( byte ) KerberosConstants.ENC_KRB_PRIV_PART_TAG );
302            buffer.put( TLV.getBytes( encKrbPrivPartLen ) );
303
304            buffer.put( UniversalTag.SEQUENCE.getValue() );
305            buffer.put( TLV.getBytes( encKrbPrivPartSeqLen ) );
306
307            // user-data
308            buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_USER_DATA_TAG );
309            buffer.put( TLV.getBytes( userDataLen ) );
310            BerValue.encode( buffer, userData );
311
312            if ( timestamp != null )
313            {
314                // timestamp tag
315                buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_TIMESTAMP_TAG );
316                buffer.put( TLV.getBytes( timestampLen ) );
317
318                // timestamp value
319                buffer.put( UniversalTag.GENERALIZED_TIME.getValue() );
320                buffer.put( ( byte ) 0x0F );
321                buffer.put( timestamp.getBytes() );
322            }
323
324            if ( usec != null )
325            {
326                // usec
327                buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_USEC_TAG );
328                buffer.put( TLV.getBytes( usecLen ) );
329                BerValue.encode( buffer, usec );
330            }
331
332            if ( seqNumber != null )
333            {
334                // seq-number
335                buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_SEQ_NUMBER_TAG );
336                buffer.put( TLV.getBytes( seqNumberLen ) );
337                BerValue.encode( buffer, seqNumber );
338            }
339
340            // s-address
341            buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_SENDER_ADDRESS_TAG );
342            buffer.put( TLV.getBytes( senderAddressLen ) );
343            senderAddress.encode( buffer );
344
345            if ( recipientAddress != null )
346            {
347                // s-address
348                buffer.put( ( byte ) KerberosConstants.KRB_SAFE_BODY_RECIPIENT_ADDRESS_TAG );
349                buffer.put( TLV.getBytes( recipientAddressLen ) );
350                recipientAddress.encode( buffer );
351            }
352        }
353        catch ( BufferOverflowException boe )
354        {
355            log.error( I18n.err( I18n.ERR_735_CANNOT_ENCODE_KRBSAFEBODY, 1 + TLV.getNbBytes( encKrbPrivPartLen )
356                + encKrbPrivPartLen, buffer.capacity() ) );
357            throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
358        }
359
360        if ( IS_DEBUG )
361        {
362            log.debug( "EncKrbPrivPart encoding : {}", Strings.dumpBytes( buffer.array() ) );
363            log.debug( "EncKrbPrivPart initial value : {}", this );
364        }
365
366        return buffer;
367    }
368
369
370    /**
371     * @see Object#toString()
372     */
373    public String toString()
374    {
375        StringBuilder sb = new StringBuilder();
376
377        sb.append( "EncKrbPrivPart : {\n" );
378        sb.append( "    user-data: " ).append( Strings.dumpBytes( userData ) ).append( '\n' );
379
380        if ( timestamp != null )
381        {
382            sb.append( "    timestamp: " ).append( timestamp.getDate() ).append( '\n' );
383        }
384
385        if ( usec != null )
386        {
387            sb.append( "    usec: " ).append( usec ).append( '\n' );
388        }
389
390        if ( seqNumber != null )
391        {
392            sb.append( "    seq-number: " ).append( seqNumber ).append( '\n' );
393        }
394
395        sb.append( "    s-address: " ).append( senderAddress ).append( '\n' );
396
397        if ( recipientAddress != null )
398        {
399            sb.append( "    r-address: " ).append( recipientAddress ).append( '\n' );
400        }
401
402        sb.append( "}\n" );
403
404        return sb.toString();
405    }
406}