1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package org.conscrypt; 19 20 import java.security.GeneralSecurityException; 21 import java.security.MessageDigest; 22 import java.util.Arrays; 23 import javax.crypto.Cipher; 24 import javax.crypto.NullCipher; 25 import javax.crypto.spec.IvParameterSpec; 26 import javax.crypto.spec.SecretKeySpec; 27 import javax.net.ssl.SSLProtocolException; 28 29 /** 30 * This class encapsulates the operating environment of the SSL v3 31 * (http://wp.netscape.com/eng/ssl3) Record Protocol and provides 32 * relating encryption/decryption functionality. 33 * The work functionality is based on the security 34 * parameters negotiated during the handshake. 35 */ 36 public class ConnectionStateSSLv3 extends ConnectionState { 37 38 // digest to create and check the message integrity info 39 private final MessageDigest messageDigest; 40 private final byte[] mac_write_secret; 41 private final byte[] mac_read_secret; 42 43 // paddings 44 private final byte[] pad_1; 45 private final byte[] pad_2; 46 // array will hold the part of the MAC material: 47 // length of 3 == 1(SSLCompressed.type) + 2(SSLCompressed.length) 48 // (more on SSLv3 MAC computation and payload protection see 49 // SSL v3 specification, p. 5.2.3) 50 private final byte[] mac_material_part = new byte[3]; 51 52 /** 53 * Creates the instance of SSL v3 Connection State. All of the 54 * security parameters are provided by session object. 55 * @param session the sessin object which incapsulates 56 * all of the security parameters established by handshake protocol. 57 * The key calculation for the state is done according 58 * to the SSL v3 Protocol specification. 59 * (http://www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt) 60 */ 61 protected ConnectionStateSSLv3(SSLSessionImpl session) { 62 try { 63 CipherSuite cipherSuite = session.cipherSuite; 64 65 boolean is_exportabe = cipherSuite.isExportable(); 66 hash_size = cipherSuite.getMACLength(); 67 int key_size = (is_exportabe) 68 ? cipherSuite.keyMaterial 69 : cipherSuite.expandedKeyMaterial; 70 int iv_size = cipherSuite.ivSize; 71 block_size = cipherSuite.getBlockSize(); 72 73 String algName = cipherSuite.getBulkEncryptionAlgorithm(); 74 String hashName = cipherSuite.getHashName(); 75 if (logger != null) { 76 logger.println("ConnectionStateSSLv3.create:"); 77 logger.println(" cipher suite name: " 78 + session.getCipherSuite()); 79 logger.println(" encryption alg name: " + algName); 80 logger.println(" hash alg name: " + hashName); 81 logger.println(" hash size: " + hash_size); 82 logger.println(" block size: " + block_size); 83 logger.println(" IV size:" + iv_size); 84 logger.println(" key size: " + key_size); 85 } 86 87 byte[] clientRandom = session.clientRandom; 88 byte[] serverRandom = session.serverRandom; 89 // so we need PRF value of size of 90 // 2*hash_size + 2*key_size + 2*iv_size 91 byte[] key_block = new byte[2*hash_size + 2*key_size + 2*iv_size]; 92 byte[] seed = new byte[clientRandom.length + serverRandom.length]; 93 System.arraycopy(serverRandom, 0, seed, 0, serverRandom.length); 94 System.arraycopy(clientRandom, 0, seed, serverRandom.length, 95 clientRandom.length); 96 97 PRF.computePRF_SSLv3(key_block, session.master_secret, seed); 98 99 byte[] client_mac_secret = new byte[hash_size]; 100 byte[] server_mac_secret = new byte[hash_size]; 101 byte[] client_key = new byte[key_size]; 102 byte[] server_key = new byte[key_size]; 103 104 boolean is_client = !session.isServer; 105 106 System.arraycopy(key_block, 0, client_mac_secret, 0, hash_size); 107 System.arraycopy(key_block, hash_size, 108 server_mac_secret, 0, hash_size); 109 System.arraycopy(key_block, 2*hash_size, client_key, 0, key_size); 110 System.arraycopy(key_block, 2*hash_size+key_size, 111 server_key, 0, key_size); 112 113 IvParameterSpec clientIV = null; 114 IvParameterSpec serverIV = null; 115 116 if (is_exportabe) { 117 if (logger != null) { 118 logger.println("ConnectionStateSSLv3: is_exportable"); 119 } 120 121 MessageDigest md5 = MessageDigest.getInstance("MD5"); 122 md5.update(client_key); 123 md5.update(clientRandom); 124 md5.update(serverRandom); 125 client_key = md5.digest(); 126 127 md5.update(server_key); 128 md5.update(serverRandom); 129 md5.update(clientRandom); 130 server_key = md5.digest(); 131 132 key_size = cipherSuite.expandedKeyMaterial; 133 134 if (block_size != 0) { 135 md5.update(clientRandom); 136 md5.update(serverRandom); 137 clientIV = new IvParameterSpec(md5.digest(), 0, iv_size); 138 md5.update(serverRandom); 139 md5.update(clientRandom); 140 serverIV = new IvParameterSpec(md5.digest(), 0, iv_size); 141 } 142 } else if (block_size != 0) { 143 clientIV = new IvParameterSpec(key_block, 144 2*hash_size+2*key_size, iv_size); 145 serverIV = new IvParameterSpec(key_block, 146 2*hash_size+2*key_size+iv_size, iv_size); 147 } 148 149 if (logger != null) { 150 logger.println("is exportable: "+is_exportabe); 151 logger.println("master_secret"); 152 logger.print(session.master_secret); 153 logger.println("client_random"); 154 logger.print(clientRandom); 155 logger.println("server_random"); 156 logger.print(serverRandom); 157 //logger.println("key_block"); 158 //logger.print(key_block); 159 logger.println("client_mac_secret"); 160 logger.print(client_mac_secret); 161 logger.println("server_mac_secret"); 162 logger.print(server_mac_secret); 163 logger.println("client_key"); 164 logger.print(client_key, 0, key_size); 165 logger.println("server_key"); 166 logger.print(server_key, 0, key_size); 167 if (clientIV != null) { 168 logger.println("client_iv"); 169 logger.print(clientIV.getIV()); 170 logger.println("server_iv"); 171 logger.print(serverIV.getIV()); 172 } else { 173 logger.println("no IV."); 174 } 175 } 176 177 if (algName == null) { 178 encCipher = new NullCipher(); 179 decCipher = new NullCipher(); 180 } else { 181 encCipher = Cipher.getInstance(algName); 182 decCipher = Cipher.getInstance(algName); 183 if (is_client) { // client side 184 encCipher.init(Cipher.ENCRYPT_MODE, 185 new SecretKeySpec(client_key, 0, key_size, algName), 186 clientIV); 187 decCipher.init(Cipher.DECRYPT_MODE, 188 new SecretKeySpec(server_key, 0, key_size, algName), 189 serverIV); 190 } else { // server side 191 encCipher.init(Cipher.ENCRYPT_MODE, 192 new SecretKeySpec(server_key, 0, key_size, algName), 193 serverIV); 194 decCipher.init(Cipher.DECRYPT_MODE, 195 new SecretKeySpec(client_key, 0, key_size, algName), 196 clientIV); 197 } 198 } 199 200 messageDigest = MessageDigest.getInstance(hashName); 201 if (is_client) { // client side 202 mac_write_secret = client_mac_secret; 203 mac_read_secret = server_mac_secret; 204 } else { // server side 205 mac_write_secret = server_mac_secret; 206 mac_read_secret = client_mac_secret; 207 } 208 if (hashName.equals("MD5")) { 209 pad_1 = SSLv3Constants.MD5pad1; 210 pad_2 = SSLv3Constants.MD5pad2; 211 } else { 212 pad_1 = SSLv3Constants.SHApad1; 213 pad_2 = SSLv3Constants.SHApad2; 214 } 215 } catch (Exception e) { 216 e.printStackTrace(); 217 throw new AlertException(AlertProtocol.INTERNAL_ERROR, 218 new SSLProtocolException( 219 "Error during computation of security parameters")); 220 } 221 } 222 223 /** 224 * Creates the GenericStreamCipher or GenericBlockCipher 225 * data structure for specified data of specified type. 226 * @throws AlertException if alert was occurred. 227 */ 228 @Override 229 protected byte[] encrypt(byte type, byte[] fragment, int offset, int len) { 230 try { 231 int content_mac_length = len + hash_size; 232 int padding_length = (block_size == 0) ? 0 : getPaddingSize(++content_mac_length); 233 byte[] res = new byte[content_mac_length + padding_length]; 234 System.arraycopy(fragment, offset, res, 0, len); 235 236 mac_material_part[0] = type; 237 mac_material_part[1] = (byte) ((0x00FF00 & len) >> 8); 238 mac_material_part[2] = (byte) (0x0000FF & len); 239 240 messageDigest.update(mac_write_secret); 241 messageDigest.update(pad_1); 242 messageDigest.update(write_seq_num); 243 messageDigest.update(mac_material_part); 244 messageDigest.update(fragment, offset, len); 245 byte[] digest = messageDigest.digest(); 246 messageDigest.update(mac_write_secret); 247 messageDigest.update(pad_2); 248 messageDigest.update(digest); 249 digest = messageDigest.digest(); 250 System.arraycopy(digest, 0, res, len, hash_size); 251 252 //if (logger != null) { 253 // logger.println("MAC Material:"); 254 // logger.print(write_seq_num); 255 // logger.print(mac_material_header); 256 // logger.print(fragment, offset, len); 257 //} 258 259 if (block_size != 0) { 260 // do padding: 261 Arrays.fill(res, content_mac_length-1, 262 res.length, (byte) (padding_length)); 263 } 264 if (logger != null) { 265 logger.println("SSLRecordProtocol.encrypt: " 266 + (block_size != 0 267 ? "GenericBlockCipher with padding[" 268 +padding_length+"]:" 269 : "GenericStreamCipher:")); 270 logger.print(res); 271 } 272 byte[] rez = new byte[encCipher.getOutputSize(res.length)]; 273 encCipher.update(res, 0, res.length, rez); 274 incSequenceNumber(write_seq_num); 275 return rez; 276 } catch (GeneralSecurityException e) { 277 e.printStackTrace(); 278 throw new AlertException(AlertProtocol.INTERNAL_ERROR, 279 new SSLProtocolException("Error during the encryption")); 280 } 281 } 282 283 /** 284 * Retrieves the fragment of the Plaintext structure of 285 * the specified type from the provided data. 286 * @throws AlertException if alert was occured. 287 */ 288 @Override 289 protected byte[] decrypt(byte type, byte[] fragment, 290 int offset, int len) { 291 // plain data of the Generic[Stream|Block]Cipher structure 292 byte[] data = decCipher.update(fragment, offset, len); 293 // the 'content' part of the structure 294 byte[] content; 295 if (block_size != 0) { 296 // check padding 297 int padding_length = data[data.length-1] & 0xFF; 298 for (int i=0; i<padding_length; i++) { 299 if ((data[data.length-2-i] & 0xFF) != padding_length) { 300 throw new AlertException( 301 AlertProtocol.DECRYPTION_FAILED, 302 new SSLProtocolException( 303 "Received message has bad padding")); 304 } 305 } 306 content = new byte[data.length - hash_size - padding_length - 1]; 307 } else { 308 content = new byte[data.length - hash_size]; 309 } 310 311 byte[] mac_value; 312 313 mac_material_part[0] = type; 314 mac_material_part[1] = (byte) ((0x00FF00 & content.length) >> 8); 315 mac_material_part[2] = (byte) (0x0000FF & content.length); 316 317 messageDigest.update(mac_read_secret); 318 messageDigest.update(pad_1); 319 messageDigest.update(read_seq_num); 320 messageDigest.update(mac_material_part); 321 messageDigest.update(data, 0, content.length); 322 mac_value = messageDigest.digest(); 323 messageDigest.update(mac_read_secret); 324 messageDigest.update(pad_2); 325 messageDigest.update(mac_value); 326 mac_value = messageDigest.digest(); 327 328 if (logger != null) { 329 logger.println("Decrypted:"); 330 logger.print(data); 331 //logger.println("MAC Material:"); 332 //logger.print(read_seq_num); 333 //logger.print(mac_material_header); 334 //logger.print(data, 0, content.length); 335 logger.println("Expected mac value:"); 336 logger.print(mac_value); 337 } 338 // checking the mac value 339 for (int i=0; i<hash_size; i++) { 340 if (mac_value[i] != data[i+content.length]) { 341 throw new AlertException(AlertProtocol.BAD_RECORD_MAC, 342 new SSLProtocolException("Bad record MAC")); 343 } 344 } 345 System.arraycopy(data, 0, content, 0, content.length); 346 incSequenceNumber(read_seq_num); 347 return content; 348 } 349 350 /** 351 * Shutdown the protocol. It will be impossible to use the instance 352 * after the calling of this method. 353 */ 354 @Override 355 protected void shutdown() { 356 Arrays.fill(mac_write_secret, (byte) 0); 357 Arrays.fill(mac_read_secret, (byte) 0); 358 super.shutdown(); 359 } 360 } 361 362