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.messages;
021
022
023import java.nio.BufferOverflowException;
024import java.nio.ByteBuffer;
025
026import org.apache.directory.api.asn1.EncoderException;
027import org.apache.directory.api.asn1.ber.tlv.BerValue;
028import org.apache.directory.api.asn1.ber.tlv.TLV;
029import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
030import org.apache.directory.api.util.Strings;
031import org.apache.directory.server.i18n.I18n;
032import org.apache.directory.shared.kerberos.KerberosConstants;
033import org.apache.directory.shared.kerberos.KerberosMessageType;
034import org.apache.directory.shared.kerberos.KerberosTime;
035import org.apache.directory.shared.kerberos.components.AuthorizationData;
036import org.apache.directory.shared.kerberos.components.Checksum;
037import org.apache.directory.shared.kerberos.components.EncryptionKey;
038import org.apache.directory.shared.kerberos.components.PrincipalName;
039import org.slf4j.Logger;
040import org.slf4j.LoggerFactory;
041
042
043/**
044 * A structure to hold the authenticator data.
045 *  It will store the object described by the ASN.1 grammar :
046 * <pre>
047 * Authenticator   ::= [APPLICATION 2] SEQUENCE  {
048 *         authenticator-vno       [0] INTEGER (5),
049 *         crealm                  [1] Realm,
050 *         cname                   [2] &lt;PrincipalName&gt;,
051 *         cksum                   [3] &lt;Checksum&gt; OPTIONAL,
052 *         cusec                   [4] Microseconds,
053 *         ctime                   [5] KerberosTime,
054 *         subkey                  [6] &lt;EncryptionKey&gt; OPTIONAL,
055 *         seq-number              [7] UInt32 OPTIONAL,
056 *         authorization-data      [8] &lt;AuthorizationData&gt; OPTIONAL
057 * }
058 * </pre>
059 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
060 */
061public class Authenticator extends KerberosMessage
062{
063    /** The logger */
064    private static final Logger LOG = LoggerFactory.getLogger( Authenticator.class );
065
066    /** Speedup for logs */
067    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
068
069    /** The authenticator version number */
070    private int versionNumber;
071
072    /** The client realm */
073    private String crealm;
074
075    /** The client principalName */
076    private PrincipalName cname;
077
078    /** The checksum */
079    private Checksum cksum;
080
081    /** The client microseconds */
082    private int cusec;
083
084    /** The client time */
085    private KerberosTime ctime;
086
087    /** The sub-session key */
088    private EncryptionKey subKey;
089
090    /** The sequence number */
091    private Integer seqNumber;
092
093    /** The authorization Data */
094    private AuthorizationData authorizationData;
095
096    // Storage for computed lengths
097    private int authenticatorVnoLength;
098    private int crealmLength;
099    private byte[] crealmBytes;
100    private int cnameLength;
101    private int cksumLength;
102    private int cusecLength;
103    private int ctimeLength;
104    private int subkeyLength;
105    private int seqNumberLength;
106    private int authorizationDataLength;
107    private int authenticatorSeqLength;
108    private int authenticatorLength;
109
110
111    /**
112     * Creates a new instance of Authenticator.
113     */
114    public Authenticator()
115    {
116        super( KerberosMessageType.AUTHENTICATOR );
117        versionNumber = getProtocolVersionNumber();
118    }
119
120
121    /**
122     * Returns the {@link AuthorizationData}.
123     *
124     * @return The {@link AuthorizationData}.
125     */
126    public AuthorizationData getAuthorizationData()
127    {
128        return authorizationData;
129    }
130
131
132    /**
133     * @param authorizationData the authorizationData to set
134     */
135    public void setAuthorizationData( AuthorizationData authorizationData )
136    {
137        this.authorizationData = authorizationData;
138    }
139
140
141    /**
142     * @return the cksum
143     */
144    public Checksum getCksum()
145    {
146        return cksum;
147    }
148
149
150    /**
151     * @param cksum the cksum to set
152     */
153    public void setCksum( Checksum cksum )
154    {
155        this.cksum = cksum;
156    }
157
158
159    /**
160     * @return the cname
161     */
162    public PrincipalName getCName()
163    {
164        return cname;
165    }
166
167
168    /**
169     * @param cname the cname to set
170     */
171    public void setCName( PrincipalName cname )
172    {
173        this.cname = cname;
174    }
175
176
177    /**
178     * @return the crealm
179     */
180    public String getCRealm()
181    {
182        return crealm;
183    }
184
185
186    /**
187     * @param crealm the crealm to set
188     */
189    public void setCRealm( String crealm )
190    {
191        this.crealm = crealm;
192    }
193
194
195    /**
196     * @return the ctime
197     */
198    public KerberosTime getCtime()
199    {
200        return ctime;
201    }
202
203
204    /**
205     * @param ctime the ctime to set
206     */
207    public void setCTime( KerberosTime ctime )
208    {
209        this.ctime = ctime;
210    }
211
212
213    /**
214     * @return the cusec
215     */
216    public int getCusec()
217    {
218        return cusec;
219    }
220
221
222    /**
223     * @param cusec the cusec to set
224     */
225    public void setCusec( int cusec )
226    {
227        this.cusec = cusec;
228    }
229
230
231    /**
232     * @return the seqNumber
233     */
234    public Integer getSeqNumber()
235    {
236        return seqNumber;
237    }
238
239
240    /**
241     * @param seqNumber the seqNumber to set
242     */
243    public void setSeqNumber( int seqNumber )
244    {
245        this.seqNumber = Integer.valueOf( seqNumber );
246    }
247
248
249    /**
250     * @return the subKey
251     */
252    public EncryptionKey getSubKey()
253    {
254        return subKey;
255    }
256
257
258    /**
259     * @param subKey the subKey to set
260     */
261    public void setSubKey( EncryptionKey subKey )
262    {
263        this.subKey = subKey;
264    }
265
266
267    /**
268     * Returns the version number of the {@link Authenticator}.
269     *
270     * @return The version number of the {@link Authenticator}.
271     */
272    public int getVersionNumber()
273    {
274        return versionNumber;
275    }
276
277
278    /**
279     * @param versionNumber the versionNumber to set
280     */
281    public void setVersionNumber( int versionNumber )
282    {
283        this.versionNumber = versionNumber;
284    }
285
286
287    /**
288     * Compute the Authenticator length
289     * <pre>
290     * Authenticator :
291     * 
292     * 0x62 L1 Authenticator [APPLICATION 2]
293     *  |
294     *  +--&gt; 0x30 L2 Authenticator SEQUENCE
295     *        |
296     *        +--&gt; 0xA0 03 authenticator-vno tag
297     *        |     |
298     *        |     +--&gt; 0x02 0x01 0x05 authenticator-vno (int, 5)
299     *        |
300     *        +--&gt; 0xA1 L3 crealm tag
301     *        |     |
302     *        |     +--&gt; 0x1B L3-1 crealm (KerberosString)
303     *        |
304     *        +--&gt; 0xA2 L4 cname (PrincipalName)
305     *        |
306     *        +--&gt; 0xA3 L5 cksum (CheckSum)
307     *        |
308     *        +--&gt; 0xA4 L6 cusec tag
309     *        |     |
310     *        |     +--&gt; 0x02 L6-1 nnn cusec value (Integer)
311     *        |
312     *        +--&gt; 0xA5 0x11 ctime tag
313     *        |     |
314     *        |     +--&gt; 0x18 0x0F ttt ctime (KerberosTime)
315     *        |
316     *        +--&gt; 0xA6 L7 subkey (EncryptionKey)
317     *        |
318     *        +--&gt; 0xA7 L8 seq-number tag
319     *        |     |
320     *        |     +--&gt; 0x02 L8-1 nnn seq-number (Integer)
321     *        |
322     *        +--&gt; 0xA8 L9 authorization-data (AuthorizationData)
323     * </pre>
324     */
325    @Override
326    public int computeLength()
327    {
328        reset();
329
330        // Compute the Authenticator version length.
331        authenticatorVnoLength = 1 + 1 + BerValue.getNbBytes( getVersionNumber() );
332        authenticatorSeqLength =  1 + TLV.getNbBytes( authenticatorVnoLength ) + authenticatorVnoLength;
333
334        // Compute the  crealm length.
335        crealmBytes = Strings.getBytesUtf8( crealm );
336        crealmLength = 1 + TLV.getNbBytes( crealmBytes.length ) + crealmBytes.length;
337        authenticatorSeqLength += 1 + TLV.getNbBytes( crealmLength ) + crealmLength;
338
339        // Compute the cname length
340        cnameLength = cname.computeLength();
341        authenticatorSeqLength += 1 + TLV.getNbBytes( cnameLength ) + cnameLength;
342
343        // Compute the cksum length if any
344        if ( cksum != null )
345        {
346            cksumLength = cksum.computeLength();
347            authenticatorSeqLength += 1 + TLV.getNbBytes( cksumLength ) + cksumLength;
348        }
349
350        // Compute the cusec length
351        cusecLength = 1 + 1 + BerValue.getNbBytes( cusec );
352        authenticatorSeqLength += 1 + TLV.getNbBytes( cusecLength ) + cusecLength;
353
354        // Compute the ctime length
355        ctimeLength = 1 + 1 + 0x0F;
356        authenticatorSeqLength += 1 + 1 + ctimeLength;
357
358        // Compute the subkey length if any
359        if ( subKey != null )
360        {
361            subkeyLength = subKey.computeLength();
362            authenticatorSeqLength += 1 + TLV.getNbBytes( subkeyLength ) + subkeyLength;
363        }
364
365        // Compute the seq-number  length if any
366        if ( seqNumber != null )
367        {
368            seqNumberLength = 1 + 1 + BerValue.getNbBytes( seqNumber );
369            authenticatorSeqLength += 1 + TLV.getNbBytes( seqNumberLength ) + seqNumberLength;
370        }
371
372        // Compute the authorization-data length if any
373        if ( authorizationData != null )
374        {
375            authorizationDataLength = authorizationData.computeLength();
376            authenticatorSeqLength += 1 + TLV.getNbBytes( authorizationDataLength ) + authorizationDataLength;
377        }
378
379        // compute the global size
380        authenticatorLength = 1 + TLV.getNbBytes( authenticatorSeqLength ) + authenticatorSeqLength;
381
382        return 1 + TLV.getNbBytes( authenticatorLength ) + authenticatorLength;
383    }
384
385
386    /**
387     * Encode the Authenticator message to a PDU.
388     * <pre>
389     * Authenticator :
390     * 
391     * 0x62 LL
392     *   0x30 LL
393     *     0xA0 0x03
394     *       0x02 0x01 0x05 authenticator-vno
395     *     0xA1 LL
396     *       0x1B LL abcd crealm
397     *     0xA2 LL
398     *       0x30 LL abcd cname
399     *    [0xA3 LL
400     *       0x30 LL abcd] cksum
401     *     0xA4 LL
402     *       0x02 LL nnn  cusec
403     *     0xA5 0x11
404     *       0x18 0x0F ttt ctime
405     *    [0xA6 LL
406     *       0x30 LL abcd] subkey
407     *    [0xA7 LL
408     *       0x02 LL nnn] seq-number
409     *    [0xA8 LL
410     *       0x30 LL abcd] authorization-data
411     * </pre>
412     * @return The constructed PDU.
413     */
414    @Override
415    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
416    {
417        if ( buffer == null )
418        {
419            buffer = ByteBuffer.allocate( computeLength() );
420        }
421
422        try
423        {
424            // The Authenticator APPLICATION Tag
425            buffer.put( ( byte ) KerberosConstants.AUTHENTICATOR_TAG );
426            buffer.put( TLV.getBytes( authenticatorLength ) );
427
428            // The Authenticator SEQUENCE Tag
429            buffer.put( UniversalTag.SEQUENCE.getValue() );
430            buffer.put( TLV.getBytes( authenticatorSeqLength ) );
431
432            // The authenticator-vno ------------------------------------------
433            // The tag
434            buffer.put( ( byte ) KerberosConstants.AUTHENTICATOR_AUTHENTICATOR_VNO_TAG );
435            buffer.put( TLV.getBytes( authenticatorVnoLength ) );
436
437            // The value
438            BerValue.encode( buffer, getVersionNumber() );
439            
440            // The crealm -----------------------------------------------------
441            // The tag
442            buffer.put( ( byte ) KerberosConstants.AUTHENTICATOR_CREALM_TAG );
443            buffer.put( TLV.getBytes( crealmLength ) );
444
445            // The value
446            buffer.put( UniversalTag.GENERAL_STRING.getValue() );
447            buffer.put( TLV.getBytes( crealmBytes.length ) );
448            buffer.put( crealmBytes );
449
450            // The cname ------------------------------------------------------
451            // The tag
452            buffer.put( ( byte ) KerberosConstants.AUTHENTICATOR_CNAME_TAG );
453            buffer.put( TLV.getBytes( cnameLength ) );
454
455            // The value
456            cname.encode( buffer );
457
458            // The cksum, if any ----------------------------------------------
459            if ( cksum != null )
460            {
461                // The tag
462                buffer.put( ( byte ) KerberosConstants.AUTHENTICATOR_CKSUM_TAG );
463                buffer.put( TLV.getBytes( cksumLength ) );
464
465                // The value
466                cksum.encode( buffer );
467            }
468
469            // The cusec ------------------------------------------------------
470            // The tag
471            buffer.put( ( byte ) KerberosConstants.AUTHENTICATOR_CUSEC_TAG );
472            buffer.put( TLV.getBytes( cusecLength ) );
473
474            // The value
475            BerValue.encode( buffer, cusec );
476
477            // The ctime ------------------------------------------------------
478            // The tag
479            buffer.put( ( byte ) KerberosConstants.AUTHENTICATOR_CTIME_TAG );
480            buffer.put( TLV.getBytes( ctimeLength ) );
481
482            // The value
483            buffer.put( UniversalTag.GENERALIZED_TIME.getValue() );
484            buffer.put( ( byte ) 0x0F );
485            buffer.put( ctime.getBytes() );
486
487            // The subkey if any ---------------------------------------------------
488            if ( subKey != null )
489            {
490                // The tag
491                buffer.put( ( byte ) KerberosConstants.AUTHENTICATOR_SUBKEY_TAG );
492                buffer.put( TLV.getBytes( subkeyLength ) );
493
494                // The value
495                subKey.encode( buffer );
496            }
497
498            // The seq-number, if any -----------------------------------------
499            if ( seqNumber != null )
500            {
501                // The tag
502                buffer.put( (byte)KerberosConstants.AUTHENTICATOR_SEQ_NUMBER_TAG );
503                buffer.put( TLV.getBytes( seqNumberLength ) );
504                
505                // The value
506                BerValue.encode( buffer, seqNumber );
507            }
508            
509            // The authorization-data, if any ---------------------------------
510            if ( authorizationData != null )
511            {
512                // The tag
513                buffer.put( ( byte ) KerberosConstants.AUTHENTICATOR_AUTHORIZATION_DATA_TAG );
514                buffer.put( TLV.getBytes( authorizationDataLength ) );
515
516                // The value
517                authorizationData.encode( buffer );
518            }
519        }
520        catch ( BufferOverflowException boe )
521        {
522            LOG.error( I18n.err( I18n.ERR_139, 1 + TLV.getNbBytes( 0 )
523                + 0, buffer.capacity() ) );
524            throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
525        }
526
527        if ( IS_DEBUG )
528        {
529            LOG.debug( "Authenticator encoding : {}", Strings.dumpBytes( buffer.array() ) );
530            LOG.debug( "Authenticator initial value : {}", this );
531        }
532
533        return buffer;
534    }
535
536
537    /**
538     * reset the fields used while computing length
539     */
540    private void reset()
541    {
542        authenticatorVnoLength = 0;
543        crealmLength = 0;
544        crealmBytes = null;
545        cnameLength = 0;
546        cksumLength = 0;
547        cusecLength = 0;
548        ctimeLength = 0;
549        subkeyLength = 0;
550        seqNumberLength = 0;
551        authorizationDataLength = 0;
552        authenticatorSeqLength = 0;
553        authenticatorLength = 0;
554    }
555
556
557    /**
558     * @see Object#toString()
559     */
560    public String toString()
561    {
562        StringBuilder sb = new StringBuilder();
563
564        sb.append( "Authenticator : \n" );
565
566        sb.append( "    authenticator-vno : " ).append( getVersionNumber() ).append( '\n' );
567        sb.append( "    crealm : " ).append( crealm ).append( '\n' );
568        sb.append( "    cname : " ).append( cname ).append( '\n' );
569
570        if ( cksum != null )
571        {
572            sb.append( "    cksum : " ).append( cksum ).append( '\n' );
573        }
574
575        sb.append( "    cusec : " ).append( cusec ).append( '\n' );
576        sb.append( "    ctime : " ).append( ctime ).append( '\n' );
577
578        if ( subKey != null )
579        {
580            sb.append( "    subkey : " ).append( subKey ).append( '\n' );
581        }
582
583        if ( seqNumber != null )
584        {
585            sb.append( "    seq-number : " ).append( seqNumber ).append( '\n' );
586        }
587
588        if ( authorizationData != null )
589        {
590            sb.append( "    authorization-data : " ).append( authorizationData ).append( '\n' );
591        }
592
593        return sb.toString();
594    }
595}