ConnectionStateSSLv3.java revision f33eae7e84eb6d3b0f4e86b59605bb3de73009f3
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 18package org.apache.harmony.xnet.provider.jsse; 19 20import java.security.GeneralSecurityException; 21import java.security.MessageDigest; 22import java.util.Arrays; 23import javax.crypto.Cipher; 24import javax.crypto.spec.IvParameterSpec; 25import javax.crypto.spec.SecretKeySpec; 26import javax.net.ssl.SSLProtocolException; 27 28/** 29 * This class encapsulates the operating environment of the SSL v3 30 * (http://wp.netscape.com/eng/ssl3) Record Protocol and provides 31 * relating encryption/decryption functionality. 32 * The work functionality is based on the security 33 * parameters negotiated during the handshake. 34 */ 35public class ConnectionStateSSLv3 extends ConnectionState { 36 37 // digest to create and check the message integrity info 38 private final MessageDigest messageDigest; 39 private final byte[] mac_write_secret; 40 private final byte[] mac_read_secret; 41 42 // paddings 43 private final byte[] pad_1; 44 private final byte[] pad_2; 45 // array will hold the part of the MAC material: 46 // length of 3 == 1(SSLCompressed.type) + 2(SSLCompressed.length) 47 // (more on SSLv3 MAC computation and payload protection see 48 // SSL v3 specification, p. 5.2.3) 49 private final byte[] mac_material_part = new byte[3]; 50 51 /** 52 * Creates the instance of SSL v3 Connection State. All of the 53 * security parameters are provided by session object. 54 * @param session: the sessin object which incapsulates 55 * all of the security parameters established by handshake protocol. 56 * The key calculation for the state is done according 57 * to the SSL v3 Protocol specification. 58 * (http://www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt) 59 */ 60 protected ConnectionStateSSLv3(SSLSessionImpl session) { 61 try { 62 CipherSuite cipherSuite = session.cipherSuite; 63 64 boolean is_exportabe = cipherSuite.isExportable(); 65 hash_size = cipherSuite.getMACLength(); 66 int key_size = (is_exportabe) 67 ? cipherSuite.keyMaterial 68 : cipherSuite.expandedKeyMaterial; 69 int iv_size = cipherSuite.getBlockSize(); 70 71 String algName = cipherSuite.getBulkEncryptionAlgorithm(); 72 String hashName = cipherSuite.getHashName(); 73 if (logger != null) { 74 logger.println("ConnectionStateSSLv3.create:"); 75 logger.println(" cipher suite name: " 76 + session.getCipherSuite()); 77 logger.println(" encryption alg name: " + algName); 78 logger.println(" hash alg name: " + hashName); 79 logger.println(" hash size: " + hash_size); 80 logger.println(" block size: " + iv_size); 81 logger.println(" IV size (== block size):" + iv_size); 82 logger.println(" key size: " + key_size); 83 } 84 85 byte[] clientRandom = session.clientRandom; 86 byte[] serverRandom = session.serverRandom; 87 // so we need PRF value of size of 88 // 2*hash_size + 2*key_size + 2*iv_size 89 byte[] key_block = new byte[2*hash_size + 2*key_size + 2*iv_size]; 90 byte[] seed = new byte[clientRandom.length + serverRandom.length]; 91 System.arraycopy(serverRandom, 0, seed, 0, serverRandom.length); 92 System.arraycopy(clientRandom, 0, seed, serverRandom.length, 93 clientRandom.length); 94 95 PRF.computePRF_SSLv3(key_block, session.master_secret, seed); 96 97 byte[] client_mac_secret = new byte[hash_size]; 98 byte[] server_mac_secret = new byte[hash_size]; 99 byte[] client_key = new byte[key_size]; 100 byte[] server_key = new byte[key_size]; 101 102 boolean is_client = !session.isServer; 103 104 is_block_cipher = (iv_size > 0); 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 (is_block_cipher) { 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 (is_block_cipher) { 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 encCipher = Cipher.getInstance(algName); 177 decCipher = Cipher.getInstance(algName); 178 messageDigest = MessageDigest.getInstance(hashName); 179 if (is_client) { // client side 180 encCipher.init(Cipher.ENCRYPT_MODE, 181 new SecretKeySpec(client_key, 0, key_size, algName), 182 clientIV); 183 decCipher.init(Cipher.DECRYPT_MODE, 184 new SecretKeySpec(server_key, 0, key_size, algName), 185 serverIV); 186 mac_write_secret = client_mac_secret; 187 mac_read_secret = server_mac_secret; 188 } else { // server side 189 encCipher.init(Cipher.ENCRYPT_MODE, 190 new SecretKeySpec(server_key, 0, key_size, algName), 191 serverIV); 192 decCipher.init(Cipher.DECRYPT_MODE, 193 new SecretKeySpec(client_key, 0, key_size, algName), 194 clientIV); 195 mac_write_secret = server_mac_secret; 196 mac_read_secret = client_mac_secret; 197 } 198 if (hashName.equals("MD5")) { 199 pad_1 = SSLv3Constants.MD5pad1; 200 pad_2 = SSLv3Constants.MD5pad2; 201 } else { 202 pad_1 = SSLv3Constants.SHApad1; 203 pad_2 = SSLv3Constants.SHApad2; 204 } 205 } catch (Exception e) { 206 e.printStackTrace(); 207 throw new AlertException(AlertProtocol.INTERNAL_ERROR, 208 new SSLProtocolException( 209 "Error during computation of security parameters")); 210 } 211 } 212 213 /** 214 * Creates the GenericStreamCipher or GenericBlockCipher 215 * data structure for specified data of specified type. 216 * @throws AlertException if alert was occurred. 217 */ 218 @Override 219 protected byte[] encrypt(byte type, byte[] fragment, int offset, int len) { 220 try { 221 int content_mac_length = len + hash_size; 222 int padding_length = is_block_cipher 223 ? padding_length = 224 ((8 - (++content_mac_length & 0x07)) & 0x07) 225 : 0; 226 byte[] res = new byte[content_mac_length + padding_length]; 227 System.arraycopy(fragment, offset, res, 0, len); 228 229 mac_material_part[0] = type; 230 mac_material_part[1] = (byte) ((0x00FF00 & len) >> 8); 231 mac_material_part[2] = (byte) (0x0000FF & len); 232 233 messageDigest.update(mac_write_secret); 234 messageDigest.update(pad_1); 235 messageDigest.update(write_seq_num); 236 messageDigest.update(mac_material_part); 237 messageDigest.update(fragment, offset, len); 238 byte[] digest = messageDigest.digest(); 239 messageDigest.update(mac_write_secret); 240 messageDigest.update(pad_2); 241 messageDigest.update(digest); 242 digest = messageDigest.digest(); 243 System.arraycopy(digest, 0, res, len, hash_size); 244 245 //if (logger != null) { 246 // logger.println("MAC Material:"); 247 // logger.print(write_seq_num); 248 // logger.print(mac_material_header); 249 // logger.print(fragment, offset, len); 250 //} 251 252 if (is_block_cipher) { 253 // do padding: 254 Arrays.fill(res, content_mac_length-1, 255 res.length, (byte) (padding_length)); 256 } 257 if (logger != null) { 258 logger.println("SSLRecordProtocol.encrypt: " 259 + (is_block_cipher 260 ? "GenericBlockCipher with padding[" 261 +padding_length+"]:" 262 : "GenericStreamCipher:")); 263 logger.print(res); 264 } 265 byte[] rez = new byte[encCipher.getOutputSize(res.length)]; 266 encCipher.update(res, 0, res.length, rez); 267 incSequenceNumber(write_seq_num); 268 return rez; 269 } catch (GeneralSecurityException e) { 270 e.printStackTrace(); 271 throw new AlertException(AlertProtocol.INTERNAL_ERROR, 272 new SSLProtocolException("Error during the encryption")); 273 } 274 } 275 276 /** 277 * Retrieves the fragment of the Plaintext structure of 278 * the specified type from the provided data. 279 * @throws AlertException if alert was occured. 280 */ 281 @Override 282 protected byte[] decrypt(byte type, byte[] fragment, 283 int offset, int len) { 284 // plain data of the Generic[Stream|Block]Cipher structure 285 byte[] data = decCipher.update(fragment, offset, len); 286 // the 'content' part of the structure 287 byte[] content; 288 if (is_block_cipher) { 289 // check padding 290 int padding_length = data[data.length-1]; 291 for (int i=0; i<padding_length; i++) { 292 if (data[data.length-2-i] != padding_length) { 293 throw new AlertException( 294 AlertProtocol.DECRYPTION_FAILED, 295 new SSLProtocolException( 296 "Received message has bad padding")); 297 } 298 } 299 content = new byte[data.length - hash_size - padding_length - 1]; 300 } else { 301 content = new byte[data.length - hash_size]; 302 } 303 304 byte[] mac_value; 305 306 mac_material_part[0] = type; 307 mac_material_part[1] = (byte) ((0x00FF00 & content.length) >> 8); 308 mac_material_part[2] = (byte) (0x0000FF & content.length); 309 310 messageDigest.update(mac_read_secret); 311 messageDigest.update(pad_1); 312 messageDigest.update(read_seq_num); 313 messageDigest.update(mac_material_part); 314 messageDigest.update(data, 0, content.length); 315 mac_value = messageDigest.digest(); 316 messageDigest.update(mac_read_secret); 317 messageDigest.update(pad_2); 318 messageDigest.update(mac_value); 319 mac_value = messageDigest.digest(); 320 321 if (logger != null) { 322 logger.println("Decrypted:"); 323 logger.print(data); 324 //logger.println("MAC Material:"); 325 //logger.print(read_seq_num); 326 //logger.print(mac_material_header); 327 //logger.print(data, 0, content.length); 328 logger.println("Expected mac value:"); 329 logger.print(mac_value); 330 } 331 // checking the mac value 332 for (int i=0; i<hash_size; i++) { 333 if (mac_value[i] != data[i+content.length]) { 334 throw new AlertException(AlertProtocol.BAD_RECORD_MAC, 335 new SSLProtocolException("Bad record MAC")); 336 } 337 } 338 System.arraycopy(data, 0, content, 0, content.length); 339 incSequenceNumber(read_seq_num); 340 return content; 341 } 342 343 /** 344 * Shutdown the protocol. It will be impossible to use the instance 345 * after the calling of this method. 346 */ 347 @Override 348 protected void shutdown() { 349 Arrays.fill(mac_write_secret, (byte) 0); 350 Arrays.fill(mac_read_secret, (byte) 0); 351 super.shutdown(); 352 } 353} 354 355