net.jradius.tls.TlsRSAKeyExchange Maven / Gradle / Ivy
package net.jradius.tls;
import java.io.IOException;
import java.io.InputStream;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509CertificateStructure;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.asn1.x509.X509Extensions;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.encodings.PKCS1Encoding;
import org.bouncycastle.crypto.engines.RSABlindedEngine;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.util.PublicKeyFactory;
/**
* TLS 1.0 RSA key exchange.
*/
class TlsRSAKeyExchange implements TlsKeyExchange
{
private TlsProtocolHandler handler;
private CertificateVerifyer verifyer;
private AsymmetricKeyParameter serverPublicKey = null;
private RSAKeyParameters rsaServerPublicKey = null;
private byte[] premasterSecret;
TlsRSAKeyExchange(TlsProtocolHandler handler, CertificateVerifyer verifyer)
{
this.handler = handler;
this.verifyer = verifyer;
}
public void skipServerCertificate() throws IOException
{
handler.failWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_unexpected_message);
}
public void processServerCertificate(Certificate serverCertificate) throws IOException
{
X509CertificateStructure x509Cert = serverCertificate.certs[0];
SubjectPublicKeyInfo keyInfo = x509Cert.getSubjectPublicKeyInfo();
try
{
this.serverPublicKey = PublicKeyFactory.createKey(keyInfo);
}
catch (RuntimeException e)
{
handler.failWithError(TlsProtocolHandler.AL_fatal,
TlsProtocolHandler.AP_unsupported_certificate);
}
// Sanity check the PublicKeyFactory
if (this.serverPublicKey.isPrivate())
{
handler.failWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_internal_error);
}
// TODO
/*
* Perform various checks per RFC2246 7.4.2: "Unless otherwise specified, the
* signing algorithm for the certificate must be the same as the algorithm for the
* certificate key."
*/
// TODO Should the 'instanceof' tests be replaces with stricter checks on keyInfo.getAlgorithmId()?
if (!(this.serverPublicKey instanceof RSAKeyParameters))
{
handler.failWithError(TlsProtocolHandler.AL_fatal,
TlsProtocolHandler.AP_certificate_unknown);
}
validateKeyUsage(x509Cert, KeyUsage.keyEncipherment);
this.rsaServerPublicKey = validateRSAPublicKey((RSAKeyParameters)this.serverPublicKey);
/*
* Verify them.
*/
if (!this.verifyer.isValid(serverCertificate.getCerts()))
{
handler.failWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_user_canceled);
}
}
public void skipServerKeyExchange() throws IOException
{
// OK
}
public void processServerKeyExchange(InputStream is, SecurityParameters securityParameters)
throws IOException
{
handler.failWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_unexpected_message);
}
public byte[] generateClientKeyExchange() throws IOException
{
/*
* Choose a PremasterSecret and send it encrypted to the server
*/
premasterSecret = new byte[48];
handler.getRandom().nextBytes(premasterSecret);
TlsUtils.writeVersion(premasterSecret, 0);
PKCS1Encoding encoding = new PKCS1Encoding(new RSABlindedEngine());
encoding.init(true, new ParametersWithRandom(this.rsaServerPublicKey, handler.getRandom()));
try
{
return encoding.processBlock(premasterSecret, 0, premasterSecret.length);
}
catch (InvalidCipherTextException e)
{
/*
* This should never happen, only during decryption.
*/
handler.failWithError(TlsProtocolHandler.AL_fatal, TlsProtocolHandler.AP_internal_error);
return null; // Unreachable!
}
}
public byte[] generatePremasterSecret() throws IOException
{
byte[] tmp = this.premasterSecret;
this.premasterSecret = null;
return tmp;
}
private void validateKeyUsage(X509CertificateStructure c, int keyUsageBits) throws IOException
{
X509Extensions exts = c.getTBSCertificate().getExtensions();
if (exts != null)
{
X509Extension ext = exts.getExtension(X509Extensions.KeyUsage);
if (ext != null)
{
DERBitString ku = KeyUsage.getInstance(ext);
int bits = ku.getBytes()[0] & 0xff;
if ((bits & keyUsageBits) != keyUsageBits)
{
handler.failWithError(TlsProtocolHandler.AL_fatal,
TlsProtocolHandler.AP_certificate_unknown);
}
}
}
}
// private 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(TlsProtocolHandler.AL_fatal,
// TlsProtocolHandler.AP_bad_certificate);
// }
// }
//
// BigInteger modulus = new BigInteger(1, modulusBytes);
// BigInteger exponent = new BigInteger(1, exponentBytes);
//
// this.rsaServerPublicKey = validateRSAPublicKey(new RSAKeyParameters(false, modulus,
// exponent));
// }
private RSAKeyParameters validateRSAPublicKey(RSAKeyParameters key) throws IOException
{
// TODO What is the minimum bit length required?
// key.getModulus().bitLength();
if (!key.getExponent().isProbablePrime(2))
{
handler.failWithError(TlsProtocolHandler.AL_fatal,
TlsProtocolHandler.AP_illegal_parameter);
}
return key;
}
}