long clockSkew, ReplayCache replayCache, boolean emptyAddressesAllowed, InetAddress clientAddress,
CipherTextHandler lockBox, KeyUsage authenticatorKeyUsage, boolean isValidate ) throws KerberosException
{
if ( authHeader.getProtocolVersionNumber() != KerberosConstants.KERBEROS_V5 )
{
throw new KerberosException( ErrorType.KRB_AP_ERR_BADVERSION );
}
if ( authHeader.getMessageType() != KerberosMessageType.AP_REQ )
{
throw new KerberosException( ErrorType.KRB_AP_ERR_MSG_TYPE );
}
if ( authHeader.getTicket().getTktVno() != KerberosConstants.KERBEROS_V5 )
{
throw new KerberosException( ErrorType.KRB_AP_ERR_BADVERSION );
}
EncryptionKey ticketKey = null;
if ( authHeader.getOption( ApOptions.USE_SESSION_KEY ) )
{
ticketKey = authHeader.getTicket().getEncTicketPart().getKey();
}
else
{
ticketKey = serverKey;
}
if ( ticketKey == null )
{
// TODO - check server key version number, skvno; requires store
// if ( false )
// {
// throw new KerberosException( ErrorType.KRB_AP_ERR_BADKEYVER );
// }
throw new KerberosException( ErrorType.KRB_AP_ERR_NOKEY );
}
byte[] encTicketPartData = lockBox.decrypt( ticketKey, ticket.getEncPart(),
KeyUsage.AS_OR_TGS_REP_TICKET_WITH_SRVKEY );
EncTicketPart encPart = KerberosDecoder.decodeEncTicketPart( encTicketPartData );
ticket.setEncTicketPart( encPart );
byte[] authenticatorData = lockBox.decrypt( ticket.getEncTicketPart().getKey(), authHeader.getAuthenticator(),
authenticatorKeyUsage );
Authenticator authenticator = KerberosDecoder.decodeAuthenticator( authenticatorData );
if ( !authenticator.getCName().getNameString().equals( ticket.getEncTicketPart().getCName().getNameString() ) )
{
throw new KerberosException( ErrorType.KRB_AP_ERR_BADMATCH );
}
if ( ticket.getEncTicketPart().getClientAddresses() != null )
{
if ( !ticket.getEncTicketPart().getClientAddresses().contains( new HostAddress( clientAddress ) ) )
{
throw new KerberosException( ErrorType.KRB_AP_ERR_BADADDR );
}
}
else
{
if ( !emptyAddressesAllowed )
{
throw new KerberosException( ErrorType.KRB_AP_ERR_BADADDR );
}
}
KerberosPrincipal serverPrincipal = getKerberosPrincipal( ticket.getSName(), ticket.getRealm() );
KerberosPrincipal clientPrincipal = getKerberosPrincipal( authenticator.getCName(), authenticator.getCRealm() );
KerberosTime clientTime = authenticator.getCtime();
int clientMicroSeconds = authenticator.getCusec();
if ( replayCache != null )
{
if ( replayCache.isReplay( serverPrincipal, clientPrincipal, clientTime, clientMicroSeconds ) )
{
throw new KerberosException( ErrorType.KRB_AP_ERR_REPEAT );
}
replayCache.save( serverPrincipal, clientPrincipal, clientTime, clientMicroSeconds );
}
if ( !authenticator.getCtime().isInClockSkew( clockSkew ) )
{
throw new KerberosException( ErrorType.KRB_AP_ERR_SKEW );
}
/*
* "The server computes the age of the ticket: local (server) time minus
* the starttime inside the Ticket. If the starttime is later than the
* current time by more than the allowable clock skew, or if the INVALID
* flag is set in the ticket, the KRB_AP_ERR_TKT_NYV error is returned."
*/
KerberosTime startTime = ( ticket.getEncTicketPart().getStartTime() != null ) ? ticket.getEncTicketPart()
.getStartTime() : ticket.getEncTicketPart().getAuthTime();
KerberosTime now = new KerberosTime();
boolean isValidStartTime = startTime.lessThan( now );
if ( !isValidStartTime || ( ticket.getEncTicketPart().getFlags().isInvalid() && !isValidate ) )
{
// it hasn't yet become valid
throw new KerberosException( ErrorType.KRB_AP_ERR_TKT_NYV );
}
// TODO - doesn't take into account skew
if ( !ticket.getEncTicketPart().getEndTime().greaterThan( now ) )
{
throw new KerberosException( ErrorType.KRB_AP_ERR_TKT_EXPIRED );
}
authHeader.getApOptions().set( ApOptions.MUTUAL_REQUIRED );
return authenticator;