blob: fea80768083d0a0491ce53d763777f1628209432 [file] [log] [blame]
/*
* 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 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;
bytes1 = toUnsignedByteArray(this.par1);
bytes2 = toUnsignedByteArray(this.par2);
length = 4 + bytes1.length + bytes2.length;
if (hash != null) {
length += 2 + hash.length;
}
if (par3 == null) {
bytes3 = null;
return;
}
bytes3 = toUnsignedByteArray(this.par3);
length += 2 + bytes3.length;
}
/**
* Remove first byte if 0. Needed because BigInteger.toByteArray() sometimes
* returns a zero prefix.
*/
public static byte[] toUnsignedByteArray(BigInteger bi) {
if (bi == null) {
return null;
}
byte[] bb = bi.toByteArray();
// bb is not null, and has at least 1 byte - ZERO is represented as [0]
if (bb[0] == 0) {
byte[] noZero = new byte[bb.length - 1];
System.arraycopy(bb, 1, noZero, 0, noZero.length);
return noZero;
} else {
return bb;
}
}
/**
* 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.KEY_EXCHANGE_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.KEY_EXCHANGE_DH_anon_EXPORT
&& keyExchange != CipherSuite.KEY_EXCHANGE_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;
}
}