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.components;
021
022
023import java.nio.BufferOverflowException;
024import java.nio.ByteBuffer;
025
026import org.apache.directory.api.asn1.Asn1Object;
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.KerberosTime;
035import org.apache.directory.shared.kerberos.flags.TicketFlags;
036import org.slf4j.Logger;
037import org.slf4j.LoggerFactory;
038
039
040/**
041 * Base class for encrypted parts of KDC responses.
042 * 
043 * The ASN.1 grammar for this structure is :
044 * <pre>
045 * EncKDCRepPart   ::= SEQUENCE {
046 *         key             [0] EncryptionKey,
047 *         last-req        [1] LastReq,
048 *         nonce           [2] UInt32,
049 *         key-expiration  [3] KerberosTime OPTIONAL,
050 *         flags           [4] TicketFlags,
051 *         authtime        [5] KerberosTime,
052 *         starttime       [6] KerberosTime OPTIONAL,
053 *         endtime         [7] KerberosTime,
054 *         renew-till      [8] KerberosTime OPTIONAL,
055 *         srealm          [9] Realm,
056 *         sname           [10] PrincipalName,
057 *         caddr           [11] HostAddresses OPTIONAL
058 * }
059 * </pre>
060 * 
061 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
062 */
063public class EncKdcRepPart implements Asn1Object
064{
065    /** The logger */
066    private static final Logger log = LoggerFactory.getLogger( EncKdcRepPart.class );
067
068    /** Speedup for logs */
069    private static final boolean IS_DEBUG = log.isDebugEnabled();
070
071    /** The encryption key */
072    private EncryptionKey key;
073
074    /** The time of the last request */
075    private LastReq lastReq;
076
077    /** The nonce */
078    private int nonce;
079
080    /** The KeyExpiration */
081    private KerberosTime keyExpiration; //optional
082
083    /** The Ticket flags */
084    private TicketFlags flags = new TicketFlags();
085
086    /** The initial Authentication time */
087    private KerberosTime authTime;
088
089    /** The ticket's start time */
090    private KerberosTime startTime; //optional
091
092    /** The Ticket expiration time */
093    private KerberosTime endTime;
094
095    /** Maximum endtime in a renewal */
096    private KerberosTime renewTill; //optional
097
098    /** The server's realm */
099    private String srealm;
100
101    /** The server's principal */
102    private PrincipalName sname;
103
104    /** The client addresses */
105    private HostAddresses caddr; //optional
106
107    // Storage for computed lengths
108    private int keyLength;
109    private int lastReqLength;
110    private int nonceLength;
111    private int flagsLength;
112    private byte[] srealmBytes;
113    private int srealmLength;
114    private int snameLength;
115    private int caddrLength;
116    private int encKdcRepPartSeqLength;
117
118
119    /**
120     * Creates a new instance of EncKdcRepPart.
121     */
122    public EncKdcRepPart()
123    {
124    }
125
126
127    /**
128     * Returns the auth {@link KerberosTime}.
129     *
130     * @return The auth {@link KerberosTime}.
131     */
132    public KerberosTime getAuthTime()
133    {
134        return authTime;
135    }
136
137
138    /**
139     * Sets the auth {@link KerberosTime}.
140     *
141     * @param time
142     */
143    public void setAuthTime( KerberosTime time )
144    {
145        authTime = time;
146    }
147
148
149    /**
150     * Returns the client {@link HostAddresses}.
151     *
152     * @return The client {@link HostAddresses}.
153     */
154    public HostAddresses getClientAddresses()
155    {
156        return caddr;
157    }
158
159
160    /**
161     * Sets the client {@link HostAddresses}.
162     *
163     * @param caddr The client addresses
164     */
165    public void setClientAddresses( HostAddresses caddr )
166    {
167        this.caddr = caddr;
168    }
169
170
171    /**
172     * Returns the end {@link KerberosTime}.
173     *
174     * @return The end {@link KerberosTime}.
175     */
176    public KerberosTime getEndTime()
177    {
178        return endTime;
179    }
180
181
182    /**
183     * Sets the end {@link KerberosTime}.
184     *
185     * @param time
186     */
187    public void setEndTime( KerberosTime time )
188    {
189        endTime = time;
190    }
191
192
193    /**
194     * Returns the {@link TicketFlags}.
195     *
196     * @return The {@link TicketFlags}.
197     */
198    public TicketFlags getFlags()
199    {
200        return flags;
201    }
202
203
204    /**
205     * Sets the {@link TicketFlags}.
206     *
207     * @param flags
208     */
209    public void setFlags( TicketFlags flags )
210    {
211        this.flags = flags;
212    }
213
214
215    /**
216     * Returns the {@link EncryptionKey}.
217     *
218     * @return The {@link EncryptionKey}.
219     */
220    public EncryptionKey getKey()
221    {
222        return key;
223    }
224
225
226    /**
227     * Sets the {@link EncryptionKey}.
228     *
229     * @param key
230     */
231    public void setKey( EncryptionKey key )
232    {
233        this.key = key;
234    }
235
236
237    /**
238     * Returns the key expiration {@link KerberosTime}.
239     *
240     * @return The key expiration {@link KerberosTime}.
241     */
242    public KerberosTime getKeyExpiration()
243    {
244        return keyExpiration;
245    }
246
247
248    /**
249     * Sets the key expiration {@link KerberosTime}.
250     *
251     * @param expiration
252     */
253    public void setKeyExpiration( KerberosTime expiration )
254    {
255        keyExpiration = expiration;
256    }
257
258
259    /**
260     * Returns the {@link LastReq}.
261     *
262     * @return The {@link LastReq}.
263     */
264    public LastReq getLastReq()
265    {
266        return lastReq;
267    }
268
269
270    /**
271     * Sets the {@link LastReq}.
272     *
273     * @param lastReq The LastReq to set
274     */
275    public void setLastReq( LastReq lastReq )
276    {
277        this.lastReq = lastReq;
278    }
279
280
281    /**
282     * Returns the nonce.
283     *
284     * @return The nonce.
285     */
286    public int getNonce()
287    {
288        return nonce;
289    }
290
291
292    /**
293     * Sets the nonce.
294     *
295     * @param nonce
296     */
297    public void setNonce( int nonce )
298    {
299        this.nonce = nonce;
300    }
301
302
303    /**
304     * Returns the renew till {@link KerberosTime}.
305     *
306     * @return The renew till {@link KerberosTime}.
307     */
308    public KerberosTime getRenewTill()
309    {
310        return renewTill;
311    }
312
313
314    /**
315     * Sets the renew till {@link KerberosTime}.
316     *
317     * @param till
318     */
319    public void setRenewTill( KerberosTime till )
320    {
321        renewTill = till;
322    }
323
324
325    /**
326     * Returns the server {@link PrincipalName}.
327     *
328     * @return The server {@link PrincipalName}.
329     */
330    public PrincipalName getSName()
331    {
332        return sname;
333    }
334
335
336    /**
337     * Sets the server {@link PrincipalName}.
338     *
339     * @param sname The server PrincipalName
340     */
341    public void setSName( PrincipalName sname )
342    {
343        this.sname = sname;
344    }
345
346
347    /**
348     * Returns the server realm.
349     *
350     * @return The server realm.
351     */
352    public String getSRealm()
353    {
354        return srealm;
355    }
356
357
358    /**
359     * Sets the server realm.
360     *
361     * @param srealm The server realm
362     */
363    public void setSRealm( String srealm )
364    {
365        this.srealm = srealm;
366    }
367
368
369    /**
370     * Returns the start {@link KerberosTime}.
371     *
372     * @return The start {@link KerberosTime}.
373     */
374    public KerberosTime getStartTime()
375    {
376        return startTime;
377    }
378
379
380    /**
381     * Sets the start {@link KerberosTime}.
382     *
383     * @param time he start time to set
384     */
385    public void setStartTime( KerberosTime time )
386    {
387        startTime = time;
388    }
389
390
391    /**
392     * Compute the EncKdcRepPart length
393     * <pre>
394     * EncKdcRepPart :
395     * 
396     * 0x30 L1 EncKdcRepPart sequence
397     *  |
398     *  +--&gt; 0xA0 L2 key tag
399     *  |     |
400     *  |     +--&gt; 0x30 L2-1 key ( EncryptionKey)
401     *  |
402     *  +--&gt; 0xA1 L3 last-req tag
403     *  |     |
404     *  |     +--&gt; 0x30 L3-1 last-req ( LastReq )
405     *  |     
406     *  +--&gt; 0xA2 L4 nonce tag
407     *  |     |
408     *  |     +--&gt; 0x02 L4-1 nonce (Int)
409     *  |     
410     * [+--&gt; 0xA3 0x11 key-expiration tag]
411     *  |     |
412     *  |     +--&gt; 0x18 0x0F key-expiration ( KerberosTime )
413     *  |     
414     *  +--&gt; 0xA4 0x07 flags tag 
415     *  |     |
416     *  |     +--&gt; 0x03 0x05 flags ( TicketFlags )
417     *  |     
418     *  +--&gt; 0xA5 0x11 authtime tag
419     *  |     |
420     *  |     +--&gt; 0x18 0x0F authtime ( KerberosTime )
421     *  |     
422     * [+--&gt; 0xA6 0x11 starttime tag]
423     *  |     |
424     *  |     +--&gt; 0x18 0x0F starttime ( KerberosTime )
425     *  |     
426     *  +--&gt; 0xA7 0x11 endtime tag
427     *  |     |
428     *  |     +--&gt; 0x18 0x0F endtime ( KerberosTime )
429     *  |     
430     * [+--&gt; 0xA8 0x11 renew-till tag]
431     *  |     |
432     *  |     +--&gt; 0x18 0x0F renew-till ( KerberosTime )
433     *  |     
434     *  +--&gt; 0xA9 L5 srealm tag
435     *  |     |
436     *  |     +--&gt; 0x1B L5-1 srealm ( KerberosString )
437     *  |     
438     *  +--&gt; 0xAA L6 sname tag
439     *  |     |
440     *  |     +--&gt; 0x30 L6-1 sname ( PrincipalName )
441     *  |     
442     * [+--&gt; 0xAB L7 caddr tag]
443     *        |
444     *        +--&gt; 0x30 L7-1 caddr ( HostAddresses )
445     *  </pre>
446     */
447    public int computeLength()
448    {
449        // The key
450        keyLength = key.computeLength();
451        encKdcRepPartSeqLength = 1 + TLV.getNbBytes( keyLength ) + keyLength;
452
453        // The last-req
454        lastReqLength = lastReq.computeLength();
455        encKdcRepPartSeqLength += 1 + TLV.getNbBytes( lastReqLength ) + lastReqLength;
456
457        // The nonce
458        nonceLength = BerValue.getNbBytes( nonce );
459        nonceLength = 1 + TLV.getNbBytes( nonceLength ) + nonceLength;
460        encKdcRepPartSeqLength += 1 + TLV.getNbBytes( nonceLength ) + nonceLength;
461
462        // The keyExpiration
463        if ( keyExpiration != null )
464        {
465            encKdcRepPartSeqLength += 1 + 1 + 0x11;
466        }
467
468        // The flags
469        flagsLength = 1 + 1 + 5;
470        encKdcRepPartSeqLength += 1 + TLV.getNbBytes( flagsLength ) + flagsLength;
471
472        // The authtime
473        encKdcRepPartSeqLength += 1 + 1 + 0x11;
474
475        // The starttime, if any
476        if ( startTime != null )
477        {
478            encKdcRepPartSeqLength += 1 + 1 + 0x11;
479        }
480
481        // The endtime
482        encKdcRepPartSeqLength += 1 + 1 + 0x11;
483
484        // The renew-till, if any
485        if ( renewTill != null )
486        {
487            encKdcRepPartSeqLength += 1 + 1 + 0x11;
488        }
489
490        // The srealm
491        srealmBytes = Strings.getBytesUtf8( srealm );
492        srealmLength = 1 + TLV.getNbBytes( srealmBytes.length ) + srealmBytes.length;
493        encKdcRepPartSeqLength += 1 + TLV.getNbBytes( srealmLength ) + srealmLength;
494
495        // The sname
496        snameLength = sname.computeLength();
497        encKdcRepPartSeqLength += 1 + TLV.getNbBytes( snameLength ) + snameLength;
498
499        // The caddr if any
500        if ( caddr != null )
501        {
502            caddrLength = caddr.computeLength();
503            encKdcRepPartSeqLength += 1 + TLV.getNbBytes( caddrLength ) + caddrLength;
504        }
505
506        return 1 + TLV.getNbBytes( encKdcRepPartSeqLength ) + encKdcRepPartSeqLength;
507    }
508
509
510    /**
511     * Encode the EncKdcRepPart message to a PDU. 
512     * 
513     * @param buffer The buffer where to put the PDU. It should have been allocated
514     * before, with the right size.
515     * @return The constructed PDU.
516     */
517    public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
518    {
519        if ( buffer == null )
520        {
521            throw new EncoderException( I18n.err( I18n.ERR_148 ) );
522        }
523
524        try
525        {
526            // The EncKdcRepPart sequence
527            buffer.put( UniversalTag.SEQUENCE.getValue() );
528            buffer.put( TLV.getBytes( encKdcRepPartSeqLength ) );
529
530            // The Key
531            buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_KEY_TAG );
532            buffer.put( TLV.getBytes( keyLength ) );
533            key.encode( buffer );
534
535            // The LastReq
536            buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_LAST_REQ_TAG );
537            buffer.put( TLV.getBytes( lastReqLength ) );
538            lastReq.encode( buffer );
539
540            // The nonce
541            buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_NONCE_TAG );
542            buffer.put( TLV.getBytes( nonceLength ) );
543            BerValue.encode( buffer, nonce );
544
545            // The key-expiration, if any
546            if ( keyExpiration != null )
547            {
548                buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_KEY_EXPIRATION_TAG );
549                buffer.put( TLV.getBytes( 0x11 ) );
550
551                buffer.put( UniversalTag.GENERALIZED_TIME.getValue() );
552                buffer.put( ( byte ) 0x0F );
553                buffer.put( keyExpiration.getBytes() );
554            }
555
556            // The flags
557            buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_FLAGS_TAG );
558            buffer.put( TLV.getBytes( 0x07 ) );
559            BerValue.encode( buffer, flags );
560
561            // The authtime
562            buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_AUTH_TIME_TAG );
563            buffer.put( TLV.getBytes( 0x11 ) );
564            buffer.put( UniversalTag.GENERALIZED_TIME.getValue() );
565            buffer.put( ( byte ) 0x0F );
566            buffer.put( authTime.getBytes() );
567
568            // The starttime if any
569            if ( startTime != null )
570            {
571                buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_START_TIME_TAG );
572                buffer.put( TLV.getBytes( 0x11 ) );
573                buffer.put( UniversalTag.GENERALIZED_TIME.getValue() );
574                buffer.put( ( byte ) 0x0F );
575                buffer.put( startTime.getBytes() );
576            }
577
578            // The endtime
579            buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_END_TIME_TAG );
580            buffer.put( TLV.getBytes( 0x11 ) );
581            buffer.put( UniversalTag.GENERALIZED_TIME.getValue() );
582            buffer.put( ( byte ) 0x0F );
583            buffer.put( endTime.getBytes() );
584
585            // The renew-till if any
586            if ( renewTill != null )
587            {
588                buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_RENEW_TILL_TAG );
589                buffer.put( TLV.getBytes( 0x11 ) );
590                buffer.put( UniversalTag.GENERALIZED_TIME.getValue() );
591                buffer.put( ( byte ) 0x0F );
592                buffer.put( renewTill.getBytes() );
593            }
594
595            // The srealm
596            buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_SREALM_TAG );
597            buffer.put( TLV.getBytes( srealmLength ) );
598            buffer.put( UniversalTag.GENERAL_STRING.getValue() );
599            buffer.put( TLV.getBytes( srealmBytes.length ) );
600            buffer.put( srealmBytes );
601
602            // The sname
603            buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_SNAME_TAG );
604            buffer.put( TLV.getBytes( snameLength ) );
605            sname.encode( buffer );
606
607            // The caddr if any
608            if ( caddr != null )
609            {
610                buffer.put( ( byte ) KerberosConstants.ENC_KDC_REP_PART_CADDR_TAG );
611                buffer.put( TLV.getBytes( caddrLength ) );
612                caddr.encode( buffer );
613            }
614        }
615        catch ( BufferOverflowException boe )
616        {
617            log.error( I18n.err( I18n.ERR_140, 1 + TLV.getNbBytes( 0 ) + 0,
618                buffer.capacity() ) );
619            throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
620        }
621
622        if ( IS_DEBUG )
623        {
624            log.debug( "EncKdcRepPart encoding : {}", Strings.dumpBytes( buffer.array() ) );
625            log.debug( "EncKdcRepPart initial value : {}", this );
626        }
627
628        return buffer;
629    }
630
631
632    /**
633     * @see Object#toString()
634     */
635    public String toString()
636    {
637        StringBuilder sb = new StringBuilder();
638
639        sb.append( "EncKdcRepPart : \n" );
640        sb.append( "    key : " ).append( key ).append( "\n" );
641        sb.append( "    last-req : " ).append( lastReq ).append( "\n" );
642        sb.append( "    nonce : " ).append( nonce ).append( "\n" );
643
644        if ( keyExpiration != null )
645        {
646            sb.append( "    key-expiration : " ).append( keyExpiration ).append( "\n" );
647        }
648
649        sb.append( "    flags : " ).append( flags ).append( "\n" );
650        sb.append( "    authtime : " ).append( authTime ).append( "\n" );
651
652        if ( startTime != null )
653        {
654            sb.append( "    starttime : " ).append( startTime ).append( "\n" );
655        }
656
657        sb.append( "    endtime : " ).append( endTime ).append( "\n" );
658
659        if ( renewTill != null )
660        {
661            sb.append( "    renew-till : " ).append( renewTill ).append( "\n" );
662        }
663
664        sb.append( "    srealm : " ).append( srealm ).append( "\n" );
665        sb.append( "    sname : " ).append( sname ).append( "\n" );
666
667        if ( caddr != null )
668        {
669            sb.append( "    caddr : " ).append( caddr ).append( "\n" );
670        }
671
672        return sb.toString();
673    }
674}