/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.harmony.auth.internal.kerberos.v5;
import java.io.IOException;
import java.math.BigInteger;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Date;
import org.apache.harmony.auth.internal.nls.Messages;
import org.apache.harmony.security.asn1.ASN1Any;
import org.apache.harmony.security.asn1.ASN1Constants;
import org.apache.harmony.security.asn1.ASN1Explicit;
import org.apache.harmony.security.asn1.ASN1Integer;
import org.apache.harmony.security.asn1.ASN1Sequence;
import org.apache.harmony.security.asn1.ASN1SequenceOf;
import org.apache.harmony.security.asn1.ASN1StringType;
import org.apache.harmony.security.asn1.ASN1Type;
/**
* @see http://www.ietf.org/rfc/rfc3961.txt
* @see http://www.ietf.org/rfc/rfc4120.txt
*/
public class KDCRequest {
/**
* Authentication Service request message type
*/
public static final int AS_REQ = 10;
/**
* Ticket-Granting Service request message type
*/
public static final int TGS_REQ = 12;
// type of a protocol message: AS_REQ or TGS_REQ
private final int msgType;
private final PrincipalName cname;
private final String realm;
private final PrincipalName sname;
/**
*
* <pre>
* KDC-REQ-BODY ::= SEQUENCE {
* kdc-options [0] KDCOptions,
* cname [1] PrincipalName OPTIONAL
* -- Used only in AS-REQ --,
* realm [2] Realm
* -- Server's realm
* -- Also client's in AS-REQ --,
* sname [3] PrincipalName OPTIONAL,
* from [4] KerberosTime OPTIONAL,
* till [5] KerberosTime,
* rtime [6] KerberosTime OPTIONAL,
* nonce [7] UInt32,
* etype [8] SEQUENCE OF Int32 -- EncryptionType
* -- in preference order --,
* addresses [9] HostAddresses OPTIONAL,
* enc-authorization-data [10] EncryptedData OPTIONAL
* -- AuthorizationData --,
* additional-tickets [11] SEQUENCE OF Ticket OPTIONAL
* -- NOTE: not empty
* }
* </pre>
*/
private static final ASN1Sequence KDC_REQ_BODY = new ASN1Sequence(
new ASN1Type[] {
new ASN1Explicit(0, ASN1Any.getInstance()), // TODO: ignored
new ASN1Explicit(1, PrincipalName.ASN1),
// TODO should we define Realm type?
new ASN1Explicit(2, ASN1StringType.GENERALSTRING),
new ASN1Explicit(3, PrincipalName.ASN1),
new ASN1Explicit(4, ASN1Any.getInstance()), // TODO: ignored
new ASN1Explicit(5, KerberosTime.getASN1()),
new ASN1Explicit(6, ASN1Any.getInstance()), // TODO: ignored
new ASN1Explicit(7, ASN1Integer.getInstance()),
new ASN1Explicit(8, new ASN1SequenceOf(
ASN1Integer.getInstance())),
new ASN1Explicit(9, ASN1Any.getInstance()), // TODO: ignored
new ASN1Explicit(10, ASN1Any.getInstance()), // TODO:
// ignored
new ASN1Explicit(11, ASN1Any.getInstance()), // TODO:
// ignored
}) {
{
setOptional(1); // cname
setOptional(3); // sname
setOptional(4); // from
setOptional(6); // rtime
setOptional(9); // addresses
setOptional(10); // enc-authorization-data
setOptional(11); // additional-tickets
}
@Override
protected void getValues(Object object, Object[] values) {
final KDCRequest request = (KDCRequest) object;
// FIXME: hardcoded - no KDCOptions are set
// note: number of bits should be >= 32
// (see RFC 4120, 5.2.8. KerberosFlags)
values[0] = new byte[] { (byte) 0x03, (byte) 0x05, (byte) 0x00,
(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, };
values[1] = request.cname;
values[2] = request.realm;
values[3] = request.sname;
// value[4] = from; //TODO
// till: requested: "19700101000000Z" FIXME
values[5] = new Date(0);
// values[6] = rtime //TODO
// nonce FIXME: hardcoded
values[7] = BigInteger.valueOf(0).toByteArray();
// etype FIXME
final ArrayList<byte[]> list = new ArrayList<byte[]>();
// see RFC 3961 (Section 8)
list.add(BigInteger.valueOf(1).toByteArray());// des-cbc-crc
list.add(BigInteger.valueOf(2).toByteArray());// des-cbc-md4
list.add(BigInteger.valueOf(3).toByteArray());// des-cbc-md5
values[8] = list;
// value[9] = FIXME
// value[10] = FIXME
// value[11] = FIXME
}
};
/**
* <pre>
* KDC-REQ ::= SEQUENCE {
* -- NOTE: first tag is [1], not [0]
* pvno [1] INTEGER (5) ,
* msg-type [2] INTEGER (10 -- AS -- | 12 -- TGS --),
* padata [3] SEQUENCE OF PA-DATA OPTIONAL
* -- NOTE: not empty --,
* req-body [4] KDC-REQ-BODY
* }
* </pre>
*/
static final ASN1Sequence KDC_REQ_ASN1 = new ASN1Sequence(new ASN1Type[] {
// pvno [1] INTEGER (5)
new ASN1Explicit(1, ASN1Integer.getInstance()),
// msg-type [2] INTEGER
new ASN1Explicit(2, ASN1Integer.getInstance()),
// padata [3] SEQUENCE OF PA-DATA OPTIONAL
new ASN1Explicit(3, new ASN1SequenceOf(ASN1Any.getInstance())),
// req-body [4] KDC-REQ-BODY
new ASN1Explicit(4, KDC_REQ_BODY), }) {
{
setOptional(2); // padata
}
@Override
protected void getValues(Object object, Object[] values) {
final KDCRequest request = (KDCRequest) object;
values[0] = BigInteger.valueOf(5).toByteArray();
values[1] = BigInteger.valueOf(request.msgType).toByteArray();
// values[2] = //FIXME
values[3] = request; // pass for further use
}
};
static final ASN1Explicit AS_REQ_ASN1 = new ASN1Explicit(
ASN1Constants.CLASS_APPLICATION, AS_REQ, KDC_REQ_ASN1);
KDCRequest(int msgType, PrincipalName cname, String realm,
PrincipalName sname) {
super();
this.msgType = msgType;
this.cname = cname;
this.realm = realm;
this.sname = sname;
}
public DatagramSocket send(InetAddress address, int port)
throws IOException {
if (msgType != AS_REQ) {
throw new RuntimeException(Messages.getString("auth.65"));
}
final byte[] enc = AS_REQ_ASN1.encode(this);
final DatagramPacket req = new DatagramPacket(enc, enc.length, address,
port);
final DatagramSocket socket = new DatagramSocket();
socket.send(req);
return socket;
}
}