| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @author Boris Kuznetsov |
| * @version $Revision$ |
| */ |
| |
| package org.apache.harmony.xnet.provider.jsse; |
| |
| import org.apache.harmony.xnet.provider.jsse.Message; |
| |
| import java.io.IOException; |
| import java.math.BigInteger; |
| import java.security.KeyFactory; |
| import java.security.interfaces.RSAPublicKey; |
| import java.security.spec.RSAPublicKeySpec; |
| |
| /** |
| * |
| * Represents server key exchange message. |
| * @see <a href="http://www.ietf.org/rfc/rfc2246.txt">TLS 1.0 spec., 7.4.3. |
| * Server key exchange message.</a> |
| * |
| */ |
| public class ServerKeyExchange extends Message { |
| |
| // ServerRSAParams ServerDHParams |
| final BigInteger par1; // rsa_modulus dh_p |
| final byte[] bytes1; |
| |
| final BigInteger par2; // rsa_exponent dh_g |
| final byte[] bytes2; |
| |
| final BigInteger par3; // dh_Ys |
| final byte[] bytes3; |
| |
| /** |
| * Signature |
| */ |
| final byte[] hash; |
| |
| private RSAPublicKey key; |
| |
| /** |
| * Creates outbound message |
| * @param par1 rsa_modulus or dh_p |
| * @param par2 rsa_exponent or dh_g |
| * @param par3 dh_Ys for ServerDHParams; should be null for ServerRSAParams |
| * @param hash should be null for anonymous SignatureAlgorithm |
| */ |
| public ServerKeyExchange(BigInteger par1, BigInteger par2, BigInteger par3, |
| byte[] hash) { |
| this.par1 = par1; |
| this.par2 = par2; |
| this.par3 = par3; |
| this.hash = hash; |
| |
| byte[] bb = this.par1.toByteArray(); |
| if (bb[0] == 0) { |
| // XXX check for par1 == 0 or bb.length > 1 |
| bytes1 = new byte[bb.length - 1]; |
| System.arraycopy(bb, 1, bytes1, 0, bytes1.length); |
| } else { |
| bytes1 = bb; |
| } |
| |
| bb = this.par2.toByteArray(); |
| if (bb[0] == 0) { |
| bytes2 = new byte[bb.length - 1]; |
| System.arraycopy(bb, 1, bytes2, 0, bytes2.length); |
| } else { |
| bytes2 = bb; |
| } |
| |
| length = 4 + bytes1.length + bytes2.length; |
| if (hash != null) { |
| length += 2 + hash.length; |
| } |
| if (par3 == null) { |
| bytes3 = null; |
| return; |
| } |
| bb = this.par3.toByteArray(); |
| if (bb[0] == 0) { |
| bytes3 = new byte[bb.length - 1]; |
| System.arraycopy(bb, 1, bytes3, 0, bytes3.length); |
| } else { |
| bytes3 = bb; |
| } |
| length += 2 + bytes3.length; |
| } |
| |
| /** |
| * Creates inbound message |
| * @param in |
| * @param length |
| * @param keyExchange |
| * @throws IOException |
| */ |
| public ServerKeyExchange(HandshakeIODataStream in, int length, |
| int keyExchange) throws IOException { |
| |
| int size = in.readUint16(); |
| bytes1 = in.read(size); |
| par1 = new BigInteger(1, bytes1); |
| this.length = 2 + bytes1.length; |
| size = in.readUint16(); |
| bytes2 = in.read(size); |
| par2 = new BigInteger(1, bytes2); |
| this.length += 2 + bytes2.length; |
| if (keyExchange != CipherSuite.KeyExchange_RSA_EXPORT) { |
| size = in.readUint16(); |
| bytes3 = in.read(size); |
| par3 = new BigInteger(1, bytes3); |
| this.length += 2 + bytes3.length; |
| } else { |
| par3 = null; |
| bytes3 = null; |
| } |
| if (keyExchange != CipherSuite.KeyExchange_DH_anon_EXPORT |
| && keyExchange != CipherSuite.KeyExchange_DH_anon) { |
| size = in.readUint16(); |
| hash = in.read(size); |
| this.length += 2 + hash.length; |
| } else { |
| hash = null; |
| } |
| if (this.length != length) { |
| fatalAlert(AlertProtocol.DECODE_ERROR, |
| "DECODE ERROR: incorrect ServerKeyExchange"); |
| } |
| } |
| |
| /** |
| * Sends message |
| * @param out |
| */ |
| public void send(HandshakeIODataStream out) { |
| out.writeUint16(bytes1.length); |
| out.write(bytes1); |
| out.writeUint16(bytes2.length); |
| out.write(bytes2); |
| if (bytes3 != null) { |
| out.writeUint16(bytes3.length); |
| out.write(bytes3); |
| } |
| if (hash != null) { |
| out.writeUint16(hash.length); |
| out.write(hash); |
| } |
| } |
| |
| /** |
| * Returns RSAPublicKey generated using ServerRSAParams |
| * (rsa_modulus and rsa_exponent). |
| * |
| * @return |
| */ |
| public RSAPublicKey getRSAPublicKey() { |
| if (key != null) { |
| return key; |
| } |
| try { |
| KeyFactory kf = KeyFactory.getInstance("RSA"); |
| key = (RSAPublicKey) kf.generatePublic(new RSAPublicKeySpec(par1, |
| par2)); |
| } catch (Exception e) { |
| return null; |
| } |
| return key; |
| } |
| |
| /** |
| * Returns message type |
| * @return |
| */ |
| public int getType() { |
| return Handshake.SERVER_KEY_EXCHANGE; |
| } |
| |
| } |