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.codec;
021
022
023import java.nio.ByteBuffer;
024
025import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswdErrorType;
026import org.apache.directory.server.kerberos.changepwd.exceptions.ChangePasswordException;
027import org.apache.directory.api.asn1.DecoderException;
028import org.apache.directory.api.asn1.ber.Asn1Container;
029import org.apache.directory.api.asn1.ber.Asn1Decoder;
030import org.apache.directory.api.asn1.ber.tlv.TLVStateEnum;
031import org.apache.directory.shared.kerberos.codec.EncKdcRepPart.EncKdcRepPartContainer;
032import org.apache.directory.shared.kerberos.codec.apRep.ApRepContainer;
033import org.apache.directory.shared.kerberos.codec.apReq.ApReqContainer;
034import org.apache.directory.shared.kerberos.codec.authenticator.AuthenticatorContainer;
035import org.apache.directory.shared.kerberos.codec.authorizationData.AuthorizationDataContainer;
036import org.apache.directory.shared.kerberos.codec.encApRepPart.EncApRepPartContainer;
037import org.apache.directory.shared.kerberos.codec.encAsRepPart.EncAsRepPartContainer;
038import org.apache.directory.shared.kerberos.codec.encKrbPrivPart.EncKrbPrivPartContainer;
039import org.apache.directory.shared.kerberos.codec.encTgsRepPart.EncTgsRepPartContainer;
040import org.apache.directory.shared.kerberos.codec.encTicketPart.EncTicketPartContainer;
041import org.apache.directory.shared.kerberos.codec.encryptedData.EncryptedDataContainer;
042import org.apache.directory.shared.kerberos.codec.encryptionKey.EncryptionKeyContainer;
043import org.apache.directory.shared.kerberos.codec.krbPriv.KrbPrivContainer;
044import org.apache.directory.shared.kerberos.codec.paEncTsEnc.PaEncTsEncContainer;
045import org.apache.directory.shared.kerberos.codec.principalName.PrincipalNameContainer;
046import org.apache.directory.shared.kerberos.codec.ticket.TicketContainer;
047import org.apache.directory.shared.kerberos.components.AuthorizationData;
048import org.apache.directory.shared.kerberos.components.EncKdcRepPart;
049import org.apache.directory.shared.kerberos.components.EncKrbPrivPart;
050import org.apache.directory.shared.kerberos.components.EncTicketPart;
051import org.apache.directory.shared.kerberos.components.EncryptedData;
052import org.apache.directory.shared.kerberos.components.EncryptionKey;
053import org.apache.directory.shared.kerberos.components.PaEncTsEnc;
054import org.apache.directory.shared.kerberos.components.PrincipalName;
055import org.apache.directory.shared.kerberos.exceptions.ErrorType;
056import org.apache.directory.shared.kerberos.exceptions.KerberosException;
057import org.apache.directory.shared.kerberos.messages.ApRep;
058import org.apache.directory.shared.kerberos.messages.ApReq;
059import org.apache.directory.shared.kerberos.messages.Authenticator;
060import org.apache.directory.shared.kerberos.messages.EncApRepPart;
061import org.apache.directory.shared.kerberos.messages.EncAsRepPart;
062import org.apache.directory.shared.kerberos.messages.EncTgsRepPart;
063import org.apache.directory.shared.kerberos.messages.KrbPriv;
064import org.apache.directory.shared.kerberos.messages.Ticket;
065import org.slf4j.Logger;
066import org.slf4j.LoggerFactory;
067
068
069/**
070 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
071 */
072public class KerberosDecoder
073{
074
075    /** The logger */
076    private static Logger LOG = LoggerFactory.getLogger( KerberosDecoder.class );
077
078    /** A speedup for logger */
079    private static final boolean IS_DEBUG = LOG.isDebugEnabled();
080
081
082    public static Object decode( KerberosMessageContainer kerberosMessageContainer ) throws DecoderException
083    {
084        ByteBuffer buf = kerberosMessageContainer.getStream();
085        
086        if ( kerberosMessageContainer.isTCP() )
087        {
088            if ( buf.remaining() > 4 )
089            {
090                kerberosMessageContainer.setTcpLength( buf.getInt() );
091                buf.mark();
092            }
093            else
094            {
095                return null;
096            }
097        }
098        else
099        {
100            buf.mark();
101        }
102
103        while ( buf.hasRemaining() )
104        {
105            try
106            {
107                Asn1Decoder.decode( buf, kerberosMessageContainer );
108                
109                if ( kerberosMessageContainer.getState() == TLVStateEnum.PDU_DECODED )
110                {
111                    if ( IS_DEBUG )
112                    {
113                        LOG.debug( "Decoded KerberosMessage : {}", kerberosMessageContainer.getMessage() );
114                        buf.mark();
115                    }
116        
117                    return kerberosMessageContainer.getMessage();
118                }
119            }
120            catch ( DecoderException de )
121            {
122                LOG.warn( "error while decoding", de );
123                buf.clear();
124                kerberosMessageContainer.clean();
125                throw de;
126            }
127        }
128        
129        return null;
130    }
131    
132    
133    /**
134     * Decode an EncrytedData structure
135     * 
136     * @param data The byte array containing the data structure to decode
137     * @return An instance of EncryptedData
138     * @throws KerberosException If the decoding fails
139     */
140    public static EncryptedData decodeEncryptedData( byte[] data ) throws KerberosException
141    {
142        ByteBuffer stream = ByteBuffer.allocate( data.length );
143        stream.put( data );
144        stream.flip();
145        
146        // Allocate a EncryptedData Container
147        Asn1Container encryptedDataContainer = new EncryptedDataContainer();
148
149        // Decode the EncryptedData PDU
150        try
151        {
152            Asn1Decoder.decode( stream, encryptedDataContainer );
153        }
154        catch ( DecoderException de )
155        {
156            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
157        }
158
159        // get the decoded EncryptedData
160        return ( ( EncryptedDataContainer ) encryptedDataContainer ).getEncryptedData();
161    }
162    
163    
164    /**
165     * Decode an PaEncTsEnc structure
166     * 
167     * @param data The byte array containing the data structure to decode
168     * @return An instance of PaEncTsEnc
169     * @throws KerberosException If the decoding fails
170     */
171    public static PaEncTsEnc decodePaEncTsEnc( byte[] data ) throws KerberosException
172    {
173        ByteBuffer stream = ByteBuffer.allocate( data.length );
174        stream.put( data );
175        stream.flip();
176        
177        // Allocate a PaEncTsEnc Container
178        Asn1Container paEncTsEncContainer = new PaEncTsEncContainer();
179
180        // Decode the PaEncTsEnc PDU
181        try
182        {
183            Asn1Decoder.decode( stream, paEncTsEncContainer );
184        }
185        catch ( DecoderException de )
186        {
187            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
188        }
189
190        // get the decoded PaEncTsEnc
191        return ( ( PaEncTsEncContainer ) paEncTsEncContainer ).getPaEncTsEnc();
192    }
193    
194    
195    /**
196     * Decode an EncApRepPart structure
197     * 
198     * @param data The byte array containing the data structure to decode
199     * @return An instance of EncApRepPart
200     * @throws KerberosException If the decoding fails
201     */
202    public static EncApRepPart decodeEncApRepPart( byte[] data ) throws KerberosException
203    {
204        ByteBuffer stream = ByteBuffer.allocate( data.length );
205        stream.put( data );
206        stream.flip();
207        
208        // Allocate a EncApRepPart Container
209        Asn1Container encApRepPartContainer = new EncApRepPartContainer( stream );
210
211        // Decode the EncApRepPart PDU
212        try
213        {
214            Asn1Decoder.decode( stream, encApRepPartContainer );
215        }
216        catch ( DecoderException de )
217        {
218            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
219        }
220
221        // get the decoded EncApRepPart
222        return ( ( EncApRepPartContainer ) encApRepPartContainer ).getEncApRepPart();
223    }
224    
225    
226    /**
227     * Decode an EncKdcRepPart structure
228     * 
229     * @param data The byte array containing the data structure to decode
230     * @return An instance of EncKdcRepPart
231     * @throws KerberosException If the decoding fails
232     */
233    public static EncKdcRepPart decodeEncKdcRepPart( byte[] data ) throws KerberosException
234    {
235        ByteBuffer stream = ByteBuffer.allocate( data.length );
236        stream.put( data );
237        stream.flip();
238        
239        // Allocate a EncKdcRepPart Container
240        Asn1Container encKdcRepPartContainer = new EncKdcRepPartContainer( stream );
241
242        // Decode the EncKdcRepPart PDU
243        try
244        {
245            Asn1Decoder.decode( stream, encKdcRepPartContainer );
246        }
247        catch ( DecoderException de )
248        {
249            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
250        }
251
252        // get the decoded EncKdcRepPart
253        return ( ( EncKdcRepPartContainer ) encKdcRepPartContainer ).getEncKdcRepPart();
254    }
255    
256    
257    /**
258     * Decode an EncKrbPrivPart structure
259     * 
260     * @param data The byte array containing the data structure to decode
261     * @return An instance of EncKrbPrivPart
262     * @throws KerberosException If the decoding fails
263     */
264    public static EncKrbPrivPart decodeEncKrbPrivPart( byte[] data ) throws KerberosException
265    {
266        ByteBuffer stream = ByteBuffer.allocate( data.length );
267        stream.put( data );
268        stream.flip();
269        
270        // Allocate a EncKrbPrivPart Container
271        Asn1Container encKrbPrivPartContainer = new EncKrbPrivPartContainer( stream );
272
273        // Decode the EncKrbPrivPart PDU
274        try
275        {
276            Asn1Decoder.decode( stream, encKrbPrivPartContainer );
277        }
278        catch ( DecoderException de )
279        {
280            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
281        }
282
283        // get the decoded EncKrbPrivPart
284        return ( ( EncKrbPrivPartContainer ) encKrbPrivPartContainer ).getEncKrbPrivPart();
285    }
286    
287    
288    /**
289     * Decode an EncTicketPart structure
290     * 
291     * @param data The byte array containing the data structure to decode
292     * @return An instance of EncTicketPart
293     * @throws KerberosException If the decoding fails
294     */
295    public static EncTicketPart decodeEncTicketPart( byte[] data ) throws KerberosException
296    {
297        ByteBuffer stream = ByteBuffer.allocate( data.length );
298        stream.put( data );
299        stream.flip();
300        
301        // Allocate a EncTicketPart Container
302        Asn1Container encTicketPartContainer = new EncTicketPartContainer( stream );
303
304        // Decode the EncTicketPart PDU
305        try
306        {
307            Asn1Decoder.decode( stream, encTicketPartContainer );
308        }
309        catch ( DecoderException de )
310        {
311            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
312        }
313
314        // get the decoded EncTicketPart
315        return ( ( EncTicketPartContainer ) encTicketPartContainer ).getEncTicketPart();
316    }
317    
318    
319    /**
320     * Decode an EncryptionKey structure
321     * 
322     * @param data The byte array containing the data structure to decode
323     * @return An instance of EncryptionKey
324     * @throws KerberosException If the decoding fails
325     */
326    public static EncryptionKey decodeEncryptionKey( byte[] data ) throws KerberosException
327    {
328        ByteBuffer stream = ByteBuffer.allocate( data.length );
329        stream.put( data );
330        stream.flip();
331        
332        // Allocate a EncryptionKey Container
333        Asn1Container encryptionKeyContainer = new EncryptionKeyContainer();
334
335        // Decode the EncryptionKey PDU
336        try
337        {
338            Asn1Decoder.decode( stream, encryptionKeyContainer );
339        }
340        catch ( DecoderException de )
341        {
342            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
343        }
344
345        // get the decoded EncryptionKey
346        return ( ( EncryptionKeyContainer ) encryptionKeyContainer ).getEncryptionKey();
347    }
348    
349    
350    /**
351     * Decode an PrincipalName structure
352     * 
353     * @param data The byte array containing the data structure to decode
354     * @return An instance of PrincipalName
355     * @throws KerberosException If the decoding fails
356     */
357    public static PrincipalName decodePrincipalName( byte[] data ) throws KerberosException
358    {
359        ByteBuffer stream = ByteBuffer.allocate( data.length );
360        stream.put( data );
361        stream.flip();
362        
363        // Allocate a PrincipalName Container
364        Asn1Container principalNameContainer = new PrincipalNameContainer();
365
366        // Decode the PrincipalName PDU
367        try
368        {
369            Asn1Decoder.decode( stream, principalNameContainer );
370        }
371        catch ( DecoderException de )
372        {
373            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
374        }
375
376        // get the decoded PrincipalName
377        return ( ( PrincipalNameContainer ) principalNameContainer ).getPrincipalName();
378    }
379    
380    
381    /**
382     * Decode a Ticket structure
383     * 
384     * @param data The byte array containing the data structure to decode
385     * @return An instance of Ticket
386     * @throws KerberosException If the decoding fails
387     */
388    public static Ticket decodeTicket( byte[] data ) throws KerberosException
389    {
390        ByteBuffer stream = ByteBuffer.allocate( data.length );
391        stream.put( data );
392        stream.flip();
393        
394        // Allocate a Ticket Container
395        Asn1Container ticketContainer = new TicketContainer( stream );
396
397        // Decode the Ticket PDU
398        try
399        {
400            Asn1Decoder.decode( stream, ticketContainer );
401        }
402        catch ( DecoderException de )
403        {
404            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
405        }
406
407        // get the decoded Ticket
408        return ( ( TicketContainer ) ticketContainer ).getTicket();
409    }
410    
411    
412    /**
413     * Decode a Authenticator structure
414     * 
415     * @param data The byte array containing the data structure to decode
416     * @return An instance of Authenticator
417     * @throws KerberosException If the decoding fails
418     */
419    public static Authenticator decodeAuthenticator( byte[] data ) throws KerberosException
420    {
421        ByteBuffer stream = ByteBuffer.allocate( data.length );
422        stream.put( data );
423        stream.flip();
424        
425        // Allocate a Authenticator Container
426        Asn1Container authenticatorContainer = new AuthenticatorContainer( stream );
427
428        // Decode the Ticket PDU
429        try
430        {
431            Asn1Decoder.decode( stream, authenticatorContainer );
432        }
433        catch ( DecoderException de )
434        {
435            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
436        }
437
438        // get the decoded Authenticator
439        return ( ( AuthenticatorContainer ) authenticatorContainer ).getAuthenticator();
440    }
441    
442    
443    /**
444     * Decode a AuthorizationData structure
445     * 
446     * @param data The byte array containing the data structure to decode
447     * @return An instance of AuthorizationData
448     * @throws KerberosException If the decoding fails
449     */
450    public static AuthorizationData decodeAuthorizationData( byte[] data ) throws KerberosException
451    {
452        ByteBuffer stream = ByteBuffer.allocate( data.length );
453        stream.put( data );
454        stream.flip();
455        
456        // Allocate a AuthorizationData Container
457        Asn1Container authorizationDataContainer = new AuthorizationDataContainer();
458
459        // Decode the Ticket PDU
460        try
461        {
462            Asn1Decoder.decode( stream, authorizationDataContainer );
463        }
464        catch ( DecoderException de )
465        {
466            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
467        }
468
469        // get the decoded AuthorizationData
470        return ( ( AuthorizationDataContainer ) authorizationDataContainer ).getAuthorizationData();
471    }
472
473    
474    /**
475     * Decode a AP-REP structure
476     * 
477     * @param data The byte array containing the data structure to decode
478     * @return An instance of ApRep
479     * @throws KerberosException If the decoding fails
480     */
481    public static ApRep decodeApRep( byte[] data ) throws KerberosException
482    {
483        ByteBuffer stream = ByteBuffer.allocate( data.length );
484        stream.put( data );
485        stream.flip();
486        
487        // Allocate a ApRep Container
488        Asn1Container apRepContainer = new ApRepContainer( stream );
489
490        // Decode the ApRep PDU
491        try
492        {
493            Asn1Decoder.decode( stream, apRepContainer );
494        }
495        catch ( DecoderException de )
496        {
497            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
498        }
499
500        // get the decoded ApRep
501        return ( ( ApRepContainer ) apRepContainer ).getApRep();
502    }
503
504    
505    /**
506     * Decode a AP-REQ structure
507     * 
508     * @param data The byte array containing the data structure to decode
509     * @return An instance of ApReq
510     * @throws KerberosException If the decoding fails
511     */
512    public static ApReq decodeApReq( byte[] data ) throws KerberosException
513    {
514        ByteBuffer stream = ByteBuffer.allocate( data.length );
515        stream.put( data );
516        stream.flip();
517        
518        // Allocate a ApReq Container
519        Asn1Container apReqContainer = new ApReqContainer( stream );
520
521        // Decode the ApReq PDU
522        try
523        {
524            Asn1Decoder.decode( stream, apReqContainer );
525        }
526        catch ( DecoderException de )
527        {
528            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
529        }
530
531        // get the decoded ApReq
532        return ( ( ApReqContainer ) apReqContainer ).getApReq();
533    }
534
535    
536    /**
537     * Decode a KRB-PRIV structure
538     * 
539     * @param data The byte array containing the data structure to decode
540     * @return An instance of KrbPriv
541     * @throws KerberosException If the decoding fails
542     */
543    public static KrbPriv decodeKrbPriv( byte[] data ) throws KerberosException
544    {
545        ByteBuffer stream = ByteBuffer.allocate( data.length );
546        stream.put( data );
547        stream.flip();
548        
549        // Allocate a KrbPriv Container
550        Asn1Container krbPrivContainer = new KrbPrivContainer( stream );
551
552        // Decode the KrbPriv PDU
553        try
554        {
555            Asn1Decoder.decode( stream, krbPrivContainer );
556        }
557        catch ( DecoderException de )
558        {
559            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
560        }
561
562        // get the decoded KrbPriv
563        return ( ( KrbPrivContainer ) krbPrivContainer ).getKrbPriv();
564    }
565    
566    
567    /**
568     * Decode an EncAsRepPart structure
569     * 
570     * @param data The byte array containing the data structure to decode
571     * @return An instance of EncAsRepPart
572     * @throws KerberosException If the decoding fails
573     */
574    public static EncAsRepPart decodeEncAsRepPart( byte[] data ) throws KerberosException
575    {
576        ByteBuffer stream = ByteBuffer.allocate( data.length );
577        stream.put( data );
578        stream.flip();
579        
580        // Allocate a EncAsRepPart Container
581        Asn1Container encAsRepPartContainer = new EncAsRepPartContainer( stream );
582
583        // Decode the EncAsRepPart PDU
584        try
585        {
586            Asn1Decoder.decode( stream, encAsRepPartContainer );
587        }
588        catch ( DecoderException de )
589        {
590            throw new KerberosException( ErrorType.KRB_AP_ERR_BAD_INTEGRITY, de );
591        }
592
593        // get the decoded EncAsRepPart
594        return ( ( EncAsRepPartContainer ) encAsRepPartContainer ).getEncAsRepPart();
595    }
596
597    
598    /**
599     * Decode an EncTgsRepPart structure
600     * 
601     * @param data The byte array containing the data structure to decode
602     * @return An instance of EncTgsRepPart
603     * @throws ChangePasswordException If the decoding fails
604     */
605    public static EncTgsRepPart decodeEncTgsRepPart( byte[] data ) throws ChangePasswordException
606    {
607        ByteBuffer stream = ByteBuffer.allocate( data.length );
608        stream.put( data );
609        stream.flip();
610        
611        // Allocate a EncTgsRepPart Container
612        Asn1Container encTgsRepPartContainer = new EncTgsRepPartContainer( stream );
613
614        // Decode the EncTgsRepPart PDU
615        try
616        {
617            Asn1Decoder.decode( stream, encTgsRepPartContainer );
618        }
619        catch ( DecoderException de )
620        {
621            throw new ChangePasswordException( ChangePasswdErrorType.KRB5_KPASSWD_MALFORMED, de );
622        }
623
624        // get the decoded EncTgsRepPart
625        return ( ( EncTgsRepPartContainer ) encTgsRepPartContainer ).getEncTgsRepPart();
626    }
627}