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.encoder;
021    
022    
023    import java.io.ByteArrayOutputStream;
024    import java.io.IOException;
025    import java.nio.ByteBuffer;
026    
027    import org.apache.directory.server.kerberos.shared.messages.KdcRequest;
028    import org.apache.directory.server.kerberos.shared.messages.value.PaData;
029    import org.apache.directory.server.kerberos.shared.messages.value.RequestBody;
030    import org.apache.directory.shared.asn1.der.ASN1OutputStream;
031    import org.apache.directory.shared.asn1.der.DERApplicationSpecific;
032    import org.apache.directory.shared.asn1.der.DERBitString;
033    import org.apache.directory.shared.asn1.der.DERGeneralString;
034    import org.apache.directory.shared.asn1.der.DERInteger;
035    import org.apache.directory.shared.asn1.der.DEROctetString;
036    import org.apache.directory.shared.asn1.der.DERSequence;
037    import org.apache.directory.shared.asn1.der.DERTaggedObject;
038    
039    
040    /**
041     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
042     * @version $Rev: 587624 $, $Date: 2007-10-23 21:22:08 +0200 (Tue, 23 Oct 2007) $
043     */
044    public class KdcRequestEncoder
045    {
046        /**
047         * Encodes a {@link KdcRequest} into a {@link ByteBuffer}.
048         * 
049         * AS-REQ ::=         [APPLICATION 10] KDC-REQ
050         * TGS-REQ ::=        [APPLICATION 12] KDC-REQ
051         *
052         * @param request
053         * @param out
054         * @throws IOException
055         */
056        public void encode( KdcRequest request, ByteBuffer out ) throws IOException
057        {
058            ASN1OutputStream aos = new ASN1OutputStream( out );
059    
060            DERSequence kdcRequest = encodeInitialSequence( request );
061            aos.writeObject( DERApplicationSpecific.valueOf( request.getMessageType().getOrdinal(), kdcRequest ) );
062            aos.close();
063        }
064    
065    
066        /*
067         KDC-REQ ::=        SEQUENCE {
068         pvno[1]               INTEGER,
069         msg-type[2]           INTEGER,
070         padata[3]             SEQUENCE OF PA-DATA OPTIONAL,
071         req-body[4]           KDC-REQ-BODY
072         }*/
073        private DERSequence encodeInitialSequence( KdcRequest app )
074        {
075            DERSequence sequence = new DERSequence();
076    
077            sequence.add( new DERTaggedObject( 1, DERInteger.valueOf( app.getProtocolVersionNumber() ) ) );
078    
079            sequence.add( new DERTaggedObject( 2, DERInteger.valueOf( app.getMessageType().getOrdinal() ) ) );
080    
081            if ( app.getPreAuthData() != null )
082            {
083                sequence.add( new DERTaggedObject( 3, encodePreAuthData( app.getPreAuthData() ) ) );
084            }
085    
086            sequence.add( new DERTaggedObject( 4, encodeKdcRequestBody( app.getRequestBody() ) ) );
087    
088            return sequence;
089        }
090    
091    
092        /**
093         * Encodes a {@link KdcRequest} into a byte[].
094         *
095         * @param requestBody
096         * @return The encoded {@link KdcRequest}.
097         * @throws IOException
098         */
099        public byte[] encodeRequestBody( RequestBody requestBody ) throws IOException
100        {
101            ByteArrayOutputStream baos = new ByteArrayOutputStream();
102            ASN1OutputStream aos = new ASN1OutputStream( baos );
103    
104            aos.writeObject( encodeKdcRequestBody( requestBody ) );
105            aos.close();
106    
107            return baos.toByteArray();
108        }
109    
110    
111        /**
112         * KDC-REQ-BODY ::=   SEQUENCE {
113         *     kdc-options[0]       KDCOptions,
114         *     cname[1]             PrincipalName OPTIONAL,
115         *                  -- Used only in AS-REQ
116         *     realm[2]             Realm, -- Server's realm
117         *                  -- Also client's in AS-REQ
118         *     sname[3]             PrincipalName OPTIONAL,
119         *     from[4]              KerberosTime OPTIONAL,
120         *     till[5]              KerberosTime,
121         *     rtime[6]             KerberosTime OPTIONAL,
122         *     nonce[7]             INTEGER,
123         * 
124         *     etype[8]             SEQUENCE OF INTEGER, -- EncryptionEngine,
125         *                  -- in preference order
126         *     addresses[9]         HostAddresses OPTIONAL,
127         *     enc-authorization-data[10]   EncryptedData OPTIONAL,
128         *                  -- Encrypted AuthorizationData encoding
129         *     additional-tickets[11]       SEQUENCE OF Ticket OPTIONAL
130         * }
131         */
132        private DERSequence encodeKdcRequestBody( RequestBody requestBody )
133        {
134            DERSequence sequence = new DERSequence();
135    
136            sequence.add( new DERTaggedObject( 0, new DERBitString( requestBody.getKdcOptions().getBytes() ) ) );
137    
138            // OPTIONAL
139            if ( requestBody.getClientPrincipal() != null )
140            {
141                sequence.add( new DERTaggedObject( 1, PrincipalNameEncoder.encode( requestBody.getClientPrincipal() ) ) );
142            }
143    
144            sequence.add( new DERTaggedObject( 2, DERGeneralString.valueOf( requestBody.getServerPrincipal().getRealm()
145                .toString() ) ) );
146    
147            // OPTIONAL
148            if ( requestBody.getServerPrincipal() != null )
149            {
150                sequence.add( new DERTaggedObject( 3, PrincipalNameEncoder.encode( requestBody.getServerPrincipal() ) ) );
151            }
152    
153            // OPTIONAL
154            if ( requestBody.getFrom() != null )
155            {
156                sequence.add( new DERTaggedObject( 4, KerberosTimeEncoder.encode( requestBody.getFrom() ) ) );
157            }
158    
159            sequence.add( new DERTaggedObject( 5, KerberosTimeEncoder.encode( requestBody.getTill() ) ) );
160    
161            // OPTIONAL
162            if ( requestBody.getRtime() != null )
163            {
164                sequence.add( new DERTaggedObject( 6, KerberosTimeEncoder.encode( requestBody.getRtime() ) ) );
165            }
166    
167            sequence.add( new DERTaggedObject( 7, DERInteger.valueOf( requestBody.getNonce() ) ) );
168    
169            sequence.add( new DERTaggedObject( 8, EncryptionTypeEncoder.encode( requestBody.getEType() ) ) );
170    
171            // OPTIONAL
172            if ( requestBody.getAddresses() != null )
173            {
174                sequence.add( new DERTaggedObject( 9, HostAddressesEncoder.encodeSequence( requestBody.getAddresses() ) ) );
175            }
176    
177            // OPTIONAL
178            if ( requestBody.getEncAuthorizationData() != null )
179            {
180                sequence.add( new DERTaggedObject( 10, EncryptedDataEncoder.encodeSequence( requestBody
181                    .getEncAuthorizationData() ) ) );
182            }
183    
184            // OPTIONAL
185            if ( requestBody.getAdditionalTickets() != null )
186            {
187                sequence
188                    .add( new DERTaggedObject( 11, TicketEncoder.encodeSequence( requestBody.getAdditionalTickets() ) ) );
189            }
190    
191            return sequence;
192        }
193    
194    
195        /*
196         PA-DATA ::=        SEQUENCE {
197         padata-type[1]        INTEGER,
198         padata-value[2]       OCTET STRING,
199         -- might be encoded AP-REQ
200         }*/
201        private DERSequence encodePreAuthData( PaData[] preAuthData )
202        {
203            DERSequence preAuth = new DERSequence();
204    
205            for ( int ii = 0; ii < preAuthData.length; ii++ )
206            {
207                DERSequence sequence = new DERSequence();
208    
209                sequence.add( new DERTaggedObject( 1, DERInteger.valueOf( preAuthData[ii].getPaDataType().getOrdinal() ) ) );
210                sequence.add( new DERTaggedObject( 2, new DEROctetString( preAuthData[ii].getPaDataValue() ) ) );
211                preAuth.add( sequence );
212            }
213    
214            return preAuth;
215        }
216    }