View Javadoc
1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  package org.apache.directory.shared.kerberos.messages;
21  
22  
23  import java.nio.BufferOverflowException;
24  import java.nio.ByteBuffer;
25  
26  import org.apache.directory.api.asn1.EncoderException;
27  import org.apache.directory.api.asn1.ber.tlv.BerValue;
28  import org.apache.directory.api.asn1.ber.tlv.TLV;
29  import org.apache.directory.api.asn1.ber.tlv.UniversalTag;
30  import org.apache.directory.api.util.Strings;
31  import org.apache.directory.server.i18n.I18n;
32  import org.apache.directory.shared.kerberos.KerberosConstants;
33  import org.apache.directory.shared.kerberos.KerberosMessageType;
34  import org.apache.directory.shared.kerberos.KerberosTime;
35  import org.apache.directory.shared.kerberos.components.PrincipalName;
36  import org.apache.directory.shared.kerberos.exceptions.ErrorType;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  
41  /**
42   * Class representing KRB-ERROR message
43   * 
44   * <pre>
45   * KRB-ERROR       ::= [APPLICATION 30] SEQUENCE {
46   *      pvno            [0] INTEGER (5),
47   *      msg-type        [1] INTEGER (30),
48   *      ctime           [2] KerberosTime OPTIONAL,
49   *      cusec           [3] Microseconds OPTIONAL,
50   *      stime           [4] KerberosTime,
51   *      susec           [5] Microseconds,
52   *      error-code      [6] Int32,
53   *      crealm          [7] Realm OPTIONAL,
54   *      cname           [8] PrincipalName OPTIONAL,
55   *      realm           [9] Realm -- service realm --,
56   *      sname           [10] PrincipalName -- service name --,
57   *      e-text          [11] KerberosString OPTIONAL,
58   *      e-data          [12] OCTET STRING OPTIONAL
59   * }
60   * </pre>
61   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
62   */
63  public class KrbError extends KerberosMessage
64  {
65  
66      /** The logger */
67      private static final Logger log = LoggerFactory.getLogger( KrbError.class );
68  
69      /** Speedup for logs */
70      private static final boolean IS_DEBUG = log.isDebugEnabled();
71  
72      /** the current time of client */
73      private KerberosTime cTime;
74  
75      /** microseconds of the client's current time */
76      private Integer cusec;
77  
78      /** current time on the server */
79      private KerberosTime sTime;
80  
81      /** microseconds of the server's time */
82      private int susec;
83  
84      /** the error code */
85      private ErrorType errorCode;
86  
87      /** the name of the realm to which the requesting client belongs */
88      private String cRealm;
89  
90      /** the client's principal */
91      private PrincipalName cName;
92  
93      /** the realm that issued the ticket */
94      private String realm;
95  
96      /** the server's principal */
97      private PrincipalName sName;
98  
99      /** the error text */
100     private String eText;
101 
102     /** the error data */
103     private byte[] eData;
104 
105     // Storage for computed lengths
106     private int pvnoLength;
107     private int msgTypeLength;
108     private int cTimeLength;
109     private int cusecLength;
110     private int sTimeLength;
111     private int susecLength;
112     private int errorCodeLength;
113     private int cRealmLength;
114     private byte[] crealmBytes;
115     private int cNameLength;
116     private int realmLength;
117     private byte[] realmBytes;
118     private int sNameLength;
119     private int eTextLength;
120     private byte[] eTextBytes;
121     private int eDataLength;
122     private int krbErrorSeqLength;
123     private int krbErrorLength;
124 
125 
126     /**
127      * Creates a new instance of KrbError.
128      */
129     public KrbError()
130     {
131         super( KerberosMessageType.KRB_ERROR );
132     }
133 
134 
135     /**
136      * @return the cTime
137      */
138     public KerberosTime getCTime()
139     {
140         return cTime;
141     }
142 
143 
144     /**
145      * @param cTime the cTime to set
146      */
147     public void setCTime( KerberosTime cTime )
148     {
149         this.cTime = cTime;
150     }
151 
152 
153     /**
154      * @return the cusec
155      */
156     public int getCusec()
157     {
158         if ( cusec == null )
159         {
160             return 0;
161         }
162 
163         return cusec;
164     }
165 
166 
167     /**
168      * @param cusec the cusec to set
169      */
170     public void setCusec( int cusec )
171     {
172         this.cusec = cusec;
173     }
174 
175 
176     /**
177      * @return the sTime
178      */
179     public KerberosTime getSTime()
180     {
181         return sTime;
182     }
183 
184 
185     /**
186      * @param sTime the sTime to set
187      */
188     public void setSTime( KerberosTime sTime )
189     {
190         this.sTime = sTime;
191     }
192 
193 
194     /**
195      * @return the susec
196      */
197     public int getSusec()
198     {
199         return susec;
200     }
201 
202 
203     /**
204      * @param susec the susec to set
205      */
206     public void setSusec( int susec )
207     {
208         this.susec = susec;
209     }
210 
211 
212     /**
213      * @return the errorCode
214      */
215     public ErrorType getErrorCode()
216     {
217         return errorCode;
218     }
219 
220 
221     /**
222      * @param errorCode the errorCode to set
223      */
224     public void setErrorCode( ErrorType errorCode )
225     {
226         this.errorCode = errorCode;
227     }
228 
229 
230     /**
231      * @return the cRealm
232      */
233     public String getCRealm()
234     {
235         return cRealm;
236     }
237 
238 
239     /**
240      * @param cRealm the cRealm to set
241      */
242     public void setCRealm( String cRealm )
243     {
244         this.cRealm = cRealm;
245     }
246 
247 
248     /**
249      * @return the cName
250      */
251     public PrincipalName getCName()
252     {
253         return cName;
254     }
255 
256 
257     /**
258      * @param cName the cName to set
259      */
260     public void setCName( PrincipalName cName )
261     {
262         this.cName = cName;
263     }
264 
265 
266     /**
267      * @return the realm
268      */
269     public String getRealm()
270     {
271         return realm;
272     }
273 
274 
275     /**
276      * @param realm the realm to set
277      */
278     public void setRealm( String realm )
279     {
280         this.realm = realm;
281     }
282 
283 
284     /**
285      * @return the sName
286      */
287     public PrincipalName getSName()
288     {
289         return sName;
290     }
291 
292 
293     /**
294      * @param sName the sName to set
295      */
296     public void setSName( PrincipalName sName )
297     {
298         this.sName = sName;
299     }
300 
301 
302     /**
303      * @return the eText
304      */
305     public String getEText()
306     {
307         return eText;
308     }
309 
310 
311     /**
312      * @param eText the eText to set
313      */
314     public void setEText( String eText )
315     {
316         this.eText = eText;
317     }
318 
319 
320     /**
321      * @return the eData
322      */
323     public byte[] getEData()
324     {
325         return eData;
326     }
327 
328 
329     /**
330      * @param eData the eData to set
331      */
332     public void setEData( byte[] eData )
333     {
334         this.eData = eData;
335     }
336 
337 
338     /**
339      * Compute the KRB-ERROR length
340      * <pre>
341      * KRB-ERROR :
342      * 
343      * 0x7E L1 KRB-ERROR APPLICATION[30]
344      *  |
345      *  +--&gt; 0x30 L2 KRB-ERROR sequence
346      *        |
347      *        +--&gt; 0xA0 0x03 pvno tag
348      *        |     |
349      *        |     +--&gt; 0x02 0x01 0x05 pvno (5)
350      *        |
351      *        +--&gt; 0xA1 0x03 msg-type tag
352      *        |     |
353      *        |     +--&gt; 0x02 0x01 0x1E msg-type (30)
354      *        |     
355      *        +--&gt; 0xA2 0x11 ctime tag
356      *        |     |
357      *        |     +--&gt; 0x18 0x0F ttt ctime (KerberosTime)
358      *        |     
359      *        +--&gt; 0xA3 L3 cusec tag
360      *        |     |
361      *        |     +--&gt; 0x02 L3-1 cusec
362      *        |     
363      *        +--&gt; 0xA4 0x11 stime tag
364      *        |     |
365      *        |     +--&gt; 0x18 0x0F ttt stime (KerberosTime)
366      *        |     
367      *        +--&gt; 0xA5 L4 susec tag
368      *        |     |
369      *        |     +--&gt; 0x02 L4-1 susec (KerberosTime)
370      *        |     
371      *        +--&gt; 0xA6 L5 error-code tag
372      *        |     |
373      *        |     +--&gt; 0x02 L5-1 nnn error-code
374      *        |     
375      *        +--&gt; 0xA7 L6 crealm tag
376      *        |     |
377      *        |     +--&gt; 0x1B L6-1 crealm (KerberosString)
378      *        |     
379      *        +--&gt; 0xA8 L7 cname tag
380      *        |     |
381      *        |     +--&gt; 0x30 L7-1 cname (PrincipalName)
382      *        |
383      *        +--&gt; 0xA9 L8 realm tag
384      *        |     |
385      *        |     +--&gt; 0x1B L8-1 realm (KerberosString)
386      *        |     
387      *        +--&gt; 0xAA L9 sname tag
388      *        |     |
389      *        |     +--&gt; 0x30 L9-1 sname (PrincipalName)
390      *        |     
391      *        +--&gt; 0xAB L10 e-text tag
392      *        |     |
393      *        |     +--&gt; 0x1B L10-1 e-text (KerberosString)
394      *        |
395      *        +--&gt; 0xAC L11 e-data
396      *              |
397      *              +--&gt; 0x04 L11-1 e-data (Octet String)
398      * </pre>       
399      */
400     public int computeLength()
401     {
402         // The PVNO
403         pvnoLength = 1 + 1 + 1;
404         krbErrorSeqLength = 1 + TLV.getNbBytes( pvnoLength ) + pvnoLength;
405 
406         // The message type
407         msgTypeLength = 1 + 1 + BerValue.getNbBytes( getMessageType().getValue() );
408         krbErrorSeqLength += 1 + TLV.getNbBytes( msgTypeLength ) + msgTypeLength;
409 
410         // The ctime, if any
411         if ( cTime != null )
412         {
413             cTimeLength = 1 + 1 + 0x0F;
414             krbErrorSeqLength += 1 + TLV.getNbBytes( cTimeLength ) + cTimeLength;
415         }
416 
417         // The cusec, if any
418         if ( cusec != null )
419         {
420             int cusecLen = BerValue.getNbBytes( cusec );
421             cusecLength = 1 + TLV.getNbBytes( cusecLen ) + cusecLen;
422             krbErrorSeqLength += 1 + TLV.getNbBytes( cusecLength ) + cusecLength;
423         }
424 
425         // The stime
426         sTimeLength = 1 + 1 + 0x0F;
427         krbErrorSeqLength += 1 + TLV.getNbBytes( sTimeLength ) + sTimeLength;
428 
429         // The susec
430         int susecLen = BerValue.getNbBytes( susec );
431         susecLength = 1 + TLV.getNbBytes( susecLen ) + susecLen;
432         krbErrorSeqLength += 1 + TLV.getNbBytes( susecLength ) + susecLength;
433 
434         // The error-code
435         errorCodeLength = 1 + 1 + BerValue.getNbBytes( errorCode.getValue() );
436         krbErrorSeqLength += 1 + TLV.getNbBytes( errorCodeLength ) + errorCodeLength;
437 
438         // The crealm, if any
439         if ( cRealm != null )
440         {
441             crealmBytes = Strings.getBytesUtf8( cRealm );
442             cRealmLength = 1 + TLV.getNbBytes( crealmBytes.length ) + crealmBytes.length;
443             krbErrorSeqLength += 1 + TLV.getNbBytes( cRealmLength ) + cRealmLength;
444         }
445 
446         // The cname if any
447         if ( cName != null )
448         {
449             cNameLength = cName.computeLength();
450             krbErrorSeqLength += 1 + TLV.getNbBytes( cNameLength ) + cNameLength;
451         }
452 
453         // The realm
454         realmBytes = Strings.getBytesUtf8( realm );
455         realmLength = 1 + TLV.getNbBytes( realmBytes.length ) + realmBytes.length;
456         krbErrorSeqLength += 1 + TLV.getNbBytes( realmLength ) + realmLength;
457 
458         // The sname
459         sNameLength = sName.computeLength();
460         krbErrorSeqLength += 1 + TLV.getNbBytes( sNameLength ) + sNameLength;
461 
462         // The e-text, if any
463         if ( eText != null )
464         {
465             eTextBytes = Strings.getBytesUtf8( eText );
466             eTextLength = 1 + TLV.getNbBytes( eTextBytes.length ) + eTextBytes.length;
467             krbErrorSeqLength += 1 + TLV.getNbBytes( eTextLength ) + eTextLength;
468         }
469 
470         // The e-data, if any
471         if ( eData != null )
472         {
473             eDataLength = 1 + TLV.getNbBytes( eData.length ) + eData.length;
474             krbErrorSeqLength += 1 + TLV.getNbBytes( eDataLength ) + eDataLength;
475         }
476 
477         // The global sequence length
478         krbErrorLength = 1 + TLV.getNbBytes( krbErrorSeqLength ) + krbErrorSeqLength;
479 
480         return 1 + TLV.getNbBytes( krbErrorLength ) + krbErrorLength;
481     }
482 
483 
484     /**
485      * Encode the KRB-ERROR message to a PDU. 
486      * <pre>
487      * KRB-ERROR :
488      * 
489      * 0x7E LL
490      *   0x30 LL
491      *     0xA0 0x03 
492      *       0x02 0x01 0x05  pvno 
493      *     0xA1 0x03 
494      *       0x02 0x01 0x1E msg-type
495      *    [0xA2 0x11
496      *       0x18 0x0F ttt] ctime
497      *    [0xA3 LL
498      *       0x02 LL nnn] cusec
499      *     0xA4 0x11
500      *       0x18 0x0F ttt  stime
501      *     0xA5 LL
502      *       0x02 LL nnn susec
503      *     0xA6 LL
504      *       0x02 LL nnn error-code
505      *    [0xA7 LL
506      *       0x1B LL abcd] crealm
507      *    [0xA8 LL
508      *       0x30 LL abcd] cname
509      *     0xA9 LL
510      *       0x1B LL abcd realm
511      *     0xAA LL
512      *       0x30 LL abcd sname
513      *    [0xAB LL
514      *       0x1B LL abcd] e-text
515      *    [0xAC LL
516      *       0x04 LL abcd] e-data
517      * </pre>
518      * @return The constructed PDU.
519      */
520     public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
521     {
522         if ( buffer == null )
523         {
524             throw new EncoderException( I18n.err( I18n.ERR_148 ) );
525         }
526 
527         try
528         {
529             // The KRB-ERROR APPLICATION tag
530             buffer.put( ( byte ) KerberosConstants.KRB_ERROR_TAG );
531             buffer.put( TLV.getBytes( krbErrorLength ) );
532 
533             // The KRB_ERROR sequence
534             buffer.put( UniversalTag.SEQUENCE.getValue() );
535             buffer.put( TLV.getBytes( krbErrorSeqLength ) );
536 
537             // pvno tag and value
538             buffer.put( ( byte ) KerberosConstants.KRB_ERROR_PVNO_TAG );
539             buffer.put( TLV.getBytes( pvnoLength ) );
540             BerValue.encode( buffer, getProtocolVersionNumber() );
541 
542             // msg-type tag and value
543             buffer.put( ( byte ) KerberosConstants.KRB_ERROR_MSGTYPE_TAG );
544             buffer.put( TLV.getBytes( msgTypeLength ) );
545             BerValue.encode( buffer, getMessageType().getValue() );
546 
547             // ctime tag and value if any
548             if ( cTimeLength > 0 )
549             {
550                 // The tag
551                 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_CTIME_TAG );
552                 buffer.put( TLV.getBytes( cTimeLength ) );
553 
554                 // The value
555                 buffer.put( UniversalTag.GENERALIZED_TIME.getValue() );
556                 buffer.put( ( byte ) 0x0F );
557                 buffer.put( cTime.getBytes() );
558             }
559 
560             // cusec tag and value if any
561             if ( cusec != null )
562             {
563                 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_CUSEC_TAG );
564                 buffer.put( TLV.getBytes( cusecLength ) );
565                 BerValue.encode( buffer, cusec );
566             }
567 
568             // stime tag and value
569             // The tag
570             buffer.put( ( byte ) KerberosConstants.KRB_ERROR_STIME_TAG );
571             buffer.put( TLV.getBytes( sTimeLength ) );
572 
573             // The value
574             buffer.put( UniversalTag.GENERALIZED_TIME.getValue() );
575             buffer.put( ( byte ) 0x0F );
576             buffer.put( sTime.getBytes() );
577 
578             // susec tag and value
579             buffer.put( ( byte ) KerberosConstants.KRB_ERROR_SUSEC_TAG );
580             buffer.put( TLV.getBytes( susecLength ) );
581             BerValue.encode( buffer, susec );
582 
583             // error-code tag and value
584             buffer.put( ( byte ) KerberosConstants.KRB_ERROR_ERROR_CODE_TAG );
585             buffer.put( TLV.getBytes( errorCodeLength ) );
586             BerValue.encode( buffer, errorCode.getValue() );
587 
588             // crealm tage and value, if any
589             if ( cRealm != null )
590             {
591                 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_CREALM_TAG );
592                 buffer.put( TLV.getBytes( cRealmLength ) );
593 
594                 buffer.put( UniversalTag.GENERAL_STRING.getValue() );
595                 buffer.put( TLV.getBytes( crealmBytes.length ) );
596                 buffer.put( crealmBytes );
597             }
598 
599             // cname tag and value, if any
600             if ( cName != null )
601             {
602                 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_CNAME_TAG );
603                 buffer.put( TLV.getBytes( cNameLength ) );
604                 cName.encode( buffer );
605             }
606 
607             // realm tag and value
608             // the tag
609             buffer.put( ( byte ) KerberosConstants.KRB_ERROR_REALM_TAG );
610             buffer.put( TLV.getBytes( realmLength ) );
611 
612             // The value
613             buffer.put( UniversalTag.GENERAL_STRING.getValue() );
614             buffer.put( TLV.getBytes( realmBytes.length ) );
615             buffer.put( realmBytes );
616 
617             // sname tag and value
618             buffer.put( ( byte ) KerberosConstants.KRB_ERROR_SNAME_TAG );
619             buffer.put( TLV.getBytes( sNameLength ) );
620             sName.encode( buffer );
621 
622             // etext tag and value, if any
623             if ( eText != null )
624             {
625                 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_ETEXT_TAG );
626                 buffer.put( TLV.getBytes( eTextLength ) );
627 
628                 buffer.put( UniversalTag.GENERAL_STRING.getValue() );
629                 buffer.put( TLV.getBytes( eTextBytes.length ) );
630                 buffer.put( eTextBytes );
631             }
632 
633             // edata tag and value, if any
634             if ( eData != null )
635             {
636                 buffer.put( ( byte ) KerberosConstants.KRB_ERROR_EDATA_TAG );
637                 buffer.put( TLV.getBytes( eDataLength ) );
638                 BerValue.encode( buffer, eData );
639             }
640         }
641         catch ( BufferOverflowException boe )
642         {
643             log.error( I18n.err( I18n.ERR_734_CANNOT_ENCODE_KRBERROR, 1 + TLV.getNbBytes( krbErrorLength )
644                 + krbErrorLength, buffer.capacity() ) );
645             throw new EncoderException( I18n.err( I18n.ERR_138 ), boe );
646         }
647 
648         if ( IS_DEBUG )
649         {
650             log.debug( "KrbError encoding : {}", Strings.dumpBytes( buffer.array() ) );
651             log.debug( "KrbError initial value : {}", this );
652         }
653 
654         return buffer;
655     }
656 
657 
658     /**
659      * @see Object#toString()
660      */
661     public String toString()
662     {
663         StringBuilder sb = new StringBuilder();
664 
665         sb.append( "\nKRB-ERROR : {\n" );
666         sb.append( "    pvno: " ).append( getProtocolVersionNumber() ).append( '\n' );
667         sb.append( "    msgType: " ).append( getMessageType() ).append( '\n' );
668 
669         if ( cTime != null )
670         {
671             sb.append( "    cTime: " ).append( cTime ).append( '\n' );
672         }
673 
674         if ( cusec != null )
675         {
676             sb.append( "    cusec: " ).append( cusec ).append( '\n' );
677         }
678 
679         sb.append( "    sTime: " ).append( sTime ).append( '\n' );
680         sb.append( "    susec: " ).append( susec ).append( '\n' );
681         sb.append( "    errorCode: " ).append( errorCode ).append( '\n' );
682 
683         if ( cRealm != null )
684         {
685             sb.append( "    cRealm: " ).append( cRealm ).append( '\n' );
686         }
687 
688         if ( cName != null )
689         {
690             sb.append( "    cName: " ).append( cName ).append( '\n' );
691         }
692 
693         sb.append( "    realm: " ).append( realm ).append( '\n' );
694 
695         sb.append( "    sName: " ).append( sName ).append( '\n' );
696 
697         if ( eText != null )
698         {
699             sb.append( "    eText: " ).append( eText ).append( '\n' );
700         }
701 
702         if ( eData != null )
703         {
704             sb.append( "    eData: " ).append( Strings.dumpBytes( eData ) ).append( '\n' );
705         }
706 
707         sb.append( "}\n" );
708 
709         return sb.toString();
710     }
711 }