diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-08-24 16:47:32 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2014-08-24 16:47:32 +0700 |
commit | da656890c709963fb112d4813a2542302994bb35 (patch) | |
tree | 9cf32b3ce55555eea21fc95fe8f19844f3134550 /crypto/test | |
parent | Add TLS test data from Java API (diff) | |
download | BouncyCastle.NET-ed25519-da656890c709963fb112d4813a2542302994bb35.tar.xz |
Finish initial porting of TLS 1.2 client from Java API
Diffstat (limited to 'crypto/test')
-rw-r--r-- | crypto/test/src/crypto/tls/test/MockTlsClient.cs | 158 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/TlsClientTest.cs | 66 | ||||
-rw-r--r-- | crypto/test/src/crypto/tls/test/TlsTestUtilities.cs | 137 |
3 files changed, 361 insertions, 0 deletions
diff --git a/crypto/test/src/crypto/tls/test/MockTlsClient.cs b/crypto/test/src/crypto/tls/test/MockTlsClient.cs new file mode 100644 index 000000000..c22e98367 --- /dev/null +++ b/crypto/test/src/crypto/tls/test/MockTlsClient.cs @@ -0,0 +1,158 @@ +using System; +using System.Collections; +using System.IO; + +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; + +namespace Org.BouncyCastle.Crypto.Tls.Test +{ + internal class MockTlsClient + : DefaultTlsClient + { + internal TlsSession mSession; + + internal MockTlsClient(TlsSession session) + { + this.mSession = session; + } + + public override TlsSession GetSessionToResume() + { + return this.mSession; + } + + public override void NotifyAlertRaised(byte alertLevel, byte alertDescription, string message, Exception cause) + { + TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out; + output.WriteLine("TLS client raised alert (AlertLevel." + alertLevel + ", AlertDescription." + alertDescription + + ")"); + if (message != null) + { + output.WriteLine("> " + message); + } + if (cause != null) + { + output.WriteLine(cause.StackTrace); + } + } + + public override void NotifyAlertReceived(byte alertLevel, byte alertDescription) + { + TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out; + output.WriteLine("TLS client received alert (AlertLevel." + alertLevel + ", AlertDescription." + + alertDescription + ")"); + } + + public override int[] GetCipherSuites() + { + return Arrays.Concatenate(base.GetCipherSuites(), + new int[] + { + CipherSuite.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + CipherSuite.TLS_ECDHE_RSA_WITH_ESTREAM_SALSA20_SHA1, + CipherSuite.TLS_ECDHE_RSA_WITH_SALSA20_SHA1, + CipherSuite.TLS_RSA_WITH_ESTREAM_SALSA20_SHA1, + CipherSuite.TLS_RSA_WITH_SALSA20_SHA1, + }); + } + + public override IDictionary GetClientExtensions() + { + IDictionary clientExtensions = TlsExtensionsUtilities.EnsureExtensionsInitialised(base.GetClientExtensions()); + TlsExtensionsUtilities.AddEncryptThenMacExtension(clientExtensions); + TlsExtensionsUtilities.AddMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9); + TlsExtensionsUtilities.AddTruncatedHMacExtension(clientExtensions); + return clientExtensions; + } + + public override void NotifyServerVersion(ProtocolVersion serverVersion) + { + base.NotifyServerVersion(serverVersion); + + Console.WriteLine("TLS client negotiated " + serverVersion); + } + + public override TlsAuthentication GetAuthentication() + { + return new MyTlsAuthentication(mContext); + } + + public override void NotifyHandshakeComplete() + { + base.NotifyHandshakeComplete(); + + TlsSession newSession = mContext.ResumableSession; + if (newSession != null) + { + byte[] newSessionID = newSession.SessionID; + string hex = Hex.ToHexString(newSessionID); + + if (this.mSession != null && Arrays.AreEqual(this.mSession.SessionID, newSessionID)) + { + Console.WriteLine("Resumed session: " + hex); + } + else + { + Console.WriteLine("Established session: " + hex); + } + + this.mSession = newSession; + } + } + + internal class MyTlsAuthentication + : TlsAuthentication + { + private readonly TlsContext mContext; + + internal MyTlsAuthentication(TlsContext context) + { + this.mContext = context; + } + + public virtual void NotifyServerCertificate(Certificate serverCertificate) + { + X509CertificateStructure[] chain = serverCertificate.GetCertificateList(); + Console.WriteLine("TLS client received server certificate chain of length " + chain.Length); + for (int i = 0; i != chain.Length; i++) + { + X509CertificateStructure entry = chain[i]; + // TODO Create Fingerprint based on certificate signature algorithm digest + Console.WriteLine(" Fingerprint:SHA-256 " + TlsTestUtilities.Fingerprint(entry) + " (" + + entry.Subject + ")"); + } + } + + public virtual TlsCredentials GetClientCredentials(CertificateRequest certificateRequest) + { + byte[] certificateTypes = certificateRequest.CertificateTypes; + if (certificateTypes == null || !Arrays.Contains(certificateTypes, ClientCertificateType.rsa_sign)) + return null; + + SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; + IList sigAlgs = certificateRequest.SupportedSignatureAlgorithms; + if (sigAlgs != null) + { + foreach (SignatureAndHashAlgorithm sigAlg in sigAlgs) + { + if (sigAlg.Signature == SignatureAlgorithm.rsa) + { + signatureAndHashAlgorithm = sigAlg; + break; + } + } + + if (signatureAndHashAlgorithm == null) + { + return null; + } + } + + return TlsTestUtilities.LoadSignerCredentials(mContext, new string[] { "x509-client.pem", "x509-ca.pem" }, + "x509-client-key.pem", signatureAndHashAlgorithm); + } + }; + } +} diff --git a/crypto/test/src/crypto/tls/test/TlsClientTest.cs b/crypto/test/src/crypto/tls/test/TlsClientTest.cs new file mode 100644 index 000000000..e68f1934c --- /dev/null +++ b/crypto/test/src/crypto/tls/test/TlsClientTest.cs @@ -0,0 +1,66 @@ +using System; +using System.IO; +using System.Net.Sockets; +using System.Text; + +using Org.BouncyCastle.Security; + +namespace Org.BouncyCastle.Crypto.Tls.Test +{ + /** + * A simple test designed to conduct a TLS handshake with an external TLS server. + * <p/> + * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external TLS server. + */ + public class TlsClientTest + { + private static readonly SecureRandom secureRandom = new SecureRandom(); + + public static void Main(string[] args) + { + string hostname = "localhost"; + int port = 5556; + + long time1 = DateTime.UtcNow.Ticks; + + MockTlsClient client = new MockTlsClient(null); + TlsClientProtocol protocol = OpenTlsConnection(hostname, port, client); + protocol.Close(); + + long time2 = DateTime.UtcNow.Ticks; + Console.WriteLine("Elapsed 1: " + (time2 - time1)/TimeSpan.TicksPerMillisecond + "ms"); + + client = new MockTlsClient(client.GetSessionToResume()); + protocol = OpenTlsConnection(hostname, port, client); + + long time3 = DateTime.UtcNow.Ticks; + Console.WriteLine("Elapsed 2: " + (time3 - time2)/TimeSpan.TicksPerMillisecond + "ms"); + + byte[] req = Encoding.UTF8.GetBytes("GET / HTTP/1.1\r\n\r\n"); + + Stream tlsStream = protocol.Stream; + tlsStream.Write(req, 0, req.Length); + tlsStream.Flush(); + + StreamReader reader = new StreamReader(tlsStream); + + String line; + while ((line = reader.ReadLine()) != null) + { + Console.WriteLine(">>> " + line); + } + + protocol.Close(); + } + + internal static TlsClientProtocol OpenTlsConnection(string hostname, int port, TlsClient client) + { + TcpClient tcp = new TcpClient(hostname, port); + + TlsClientProtocol protocol = new TlsClientProtocol(tcp.GetStream(), secureRandom); + protocol.Connect(client); + return protocol; + } + } +} diff --git a/crypto/test/src/crypto/tls/test/TlsTestUtilities.cs b/crypto/test/src/crypto/tls/test/TlsTestUtilities.cs new file mode 100644 index 000000000..85a47d5e9 --- /dev/null +++ b/crypto/test/src/crypto/tls/test/TlsTestUtilities.cs @@ -0,0 +1,137 @@ +using System; +using System.IO; +using System.Text; + +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.Utilities.Encoders; +using Org.BouncyCastle.Utilities.IO.Pem; +using Org.BouncyCastle.Utilities.Test; + +namespace Org.BouncyCastle.Crypto.Tls.Test +{ + public abstract class TlsTestUtilities + { + internal static readonly byte[] RsaCertData = Base64 + .Decode("MIICUzCCAf2gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBjzELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb2" + + "4gb2YgdGhlIEJvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExLzAtBgkq" + + "hkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMB4XDTEzMDIyNTA2MDIwNVoXDTEzMDIyNT" + + "A2MDM0NVowgY8xCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIw" + + "EAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWVkYmFjay1jcnlwdG" + + "9AYm91bmN5Y2FzdGxlLm9yZzBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr5YtqKmKXmEGb4Shy" + + "pL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERo0QwQjAOBgNVHQ8BAf8EBAMCBSAwEgYDVR" + + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAHU55Ncz" + + "eglREcTg54YLUlGWu2WOYWhit/iM1eeq8Kivro7q98eW52jTuMI3CI5ulqd0hYzshQKQaZ5GDzErMyM="); + + internal static readonly byte[] DudRsaCertData = Base64 + .Decode("MIICUzCCAf2gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBjzELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb2" + + "4gb2YgdGhlIEJvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExLzAtBgkq" + + "hkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMB4XDTEzMDIyNTA1NDcyOFoXDTEzMDIyNT" + + "A1NDkwOFowgY8xCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIw" + + "EAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWVkYmFjay1jcnlwdG" + + "9AYm91bmN5Y2FzdGxlLm9yZzBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr5YtqKmKXmEGb4Shy" + + "pL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERo0QwQjAOBgNVHQ8BAf8EBAMCAAEwEgYDVR" + + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAJg55PBS" + + "weg6obRUKF4FF6fCrWFi6oCYSQ99LWcAeupc5BofW5MstFMhCOaEucuGVqunwT5G7/DweazzCIrSzB0="); + + internal static string Fingerprint(X509CertificateStructure c) + { + byte[] der = c.GetEncoded(); + byte[] sha1 = Sha256DigestOf(der); + byte[] hexBytes = Hex.Encode(sha1); + string hex = Platform.ToUpperInvariant(Encoding.ASCII.GetString(hexBytes)); + + StringBuilder fp = new StringBuilder(); + int i = 0; + fp.Append(hex.Substring(i, 2)); + while ((i += 2) < hex.Length) + { + fp.Append(':'); + fp.Append(hex.Substring(i, 2)); + } + return fp.ToString(); + } + + internal static byte[] Sha256DigestOf(byte[] input) + { + return DigestUtilities.CalculateDigest("SHA256", input); + } + + internal static TlsAgreementCredentials LoadAgreementCredentials(TlsContext context, + string[] certResources, string keyResource) + { + Certificate certificate = LoadCertificateChain(certResources); + AsymmetricKeyParameter privateKey = LoadPrivateKeyResource(keyResource); + + return new DefaultTlsAgreementCredentials(certificate, privateKey); + } + + internal static TlsEncryptionCredentials LoadEncryptionCredentials(TlsContext context, + string[] certResources, string keyResource) + { + Certificate certificate = LoadCertificateChain(certResources); + AsymmetricKeyParameter privateKey = LoadPrivateKeyResource(keyResource); + + return new DefaultTlsEncryptionCredentials(context, certificate, privateKey); + } + + internal static TlsSignerCredentials LoadSignerCredentials(TlsContext context, string[] certResources, + string keyResource, SignatureAndHashAlgorithm signatureAndHashAlgorithm) + { + Certificate certificate = LoadCertificateChain(certResources); + AsymmetricKeyParameter privateKey = LoadPrivateKeyResource(keyResource); + + return new DefaultTlsSignerCredentials(context, certificate, privateKey, signatureAndHashAlgorithm); + } + + internal static Certificate LoadCertificateChain(string[] resources) + { + X509CertificateStructure[] chain = new X509CertificateStructure[resources.Length]; + for (int i = 0; i < resources.Length; ++i) + { + chain[i] = LoadCertificateResource(resources[i]); + } + return new Certificate(chain); + } + + internal static X509CertificateStructure LoadCertificateResource(string resource) + { + PemObject pem = LoadPemResource(resource); + if (pem.Type.EndsWith("CERTIFICATE")) + { + return X509CertificateStructure.GetInstance(pem.Content); + } + throw new ArgumentException("doesn't specify a valid certificate", "resource"); + } + + internal static AsymmetricKeyParameter LoadPrivateKeyResource(string resource) + { + PemObject pem = LoadPemResource(resource); + if (pem.Type.EndsWith("RSA PRIVATE KEY")) + { + RsaPrivateKeyStructure rsa = RsaPrivateKeyStructure.GetInstance(pem.Content); + return new RsaPrivateCrtKeyParameters(rsa.Modulus, rsa.PublicExponent, + rsa.PrivateExponent, rsa.Prime1, rsa.Prime2, rsa.Exponent1, + rsa.Exponent2, rsa.Coefficient); + } + if (pem.Type.EndsWith("PRIVATE KEY")) + { + return PrivateKeyFactory.CreateKey(pem.Content); + } + throw new ArgumentException("doesn't specify a valid private key", "resource"); + } + + internal static PemObject LoadPemResource(string resource) + { + Stream s = SimpleTest.GetTestDataAsStream("tls." + resource); + PemReader p = new PemReader(new StreamReader(s)); + PemObject o = p.ReadPemObject(); + p.Reader.Close(); + return o; + } + } +} |