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.
/** * (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; } }