/* * 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. */ 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 */ @Override 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 */ @Override public int getType() { return Handshake.SERVER_KEY_EXCHANGE; } }