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    package org.apache.directory.server.kerberos.shared.io.decoder;
021    
022    
023    import java.io.IOException;
024    import java.nio.ByteBuffer;
025    import java.util.Enumeration;
026    
027    import org.apache.directory.server.kerberos.shared.KerberosConstants;
028    import org.apache.directory.server.kerberos.shared.KerberosMessageType;
029    import org.apache.directory.server.kerberos.shared.messages.KdcRequest;
030    import org.apache.directory.server.kerberos.shared.messages.value.KdcOptions;
031    import org.apache.directory.server.kerberos.shared.messages.value.PaData;
032    import org.apache.directory.server.kerberos.shared.messages.value.RequestBody;
033    import org.apache.directory.server.kerberos.shared.messages.value.RequestBodyModifier;
034    import org.apache.directory.shared.asn1.der.ASN1InputStream;
035    import org.apache.directory.shared.asn1.der.DERApplicationSpecific;
036    import org.apache.directory.shared.asn1.der.DERBitString;
037    import org.apache.directory.shared.asn1.der.DEREncodable;
038    import org.apache.directory.shared.asn1.der.DERGeneralString;
039    import org.apache.directory.shared.asn1.der.DERGeneralizedTime;
040    import org.apache.directory.shared.asn1.der.DERInteger;
041    import org.apache.directory.shared.asn1.der.DERSequence;
042    import org.apache.directory.shared.asn1.der.DERTaggedObject;
043    
044    
045    /**
046     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
047     * @version $Rev: 590715 $, $Date: 2007-10-31 16:23:32 +0100 (Wed, 31 Oct 2007) $
048     */
049    public class KdcRequestDecoder
050    {
051        /**
052         * Decodes a {@link ByteBuffer} into a {@link KdcRequest}.
053         *
054         * @param in
055         * @return The {@link KdcRequest}.
056         * @throws IOException
057         */
058        public KdcRequest decode( ByteBuffer in ) throws IOException
059        {
060            ASN1InputStream ais = new ASN1InputStream( in );
061    
062            DERApplicationSpecific app = ( DERApplicationSpecific ) ais.readObject();
063    
064            DERSequence kdcreq = ( DERSequence ) app.getObject();
065    
066            return decodeKdcRequestSequence( kdcreq );
067        }
068    
069    
070        /*
071         AS-REQ ::=         [APPLICATION 10] KDC-REQ
072         TGS-REQ ::=        [APPLICATION 12] KDC-REQ
073         
074         KDC-REQ ::=        SEQUENCE {
075         pvno[1]               INTEGER,
076         msg-type[2]           INTEGER,
077         padata[3]             SEQUENCE OF PA-DATA OPTIONAL,
078         req-body[4]           KDC-REQ-BODY
079         }*/
080        private KdcRequest decodeKdcRequestSequence( DERSequence sequence ) throws IOException
081        {
082            int pvno = KerberosConstants.KERBEROS_V5;
083            KerberosMessageType msgType = null;
084    
085            PaData[] paData = null;
086            RequestBody requestBody = null;
087            byte[] bodyBytes = null;
088    
089            for ( Enumeration<DEREncodable> e = sequence.getObjects(); e.hasMoreElements(); )
090            {
091                DERTaggedObject object = ( DERTaggedObject ) e.nextElement();
092                int tag = object.getTagNo();
093                DEREncodable derObject = object.getObject();
094    
095                switch ( tag )
096                {
097                    case 1:
098                        DERInteger tag1 = ( DERInteger ) derObject;
099                        pvno = tag1.intValue();
100                        break;
101                        
102                    case 2:
103                        DERInteger tag2 = ( DERInteger ) derObject;
104                        msgType = KerberosMessageType.getTypeByOrdinal( tag2.intValue() );
105                        break;
106                        
107                    case 3:
108                        DERSequence tag3 = ( DERSequence ) derObject;
109                        paData = PreAuthenticationDataDecoder.decodeSequence( tag3 );
110                        break;
111                        
112                    case 4:
113                        DERSequence tag4 = ( DERSequence ) derObject;
114                        requestBody = decodeRequestBody( tag4 );
115    
116                        /**
117                         * Get the raw bytes of the KDC-REQ-BODY for checksum calculation and
118                         * comparison with the authenticator checksum during the verification
119                         * stage of ticket grant processing.
120                         */
121                        bodyBytes = object.getOctets();
122    
123                        break;
124                }
125            }
126    
127            return new KdcRequest( pvno, msgType, paData, requestBody, bodyBytes );
128        }
129    
130    
131        /*
132         KDC-REQ-BODY ::=   SEQUENCE {
133         kdc-options[0]       KdcOptions,
134         cname[1]             PrincipalName OPTIONAL,
135         -- Used only in AS-REQ
136         realm[2]             Realm, -- Server's realm
137         -- Also client's in AS-REQ
138         sname[3]             PrincipalName OPTIONAL,
139         from[4]              KerberosTime OPTIONAL,
140         till[5]              KerberosTime,
141         rtime[6]             KerberosTime OPTIONAL,
142         nonce[7]             INTEGER,
143         etype[8]             SEQUENCE OF INTEGER, -- EncryptionType,
144         -- in preference order
145         addresses[9]         HostAddresses OPTIONAL,
146         enc-authorization-data[10]   EncryptedData OPTIONAL,
147         -- Encrypted AuthorizationData encoding
148         additional-tickets[11]       SEQUENCE OF Ticket OPTIONAL
149         }*/
150        private RequestBody decodeRequestBody( DERSequence sequence ) throws IOException
151        {
152            RequestBodyModifier modifier = new RequestBodyModifier();
153    
154            for ( Enumeration<DEREncodable> e = sequence.getObjects(); e.hasMoreElements(); )
155            {
156                DERTaggedObject object = ( DERTaggedObject ) e.nextElement();
157                int tag = object.getTagNo();
158                DEREncodable derObject = object.getObject();
159    
160                switch ( tag )
161                {
162                    case 0:
163                        DERBitString kdcOptions = ( DERBitString ) derObject;
164                        modifier.setKdcOptions( new KdcOptions( kdcOptions.getOctets() ) );
165                        break;
166                    case 1:
167                        DERSequence cName = ( DERSequence ) derObject;
168                        modifier.setClientName( PrincipalNameDecoder.decode( cName ) );
169                        break;
170                    case 2:
171                        DERGeneralString realm = ( DERGeneralString ) derObject;
172                        modifier.setRealm( realm.getString() );
173                        break;
174                    case 3:
175                        DERSequence sname = ( DERSequence ) derObject;
176                        modifier.setServerName( PrincipalNameDecoder.decode( sname ) );
177                        break;
178                    case 4:
179                        DERGeneralizedTime from = ( DERGeneralizedTime ) derObject;
180                        modifier.setFrom( KerberosTimeDecoder.decode( from ) );
181                        break;
182                    case 5:
183                        DERGeneralizedTime till = ( DERGeneralizedTime ) derObject;
184                        modifier.setTill( KerberosTimeDecoder.decode( till ) );
185                        break;
186                    case 6:
187                        DERGeneralizedTime rtime = ( DERGeneralizedTime ) derObject;
188                        modifier.setRtime( KerberosTimeDecoder.decode( rtime ) );
189                        break;
190                    case 7:
191                        DERInteger nonce = ( DERInteger ) derObject;
192                        modifier.setNonce( nonce.intValue() );
193                        break;
194                    case 8:
195                        DERSequence etype = ( DERSequence ) derObject;
196                        modifier.setEType( EncryptionTypeDecoder.decode( etype ) );
197                        break;
198                        
199                    case 9:
200                        DERSequence hostAddresses = ( DERSequence ) derObject;
201                        modifier.setAddresses( HostAddressDecoder.decodeSequence( hostAddresses ) );
202                        break;
203                    case 10:
204                        DERSequence encryptedData = ( DERSequence ) derObject;
205                        modifier.setEncAuthorizationData( EncryptedDataDecoder.decode( encryptedData ) );
206                        break;
207                    case 11:
208                        DERSequence tag11 = ( DERSequence ) derObject;
209                        modifier.setAdditionalTickets( TicketDecoder.decodeSequence( tag11 ) );
210                        break;
211                }
212            }
213    
214            return modifier.getRequestBody();
215        }
216    }