1/* 2 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package sun.security.krb5.internal.ssl; 27 28import java.io.*; 29import java.security.*; 30import java.util.Arrays; 31 32import javax.net.ssl.*; 33 34import sun.security.krb5.EncryptionKey; 35import sun.security.krb5.EncryptedData; 36import sun.security.krb5.KrbException; 37import sun.security.krb5.internal.crypto.KeyUsage; 38 39import sun.security.ssl.Debug; 40import sun.security.ssl.HandshakeInStream; 41import sun.security.ssl.HandshakeMessage; 42import sun.security.ssl.ProtocolVersion; 43 44/** 45 * This is the Kerberos premaster secret in the Kerberos client key 46 * exchange message (CLIENT --> SERVER); it holds the 47 * Kerberos-encrypted pre-master secret. The secret is encrypted using the 48 * Kerberos session key. The padding and size of the resulting message 49 * depends on the session key type, but the pre-master secret is 50 * always exactly 48 bytes. 51 * 52 */ 53final class KerberosPreMasterSecret { 54 55 private ProtocolVersion protocolVersion; // preMaster [0,1] 56 private byte[] preMaster; // 48 bytes 57 private byte[] encrypted; 58 59 /** 60 * Constructor used by client to generate premaster secret. 61 * 62 * Client randomly creates a pre-master secret and encrypts it 63 * using the Kerberos session key; only the server can decrypt 64 * it, using the session key available in the service ticket. 65 * 66 * @param protocolVersion used to set preMaster[0,1] 67 * @param generator random number generator for generating premaster secret 68 * @param sessionKey Kerberos session key for encrypting premaster secret 69 */ 70 KerberosPreMasterSecret(ProtocolVersion protocolVersion, 71 SecureRandom generator, EncryptionKey sessionKey) throws IOException { 72 73 if (sessionKey.getEType() == 74 EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) { 75 throw new IOException( 76 "session keys with des3-cbc-hmac-sha1-kd encryption type " + 77 "are not supported for TLS Kerberos cipher suites"); 78 } 79 80 this.protocolVersion = protocolVersion; 81 preMaster = generatePreMaster(generator, protocolVersion); 82 83 // Encrypt premaster secret 84 try { 85 EncryptedData eData = new EncryptedData(sessionKey, preMaster, 86 KeyUsage.KU_UNKNOWN); 87 encrypted = eData.getBytes(); // not ASN.1 encoded. 88 89 } catch (KrbException e) { 90 throw (SSLKeyException)new SSLKeyException 91 ("Kerberos premaster secret error").initCause(e); 92 } 93 } 94 95 /* 96 * Constructor used by server to decrypt encrypted premaster secret. 97 * The protocol version in preMaster[0,1] must match either currentVersion 98 * or clientVersion, otherwise, the premaster secret is set to 99 * a random one to foil possible attack. 100 * 101 * @param currentVersion version of protocol being used 102 * @param clientVersion version requested by client 103 * @param generator random number generator used to generate 104 * bogus premaster secret if premaster secret verification fails 105 * @param input input stream from which to read the encrypted 106 * premaster secret 107 * @param sessionKey Kerberos session key to be used for decryption 108 */ 109 KerberosPreMasterSecret(ProtocolVersion currentVersion, 110 ProtocolVersion clientVersion, 111 SecureRandom generator, byte[] encrypted, 112 EncryptionKey sessionKey) throws IOException { 113 114 if (HandshakeMessage.debug != null && Debug.isOn("handshake")) { 115 if (encrypted != null) { 116 Debug.println(System.out, 117 "encrypted premaster secret", encrypted); 118 } 119 } 120 121 if (sessionKey.getEType() == 122 EncryptedData.ETYPE_DES3_CBC_HMAC_SHA1_KD) { 123 throw new IOException( 124 "session keys with des3-cbc-hmac-sha1-kd encryption type " + 125 "are not supported for TLS Kerberos cipher suites"); 126 } 127 128 // Decrypt premaster secret 129 try { 130 EncryptedData data = new EncryptedData(sessionKey.getEType(), 131 null /* optional kvno */, encrypted); 132 133 byte[] temp = data.decrypt(sessionKey, KeyUsage.KU_UNKNOWN); 134 if (HandshakeMessage.debug != null && Debug.isOn("handshake")) { 135 if (encrypted != null) { 136 Debug.println(System.out, 137 "decrypted premaster secret", temp); 138 } 139 } 140 141 // Remove padding bytes after decryption. Only DES and DES3 have 142 // paddings and we don't support DES3 in TLS (see above) 143 144 if (temp.length == 52 && 145 data.getEType() == EncryptedData.ETYPE_DES_CBC_CRC) { 146 // For des-cbc-crc, 4 paddings. Value can be 0x04 or 0x00. 147 if (paddingByteIs(temp, 52, (byte)4) || 148 paddingByteIs(temp, 52, (byte)0)) { 149 temp = Arrays.copyOf(temp, 48); 150 } 151 } else if (temp.length == 56 && 152 data.getEType() == EncryptedData.ETYPE_DES_CBC_MD5) { 153 // For des-cbc-md5, 8 paddings with 0x08, or no padding 154 if (paddingByteIs(temp, 56, (byte)8)) { 155 temp = Arrays.copyOf(temp, 48); 156 } 157 } 158 159 preMaster = temp; 160 161 protocolVersion = ProtocolVersion.valueOf(preMaster[0], 162 preMaster[1]); 163 if (HandshakeMessage.debug != null && Debug.isOn("handshake")) { 164 System.out.println("Kerberos PreMasterSecret version: " 165 + protocolVersion); 166 } 167 } catch (Exception e) { 168 // catch exception & process below 169 preMaster = null; 170 protocolVersion = currentVersion; 171 } 172 173 // check if the premaster secret version is ok 174 // the specification says that it must be the maximum version supported 175 // by the client from its ClientHello message. However, many 176 // old implementations send the negotiated version, so accept both 177 // for SSL v3.0 and TLS v1.0. 178 // NOTE that we may be comparing two unsupported version numbers in 179 // the second case, which is why we cannot use object references 180 // equality in this special case 181 boolean versionMismatch = (protocolVersion.v != clientVersion.v); 182 183 /* 184 * we never checked the client_version in server side 185 * for TLS v1.0 and SSL v3.0. For compatibility, we 186 * maintain this behavior. 187 */ 188 if (versionMismatch && (clientVersion.v <= 0x0301)) { 189 versionMismatch = (protocolVersion.v != currentVersion.v); 190 } 191 192 /* 193 * Bogus decrypted ClientKeyExchange? If so, conjure a 194 * a random preMaster secret that will fail later during 195 * Finished message processing. This is a countermeasure against 196 * the "interactive RSA PKCS#1 encryption envelop attack" reported 197 * in June 1998. Preserving the executation path will 198 * mitigate timing attacks and force consistent error handling 199 * that will prevent an attacking client from differentiating 200 * different kinds of decrypted ClientKeyExchange bogosities. 201 */ 202 if ((preMaster == null) || (preMaster.length != 48) 203 || versionMismatch) { 204 if (HandshakeMessage.debug != null && Debug.isOn("handshake")) { 205 System.out.println("Kerberos PreMasterSecret error, " 206 + "generating random secret"); 207 if (preMaster != null) { 208 Debug.println(System.out, "Invalid secret", preMaster); 209 } 210 } 211 212 /* 213 * Randomize the preMaster secret with the 214 * ClientHello.client_version, as will produce invalid master 215 * secret to prevent the attacks. 216 */ 217 preMaster = generatePreMaster(generator, clientVersion); 218 protocolVersion = clientVersion; 219 } 220 } 221 222 /** 223 * Checks if all paddings of data are b 224 * @param data the block with padding 225 * @param len length of data, >= 48 226 * @param b expected padding byte 227 */ 228 private static boolean paddingByteIs(byte[] data, int len, byte b) { 229 for (int i=48; i<len; i++) { 230 if (data[i] != b) return false; 231 } 232 return true; 233 } 234 235 /* 236 * Used by server to generate premaster secret in case of 237 * problem decoding ticket. 238 * 239 * @param protocolVersion used for preMaster[0,1] 240 * @param generator random number generator to use for generating secret. 241 */ 242 KerberosPreMasterSecret(ProtocolVersion protocolVersion, 243 SecureRandom generator) { 244 245 this.protocolVersion = protocolVersion; 246 preMaster = generatePreMaster(generator, protocolVersion); 247 } 248 249 private static byte[] generatePreMaster(SecureRandom rand, 250 ProtocolVersion ver) { 251 252 byte[] pm = new byte[48]; 253 rand.nextBytes(pm); 254 pm[0] = ver.major; 255 pm[1] = ver.minor; 256 257 return pm; 258 } 259 260 // Clone not needed; internal use only 261 byte[] getUnencrypted() { 262 return preMaster; 263 } 264 265 // Clone not needed; internal use only 266 byte[] getEncrypted() { 267 return encrypted; 268 } 269} 270