Author: elecharny Date: Mon Mar 11 18:34:59 2013 New Revision: 1455280 URL: http://svn.apache.org/r1455280 Log: Fixed the way we select the Encryptiontype : we are now selecting the strongest algorithm Modified: directory/apacheds/trunk/kerberos-codec/src/main/java/org/apache/directory/shared/kerberos/KerberosUtils.java Modified: directory/apacheds/trunk/kerberos-codec/src/main/java/org/apache/directory/shared/kerberos/KerberosUtils.java URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/kerberos-codec/src/main/java/org/apache/directory/shared/kerberos/KerberosUtils.java?rev=1455280&r1=1455279&r2=1455280&view=diff ============================================================================== --- directory/apacheds/trunk/kerberos-codec/src/main/java/org/apache/directory/shared/kerberos/KerberosUtils.java (original) +++ directory/apacheds/trunk/kerberos-codec/src/main/java/org/apache/directory/shared/kerberos/KerberosUtils.java Mon Mar 11 18:34:59 2013 @@ -19,6 +19,7 @@ */ package org.apache.directory.shared.kerberos; + import static org.apache.directory.shared.kerberos.codec.types.EncryptionType.DES3_CBC_MD5; import static org.apache.directory.shared.kerberos.codec.types.EncryptionType.DES3_CBC_SHA1; import static org.apache.directory.shared.kerberos.codec.types.EncryptionType.DES3_CBC_SHA1_KD; @@ -87,24 +88,24 @@ public class KerberosUtils * names in the descending order of strength */ private static final Map cipherAlgoMap = new LinkedHashMap(); - + public static final TimeZone UTC_TIME_ZONE = TimeZone.getTimeZone( "UTC" ); /** Defines a default date format with a "yyyyMMddHHmmss'Z'" pattern */ public static final SimpleDateFormat UTC_DATE_FORMAT = new SimpleDateFormat( "yyyyMMddHHmmss'Z'" ); private static final Set oldEncTypes = new HashSet(); - + static { UTC_DATE_FORMAT.setTimeZone( UTC_TIME_ZONE ); - + cipherAlgoMap.put( "rc4", "ArcFourHmac" ); cipherAlgoMap.put( "aes256", "AES256" ); cipherAlgoMap.put( "aes128", "AES128" ); cipherAlgoMap.put( "des3", "DESede" ); cipherAlgoMap.put( "des", "DES" ); - + oldEncTypes.add( DES_CBC_CRC ); oldEncTypes.add( DES_CBC_MD4 ); oldEncTypes.add( DES_CBC_MD5 ); @@ -120,7 +121,8 @@ public class KerberosUtils oldEncTypes.add( RSAES_OAEP_ENV_OID ); oldEncTypes.add( RC4_HMAC ); } - + + /** * Parse a KerberosPrincipal instance and return the names. The Principal name * is described in RFC 1964 :
@@ -311,11 +313,12 @@ public class KerberosUtils * @param configuredTypes The configured encryption types * @return The first matching encryption type. */ - public static EncryptionType getBestEncryptionType( Set requestedTypes, Set configuredTypes ) + public static EncryptionType getBestEncryptionType( Set requestedTypes, + Set configuredTypes ) { - for ( EncryptionType encryptionType : requestedTypes ) + for ( EncryptionType encryptionType : configuredTypes ) { - if ( configuredTypes.contains( encryptionType ) ) + if ( requestedTypes.contains( encryptionType ) ) { return encryptionType; } @@ -376,39 +379,46 @@ public class KerberosUtils public static String getAlgoNameFromEncType( EncryptionType encType ) { String cipherName = encType.getName().toLowerCase(); - - for( String c : cipherAlgoMap.keySet() ) + + for ( String c : cipherAlgoMap.keySet() ) { if ( cipherName.startsWith( c ) ) { return cipherAlgoMap.get( c ); } } - + throw new IllegalArgumentException( "Unknown algorithm name for the encryption type " + encType ); } - + + /** + * Order a list of EncryptionType in a decreasing strength order + * + * @param etypes The ETypes to order + * @return A list of ordered ETypes. he strongest is on the left. + */ public static Set orderEtypesByStrength( Set etypes ) { Set ordered = new LinkedHashSet( etypes.size() ); - - for( String algo : cipherAlgoMap.values() ) + + for ( String algo : cipherAlgoMap.values() ) { - for( EncryptionType encType : etypes ) + for ( EncryptionType encType : etypes ) { String foundAlgo = getAlgoNameFromEncType( encType ); - + if ( algo.equals( foundAlgo ) ) { ordered.add( encType ); } } } - + return ordered; } + /** * Get a PrincipalStoreEntry given a principal. The ErrorType is used to indicate * whether any resulting error pertains to a server or client. @@ -417,7 +427,7 @@ public class KerberosUtils throws KerberosException { PrincipalStoreEntry entry = null; - + try { entry = store.getPrincipal( principal ); @@ -426,20 +436,21 @@ public class KerberosUtils { throw new KerberosException( errorType, e ); } - + if ( entry == null ) { throw new KerberosException( errorType ); } - + if ( entry.getKeyMap() == null || entry.getKeyMap().isEmpty() ) { throw new KerberosException( ErrorType.KDC_ERR_NULL_KEY ); } - + return entry; } + /** * Verifies an AuthHeader using guidelines from RFC 1510 section A.10., "KRB_AP_REQ verification." * @@ -456,123 +467,127 @@ public class KerberosUtils * @return The authenticator. * @throws KerberosException */ - public static Authenticator verifyAuthHeader( ApReq authHeader, Ticket ticket, EncryptionKey serverKey, - long clockSkew, ReplayCache replayCache, boolean emptyAddressesAllowed, InetAddress clientAddress, - CipherTextHandler lockBox, KeyUsage authenticatorKeyUsage, boolean isValidate ) throws KerberosException + public static Authenticator verifyAuthHeader( ApReq authHeader, Ticket ticket, EncryptionKey serverKey, + long clockSkew, ReplayCache replayCache, boolean emptyAddressesAllowed, InetAddress clientAddress, + CipherTextHandler lockBox, KeyUsage authenticatorKeyUsage, boolean isValidate ) throws KerberosException + { + if ( authHeader.getProtocolVersionNumber() != KerberosConstants.KERBEROS_V5 ) { - 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 + 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 ) ) ) { - if ( !emptyAddressesAllowed ) - { - throw new KerberosException( ErrorType.KRB_AP_ERR_BADADDR ); - } + 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 ) + } + else + { + if ( !emptyAddressesAllowed ) { - if ( replayCache.isReplay( serverPrincipal, clientPrincipal, clientTime, clientMicroSeconds ) ) - { - throw new KerberosException( ErrorType.KRB_AP_ERR_REPEAT ); - } - - replayCache.save( serverPrincipal, clientPrincipal, clientTime, clientMicroSeconds ); + throw new KerberosException( ErrorType.KRB_AP_ERR_BADADDR ); } - - if ( !authenticator.getCtime().isInClockSkew( clockSkew ) ) + } + + 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_SKEW ); + throw new KerberosException( ErrorType.KRB_AP_ERR_REPEAT ); } - - /* - * "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; + + 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; + } + + /** * checks if the given encryption type is *new* (ref sec#3.1.3 of rfc4120) * @@ -583,7 +598,7 @@ public class KerberosUtils { return !oldEncTypes.contains( eType ); } - + /** * Verifies an AuthHeader using guidelines from RFC 1510 section A.10., "KRB_AP_REQ verification." *