ServerKeyExchange.java revision aacf6f9741dea0f12fbff5e7696e53f251177280
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 org.apache.harmony.xnet.provider.jsse.Message; 21 22import java.io.IOException; 23import java.math.BigInteger; 24import java.security.KeyFactory; 25import java.security.interfaces.RSAPublicKey; 26import java.security.spec.RSAPublicKeySpec; 27 28/** 29 * 30 * Represents server key exchange message. 31 * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.3. 32 * Server key exchange message.</a> 33 * 34 */ 35public class ServerKeyExchange extends Message { 36 37 // ServerRSAParams ServerDHParams 38 final BigInteger par1; // rsa_modulus dh_p 39 final byte[] bytes1; 40 41 final BigInteger par2; // rsa_exponent dh_g 42 final byte[] bytes2; 43 44 final BigInteger par3; // dh_Ys 45 final byte[] bytes3; 46 47 /** 48 * Signature 49 */ 50 final byte[] hash; 51 52 private RSAPublicKey key; 53 54 /** 55 * Creates outbound message 56 * @param par1 rsa_modulus or dh_p 57 * @param par2 rsa_exponent or dh_g 58 * @param par3 dh_Ys for ServerDHParams; should be null for ServerRSAParams 59 * @param hash should be null for anonymous SignatureAlgorithm 60 */ 61 public ServerKeyExchange(BigInteger par1, BigInteger par2, BigInteger par3, 62 byte[] hash) { 63 this.par1 = par1; 64 this.par2 = par2; 65 this.par3 = par3; 66 this.hash = hash; 67 68 bytes1 = toUnsignedByteArray(this.par1); 69 70 bytes2 = toUnsignedByteArray(this.par2); 71 72 length = 4 + bytes1.length + bytes2.length; 73 if (hash != null) { 74 length += 2 + hash.length; 75 } 76 if (par3 == null) { 77 bytes3 = null; 78 return; 79 } 80 bytes3 = toUnsignedByteArray(this.par3); 81 length += 2 + bytes3.length; 82 } 83 84 /** 85 * Remove first byte if 0. Needed because BigInteger.toByteArray() sometimes 86 * returns a zero prefix. 87 */ 88 public static byte[] toUnsignedByteArray(BigInteger bi) { 89 if (bi == null) { 90 return null; 91 } 92 byte[] bb = bi.toByteArray(); 93 // bb is not null, and has at least 1 byte - ZERO is represented as [0] 94 if (bb[0] == 0) { 95 byte[] noZero = new byte[bb.length - 1]; 96 System.arraycopy(bb, 1, noZero, 0, noZero.length); 97 return noZero; 98 } else { 99 return bb; 100 } 101 } 102 103 /** 104 * Creates inbound message 105 * @param in 106 * @param length 107 * @param keyExchange 108 * @throws IOException 109 */ 110 public ServerKeyExchange(HandshakeIODataStream in, int length, 111 int keyExchange) throws IOException { 112 113 int size = in.readUint16(); 114 bytes1 = in.read(size); 115 par1 = new BigInteger(1, bytes1); 116 this.length = 2 + bytes1.length; 117 size = in.readUint16(); 118 bytes2 = in.read(size); 119 par2 = new BigInteger(1, bytes2); 120 this.length += 2 + bytes2.length; 121 if (keyExchange != CipherSuite.KEY_EXCHANGE_RSA_EXPORT) { 122 size = in.readUint16(); 123 bytes3 = in.read(size); 124 par3 = new BigInteger(1, bytes3); 125 this.length += 2 + bytes3.length; 126 } else { 127 par3 = null; 128 bytes3 = null; 129 } 130 if (keyExchange != CipherSuite.KEY_EXCHANGE_DH_anon_EXPORT 131 && keyExchange != CipherSuite.KEY_EXCHANGE_DH_anon) { 132 size = in.readUint16(); 133 hash = in.read(size); 134 this.length += 2 + hash.length; 135 } else { 136 hash = null; 137 } 138 if (this.length != length) { 139 fatalAlert(AlertProtocol.DECODE_ERROR, 140 "DECODE ERROR: incorrect ServerKeyExchange"); 141 } 142 } 143 144 /** 145 * Sends message 146 * @param out 147 */ 148 @Override 149 public void send(HandshakeIODataStream out) { 150 out.writeUint16(bytes1.length); 151 out.write(bytes1); 152 out.writeUint16(bytes2.length); 153 out.write(bytes2); 154 if (bytes3 != null) { 155 out.writeUint16(bytes3.length); 156 out.write(bytes3); 157 } 158 if (hash != null) { 159 out.writeUint16(hash.length); 160 out.write(hash); 161 } 162 } 163 164 /** 165 * Returns RSAPublicKey generated using ServerRSAParams 166 * (rsa_modulus and rsa_exponent). 167 * 168 * @return 169 */ 170 public RSAPublicKey getRSAPublicKey() { 171 if (key != null) { 172 return key; 173 } 174 try { 175 KeyFactory kf = KeyFactory.getInstance("RSA"); 176 key = (RSAPublicKey) kf.generatePublic(new RSAPublicKeySpec(par1, 177 par2)); 178 } catch (Exception e) { 179 return null; 180 } 181 return key; 182 } 183 184 /** 185 * Returns message type 186 * @return 187 */ 188 @Override 189 public int getType() { 190 return Handshake.SERVER_KEY_EXCHANGE; 191 } 192 193} 194