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