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