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 */
020package org.apache.directory.shared.kerberos.components;
021
022
023import java.nio.BufferOverflowException;
024import java.nio.ByteBuffer;
025
026import org.apache.directory.api.asn1.Asn1Object;
027import org.apache.directory.api.asn1.EncoderException;
028import org.apache.directory.api.asn1.ber.tlv.BerValue;
029import org.apache.directory.api.asn1.ber.tlv.TLV;
030import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
031import org.apache.directory.api.util.Strings;
032import org.apache.directory.server.i18n.I18n;
033import org.apache.directory.shared.kerberos.KerberosConstants;
034import org.apache.directory.shared.kerberos.KerberosTime;
035import org.slf4j.Logger;
036import org.slf4j.LoggerFactory;
037
038
039/**
040 * The PaEncTsEnc structure is used to store a PA-ENC-TS-ENC associated to a type.
041 * 
042 * The ASN.1 grammar is :
043 * <pre>
044 * PA-ENC-TS-ENC           ::= SEQUENCE {
045 *         patimestamp     [0] KerberosTime -- client's time --,
046 *         pausec          [1] Microseconds OPTIONAL
047 * }
048 * </pre>
049 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
050 */
051public class PaEncTsEnc implements Asn1Object
052{
053    /** The logger */
054    private static final Logger log = LoggerFactory.getLogger( PaEncTsEnc.class );
055
056    /** Speedup for logs */
057    private static final boolean IS_DEBUG = log.isDebugEnabled();
058
059    /** The patimestamp */
060    private KerberosTime patimestamp;
061
062    /** The pausec */
063    private Integer pausec;
064
065    // Storage for computed lengths
066    private int paTimestampLength;
067    private int paUsecLength;
068    private int paEncTsEncLength;
069
070
071    /**
072     * Creates a new instance of PaEncTsEnc.
073     */
074    public PaEncTsEnc()
075    {
076    }
077
078
079    /**
080     * Creates a new instance of PaEncTsEnc.
081     */
082    public PaEncTsEnc( KerberosTime paTimestamp, int pausec )
083    {
084        this.patimestamp = paTimestamp;
085        this.pausec = pausec;
086    }
087
088
089    /**
090     * Returns the patimestamp value.
091     *
092     * @return The patimestamp value.
093     */
094    public KerberosTime getPaTimestamp()
095    {
096        return patimestamp;
097    }
098
099
100    /**
101     * Set the patimestamp.
102     *
103     * @param patimestamp The patimestamp value
104     */
105    public void setPaTimestamp( KerberosTime patimestamp )
106    {
107        this.patimestamp = patimestamp;
108    }
109
110
111    /**
112     * @return the pausec
113     */
114    public int getPausec()
115    {
116        if ( pausec == null )
117        {
118            return -1;
119        }
120
121        return pausec;
122    }
123
124
125    /**
126     * @param pausec the pausec to set
127     */
128    public void setPausec( int pausec )
129    {
130        this.pausec = pausec;
131    }
132
133
134    /**
135     * Compute the PA-ENC-TS-ENC length
136     * <pre>
137     * PA-ENC-TS-ENC :
138     * 
139     * 0x30 L1 PA-ENC-TS-ENC sequence
140     *  |
141     *  +--&gt; 0xA0 0x11 patimestamp tag
142     *  |     |
143     *  |     +--&gt; 0x18 0x0F patimestamp value (KerberosTime)
144     *  |
145     *  +--&gt; 0xA1 L2 pausec tag
146     *        |
147     *        +--&gt; 0x02 L2-1 pausec (INTEGER)
148     *        
149     *  </pre>
150     */
151    public int computeLength()
152    {
153        // The paTimestamp
154        paTimestampLength = 0x11;
155
156        paEncTsEncLength = 1 + TLV.getNbBytes( paTimestampLength ) + paTimestampLength;
157
158        // The pausec, if any
159        if ( pausec != null )
160        {
161            int pausecLength = BerValue.getNbBytes( pausec );
162            paUsecLength = 1 + TLV.getNbBytes( pausecLength ) + pausecLength;
163            paEncTsEncLength += 1 + TLV.getNbBytes( paUsecLength ) + paUsecLength;
164        }
165
166        // Compute the whole sequence length
167        return 1 + TLV.getNbBytes( paEncTsEncLength ) + paEncTsEncLength;
168    }
169
170
171    /**
172     * Encode the PA-ENC-TS-ENC message to a PDU. 
173     * 
174     * <pre>
175     * PA-ENC-TS-ENC :
176     * 
177     * 0x30 LL
178     *   0xA0 0x11 
179     *     0x18 0x0F patimestamp
180     *  [0xA1 LL 
181     *     0x02 LL pausec]
182     * </pre>
183     * @param buffer The buffer where to put the PDU. It should have been allocated
184     * before, with the right size.
185     * @return The constructed PDU.
186     */
187    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
188    {
189        if ( buffer == null )
190        {
191            throw new EncoderException( I18n.err( I18n.ERR_148 ) );
192        }
193
194        try
195        {
196            // The PA-ENC-TS-ENC SEQ Tag
197            buffer.put( UniversalTag.SEQUENCE.getValue() );
198            buffer.put( TLV.getBytes( paEncTsEncLength ) );
199
200            // The patimestamp, first the tag, then the value
201            buffer.put( ( byte ) KerberosConstants.PA_ENC_TS_ENC_PA_TIMESTAMP_TAG );
202            buffer.put( ( byte ) 0x11 );
203
204            buffer.put( UniversalTag.GENERALIZED_TIME.getValue() );
205            buffer.put( ( byte ) 0x0F );
206            buffer.put( patimestamp.getBytes() );
207
208            // The pausec, first the tag, then the value, if any
209            if ( pausec != null )
210            {
211                buffer.put( ( byte ) KerberosConstants.PA_ENC_TS_ENC_PA_USEC_TAG );
212                buffer.put( TLV.getBytes( paUsecLength ) );
213                BerValue.encode( buffer, pausec );
214            }
215        }
216        catch ( BufferOverflowException boe )
217        {
218            log.error( I18n.err( I18n.ERR_140, 1 + TLV.getNbBytes( paEncTsEncLength ) + paEncTsEncLength,
219                buffer.capacity() ) );
220            throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
221        }
222
223        if ( IS_DEBUG )
224        {
225            log.debug( "Checksum encoding : {}", Strings.dumpBytes( buffer.array() ) );
226            log.debug( "Checksum initial value : {}", this );
227        }
228
229        return buffer;
230    }
231
232
233    /**
234     * @see Object#toString()
235     */
236    public String toString()
237    {
238        return toString( "" );
239    }
240
241
242    /**
243     * @see Object#toString()
244     */
245    public String toString( String tabs )
246    {
247        StringBuilder sb = new StringBuilder();
248
249        sb.append( tabs ).append( "PA-ENC-TS-ENC : {\n" );
250        sb.append( tabs ).append( "    patimestamp : " ).append( patimestamp ).append( '\n' );
251
252        if ( pausec != null )
253        {
254            sb.append( tabs + "    pausec :" ).append( pausec ).append( '\n' );
255        }
256
257        sb.append( tabs + "}\n" );
258
259        return sb.toString();
260    }
261}