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    package org.apache.directory.server.kerberos.shared.messages.value;
021    
022    
023    import java.nio.BufferOverflowException;
024    import java.nio.ByteBuffer;
025    
026    import org.apache.directory.server.i18n.I18n;
027    import org.apache.directory.server.kerberos.shared.messages.value.types.PaDataType;
028    import org.apache.directory.shared.asn1.AbstractAsn1Object;
029    import org.apache.directory.shared.asn1.ber.tlv.TLV;
030    import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
031    import org.apache.directory.shared.asn1.ber.tlv.Value;
032    import org.apache.directory.shared.asn1.codec.EncoderException;
033    import org.apache.directory.shared.ldap.util.StringTools;
034    import org.slf4j.Logger;
035    import org.slf4j.LoggerFactory;
036    
037    
038    /**
039     * The Pre-Authentication data. Tha ASN.1 GRAMMAR IS :
040     * 
041     * PA-DATA         ::= SEQUENCE {
042     *         -- NOTE: first tag is [1], not [0]
043     *         padata-type     [1] Int32,
044     *         padata-value    [2] OCTET STRING -- might be encoded AP-REQ
045     * }
046     * 
047     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
048     * @version $Rev: 902575 $, $Date: 2010-01-24 15:38:06 +0100 (Sun, 24 Jan 2010) $
049     */
050    public class PaData extends AbstractAsn1Object
051    {
052        /** The logger */
053        private static final Logger log = LoggerFactory.getLogger( PaData.class );
054    
055        /** Speedup for logs */
056        private static final boolean IS_DEBUG = log.isDebugEnabled();
057    
058        /** The Pre-authentication type */
059        private PaDataType paDataType;
060        
061        /** The authentication data */
062        private byte[] paDataValue;
063    
064        // Storage for computed lengths
065        private transient int paDataTypeTagLength;
066        private transient int paDataValueTagLength;
067        private transient int preAuthenticationDataSeqLength;
068        
069    
070        /**
071         * Creates a new instance of PreAuthenticationData.
072         */
073        public PaData()
074        {
075        }
076    
077        
078        /**
079         * Creates a new instance of PreAuthenticationData.
080         *
081         * @param paDataType
082         * @param paDataValue
083         */
084        public PaData( PaDataType paDataType, byte[] paDataValue )
085        {
086            this.paDataType = paDataType;
087            this.paDataValue = paDataValue;
088        }
089    
090    
091        /**
092         * Returns the {@link PaDataType}.
093         *
094         * @return The {@link PaDataType}.
095         */
096        public PaDataType getPaDataType()
097        {
098            return paDataType;
099        }
100    
101    
102        /**
103         * Set the PA-DATA type
104         *
105         * @param paDataType The PA-DATA type
106         */
107        public void setPaDataType( int paDataType )
108        {
109            this.paDataType = PaDataType.getTypeByOrdinal( paDataType );
110        }
111    
112        
113        /**
114         * Set the PA-DATA type
115         *
116         * @param paDataType The PA-DATA type
117         */
118        public void setPaDataType( PaDataType paDataType )
119        {
120            this.paDataType = paDataType;
121        }
122    
123        
124        /**
125         * Returns the raw bytes of the {@link PaData}.
126         *
127         * @return The raw bytes of the {@link PaData}.
128         */
129        public byte[] getPaDataValue()
130        {
131            return paDataValue;
132        }
133    
134    
135        /**
136         * Set the PA-DATA value
137         *
138         * @param paDataValue The PA-DATA value
139         */
140        public void setPaDataValue( byte[] paDataValue )
141        {
142            this.paDataValue = paDataValue;
143        }
144    
145        
146        /**
147         * Compute the PreAuthenticationData length
148         * 
149         * PreAuthenticationData :
150         * 
151         * 0x30 L1 PreAuthenticationData sequence
152         *  |
153         *  +--> 0xA0 L2 padata-type tag
154         *  |     |
155         *  |     +--> 0x02 L2-1 padata-type (int)
156         *  |
157         *  +--> 0xA1 L3 padata-value tag
158         *        |
159         *        +--> 0x04 L3-1 padata-value (OCTET STRING)
160         *        
161         *  where L1 = L2 + lenght(0xA0) + length(L2) +
162         *             L3 + lenght(0xA1) + length(L3) 
163         *  and
164         *  L2 = L2-1 + length(0x02) + length( L2-1) 
165         *  L3 = L3-1 + length(0x04) + length( L3-1) 
166         */
167        public int computeLength()
168        {
169            // Compute the paDataType. The Length will always be contained in 1 byte
170            int paDataTypeLength = Value.getNbBytes( paDataType.getOrdinal() );
171            paDataTypeTagLength = 1 + TLV.getNbBytes( paDataTypeLength ) + paDataTypeLength;
172            preAuthenticationDataSeqLength = 1 + TLV.getNbBytes( paDataTypeTagLength ) + paDataTypeTagLength;
173    
174            // Compute the paDataValue
175            if ( paDataValue == null )
176            {
177                paDataValueTagLength = 1 + 1;
178            }
179            else
180            {
181                paDataValueTagLength = 1 + TLV.getNbBytes( paDataValue.length ) + paDataValue.length;
182            }
183    
184            // Compute the whole sequence length
185            preAuthenticationDataSeqLength += 1 + TLV.getNbBytes( paDataValueTagLength ) + paDataValueTagLength;
186    
187            return 1 + TLV.getNbBytes( preAuthenticationDataSeqLength ) + preAuthenticationDataSeqLength;
188    
189        }
190    
191    
192        /**
193         * Encode the PreAuthenticationData message to a PDU. 
194         * 
195         * PreAuthenticationData :
196         * 
197         * 0x30 LL
198         *   0xA0 LL 
199         *     0x02 0x01 padata-type
200         *   0xA1 LL 
201         *     0x04 LL padata-value
202         * 
203         * @param buffer The buffer where to put the PDU. It should have been allocated
204         * before, with the right size.
205         * @return The constructed PDU.
206         */
207        public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
208        {
209            if ( buffer == null )
210            {
211                throw new EncoderException( I18n.err( I18n.ERR_148 ) );
212            }
213    
214            try
215            {
216                // The Checksum SEQ Tag
217                buffer.put( UniversalTag.SEQUENCE_TAG );
218                buffer.put( TLV.getBytes( preAuthenticationDataSeqLength ) );
219    
220                // The cksumtype, first the tag, then the value
221                buffer.put( ( byte ) 0xA1 );
222                buffer.put( TLV.getBytes( paDataTypeTagLength ) );
223                Value.encode( buffer, paDataType.getOrdinal() );
224    
225                // The checksum, first the tag, then the value
226                buffer.put( ( byte ) 0xA2 );
227                buffer.put( TLV.getBytes( paDataValueTagLength ) );
228                Value.encode( buffer, paDataValue );
229            }
230            catch ( BufferOverflowException boe )
231            {
232                log.error( I18n.err( I18n.ERR_145, 1 + TLV.getNbBytes( preAuthenticationDataSeqLength )
233                    + preAuthenticationDataSeqLength, buffer.capacity() ) );
234                throw new EncoderException( I18n.err( I18n.ERR_138 ) );
235            }
236    
237            if ( IS_DEBUG )
238            {
239                log.debug( "PreAuthenticationData encoding : {}", StringTools.dumpBytes( buffer.array() ) );
240                log.debug( "PreAuthenticationData initial value : {}", toString() );
241            }
242    
243            return buffer;
244        }
245    
246        /**
247         * @see Object#toString()
248         */
249        public String toString()
250        {
251            return toString( "" );
252        }
253    
254    
255        /**
256         * @see Object#toString()
257         */
258        public String toString( String tabs )
259        {
260            StringBuilder sb = new StringBuilder();
261    
262            sb.append( tabs ).append( "PreAuthenticationData : {\n" );
263            sb.append( tabs ).append( "    padata-type: " ).append( paDataType ).append( '\n' );
264    
265            if ( paDataValue != null )
266            {
267                sb.append( tabs + "    padata-value:" ).append( StringTools.dumpBytes( paDataValue ) ).append( '\n' );
268            }
269    
270            sb.append( tabs + "}\n" );
271    
272            return sb.toString();
273        }
274    }