Author: erodriguez
Date: Thu Feb 3 15:37:40 2005
New Revision: 151253
URL: http://svn.apache.org/viewcvs?view=rev&rev=151253
Log:
Additional pre-authentication support for SAM.
Added:
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/sam/TimestampChecker.java
Modified:
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/kdc/AuthenticationService.java
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/kdc/KerberosService.java
Modified:
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/kdc/AuthenticationService.java
URL:
http://svn.apache.org/viewcvs/incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/kdc/AuthenticationService.java?view=diff&r1=151252&r2=151253
==============================================================================
---
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/kdc/AuthenticationService.java
(original)
+++
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/kdc/AuthenticationService.java
Thu Feb 3 15:37:40 2005
@@ -19,16 +19,20 @@
import java.io.IOException;
+import javax.security.auth.kerberos.KerberosKey;
import javax.security.auth.kerberos.KerberosPrincipal;
import org.apache.kerberos.crypto.RandomKey;
import org.apache.kerberos.crypto.encryption.EncryptionEngine;
import org.apache.kerberos.crypto.encryption.EncryptionEngineFactory;
+import org.apache.kerberos.crypto.encryption.EncryptionType;
import org.apache.kerberos.io.decoder.EncryptedDataDecoder;
import org.apache.kerberos.io.decoder.EncryptedTimestampDecoder;
import org.apache.kerberos.io.encoder.EncAsRepPartEncoder;
import org.apache.kerberos.io.encoder.EncTicketPartEncoder;
+import org.apache.kerberos.io.encoder.PreAuthenticationDataEncoder;
import org.apache.kerberos.kdc.store.PrincipalStore;
+import org.apache.kerberos.kdc.store.PrincipalStoreEntry;
import org.apache.kerberos.messages.AuthenticationReply;
import org.apache.kerberos.messages.KdcRequest;
import org.apache.kerberos.messages.components.EncTicketPart;
@@ -44,134 +48,187 @@
import org.apache.kerberos.messages.value.PreAuthenticationDataType;
import org.apache.kerberos.messages.value.TicketFlags;
import org.apache.kerberos.messages.value.TransitedEncoding;
+import org.apache.kerberos.sam.SamException;
+import org.apache.kerberos.sam.SamSubsystem;
+import org.apache.kerberos.sam.SamType;
+import org.apache.kerberos.sam.TimestampChecker;
public class AuthenticationService extends KerberosService
{
- private KdcConfiguration config;
-
- public AuthenticationService( PrincipalStore store, PrincipalStore
bootstrap, KdcConfiguration config )
+ static
+ {
+ SamSubsystem.setIntegrityChecker( new TimestampChecker() );
+ }
+
+ public AuthenticationService( KdcConfiguration config, PrincipalStore
bootstrap, PrincipalStore store )
{
super( config, bootstrap, store );
-
- this.config = config;
}
public AuthenticationReply getReplyFor( KdcRequest request ) throws
KerberosException
{
- KerberosPrincipal clientPrincipal =
request.getClientPrincipal();
-
- EncryptionKey clientKey = getKeyForPrincipal( clientPrincipal );
-
- if ( clientKey == null )
- {
- throw KerberosException.KDC_ERR_C_PRINCIPAL_UNKNOWN;
- }
-
- KerberosPrincipal serverPrincipal =
request.getServerPrincipal();
-
- EncryptionKey serverKey = getKeyForPrincipal( serverPrincipal );
-
- if ( serverKey == null )
- {
- throw KerberosException.KDC_ERR_S_PRINCIPAL_UNKNOWN;
- }
-
- verifyPreAuthentication( request, clientKey );
+ EncryptionKey clientKey = verifyPreAuthentication( request );
+
+ Ticket ticket = generateNewTicket( request );
- Ticket ticket = getNewTicket( request, serverKey );
AuthenticationReply reply = getAuthenticationReply( request,
ticket );
- encryptReplyPart( reply, clientKey );
- System.out.print( "Issuing ticket to client " +
clientPrincipal.toString() + " " );
- System.out.println( "for access to " +
serverPrincipal.toString() );
+ encryptReplyPart( reply, clientKey );
return reply;
}
- private void verifyPreAuthentication( KdcRequest request, EncryptionKey
clientKey )
+ private EncryptionKey verifyPreAuthentication( KdcRequest request )
throws KerberosException
{
- if ( config.isPaEncTimestampRequired() )
- {
- PreAuthenticationData[] paData = request.getPreAuthData();
+ KerberosPrincipal clientPrincipal =
request.getClientPrincipal();
+
+ PrincipalStoreEntry entry = store.getEntry( clientPrincipal );
+
+ if ( entry == null )
+ {
+ throw KerberosException.KDC_ERR_C_PRINCIPAL_UNKNOWN;
+ }
+
+ EncryptionKey clientKey = null;
+
+ if ( entry.getSamType() == null )
+ {
+ clientKey = entry.getEncryptionKey();
- if ( paData == null )
- {
- throw KerberosException.KDC_ERR_PREAUTH_REQUIRED;
- }
-
- EncryptedTimeStamp timestamp = null;
-
- for ( int ii = 0; ii < paData.length; ii++ )
+ if ( config.isPaEncTimestampRequired() )
+ {
+ PreAuthenticationData[] preAuthData =
request.getPreAuthData();
+
+ if ( preAuthData == null )
+ {
+ throw KerberosException.KDC_ERR_PREAUTH_REQUIRED;
+ }
+
+ EncryptedTimeStamp timestamp = null;
+
+ for ( int ii = 0; ii < preAuthData.length; ii++ )
+ {
+ if ( preAuthData[ ii ].getDataType().equals(
PreAuthenticationDataType.PA_ENC_TIMESTAMP ) )
+ {
+ try
+ {
+ EncryptedData dataValue =
EncryptedDataDecoder.decode( preAuthData[ ii ].getDataValue() );
+
+ EncryptionEngine engine =
EncryptionEngineFactory.getEncryptionEngineFor( clientKey );
+
+ byte[] decTimestamp =
engine.getDecryptedData( clientKey, dataValue );
+
+ EncryptedTimestampDecoder
timeStampDecoder = new EncryptedTimestampDecoder();
+ timestamp =
timeStampDecoder.decode( decTimestamp );
+ }
+ catch (KerberosException ke)
+ {
+ throw
KerberosException.KRB_AP_ERR_BAD_INTEGRITY;
+ }
+ catch (IOException ioe)
+ {
+ throw
KerberosException.KRB_AP_ERR_BAD_INTEGRITY;
+ }
+ }
+ }
+
+ if ( timestamp == null )
+ {
+ throw KerberosException.KDC_ERR_PREAUTH_REQUIRED;
+ }
+
+ if ( !timestamp.getTimeStamp().isInClockSkew(
config.getClockSkew() ) )
+ {
+ throw KerberosException.KDC_ERR_PREAUTH_FAILED;
+ }
+
+ /*
+ if(decrypted_enc_timestamp and usec is replay)
+ error_out(KDC_ERR_PREAUTH_FAILED);
+ endif
+
+ add decrypted_enc_timestamp and usec to replay cache;
+ */
+ }
+ }
+ else
+ {
+ try
{
- if ( paData[ ii ].getDataType().equals(
PreAuthenticationDataType.PA_ENC_TIMESTAMP ) )
+ PreAuthenticationData[] preAuthData =
request.getPreAuthData();
+
+ if ( preAuthData == null )
{
- try
- {
- EncryptedDataDecoder decoder = new
EncryptedDataDecoder();
- EncryptedData dataValue = decoder.decode(
paData[ ii ].getDataValue() );
-
- EncryptionEngine engine =
EncryptionEngineFactory.getEncryptionEngineFor( clientKey );
-
- byte[] decTimestamp =
engine.getDecryptedData( clientKey, dataValue );
-
- EncryptedTimestampDecoder
timeStampDecoder = new EncryptedTimestampDecoder();
- timestamp = timeStampDecoder.decode(
decTimestamp );
- }
- catch (KerberosException ke)
- {
- throw
KerberosException.KRB_AP_ERR_BAD_INTEGRITY;
- }
- catch (IOException ioe)
- {
- throw
KerberosException.KRB_AP_ERR_BAD_INTEGRITY;
- }
+ throw new SamException( SamType.PA_SAM_TYPE_APACHE,
"Client principal requires SAM pre-authentication." );
}
+
+ for ( int ii = 0; ii < preAuthData.length; ii++ )
+ {
+ if ( preAuthData[ ii ].getDataType().equals(
PreAuthenticationDataType.PA_ENC_TIMESTAMP ) )
+ {
+ PreAuthenticationDataEncoder preAuthEncoder
= new PreAuthenticationDataEncoder();
+ byte[] sad = preAuthEncoder.encode(
preAuthData[ii] );
+ KerberosKey samKey = SamSubsystem.verify(
entry, sad );
+ clientKey = new EncryptionKey(
EncryptionType.getTypeByOrdinal( samKey.getKeyType() ), samKey.getEncoded() );
+ }
+ }
+ }
+ catch (IOException ioe)
+ {
+ throw KerberosException.KRB_AP_ERR_BAD_INTEGRITY;
+ }
+ catch (SamException se)
+ {
+ throw new KerberosException( 77, se.getMessage() );
}
-
- if ( timestamp == null )
- {
- throw KerberosException.KDC_ERR_PREAUTH_REQUIRED;
- }
-
- if ( !timestamp.getTimeStamp().isInClockSkew(
config.getClockSkew() ) )
- {
- throw KerberosException.KDC_ERR_PREAUTH_FAILED;
- }
-
- /*
- if(decrypted_enc_timestamp and usec is replay)
- error_out(KDC_ERR_PREAUTH_FAILED);
- endif
-
- add decrypted_enc_timestamp and usec to replay cache;
- */
}
+
+ System.out.println( "Ticket will be issued to client " +
clientPrincipal.toString() + "." );
+
+ return clientKey;
}
// TODO - client and server parameters; requires store
- private Ticket getNewTicket(KdcRequest request, EncryptionKey
serverKey) throws KerberosException
+ private Ticket generateNewTicket( KdcRequest request ) throws
KerberosException
{
+ KerberosPrincipal serverPrincipal =
request.getServerPrincipal();
+
+ EncryptionKey serverKey = getKeyForPrincipal( serverPrincipal );
+
+ if ( serverKey == null )
+ {
+ throw KerberosException.KDC_ERR_S_PRINCIPAL_UNKNOWN;
+ }
+
KerberosPrincipal ticketPrincipal =
request.getServerPrincipal();
EncTicketPartModifier newTicketBody = new
EncTicketPartModifier();
if(request.getKdcOptions().get(KdcOptions.FORWARDABLE))
+ {
newTicketBody.setFlag(TicketFlags.FORWARDABLE);
+ }
if(request.getKdcOptions().get(KdcOptions.PROXIABLE))
+ {
newTicketBody.setFlag(TicketFlags.PROXIABLE);
+ }
if(request.getKdcOptions().get(KdcOptions.ALLOW_POSTDATE))
+ {
newTicketBody.setFlag(TicketFlags.MAY_POSTDATE);
+ }
if(request.getKdcOptions().get(KdcOptions.RENEW) ||
request.getKdcOptions().get(KdcOptions.VALIDATE) ||
request.getKdcOptions().get(KdcOptions.PROXY) ||
request.getKdcOptions().get(KdcOptions.FORWARDED) ||
request.getKdcOptions().get(KdcOptions.ENC_TKT_IN_SKEY))
+ {
throw KerberosException.KDC_ERR_BADOPTION;
+ }
newTicketBody.setSessionKey(new RandomKey().getNewSessionKey());
newTicketBody.setClientPrincipal(request.getClientPrincipal());
@@ -247,6 +304,8 @@
Ticket newTicket = new Ticket(ticketPrincipal, encryptedData);
newTicket.setEncTicketPart(ticketPart);
+
+ System.out.println( "Ticket will be issued for access to " +
serverPrincipal.toString() + "." );
return newTicket;
}
Modified:
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/kdc/KerberosService.java
URL:
http://svn.apache.org/viewcvs/incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/kdc/KerberosService.java?view=diff&r1=151252&r2=151253
==============================================================================
---
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/kdc/KerberosService.java
(original)
+++
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/kdc/KerberosService.java
Thu Feb 3 15:37:40 2005
@@ -51,171 +51,210 @@
public class KerberosService
{
- private KdcConfiguration config;
- private PrincipalStore bootstrap;
- private PrincipalStore store;
+ protected KdcConfiguration config;
+ protected PrincipalStore bootstrap;
+ protected PrincipalStore store;
private ReplayCache replayCache = new InMemoryReplayCache();
private Map checksumEngines = new HashMap();
- public KerberosService(KdcConfiguration config, PrincipalStore bootstrap,
PrincipalStore store)
+ public KerberosService( KdcConfiguration config, PrincipalStore bootstrap,
PrincipalStore store )
{
this.config = config;
this.bootstrap = bootstrap;
this.store = store;
- checksumEngines.put(ChecksumType.CRC32, new Crc32Checksum());
- checksumEngines.put(ChecksumType.RSA_MD4, new RsaMd4Checksum());
- checksumEngines.put(ChecksumType.RSA_MD5, new RsaMd5Checksum());
- checksumEngines.put(ChecksumType.SHA1, new Sha1Checksum());
+ checksumEngines.put( ChecksumType.CRC32, new Crc32Checksum() );
+ checksumEngines.put( ChecksumType.RSA_MD4, new RsaMd4Checksum() );
+ checksumEngines.put( ChecksumType.RSA_MD5, new RsaMd5Checksum() );
+ checksumEngines.put( ChecksumType.SHA1, new Sha1Checksum() );
}
- public EncryptionKey getKeyForPrincipal(KerberosPrincipal principal)
+ public EncryptionKey getKeyForPrincipal( KerberosPrincipal principal )
{
EncryptionKey key = null;
- try {
- PrincipalStoreEntry entry =
bootstrap.getEntry(principal);
- if (entry != null) {
+ try
+ {
+ PrincipalStoreEntry entry = bootstrap.getEntry(
principal );
+ if ( entry != null )
+ {
key = entry.getEncryptionKey();
- } else {
- key =
store.getEntry(principal).getEncryptionKey();
}
- } catch (Exception e) {
+ else
+ {
+ key = store.getEntry( principal
).getEncryptionKey();
+ }
+ }
+ catch (Exception e)
+ {
e.printStackTrace();
}
return key;
}
- protected EncryptionType getBestEncryptionType(EncryptionType[]
requestedTypes)
+ protected EncryptionType getBestEncryptionType( EncryptionType[]
requestedTypes )
throws KerberosException
{
EncryptionType[] encryptionTypes = config.getEncryptionTypes();
- for (int i = 0; i < requestedTypes.length; i++) {
- for (int j = 0; j < encryptionTypes.length; j++) {
- if (requestedTypes[i] == encryptionTypes[j])
- return encryptionTypes[j];
+ for ( int ii = 0; ii < requestedTypes.length; ii++ )
+ {
+ for ( int jj = 0; jj < encryptionTypes.length; jj++ )
+ {
+ if ( requestedTypes[ii] == encryptionTypes[jj] )
+ {
+ return encryptionTypes[jj];
+ }
}
}
+
throw KerberosException.KDC_ERR_ETYPE_NOSUPP;
}
- protected void verifyTicket(Ticket ticket, KerberosPrincipal
serverPrincipal)
- throws KerberosException {
-
- if (!ticket.getRealm().equals(config.getPrimaryRealm())
- &&
!ticket.getServerPrincipal().equals(serverPrincipal))
+ protected void verifyTicket( Ticket ticket, KerberosPrincipal
serverPrincipal )
+ throws KerberosException
+ {
+ if ( !ticket.getRealm().equals( config.getPrimaryRealm() )
+ && !ticket.getServerPrincipal().equals(
serverPrincipal ) )
+ {
throw KerberosException.KRB_AP_ERR_NOT_US;
+ }
}
// RFC 1510 A.10. KRB_AP_REQ verification
- protected Authenticator verifyAuthHeader(ApplicationRequest authHeader,
Ticket ticket)
- throws KerberosException, IOException {
-
- if (authHeader.getProtocolVersionNumber() != 5)
+ protected Authenticator verifyAuthHeader( ApplicationRequest
authHeader, Ticket ticket )
+ throws KerberosException, IOException
+ {
+ if ( authHeader.getProtocolVersionNumber() != 5 )
+ {
throw KerberosException.KRB_AP_ERR_BADVERSION;
- if (authHeader.getMessageType() != MessageType.KRB_AP_REQ)
+ }
+
+ if ( authHeader.getMessageType() != MessageType.KRB_AP_REQ )
+ {
throw KerberosException.KRB_AP_ERR_MSG_TYPE;
- if (authHeader.getTicket().getTicketVersionNumber() != 5)
+ }
+
+ if ( authHeader.getTicket().getTicketVersionNumber() != 5 )
+ {
throw KerberosException.KRB_AP_ERR_BADVERSION;
+ }
KerberosPrincipal serverPrincipal = ticket.getServerPrincipal();
EncryptionKey serverKey = null;
- if (authHeader.getOption(ApOptions.USE_SESSION_KEY))
+ if ( authHeader.getOption( ApOptions.USE_SESSION_KEY ) )
{
serverKey = authHeader.getTicket().getSessionKey();
}
else
{
- serverKey = getKeyForPrincipal(serverPrincipal);
+ serverKey = getKeyForPrincipal( serverPrincipal );
}
- if (serverKey == null)
+ if ( serverKey == null )
{
// TODO - check server key version number, skvno;
requires store
- if (false)
+ if ( false )
+ {
throw KerberosException.KRB_AP_ERR_BADKEYVER;
+ }
throw KerberosException.KRB_AP_ERR_NOKEY;
}
- try {
+ try
+ {
EncryptionEngine engine =
EncryptionEngineFactory.getEncryptionEngineFor( serverKey );
- byte[] decTicketPart =
engine.getDecryptedData(serverKey, ticket.getEncPart());
+ byte[] decTicketPart = engine.getDecryptedData(
serverKey, ticket.getEncPart() );
EncTicketPartDecoder ticketPartDecoder = new
EncTicketPartDecoder();
- EncTicketPart encPart =
ticketPartDecoder.decode(decTicketPart);
- ticket.setEncTicketPart(encPart);
- } catch (KerberosException ke) {
+ EncTicketPart encPart = ticketPartDecoder.decode(
decTicketPart );
+ ticket.setEncTicketPart( encPart );
+ }
+ catch (KerberosException ke)
+ {
throw KerberosException.KRB_AP_ERR_BAD_INTEGRITY;
}
Authenticator authenticator;
- try {
+ try
+ {
EncryptionEngine engine =
EncryptionEngineFactory.getEncryptionEngineFor( ticket.getSessionKey() );
- byte[] decAuthenticator =
engine.getDecryptedData(ticket.getSessionKey(), authHeader.getEncPart());
+ byte[] decAuthenticator = engine.getDecryptedData(
ticket.getSessionKey(), authHeader.getEncPart() );
AuthenticatorDecoder authDecoder = new
AuthenticatorDecoder();
- authenticator = authDecoder.decode(decAuthenticator);
- } catch (KerberosException ke) {
+ authenticator = authDecoder.decode( decAuthenticator );
+ }
+ catch (KerberosException ke)
+ {
throw KerberosException.KRB_AP_ERR_BAD_INTEGRITY;
}
- if
(!authenticator.getClientPrincipal().getName().equals(ticket.getClientPrincipal().getName()))
{
+ if ( !authenticator.getClientPrincipal().getName().equals(
ticket.getClientPrincipal().getName() ) )
+ {
throw KerberosException.KRB_AP_ERR_BADMATCH;
}
// TODO - need to get at IP Address for sender
- if (ticket.getClientAddresses() != null) {
+ if ( ticket.getClientAddresses() != null )
+ {
// if (sender_address(packet) is not in
decr_ticket.caddr)
// then error_out(KRB_AP_ERR_BADADDR);
}
- else {
+ else
+ {
// if (application requires addresses) then
// error_out(KRB_AP_ERR_BADADDR);
}
- if(replayCache.isReplay(authenticator.getClientTime(),
authenticator.getClientPrincipal())) {
+ if( replayCache.isReplay( authenticator.getClientTime(),
authenticator.getClientPrincipal() ) )
+ {
throw KerberosException.KRB_AP_ERR_REPEAT;
}
- replayCache.save(authenticator.getClientTime(),
authenticator.getClientPrincipal());
+ replayCache.save( authenticator.getClientTime(),
authenticator.getClientPrincipal() );
- if
(!authenticator.getClientTime().isInClockSkew(config.getClockSkew()))
+ if ( !authenticator.getClientTime().isInClockSkew(
config.getClockSkew() ) )
+ {
throw KerberosException.KRB_AP_ERR_SKEW;
+ }
- if (ticket.getStartTime() != null &&
!ticket.getStartTime().isInClockSkew(config.getClockSkew()) ||
- ticket.getFlag(TicketFlags.INVALID))
- // it hasn't yet become valid
- throw KerberosException.KRB_AP_ERR_TKT_NYV;
+ if ( ticket.getStartTime() != null &&
!ticket.getStartTime().isInClockSkew( config.getClockSkew() ) ||
+ ticket.getFlag( TicketFlags.INVALID ) )
+ {
+ // it hasn't yet become valid
+ throw KerberosException.KRB_AP_ERR_TKT_NYV;
+ }
// TODO - doesn't take into account skew
- if (!ticket.getEndTime().greaterThan(new KerberosTime()))
+ if ( !ticket.getEndTime().greaterThan( new KerberosTime() ) )
+ {
throw KerberosException.KRB_AP_ERR_TKT_EXPIRED;
+ }
- authHeader.setOption(ApOptions.MUTUAL_REQUIRED);
+ authHeader.setOption( ApOptions.MUTUAL_REQUIRED );
return authenticator;
}
-
- protected void echoTicket(EncTicketPartModifier newTicketBody, Ticket tgt)
+
+ protected void echoTicket( EncTicketPartModifier newTicketBody, Ticket tgt
)
{
- newTicketBody.setAuthorizationData(tgt.getAuthorizationData());
- newTicketBody.setAuthTime(tgt.getAuthTime());
- newTicketBody.setClientAddresses(tgt.getClientAddresses());
- newTicketBody.setClientPrincipal(tgt.getClientPrincipal());
- newTicketBody.setEndTime(tgt.getEndTime());
- newTicketBody.setFlags(tgt.getFlags());
- newTicketBody.setRenewTill(tgt.getRenewTill());
- newTicketBody.setSessionKey(tgt.getSessionKey());
- newTicketBody.setTransitedEncoding(tgt.getTransitedEncoding());
+ newTicketBody.setAuthorizationData( tgt.getAuthorizationData() );
+ newTicketBody.setAuthTime( tgt.getAuthTime() );
+ newTicketBody.setClientAddresses( tgt.getClientAddresses() );
+ newTicketBody.setClientPrincipal( tgt.getClientPrincipal() );
+ newTicketBody.setEndTime( tgt.getEndTime() );
+ newTicketBody.setFlags( tgt.getFlags() );
+ newTicketBody.setRenewTill( tgt.getRenewTill() );
+ newTicketBody.setSessionKey( tgt.getSessionKey() );
+ newTicketBody.setTransitedEncoding( tgt.getTransitedEncoding() );
}
}
Added:
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/sam/TimestampChecker.java
URL:
http://svn.apache.org/viewcvs/incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/sam/TimestampChecker.java?view=auto&rev=151253
==============================================================================
---
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/sam/TimestampChecker.java
(added)
+++
incubator/directory/kerberos/trunk/core/src/java/org/apache/kerberos/sam/TimestampChecker.java
Thu Feb 3 15:37:40 2005
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2005 The Apache Software Foundation
+ *
+ * Licensed 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.kerberos.sam;
+
+import java.io.IOException;
+
+import javax.security.auth.kerberos.KerberosKey;
+
+import org.apache.kerberos.crypto.encryption.EncryptionEngine;
+import org.apache.kerberos.crypto.encryption.EncryptionEngineFactory;
+import org.apache.kerberos.crypto.encryption.EncryptionType;
+import org.apache.kerberos.io.decoder.EncryptedDataDecoder;
+import org.apache.kerberos.io.decoder.EncryptedTimestampDecoder;
+import org.apache.kerberos.io.decoder.PreAuthenticationDataDecoder;
+import org.apache.kerberos.kdc.KerberosException;
+import org.apache.kerberos.messages.value.EncryptedData;
+import org.apache.kerberos.messages.value.EncryptedTimeStamp;
+import org.apache.kerberos.messages.value.EncryptionKey;
+import org.apache.kerberos.messages.value.KerberosTime;
+import org.apache.kerberos.messages.value.PreAuthenticationData;
+import org.apache.kerberos.messages.value.PreAuthenticationDataType;
+import org.apache.kerberos.sam.KeyIntegrityChecker;
+
+
+public class TimestampChecker implements KeyIntegrityChecker
+{
+ private static final long FIVE_MINUTES = 300000;
+
+ public boolean checkKeyIntegrity( byte[] preauthData, KerberosKey
kerberosKey )
+ {
+ EncryptionType keyType = EncryptionType.getTypeByOrdinal(
kerberosKey.getKeyType() );
+ EncryptionKey key = new EncryptionKey( keyType,
kerberosKey.getEncoded() );
+
+ try
+ {
+ // Decode the pre-authentication data from ASN.1
+ PreAuthenticationDataDecoder preAuthDecoder = new
PreAuthenticationDataDecoder();
+ PreAuthenticationData sad = preAuthDecoder.decode( preauthData
);
+
+ // If this pre-auth is not an encrypted timestamp, we aren't
interested
+ if ( sad.getDataType() !=
PreAuthenticationDataType.PA_ENC_TIMESTAMP )
+ {
+ return false;
+ }
+
+ // Since the pre-auth value is of type PA-ENC-TIMESTAMP, it
should be a valid
+ // ASN.1 PA-ENC-TS-ENC structure, so we can decode it into
EncryptedData.
+ EncryptedData sadValue = EncryptedDataDecoder.decode(
sad.getDataValue() );
+
+ // Decrypt the EncryptedData structure to get the PA-ENC-TS-ENC
+ EncryptionEngine engine =
EncryptionEngineFactory.getEncryptionEngineFor( key );
+ byte[] decryptedTimestamp = engine.getDecryptedData( key, sadValue
);
+
+ // Decode the decrypted timestamp into our timestamp object.
+ EncryptedTimestampDecoder decoder = new
EncryptedTimestampDecoder();
+ EncryptedTimeStamp timestamp = decoder.decode( decryptedTimestamp
);
+
+ // Since we got here we must have a valid timestamp structure that
we can
+ // validate to be within a five minute skew.
+ KerberosTime time = timestamp.getTimeStamp();
+
+ if ( time.isInClockSkew( FIVE_MINUTES ) )
+ {
+ return true;
+ }
+ }
+ catch (IOException ioe)
+ {
+ return false;
+ }
+ catch (KerberosException ke)
+ {
+ return false;
+ }
+ catch (ClassCastException cce)
+ {
+ return false;
+ }
+
+ return false;
+ }
+}
+