Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/quite/humla-spongycastle.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/java/org/spongycastle/crypto/tls/TlsECDHKeyExchange.java')
-rw-r--r--core/src/main/java/org/spongycastle/crypto/tls/TlsECDHKeyExchange.java219
1 files changed, 219 insertions, 0 deletions
diff --git a/core/src/main/java/org/spongycastle/crypto/tls/TlsECDHKeyExchange.java b/core/src/main/java/org/spongycastle/crypto/tls/TlsECDHKeyExchange.java
new file mode 100644
index 00000000..87ecaedb
--- /dev/null
+++ b/core/src/main/java/org/spongycastle/crypto/tls/TlsECDHKeyExchange.java
@@ -0,0 +1,219 @@
+package org.spongycastle.crypto.tls;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Vector;
+
+import org.spongycastle.asn1.x509.KeyUsage;
+import org.spongycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.spongycastle.crypto.params.AsymmetricKeyParameter;
+import org.spongycastle.crypto.params.ECDomainParameters;
+import org.spongycastle.crypto.params.ECPrivateKeyParameters;
+import org.spongycastle.crypto.params.ECPublicKeyParameters;
+import org.spongycastle.crypto.util.PublicKeyFactory;
+
+/**
+ * ECDH key exchange (see RFC 4492)
+ */
+public class TlsECDHKeyExchange extends AbstractTlsKeyExchange
+{
+ protected TlsSigner tlsSigner;
+ protected int[] namedCurves;
+ protected short[] clientECPointFormats, serverECPointFormats;
+
+ protected AsymmetricKeyParameter serverPublicKey;
+ protected TlsAgreementCredentials agreementCredentials;
+
+ protected ECPrivateKeyParameters ecAgreePrivateKey;
+ protected ECPublicKeyParameters ecAgreePublicKey;
+
+ public TlsECDHKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, int[] namedCurves,
+ short[] clientECPointFormats, short[] serverECPointFormats)
+ {
+ super(keyExchange, supportedSignatureAlgorithms);
+
+ switch (keyExchange)
+ {
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ this.tlsSigner = new TlsRSASigner();
+ break;
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ this.tlsSigner = new TlsECDSASigner();
+ break;
+ case KeyExchangeAlgorithm.ECDH_RSA:
+ case KeyExchangeAlgorithm.ECDH_ECDSA:
+ this.tlsSigner = null;
+ break;
+ default:
+ throw new IllegalArgumentException("unsupported key exchange algorithm");
+ }
+
+ this.keyExchange = keyExchange;
+ this.namedCurves = namedCurves;
+ this.clientECPointFormats = clientECPointFormats;
+ this.serverECPointFormats = serverECPointFormats;
+ }
+
+ public void init(TlsContext context)
+ {
+ super.init(context);
+
+ if (this.tlsSigner != null)
+ {
+ this.tlsSigner.init(context);
+ }
+ }
+
+ public void skipServerCredentials() throws IOException
+ {
+ throw new TlsFatalAlert(AlertDescription.unexpected_message);
+ }
+
+ public void processServerCertificate(Certificate serverCertificate) throws IOException
+ {
+ if (serverCertificate.isEmpty())
+ {
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+ }
+
+ org.spongycastle.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);
+ }
+
+ if (tlsSigner == null)
+ {
+ try
+ {
+ this.ecAgreePublicKey = TlsECCUtils.validateECPublicKey((ECPublicKeyParameters) this.serverPublicKey);
+ }
+ catch (ClassCastException e)
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+
+ TlsUtils.validateKeyUsage(x509Cert, KeyUsage.keyAgreement);
+ }
+ else
+ {
+ if (!tlsSigner.isValidPublicKey(this.serverPublicKey))
+ {
+ throw new TlsFatalAlert(AlertDescription.certificate_unknown);
+ }
+
+ TlsUtils.validateKeyUsage(x509Cert, KeyUsage.digitalSignature);
+ }
+
+ super.processServerCertificate(serverCertificate);
+ }
+
+ public boolean requiresServerKeyExchange()
+ {
+ switch (keyExchange)
+ {
+ case KeyExchangeAlgorithm.ECDHE_ECDSA:
+ case KeyExchangeAlgorithm.ECDHE_RSA:
+ case KeyExchangeAlgorithm.ECDH_anon:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public void validateCertificateRequest(CertificateRequest certificateRequest) throws IOException
+ {
+ /*
+ * RFC 4492 3. [...] The ECDSA_fixed_ECDH and RSA_fixed_ECDH mechanisms are usable with
+ * ECDH_ECDSA and ECDH_RSA. Their use with ECDHE_ECDSA and ECDHE_RSA is prohibited because
+ * the use of a long-term ECDH client key would jeopardize the forward secrecy property of
+ * these algorithms.
+ */
+ 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:
+ case ClientCertificateType.rsa_fixed_ecdh:
+ case ClientCertificateType.ecdsa_fixed_ecdh:
+ break;
+ default:
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+ }
+ }
+
+ public void processClientCredentials(TlsCredentials clientCredentials) throws IOException
+ {
+ if (clientCredentials instanceof TlsAgreementCredentials)
+ {
+ // TODO Validate client cert has matching parameters (see 'TlsECCUtils.areOnSameCurve')?
+
+ this.agreementCredentials = (TlsAgreementCredentials) clientCredentials;
+ }
+ else if (clientCredentials instanceof TlsSignerCredentials)
+ {
+ // OK
+ }
+ else
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+ }
+
+ public void generateClientKeyExchange(OutputStream output) throws IOException
+ {
+ if (agreementCredentials == null)
+ {
+ this.ecAgreePrivateKey = TlsECCUtils.generateEphemeralClientKeyExchange(context.getSecureRandom(),
+ serverECPointFormats, ecAgreePublicKey.getParameters(), output);
+ }
+ }
+
+ public void processClientCertificate(Certificate clientCertificate) throws IOException
+ {
+ // TODO Extract the public key
+ // TODO If the certificate is 'fixed', take the public key as ecAgreeClientPublicKey
+ }
+
+ public void processClientKeyExchange(InputStream input) throws IOException
+ {
+ if (ecAgreePublicKey != null)
+ {
+ // For ecdsa_fixed_ecdh and rsa_fixed_ecdh, the key arrived in the client certificate
+ return;
+ }
+
+ byte[] point = TlsUtils.readOpaque8(input);
+
+ ECDomainParameters curve_params = this.ecAgreePrivateKey.getParameters();
+
+ this.ecAgreePublicKey = TlsECCUtils.validateECPublicKey(TlsECCUtils.deserializeECPublicKey(
+ serverECPointFormats, curve_params, point));
+ }
+
+ public byte[] generatePremasterSecret() throws IOException
+ {
+ if (agreementCredentials != null)
+ {
+ return agreementCredentials.generateAgreement(ecAgreePublicKey);
+ }
+
+ if (ecAgreePrivateKey != null)
+ {
+ return TlsECCUtils.calculateECDHBasicAgreement(ecAgreePublicKey, ecAgreePrivateKey);
+ }
+
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+}