|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  */ | 
|  |  | 
|  | package sun.security.ssl; | 
|  |  | 
|  | import javax.crypto.SecretKey; | 
|  | import javax.crypto.spec.SecretKeySpec; | 
|  | import javax.net.ssl.SSLHandshakeException; | 
|  |  | 
|  | import java.io.IOException; | 
|  | import java.security.AccessControlContext; | 
|  | import java.security.AccessController; | 
|  | import java.security.PrivilegedActionException; | 
|  | import java.security.PrivilegedExceptionAction; | 
|  | import java.security.SecureRandom; | 
|  | import java.security.spec.AlgorithmParameterSpec; | 
|  |  | 
|  | final class KrbKeyExchange { | 
|  |     static final SSLPossessionGenerator poGenerator = | 
|  |             new KrbPossessionGenerator(); | 
|  |     static final SSLKeyAgreementGenerator kaGenerator = | 
|  |             new KrbKAGenerator(); | 
|  |  | 
|  |     static final | 
|  |             class KrbPossessionGenerator implements SSLPossessionGenerator { | 
|  |          | 
|  |  | 
|  |  | 
|  |  | 
|  |          */ | 
|  |         @Override | 
|  |         public SSLPossession createPossession(HandshakeContext handshakeContext) { | 
|  |             Object serviceCreds = null; | 
|  |             try { | 
|  |                 final AccessControlContext acc = handshakeContext.conContext.acc; | 
|  |                 serviceCreds = AccessController.doPrivileged( | 
|  |                          | 
|  |                         new PrivilegedExceptionAction<Object>() { | 
|  |                             @Override | 
|  |                             public Object run() throws Exception { | 
|  |                                  | 
|  |                                 return Krb5Helper.getServiceCreds(acc); | 
|  |                             }}); | 
|  |  | 
|  |                 // check permission to access and use the secret key of the | 
|  |                  | 
|  |                 if (serviceCreds != null) { | 
|  |                     if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
|  |                         SSLLogger.fine("Using Kerberos creds"); | 
|  |                     } | 
|  |                     String serverPrincipal = | 
|  |                             Krb5Helper.getServerPrincipalName(serviceCreds); | 
|  |                     if (serverPrincipal != null) { | 
|  |                         // When service is bound, we check ASAP. Otherwise, | 
|  |                         // will check after client request is received | 
|  |                          | 
|  |                         SecurityManager sm = System.getSecurityManager(); | 
|  |                         try { | 
|  |                             if (sm != null) { | 
|  |                                  | 
|  |                                 sm.checkPermission(Krb5Helper.getServicePermission( | 
|  |                                         serverPrincipal, "accept"), acc); | 
|  |                             } | 
|  |                         } catch (SecurityException se) { | 
|  |                              | 
|  |                             if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
|  |                                 SSLLogger.fine("Permission to access Kerberos" | 
|  |                                         + " secret key denied"); | 
|  |                             } | 
|  |                             return null; | 
|  |                         } | 
|  |                     } | 
|  |                     return new KrbServiceCreds(serviceCreds); | 
|  |                 } | 
|  |             } catch (PrivilegedActionException e) { | 
|  |                  | 
|  |                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
|  |                     SSLLogger.fine("Attempt to obtain Kerberos key failed: " | 
|  |                             + e.toString()); | 
|  |                 } | 
|  |             } | 
|  |             return null; | 
|  |         } | 
|  |     } | 
|  |  | 
|  |     static final | 
|  |         class KrbServiceCreds implements SSLPossession { | 
|  |         final Object serviceCreds; | 
|  |  | 
|  |         KrbServiceCreds(Object serviceCreds) { | 
|  |             this.serviceCreds = serviceCreds; | 
|  |         } | 
|  |     } | 
|  |  | 
|  |     static final | 
|  |         class KrbPremasterSecret implements SSLPossession, SSLCredentials { | 
|  |         final byte[] preMaster;  | 
|  |  | 
|  |         KrbPremasterSecret(byte[] premasterSecret) { | 
|  |             preMaster = premasterSecret; | 
|  |         } | 
|  |  | 
|  |         static KrbPremasterSecret createPremasterSecret( | 
|  |                 ProtocolVersion protocolVersion, SecureRandom rand) { | 
|  |             byte[] pm = new byte[48]; | 
|  |             rand.nextBytes(pm); | 
|  |             pm[0] = protocolVersion.major; | 
|  |             pm[1] = protocolVersion.minor; | 
|  |             return new KrbPremasterSecret(pm); | 
|  |         } | 
|  |  | 
|  |         static KrbPremasterSecret decode(ProtocolVersion protocolVersion, | 
|  |                 ProtocolVersion clientVersion, byte[] preMaster, | 
|  |                 SecureRandom rand) { | 
|  |             KrbPremasterSecret preMasterSecret = null; | 
|  |             boolean versionMismatch = true; | 
|  |             ProtocolVersion preMasterProtocolVersion = null; | 
|  |             if (preMaster != null && preMaster.length == 48) { | 
|  |                 preMasterProtocolVersion = | 
|  |                         ProtocolVersion.valueOf(preMaster[0], preMaster[1]); | 
|  |                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
|  |                      SSLLogger.fine("Kerberos pre-master secret protocol" + | 
|  |                              " version: " + preMasterProtocolVersion); | 
|  |                 } | 
|  |  | 
|  |                 // Check if the pre-master secret protocol version is valid. | 
|  |                 // The specification states that it must be the maximum version | 
|  |                 // supported by the client from its ClientHello message. However, | 
|  |                 // many old implementations send the negotiated version, so accept | 
|  |                  | 
|  |                 versionMismatch = | 
|  |                         (preMasterProtocolVersion.compare(clientVersion) != 0); | 
|  |                 if (versionMismatch && | 
|  |                         (clientVersion.compare(ProtocolVersion.TLS10) <= 0)) { | 
|  |                     versionMismatch = | 
|  |                             (preMasterProtocolVersion.compare(protocolVersion) != 0); | 
|  |                 } | 
|  |             } | 
|  |  | 
|  |             if (versionMismatch) { | 
|  |                  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  |                  */ | 
|  |                 preMasterSecret = createPremasterSecret(clientVersion, rand); | 
|  |                 if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { | 
|  |                     SSLLogger.fine("Kerberos pre-master secret error," + | 
|  |                             " generating random secret for safe failure."); | 
|  |                 } | 
|  |             } else { | 
|  |                 preMasterSecret = new KrbPremasterSecret(preMaster); | 
|  |             } | 
|  |             return preMasterSecret; | 
|  |         } | 
|  |     } | 
|  |  | 
|  |     private static final class KrbKAGenerator implements SSLKeyAgreementGenerator { | 
|  |          | 
|  |         private KrbKAGenerator() { | 
|  |             // blank | 
|  |         } | 
|  |  | 
|  |         @Override | 
|  |         public SSLKeyDerivation createKeyDerivation( | 
|  |                 HandshakeContext context) throws IOException { | 
|  |  | 
|  |             KrbPremasterSecret premaster = null; | 
|  |             if (context instanceof ClientHandshakeContext) { | 
|  |                 for (SSLPossession possession : context.handshakePossessions) { | 
|  |                     if (possession instanceof KrbPremasterSecret) { | 
|  |                         premaster = (KrbPremasterSecret)possession; | 
|  |                         break; | 
|  |                     } | 
|  |                 } | 
|  |             } else { | 
|  |                 for (SSLCredentials credential : context.handshakeCredentials) { | 
|  |                     if (credential instanceof KrbPremasterSecret) { | 
|  |                         premaster = (KrbPremasterSecret)credential; | 
|  |                         break; | 
|  |                     } | 
|  |                 } | 
|  |             } | 
|  |  | 
|  |             if (premaster == null) { | 
|  |                 throw context.conContext.fatal(Alert.HANDSHAKE_FAILURE, | 
|  |                         "No sufficient KRB key agreement parameters negotiated"); | 
|  |             } | 
|  |  | 
|  |             return new KRBKAKeyDerivation(context, premaster.preMaster); | 
|  |  | 
|  |         } | 
|  |  | 
|  |         private static final | 
|  |             class KRBKAKeyDerivation implements SSLKeyDerivation { | 
|  |             private final HandshakeContext context; | 
|  |             private final byte[] secretBytes; | 
|  |  | 
|  |             KRBKAKeyDerivation(HandshakeContext context, | 
|  |                                byte[] secret) { | 
|  |                 this.context = context; | 
|  |                 this.secretBytes = secret; | 
|  |             } | 
|  |  | 
|  |             @Override | 
|  |             public SecretKey deriveKey(String algorithm, | 
|  |                                        AlgorithmParameterSpec params) throws IOException { | 
|  |                 try { | 
|  |                     SecretKey preMasterSecret = new SecretKeySpec(secretBytes, | 
|  |                             "TlsPremasterSecret"); | 
|  |  | 
|  |                     SSLMasterKeyDerivation mskd = | 
|  |                             SSLMasterKeyDerivation.valueOf( | 
|  |                                     context.negotiatedProtocol); | 
|  |                     if (mskd == null) { | 
|  |                          | 
|  |                         throw new SSLHandshakeException( | 
|  |                                 "No expected master key derivation for protocol: " + | 
|  |                                         context.negotiatedProtocol.name); | 
|  |                     } | 
|  |                     SSLKeyDerivation kd = mskd.createKeyDerivation( | 
|  |                             context, preMasterSecret); | 
|  |                     return kd.deriveKey("MasterSecret", params); | 
|  |                 } catch (Exception gse) { | 
|  |                     throw (SSLHandshakeException) new SSLHandshakeException( | 
|  |                             "Could not generate secret").initCause(gse); | 
|  |                 } | 
|  |             } | 
|  |         } | 
|  |     } | 
|  | } |