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.messages;
022
023
024import java.nio.BufferOverflowException;
025import java.nio.ByteBuffer;
026import java.util.ArrayList;
027import java.util.List;
028
029import org.apache.directory.api.asn1.EncoderException;
030import org.apache.directory.api.asn1.ber.tlv.BerValue;
031import org.apache.directory.api.asn1.ber.tlv.TLV;
032import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
033import org.apache.directory.api.util.Strings;
034import org.apache.directory.server.i18n.I18n;
035import org.apache.directory.shared.kerberos.KerberosConstants;
036import org.apache.directory.shared.kerberos.KerberosMessageType;
037import org.apache.directory.shared.kerberos.components.EncryptedData;
038import org.slf4j.Logger;
039import org.slf4j.LoggerFactory;
040
041
042/**
043 * KRB-CRED        ::= [APPLICATION 22] SEQUENCE {
044 *         pvno            [0] INTEGER (5),
045 *         msg-type        [1] INTEGER (22),
046 *         tickets         [2] SEQUENCE OF Ticket,
047 *         enc-part        [3] EncryptedData -- EncKrbCredPart
048 * }
049 *
050 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
051 */
052public class KrbCred extends KerberosMessage
053{
054    /** The logger */
055    private static final Logger log = LoggerFactory.getLogger( KrbCred.class );
056
057    /** Speedup for logs */
058    private static final boolean IS_DEBUG = log.isDebugEnabled();
059
060    /** list of tickets */
061    private List<Ticket> tickets;
062
063    /** encrypted part of the message */
064    private EncryptedData encPart;
065
066    private int pvnoLen;
067    private int msgTypeLen;
068    private int ticketsSeqLen;
069    private int ticketsLen;
070    private int encPartLen;
071    private int krbCredSeqLen;
072    private int krbCredLen;
073
074
075    /**
076     * Creates a new instance of KrbCred.
077     */
078    public KrbCred()
079    {
080        super( 5, KerberosMessageType.KRB_CRED );
081    }
082
083
084    /**
085     * Compute the KRB-CRED length
086     * <pre>
087     * KRB-CRED :
088     * 
089     * 0x76 L1 KRB-CRED APPLICATION[22]
090     *  |
091     *  +--&gt; 0x30 L2 KRB-CRED sequence
092     *        |
093     *        +--&gt; 0xA0 0x03 pvno tag
094     *        |     |
095     *        |     +--&gt; 0x02 0x01 0x05 pvno (5)
096     *        |
097     *        +--&gt; 0xA1 0x03 msg-type tag
098     *        |     |
099     *        |     +--&gt; 0x02 0x01 0x16 msg-type (22)
100     *        |     
101     *        +--&gt; 0xA2 L3 tickets tag
102     *        |     |
103     *        |     +--&gt; 0x30 LL tickets seq tag
104     *        |           |
105     *        |           +--&gt; 0x30 LL1 ticket (Ticket)
106     *        |           .         ...
107     *        |           +--&gt; 0x30 LLn ticket (Ticket)
108     *        |
109     *        +--&gt; 0xA3 L4 enc-part tag
110     *              |
111     *              +--&gt; 0x30 L4-2 enc-part (EncryptedData)
112     * </pre>
113     */
114    @Override
115    public int computeLength()
116    {
117        pvnoLen = 1 + 1 + 1;
118        krbCredSeqLen = 1 + TLV.getNbBytes( pvnoLen ) + pvnoLen;
119
120        msgTypeLen = 1 + 1 + BerValue.getNbBytes( getMessageType().getValue() );
121        krbCredSeqLen += 1 + TLV.getNbBytes( msgTypeLen ) + msgTypeLen;
122
123        for ( Ticket t : tickets )
124        {
125            ticketsSeqLen += t.computeLength();
126        }
127
128        ticketsLen = 1 + TLV.getNbBytes( ticketsSeqLen ) + ticketsSeqLen;
129
130        krbCredSeqLen += 1 + TLV.getNbBytes( ticketsLen ) + ticketsLen;
131
132        encPartLen = encPart.computeLength();
133        krbCredSeqLen += 1 + TLV.getNbBytes( encPartLen ) + encPartLen;
134
135        krbCredLen = 1 + TLV.getNbBytes( krbCredSeqLen ) + krbCredSeqLen;
136
137        return 1 + TLV.getNbBytes( krbCredLen ) + krbCredLen;
138    }
139
140
141    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
142    {
143        if ( buffer == null )
144        {
145            throw new EncoderException( I18n.err( I18n.ERR_148 ) );
146        }
147
148        try
149        {
150            // The KRB-CRED APPLICATION tag
151            buffer.put( ( byte ) KerberosConstants.KRB_CRED_TAG );
152            buffer.put( TLV.getBytes( krbCredLen ) );
153
154            // The KRB-CRED sequence
155            buffer.put( UniversalTag.SEQUENCE.getValue() );
156            buffer.put( TLV.getBytes( krbCredSeqLen ) );
157
158            // pvno tag and value
159            buffer.put( ( byte ) KerberosConstants.KRB_CRED_PVNO_TAG );
160            buffer.put( TLV.getBytes( pvnoLen ) );
161            BerValue.encode( buffer, getProtocolVersionNumber() );
162
163            // msg-type tag and value
164            buffer.put( ( byte ) KerberosConstants.KRB_CRED_MSGTYPE_TAG );
165            buffer.put( TLV.getBytes( msgTypeLen ) );
166            BerValue.encode( buffer, getMessageType().getValue() );
167
168            // tickets tag and value
169            buffer.put( ( byte ) KerberosConstants.KRB_CRED_TICKETS_TAG );
170            buffer.put( TLV.getBytes( ticketsLen ) );
171
172            buffer.put( UniversalTag.SEQUENCE.getValue() );
173            buffer.put( TLV.getBytes( ticketsSeqLen ) );
174
175            for ( Ticket t : tickets )
176            {
177                t.encode( buffer );
178            }
179
180            // enc-part tag and value
181            buffer.put( ( byte ) KerberosConstants.KRB_CRED_ENCPART_TAG );
182            buffer.put( TLV.getBytes( encPartLen ) );
183            encPart.encode( buffer );
184        }
185        catch ( BufferOverflowException boe )
186        {
187            log.error( I18n.err( I18n.ERR_741_CANNOT_ENCODE_KRB_CRED, 1 + TLV.getNbBytes( krbCredLen )
188                + krbCredLen, buffer.capacity() ) );
189            throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
190        }
191
192        if ( IS_DEBUG )
193        {
194            log.debug( "KrbCred encoding : {}", Strings.dumpBytes( buffer.array() ) );
195            log.debug( "KrbCred initial value : {}", this );
196        }
197
198        return buffer;
199    }
200
201
202    /**
203     * @return the tickets
204     */
205    public List<Ticket> getTickets()
206    {
207        return tickets;
208    }
209
210
211    /**
212     * @param tickets the tickets to set
213     */
214    public void setTickets( List<Ticket> tickets )
215    {
216        this.tickets = tickets;
217    }
218
219
220    /**
221     * @return the encPart
222     */
223    public EncryptedData getEncPart()
224    {
225        return encPart;
226    }
227
228
229    /**
230     * @param encPart the encPart to set
231     */
232    public void setEncPart( EncryptedData encPart )
233    {
234        this.encPart = encPart;
235    }
236
237
238    /**
239     * adds a Ticket to the ticket list
240     * 
241     * @param ticket the Ticket to be added
242     */
243    public void addTicket( Ticket ticket )
244    {
245        if ( ticket == null )
246        {
247            throw new IllegalArgumentException( "null ticket cannot be added" );
248        }
249
250        if ( tickets == null )
251        {
252            tickets = new ArrayList<>();
253        }
254
255        tickets.add( ticket );
256    }
257
258
259    /**
260     * @see Object#toString()
261     */
262    public String toString()
263    {
264        StringBuilder sb = new StringBuilder();
265
266        sb.append( "KRB-CRED : {\n" );
267        sb.append( "    pvno: " ).append( getProtocolVersionNumber() ).append( '\n' );
268        sb.append( "    msg-type: " ).append( getMessageType() ).append( '\n' );
269        sb.append( "    tickets: " ).append( tickets ).append( '\n' );
270        sb.append( "    en-part: " ).append( encPart ).append( '\n' );
271
272        sb.append( "}\n" );
273
274        return sb.toString();
275    }
276}