blob: 3efdd6c83c35c93c89818acee241468263511f6f [file] [log] [blame]
package org.bouncycastle.crypto.tls;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Vector;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.util.io.Streams;
/**
* (D)TLS and SSLv3 RSA key exchange.
*/
public class TlsRSAKeyExchange
extends AbstractTlsKeyExchange
{
protected AsymmetricKeyParameter serverPublicKey = null;
protected RSAKeyParameters rsaServerPublicKey = null;
protected TlsEncryptionCredentials serverCredentials = null;
protected byte[] premasterSecret;
public TlsRSAKeyExchange(Vector supportedSignatureAlgorithms)
{
super(KeyExchangeAlgorithm.RSA, supportedSignatureAlgorithms);
}
public void skipServerCredentials()
throws IOException
{
throw new TlsFatalAlert(AlertDescription.unexpected_message);
}
public void processServerCredentials(TlsCredentials serverCredentials)
throws IOException
{
if (!(serverCredentials instanceof TlsEncryptionCredentials))
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
processServerCertificate(serverCredentials.getCertificate());
this.serverCredentials = (TlsEncryptionCredentials)serverCredentials;
}
public void processServerCertificate(Certificate serverCertificate)
throws IOException
{
if (serverCertificate.isEmpty())
{
throw new TlsFatalAlert(AlertDescription.bad_certificate);
}
org.bouncycastle.asn1.x509.Certificate x509Cert = serverCertificate.getCertificateAt(0);
SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();
try
{
this.serverPublicKey = PublicKeyFactory.createKey(keyInfo);
}
catch (RuntimeException e)
{
throw new TlsFatalAlert(AlertDescription.unsupported_certificate, e);
}
// Sanity check the PublicKeyFactory
if (this.serverPublicKey.isPrivate())
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
this.rsaServerPublicKey = validateRSAPublicKey((RSAKeyParameters)this.serverPublicKey);
TlsUtils.validateKeyUsage(x509Cert, KeyUsage.keyEncipherment);
super.processServerCertificate(serverCertificate);
}
public void validateCertificateRequest(CertificateRequest certificateRequest)
throws IOException
{
short[] types = certificateRequest.getCertificateTypes();
for (int i = 0; i < types.length; ++i)
{
switch (types[i])
{
case ClientCertificateType.rsa_sign:
case ClientCertificateType.dss_sign:
case ClientCertificateType.ecdsa_sign:
break;
default:
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
}
}
public void processClientCredentials(TlsCredentials clientCredentials)
throws IOException
{
if (!(clientCredentials instanceof TlsSignerCredentials))
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
}
public void generateClientKeyExchange(OutputStream output)
throws IOException
{
this.premasterSecret = TlsRSAUtils.generateEncryptedPreMasterSecret(context, rsaServerPublicKey, output);
}
public void processClientKeyExchange(InputStream input)
throws IOException
{
byte[] encryptedPreMasterSecret;
if (TlsUtils.isSSL(context))
{
// TODO Do any SSLv3 clients actually include the length?
encryptedPreMasterSecret = Streams.readAll(input);
}
else
{
encryptedPreMasterSecret = TlsUtils.readOpaque16(input);
}
this.premasterSecret = serverCredentials.decryptPreMasterSecret(encryptedPreMasterSecret);
}
public byte[] generatePremasterSecret()
throws IOException
{
if (this.premasterSecret == null)
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
byte[] tmp = this.premasterSecret;
this.premasterSecret = null;
return tmp;
}
// Would be needed to process RSA_EXPORT server key exchange
// protected void processRSAServerKeyExchange(InputStream is, Signer signer) throws IOException
// {
// InputStream sigIn = is;
// if (signer != null)
// {
// sigIn = new SignerInputStream(is, signer);
// }
//
// byte[] modulusBytes = TlsUtils.readOpaque16(sigIn);
// byte[] exponentBytes = TlsUtils.readOpaque16(sigIn);
//
// if (signer != null)
// {
// byte[] sigByte = TlsUtils.readOpaque16(is);
//
// if (!signer.verifySignature(sigByte))
// {
// handler.failWithError(AlertLevel.fatal, AlertDescription.bad_certificate);
// }
// }
//
// BigInteger modulus = new BigInteger(1, modulusBytes);
// BigInteger exponent = new BigInteger(1, exponentBytes);
//
// this.rsaServerPublicKey = validateRSAPublicKey(new RSAKeyParameters(false, modulus,
// exponent));
// }
protected RSAKeyParameters validateRSAPublicKey(RSAKeyParameters key)
throws IOException
{
// TODO What is the minimum bit length required?
// key.getModulus().bitLength();
if (!key.getExponent().isProbablePrime(2))
{
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
return key;
}
}