blob: 5480650b70875507f1a6f9c5368fe7025357926d [file] [log] [blame]
/*
* 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.directory.server.kerberos.shared.messages.components;
import java.nio.BufferOverflowException;
import java.nio.ByteBuffer;
import java.text.ParseException;
import javax.security.auth.kerberos.KerberosPrincipal;
import org.apache.directory.server.kerberos.shared.KerberosUtils;
import org.apache.directory.server.kerberos.shared.messages.Encodable;
import org.apache.directory.server.kerberos.shared.messages.value.AuthorizationData;
import org.apache.directory.server.kerberos.shared.messages.value.Checksum;
import org.apache.directory.server.kerberos.shared.messages.value.EncryptionKey;
import org.apache.directory.server.kerberos.shared.messages.value.KerberosTime;
import org.apache.directory.server.kerberos.shared.messages.value.PrincipalName;
import org.apache.directory.shared.asn1.AbstractAsn1Object;
import org.apache.directory.shared.asn1.ber.tlv.TLV;
import org.apache.directory.shared.asn1.ber.tlv.UniversalTag;
import org.apache.directory.shared.asn1.ber.tlv.Value;
import org.apache.directory.shared.asn1.codec.EncoderException;
import org.apache.directory.shared.ldap.util.StringTools;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The Authenticator class
*
* The ASN.1 grammar is the following :
*
* -- Unencrypted authenticator
* Authenticator ::= [APPLICATION 2] SEQUENCE {
* authenticator-vno [0] INTEGER (5),
* crealm [1] Realm,
* cname [2] PrincipalName,
* cksum [3] Checksum OPTIONAL,
* cusec [4] Microseconds,
* ctime [5] KerberosTime,
* subkey [6] EncryptionKey OPTIONAL,
* seq-number [7] UInt32 OPTIONAL,
* authorization-data [8] AuthorizationData OPTIONAL
* }
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$, $Date$
*/
public class Authenticator extends AbstractAsn1Object implements Encodable
{
/** The logger */
private static final Logger log = LoggerFactory.getLogger( Authenticator.class );
/** Speedup for logs */
private static final boolean IS_DEBUG = log.isDebugEnabled();
/**
* Constant for the authenticator version number.
*/
public static final int AUTHENTICATOR_VNO = 5;
/** the version number for the format of the authenticator */
private int authenticatorVno;
/** The client PrincipalName */
private PrincipalName cName;
/** The client KerberosPrincipal */
private KerberosPrincipal clientPrincipal;
/** The client realm */
private String cRealm;
/** The client realm as a byte array */
private byte[] cRealmBytes;
/** checksum of the the application data */
private Checksum cksum;
/** the microsecond part of the client's timestamp */
private int cusec;
/** the current time on the client's host */
private KerberosTime cTime;
/** the client's choice for an encryption key */
private EncryptionKey subKey;
/** the initial sequence number to be used by the KRB_PRIV or KRB_SAFE messages */
private int seqNumber;
/** Authorization data */
private AuthorizationData authorizationData;
// Storage for computed lengths
private transient int authenticatorAppLength;
private transient int authenticatorSeqLength;
private transient int authenticatorVnoTagLength;
private transient int cRealmTagLength;
private transient int cNameTagLength;
private transient int cksumTagLength;
private transient int cusecTagLength;
private transient int cTimeTagLength;
private transient int cTimeLength;
private transient int subKeyTagLength;
private transient int seqNumberTagLength;
private transient int authorizationDataTagLength;
/**
* Creates a new instance of Authenticator.
*/
public Authenticator()
{
cksum = null; // optional
subKey = null; // optional
authorizationData = null; // optional
seqNumber = KerberosUtils.NULL; // optional
}
/**
* Returns the client {@link PrincipalName}.
*
* @return The client {@link PrincipalName}.
*/
public PrincipalName getClientPrincipalName()
{
return cName;
}
/**
* Returns the client {@link KerberosPrincipal}.
*
* @return The client {@link KerberosPrincipal}.
*/
public KerberosPrincipal getClientPrincipal()
{
return clientPrincipal;
}
/**
* Sets the client {@link PrincipalName}.
*
* @param clientPrincipal
*/
public void setClientPrincipalName( PrincipalName cName )
{
this.cName = cName;
}
/**
* Sets the client {@link KerberosPrincipal}.
*
* @param clientPrincipal
*/
public void setClientPrincipal( KerberosPrincipal clientPrincipal )
{
this.clientPrincipal = clientPrincipal;
try
{
this.cName = new PrincipalName( clientPrincipal.getName(), clientPrincipal.getNameType() );
}
catch ( ParseException pe )
{
this.cName = null;
}
}
/**
* Returns the client {@link KerberosTime}.
*
* @return The client {@link KerberosTime}.
*/
public KerberosTime getClientTime()
{
return cTime;
}
/**
* Sets the client {@link KerberosTime}.
*
* @param time the client {@link KerberosTime}.
*/
public void setClientTime( KerberosTime cTime )
{
this.cTime = cTime;
}
/**
* Returns the client microsecond.
*
* @return The client microsecond.
*/
public int getClientMicroSecond()
{
return cusec;
}
/**
* Sets the client microsecond.
*
* @param microSecond the client microsecond.
*/
public void setClientMicroSecond( int cusec )
{
this.cusec = cusec;
}
/**
* Returns the {@link AuthorizationData}.
*
* @return The {@link AuthorizationData}.
*/
public AuthorizationData getAuthorizationData()
{
return authorizationData;
}
/**
* Sets the {@link AuthorizationData}.
*
* @param data the {@link AuthorizationData}.
*/
public void setAuthorizationData( AuthorizationData authorizationData )
{
this.authorizationData = authorizationData;
}
/**
* Returns the {@link Checksum}.
*
* @return The {@link Checksum}.
*/
public Checksum getChecksum()
{
return cksum;
}
/**
* Sets the {@link Checksum}.
*
* @param checksum the {@link Checksum}.
*/
public void setChecksum( Checksum cksum )
{
this.cksum = cksum;
}
/**
* Returns the sequence number.
*
* @return The sequence number.
*/
public int getSequenceNumber()
{
return seqNumber;
}
/**
* Sets the sequence number.
*
* @param seqNumber the sequence number
*/
public void setSequenceNumber( int seqNumber )
{
this.seqNumber = seqNumber;
}
/**
* Returns the sub-session key.
*
* @return The sub-session key.
*/
public EncryptionKey getSubSessionKey()
{
return subKey;
}
/**
* Sets the sub-session {@link EncryptionKey}.
*
* @param subKey the sub-session
*/
public void setSubSessionKey( EncryptionKey subKey )
{
this.subKey = subKey;
}
/**
* Returns the version number of the {@link Authenticator}.
*
* @return The version number of the {@link Authenticator}.
*/
public int getVersionNumber()
{
return authenticatorVno;
}
/**
* Sets the version number.
*
* @param versionNumber The version number
*/
public void setVersionNumber( int authenticatorVno )
{
this.authenticatorVno = authenticatorVno;
}
/**
* @return The client realm
*/
public String getClientRealm()
{
return cRealm;
}
/**
* Sets the client realm.
*
* @param realm the client realm.
*/
public void setClientRealm( String cRealm )
{
this.cRealm = cRealm;
}
/**
* Compute the Authenticator length
*
* Authenticator :
*
* 0x62 L1 Authenticator Tag (Application 2)
* |
* +--> 0x30 L2 Authenticator sequence
* |
* +--> 0xA0 L2 authenticator-vno tag
* | |
* | +--> 0x02 L2-1 authenticator-vno (int)
* |
* +--> 0xA1 L3 crealm tag
* | |
* | +--> 0x1B L3-1 crealm (crealm)
* |
* +--> 0xA2 L4 cname tag
* | |
* | +--> 0x30 L4-1 cname (PrincipalName)
* |
* +--> [0xA3 L5 cksum tag
* | |
* | +--> 0x30 L5-1 cksum (Checksum)] (optional)
* |
* +--> 0xA4 L6 cusec tag
* | |
* | +--> 0x02 L6-1 cusec (int)
* |
* +--> 0xA5 0x11 ctime tag
* | |
* | +--> 0x18 0x0F ctime (KerberosTime)
* |
* +--> [0xA6 L7 subkey tag
* | |
* | +--> 0x30 L7-1 subkey (EncryptionKey)] (optional)
* |
* +--> [0xA7 L8 seqNumber tag
* | |
* | +--> 0x02 L8-1 seqNulber (int > 0)] (optional)
* |
* +--> [0xA8 L9 authorization-data tag
* |
* +--> 0x30 L9-1 authorization-data (AuthorizationData)] (optional)
*/
public int computeLength()
{
authenticatorAppLength = 0;
authenticatorSeqLength = 0;
// Compute the authenticator-vno length
int authenticatorVnoLength = Value.getNbBytes( authenticatorVno );
authenticatorVnoTagLength = 1 + TLV.getNbBytes( authenticatorVnoLength ) + authenticatorVnoLength;
authenticatorSeqLength += 1 + TLV.getNbBytes( authenticatorVnoTagLength ) + authenticatorVnoTagLength;
// Compute the client Realm length
cRealmBytes = StringTools.getBytesUtf8( cRealm );
cRealmTagLength = 1 + TLV.getNbBytes( cRealmBytes.length ) + cRealmBytes.length;
authenticatorSeqLength += 1 + TLV.getNbBytes( cRealmTagLength ) + cRealmTagLength;
// Compute the clientPrincipalName length
cNameTagLength = cName.computeLength();
authenticatorSeqLength += 1 + TLV.getNbBytes( cNameTagLength ) + cNameTagLength;
// Compute the cksum length, if any
if ( cksum != null )
{
cksumTagLength = cksum.computeLength();
authenticatorSeqLength += 1 + TLV.getNbBytes( cksumTagLength ) + cksumTagLength;
}
// Compute the cusec length
int cusecLength = Value.getNbBytes( cusec );
cusecTagLength = 1 + TLV.getNbBytes( cusecLength ) + cusecLength;
authenticatorSeqLength += 1 + TLV.getNbBytes( cusecTagLength ) + cusecTagLength;
// Compute the clientTime length
cTimeLength = 15;
cTimeTagLength = 1 + 1 + cTimeLength;
authenticatorSeqLength +=
1 + TLV.getNbBytes( cTimeTagLength ) + cTimeTagLength;
// Compute the subkey length, if any
if ( subKey != null )
{
subKeyTagLength = subKey.computeLength();
authenticatorSeqLength += 1 + TLV.getNbBytes( subKeyTagLength ) + subKeyTagLength;
}
// Compute the seqNumber length
int seqNumberLength = Value.getNbBytes( seqNumber );
seqNumberTagLength = 1 + TLV.getNbBytes( seqNumberLength ) + seqNumberLength;
authenticatorSeqLength += 1 + TLV.getNbBytes( seqNumberTagLength ) + seqNumberTagLength;
// Compute the authorization-data length, if any
if ( authorizationData != null )
{
authorizationDataTagLength = authorizationData.computeLength();
authenticatorSeqLength += 1 + TLV.getNbBytes( authorizationDataTagLength ) + authorizationDataTagLength;
}
// Compute the whole sequence length
authenticatorAppLength = 1 + TLV.getNbBytes( authenticatorSeqLength ) + authenticatorSeqLength;
// Compute the whole application length
return 1 + TLV.getNbBytes( authenticatorAppLength ) + authenticatorAppLength;
}
/**
* Encode the Authenticator message to a PDU.
*
* Authenticator :
*
* 0x62 LL
* 0x30 LL
* 0xA0 LL
* 0x03 LL authenticator-vno (int)
* 0xA1 LL
* 0x1B LL crealm (KerberosString)
* 0xA2 LL
* 0x30 LL cname (PrincipalName)
* [0xA3 LL
* 0x30 LL cksum (Checksum) (optional)]
* 0xA4 LL
* 0x02 LL cusec (int)
* 0xA5 0x11
* 0x18 0x0F ctime (KerberosTime)
* [0xA6 LL
* 0x30 LL subkey (EncryptionKey) (optional)]
* [0xA7 LL
* 0x02 LL seqNulber (int) (optional)]
* [0xA8 LL
* 0x30 LL authorization-data (AuthorizationData) (optional)]
*
* @param buffer The buffer where to put the PDU. It should have been allocated
* before, with the right size.
* @return The constructed PDU.
*/
public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException
{
if ( buffer == null )
{
buffer = ByteBuffer.allocate( computeLength() );
}
try
{
// The authenticator APP Tag
buffer.put( (byte)0x62 );
buffer.put( TLV.getBytes( authenticatorAppLength ) );
// The authenticator SEQ Tag
buffer.put( UniversalTag.SEQUENCE_TAG );
buffer.put( TLV.getBytes( authenticatorSeqLength ) );
// The authenticator-vno encoding, first the tag, then the value
buffer.put( ( byte ) 0xA0 );
buffer.put( TLV.getBytes( authenticatorVnoTagLength ) );
Value.encode( buffer, authenticatorVno );
// The client realm encoding
buffer.put( (byte)0xA1 );
buffer.put( TLV.getBytes( cRealmTagLength ) );
buffer.put( UniversalTag.GENERALIZED_STRING_TAG );
buffer.put( TLV.getBytes( cRealmBytes.length ) );
buffer.put( cRealmBytes );
// The clientprincipalName encoding
buffer.put( (byte)0xA2 );
buffer.put( TLV.getBytes( cNameTagLength ) );
cName.encode( buffer );
// The cksum encoding, if any
if ( cksum != null )
{
buffer.put( (byte)0xA3 );
buffer.put( TLV.getBytes( cksumTagLength ) );
cksum.encode( buffer );
}
// Client millisecond encoding
buffer.put( ( byte )0xA4 );
buffer.put( TLV.getBytes( cusecTagLength ) );
Value.encode( buffer, cusec );
// The clientTime Tag and value
buffer.put( ( byte )0xA5 );
buffer.put( TLV.getBytes( cTimeTagLength ) );
buffer.put( UniversalTag.GENERALIZED_TIME_TAG );
buffer.put( TLV.getBytes( cTimeLength ) );
buffer.put( StringTools.getBytesUtf8( cTime.toString() ) );
// The subkey encoding, if any
if ( subKey != null )
{
buffer.put( (byte)0xA6 );
buffer.put( TLV.getBytes( subKeyTagLength ) );
subKey.encode( buffer );
}
// The seqNumber encoding, if any
if ( seqNumber != KerberosUtils.NULL )
{
buffer.put( ( byte )0xA7 );
buffer.put( TLV.getBytes( seqNumberTagLength ) );
Value.encode( buffer, seqNumber );
}
// The authorization-data encoding, if any
if ( authorizationData != null )
{
buffer.put( (byte)0xA8 );
buffer.put( TLV.getBytes( authorizationDataTagLength ) );
authorizationData.encode( buffer );
}
}
catch ( BufferOverflowException boe )
{
log.error(
"Cannot encode the Authenticator object, the PDU size is {} when only {} bytes has been allocated", 1
+ TLV.getNbBytes( authenticatorAppLength ) + authenticatorAppLength, buffer.capacity() );
throw new EncoderException( "The PDU buffer size is too small !" );
}
if ( IS_DEBUG )
{
log.debug( "Authenticator encoding : {}", StringTools.dumpBytes( buffer.array() ) );
log.debug( "Authenticator initial value : {}", toString() );
}
return buffer;
}
/**
* @see Object#toString()
*/
public String toString()
{
return "NYI";
}
}