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;
026
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.KerberosMessageType;
035import org.apache.directory.shared.kerberos.components.Checksum;
036import org.apache.directory.shared.kerberos.components.KrbSafeBody;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040
041/**
042 * Class representing KRB-SAFE message
043 * 
044 * <pre>
045 * KRB-SAFE        ::= [APPLICATION 20] SEQUENCE {
046 *      pvno            [0] INTEGER (5),
047 *      msg-type        [1] INTEGER (20),
048 *      safe-body       [2] KRB-SAFE-BODY,
049 *      cksum           [3] Checksum
050 * }
051 * </pre>
052 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
053 */
054public class KrbSafe extends KerberosMessage
055{
056    /** The logger */
057    private static final Logger log = LoggerFactory.getLogger( KrbError.class );
058
059    /** Speedup for logs */
060    private static final boolean IS_DEBUG = log.isDebugEnabled();
061
062    /** body of this message */
063    private KrbSafeBody krbSafeBody;
064
065    /** the checksum */
066    private Checksum checksum;
067
068    // Storage for computed lengths
069    private int pvnoLen;
070    private int msgTypeLength;
071    private int krbSafeBodyLen;
072    private int checksumLen;
073    private int krbSafeSeqLen;
074    private int krbSafeLen;
075
076
077    /**
078     * Creates a new instance of KrbSafe.
079     */
080    public KrbSafe()
081    {
082        super( KerberosMessageType.KRB_SAFE );
083    }
084
085
086    /**
087     * @return the krbSafeBody
088     */
089    public KrbSafeBody getSafeBody()
090    {
091        return krbSafeBody;
092    }
093
094
095    /**
096     * @param safeBody the KrbSafeBody to set
097     */
098    public void setSafeBody( KrbSafeBody safeBody )
099    {
100        this.krbSafeBody = safeBody;
101    }
102
103
104    /**
105     * @return the checksum
106     */
107    public Checksum getChecksum()
108    {
109        return checksum;
110    }
111
112
113    /**
114     * @param checksum the checksum to set
115     */
116    public void setChecksum( Checksum checksum )
117    {
118        this.checksum = checksum;
119    }
120
121
122    /**
123     * Compute the KRB-SAFE length
124     * <pre>
125     * KRB-SAFE :
126     * 
127     * 0x74 L1 KRB-SAFE APPLICATION[20]
128     *  |
129     *  +--&gt; 0x30 L2 KRB-ERROR sequence
130     *        |
131     *        +--&gt; 0xA0 0x03 pvno tag
132     *        |     |
133     *        |     +--&gt; 0x02 0x01 0x05 pvno (5)
134     *        |
135     *        +--&gt; 0xA1 0x03 msg-type tag
136     *        |     |
137     *        |     +--&gt; 0x02 0x01 0x14 msg-type (20)
138     *        |     
139     *        +--&gt; 0xA2 L3 safe-body tag
140     *        |     |
141     *        |     +--&gt; 0x30 L3-1 safe-body (KRB-SAFE-BODY)
142     *        |
143     *        +--&gt; 0xA3 L4 cksum tag
144     *              |
145     *              +--&gt; 0x30 L4-1 cksum (CHECKSUM)
146     * </pre>
147     */
148    @Override
149    public int computeLength()
150    {
151        pvnoLen = 1 + 1 + 1;
152        krbSafeSeqLen = 1 + TLV.getNbBytes( pvnoLen ) + pvnoLen;
153
154        msgTypeLength = 1 + 1 + BerValue.getNbBytes( getMessageType().getValue() );
155        krbSafeSeqLen += 1 + TLV.getNbBytes( msgTypeLength ) + msgTypeLength;
156
157        krbSafeBodyLen = krbSafeBody.computeLength();
158        krbSafeSeqLen += 1 + TLV.getNbBytes( krbSafeBodyLen ) + krbSafeBodyLen;
159
160        checksumLen = checksum.computeLength();
161        krbSafeSeqLen += 1 + TLV.getNbBytes( checksumLen ) + checksumLen;
162
163        krbSafeLen = 1 + TLV.getNbBytes( krbSafeSeqLen ) + krbSafeSeqLen;
164
165        return 1 + TLV.getNbBytes( krbSafeLen ) + krbSafeLen;
166    }
167
168
169    /**
170     * {@inheritDoc}
171     */
172    @Override
173    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
174    {
175        if ( buffer == null )
176        {
177            throw new EncoderException( I18n.err( I18n.ERR_148 ) );
178        }
179
180        try
181        {
182            // The KRB-SAFE APPLICATION tag
183            buffer.put( ( byte ) KerberosConstants.KRB_SAFE_TAG );
184            buffer.put( TLV.getBytes( krbSafeLen ) );
185
186            // The KRB-SAFE sequence
187            buffer.put( UniversalTag.SEQUENCE.getValue() );
188            buffer.put( TLV.getBytes( krbSafeSeqLen ) );
189
190            // pvno tag and value
191            buffer.put( ( byte ) KerberosConstants.KRB_SAFE_PVNO_TAG );
192            buffer.put( TLV.getBytes( pvnoLen ) );
193            BerValue.encode( buffer, getProtocolVersionNumber() );
194
195            // msg-type tag and value
196            buffer.put( ( byte ) KerberosConstants.KRB_SAFE_MSGTYPE_TAG );
197            buffer.put( TLV.getBytes( msgTypeLength ) );
198            BerValue.encode( buffer, getMessageType().getValue() );
199
200            // safe-body tag and value
201            buffer.put( ( byte ) KerberosConstants.KRB_SAFE_SAFE_BODY_TAG );
202            buffer.put( TLV.getBytes( krbSafeBodyLen ) );
203            krbSafeBody.encode( buffer );
204
205            // cksum tag and value
206            buffer.put( ( byte ) KerberosConstants.KRB_SAFE_CKSUM_TAG );
207            buffer.put( TLV.getBytes( checksumLen ) );
208            checksum.encode( buffer );
209        }
210        catch ( BufferOverflowException boe )
211        {
212            log.error( I18n.err( I18n.ERR_736_CANNOT_ENCODE_KRBSAFE, 1 + TLV.getNbBytes( krbSafeLen )
213                + krbSafeLen, buffer.capacity() ) );
214            throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
215        }
216
217        if ( IS_DEBUG )
218        {
219            log.debug( "KrbSafe encoding : {}", Strings.dumpBytes( buffer.array() ) );
220            log.debug( "KrbSafe initial value : {}", this );
221        }
222
223        return buffer;
224    }
225
226
227    /**
228     * @see Object#toString()
229     */
230    public String toString()
231    {
232        StringBuilder sb = new StringBuilder();
233
234        sb.append( "KRB-SAFE : {\n" );
235        sb.append( "    pvno: " ).append( getProtocolVersionNumber() ).append( '\n' );
236        sb.append( "    msgType: " ).append( getMessageType() ).append( '\n' );
237
238        if ( krbSafeBody != null )
239        {
240            sb.append( "    safe-body: " ).append( krbSafeBody ).append( '\n' );
241        }
242
243        if ( checksum != null )
244        {
245            sb.append( "    cusec: " ).append( checksum ).append( '\n' );
246        }
247
248        sb.append( "}\n" );
249
250        return sb.toString();
251    }
252}