/*
* Copyright (C) 2006-2008 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
package org.alfresco.jlan.server.auth.kerberos;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import org.alfresco.jlan.server.auth.asn.DERApplicationSpecific;
import org.alfresco.jlan.server.auth.asn.DERBitString;
import org.alfresco.jlan.server.auth.asn.DERBuffer;
import org.alfresco.jlan.server.auth.asn.DERInteger;
import org.alfresco.jlan.server.auth.asn.DERObject;
import org.alfresco.jlan.server.auth.asn.DEROctetString;
import org.alfresco.jlan.server.auth.asn.DERSequence;
/**
* Kerberos AP-REQ Class
*
* @author gkspencer
*/
public class KerberosApReq {
// Constants
public static final int APOptionUseSessionKey = 1;
public static final int APOptionMutualAuthReq = 2;
// Bit masks for AP options
private static final int APOptionUseSessionKeyMask = 0x40000000;
private static final int APOptionsMutualAuthReqMask = 0x20000000;
// AP-REQ fields
private int m_APOptions;
private byte[] m_ticket;
// Authenticator encrypted data
private int m_authEncType;
private byte[] m_authEncData;
private int m_authEncKvno = -1;
/**
* Default constructor
*/
public KerberosApReq()
{
}
/**
* Class constructor
*
* @param byte[] blob
* @exception IOException
*/
public KerberosApReq(byte[] blob)
throws IOException
{
parseApReq( blob);
}
/**
* Return the APOptions
*
* @return int
*/
public final int getAPOptions()
{
return m_APOptions;
}
/**
* Check if the use session key option is enabled
*
* @return boolean
*/
public final boolean useSessionKey()
{
return (m_APOptions & APOptionUseSessionKeyMask) != 0 ? true : false;
}
/**
* Check if the mutual authentication required option is enabled
*
* @return boolean
*/
public final boolean hasMutualAuthentication()
{
return (m_APOptions & APOptionsMutualAuthReqMask) != 0 ? true : false;
}
/**
* Return the ticket
*
* @return byte[]
*/
public final byte[] getTicket()
{
return m_ticket;
}
/**
* Return the authenticator encryption type
*
* @return int
*/
public final int getAuthenticatorEncType()
{
return m_authEncType;
}
/**
* Return the authenticator encrypted data block
*
* @return byte[]
*/
public final byte[] getAuthenticator()
{
return m_authEncData;
}
/**
* Return the authenticator key version number
*
* @return int
*/
public final int getAuthenticatorKeyVersion()
{
return m_authEncKvno;
}
/**
* Parse an AP-REQ blob
*
* @param byte[] blob
* @exception IOException
*/
private final void parseApReq( byte[] blob)
throws IOException
{
// Create a stream to parse the ASN.1 encoded AP-REQ blob
DERBuffer derBuf = new DERBuffer( blob);
DERObject derObj = derBuf.unpackObject();
if ( derObj instanceof DERSequence)
{
// Enumerate the AP-REQ objects
DERSequence derSeq = (DERSequence) derObj;
Iterator<DERObject> iterObj = derSeq.getObjects();
while ( iterObj.hasNext())
{
// Read an object
derObj = (DERObject) iterObj.next();
if ( derObj != null && derObj.isTagged())
{
switch ( derObj.getTagNo())
{
// PVno
case 0:
if ( derObj instanceof DERInteger)
{
DERInteger derInt = (DERInteger) derObj;
if ( derInt.getValue() != 5)
throw new IOException("Unexpected PVNO value in AP-REQ");
}
break;
// Message type
case 1:
if ( derObj instanceof DERInteger)
{
DERInteger derInt = (DERInteger) derObj;
if ( derInt.getValue() != 14)
throw new IOException("Unexpected msg-type value in AP-REQ");
}
break;
// AP-Options
case 2:
if ( derObj instanceof DERBitString)
{
DERBitString derBit = (DERBitString) derObj;
m_APOptions = derBit.intValue();
}
break;
// Ticket
case 3:
if ( derObj instanceof DERApplicationSpecific)
{
DERApplicationSpecific derApp = (DERApplicationSpecific) derObj;
m_ticket = derApp.getValue();
}
break;
// Authenticator
case 4:
if ( derObj instanceof DERSequence)
{
DERSequence derAuthSeq = (DERSequence) derObj;
// Enumerate the sequence
Iterator<DERObject> iterSeq = derAuthSeq.getObjects();
while ( iterSeq.hasNext())
{
// Get the current sequence element
derObj = (DERObject) iterSeq.next();
if ( derObj != null && derObj.isTagged())
{
switch ( derObj.getTagNo())
{
// Encryption type
case 0:
if ( derObj instanceof DERInteger)
{
DERInteger derInt = (DERInteger) derObj;
m_authEncType = derInt.intValue();
}
break;
// Kvno
case 1:
if ( derObj instanceof DERInteger)
{
DERInteger derInt = (DERInteger) derObj;
m_authEncKvno = derInt.intValue();
}
break;
// Cipher
case 2:
if ( derObj instanceof DEROctetString)
{
DEROctetString derOct = (DEROctetString) derObj;
m_authEncData = derOct.getValue();
}
break;
}
}
}
}
break;
}
}
}
}
}
/**
* Parse a mech token to get the AP-REQ
*
* @param byte[] mechToken
* @exception IOException
*/
public final void parseMechToken( byte[] mechToken)
throws IOException
{
// Create a stream to parse the ASN.1 encoded mech token
DERBuffer derBuf = new DERBuffer( mechToken);
byte[] apreqBlob = null;
// Get the application specific object
byte[] appByts = derBuf.unpackApplicationSpecificBytes();
if ( appByts != null) {
// Read the OID and token id
derBuf = new DERBuffer( appByts);
DERObject derObj = derBuf.unpackObject();
derBuf.unpackByte();
derBuf.unpackByte();
// Read the AP-REQ object
apreqBlob = derBuf.unpackApplicationSpecificBytes();
}
// Parse the AP-REQ, if found
if ( apreqBlob != null)
parseApReq( apreqBlob);
else
throw new IOException("AP-REQ blob not found in mechToken");
}
/**
* Return the AP-REQ as a string
*
* @return String
*/
public String toString()
{
StringBuilder str = new StringBuilder();
str.append("[AP-REQ:APOptions=");
str.append( hasMutualAuthentication() ? "MutualAuth " : "");
str.append( useSessionKey() ? "UseSessKey" : "");
str.append(",Ticket=Len=");
str.append(m_ticket != null ? m_ticket.length : 0);
str.append(",Authenticator=EncType=");
str.append(m_authEncType);
str.append(",Kvno=");
str.append(getAuthenticatorKeyVersion());
str.append(",Len=");
str.append(m_authEncData != null ? m_authEncData.length : 0);
str.append("]");
return str.toString();
}
}