diff --git a/crypto/crypto.csproj b/crypto/crypto.csproj
index e6ab94ee2..e4bd2e036 100644
--- a/crypto/crypto.csproj
+++ b/crypto/crypto.csproj
@@ -11840,6 +11840,16 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\crypto\tls\test\DtlsTestClientProtocol.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
+ RelPath = "test\src\crypto\tls\test\DtlsTestServerProtocol.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\crypto\tls\test\DtlsTestSuite.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -11950,6 +11960,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\crypto\tls\test\TlsTestClientProtocol.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\crypto\tls\test\TlsTestConfig.cs"
SubType = "Code"
BuildAction = "Compile"
@@ -11960,6 +11975,11 @@
BuildAction = "Compile"
/>
<File
+ RelPath = "test\src\crypto\tls\test\TlsTestServerProtocol.cs"
+ SubType = "Code"
+ BuildAction = "Compile"
+ />
+ <File
RelPath = "test\src\crypto\tls\test\TlsTestSuite.cs"
SubType = "Code"
BuildAction = "Compile"
diff --git a/crypto/src/crypto/tls/DeferredHash.cs b/crypto/src/crypto/tls/DeferredHash.cs
index 1112d4a3c..f402f26d2 100644
--- a/crypto/src/crypto/tls/DeferredHash.cs
+++ b/crypto/src/crypto/tls/DeferredHash.cs
@@ -103,7 +103,7 @@ namespace Org.BouncyCastle.Crypto.Tls
{
IDigest d = (IDigest)mHashes[hashAlgorithm];
if (d == null)
- throw new InvalidOperationException("HashAlgorithm " + hashAlgorithm + " is not being tracked");
+ throw new InvalidOperationException("HashAlgorithm." + HashAlgorithm.GetText(hashAlgorithm) + " is not being tracked");
d = TlsUtilities.CloneHash(hashAlgorithm, d);
if (mBuf != null)
diff --git a/crypto/src/crypto/tls/DtlsServerProtocol.cs b/crypto/src/crypto/tls/DtlsServerProtocol.cs
index 9c7caf290..e2e9eddfc 100644
--- a/crypto/src/crypto/tls/DtlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/DtlsServerProtocol.cs
@@ -458,6 +458,9 @@ namespace Org.BouncyCastle.Crypto.Tls
protected virtual void ProcessCertificateVerify(ServerHandshakeState state, byte[] body, TlsHandshakeHash prepareFinishHash)
{
+ if (state.certificateRequest == null)
+ throw new InvalidOperationException();
+
MemoryStream buf = new MemoryStream(body, false);
TlsServerContextImpl context = state.serverContext;
@@ -466,13 +469,15 @@ namespace Org.BouncyCastle.Crypto.Tls
TlsProtocol.AssertEmpty(buf);
// Verify the CertificateVerify message contains a correct signature.
- bool verified = false;
try
{
+ SignatureAndHashAlgorithm signatureAlgorithm = clientCertificateVerify.Algorithm;
+
byte[] hash;
if (TlsUtilities.IsTlsV12(context))
{
- hash = prepareFinishHash.GetFinalHash(clientCertificateVerify.Algorithm.Hash);
+ TlsUtilities.VerifySupportedSignatureAlgorithm(state.certificateRequest.SupportedSignatureAlgorithms, signatureAlgorithm);
+ hash = prepareFinishHash.GetFinalHash(signatureAlgorithm.Hash);
}
else
{
@@ -485,15 +490,17 @@ namespace Org.BouncyCastle.Crypto.Tls
TlsSigner tlsSigner = TlsUtilities.CreateTlsSigner((byte)state.clientCertificateType);
tlsSigner.Init(context);
- verified = tlsSigner.VerifyRawSignature(clientCertificateVerify.Algorithm,
- clientCertificateVerify.Signature, publicKey, hash);
+ if (!tlsSigner.VerifyRawSignature(signatureAlgorithm, clientCertificateVerify.Signature, publicKey, hash))
+ throw new TlsFatalAlert(AlertDescription.decrypt_error);
}
- catch (Exception)
+ catch (TlsFatalAlert e)
{
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new TlsFatalAlert(AlertDescription.decrypt_error, e);
}
-
- if (!verified)
- throw new TlsFatalAlert(AlertDescription.decrypt_error);
}
protected virtual void ProcessClientHello(ServerHandshakeState state, byte[] body)
diff --git a/crypto/src/crypto/tls/HashAlgorithm.cs b/crypto/src/crypto/tls/HashAlgorithm.cs
index ac6def26f..ff540d2e0 100644
--- a/crypto/src/crypto/tls/HashAlgorithm.cs
+++ b/crypto/src/crypto/tls/HashAlgorithm.cs
@@ -12,5 +12,33 @@ namespace Org.BouncyCastle.Crypto.Tls
public const byte sha256 = 4;
public const byte sha384 = 5;
public const byte sha512 = 6;
+
+ public static string GetName(byte hashAlgorithm)
+ {
+ switch (hashAlgorithm)
+ {
+ case none:
+ return "none";
+ case md5:
+ return "md5";
+ case sha1:
+ return "sha1";
+ case sha224:
+ return "sha224";
+ case sha256:
+ return "sha256";
+ case sha384:
+ return "sha384";
+ case sha512:
+ return "sha512";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ public static string GetText(byte hashAlgorithm)
+ {
+ return GetName(hashAlgorithm) + "(" + hashAlgorithm + ")";
+ }
}
}
diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs
index 4ab628b13..5716c0cd1 100644
--- a/crypto/src/crypto/tls/TlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/TlsServerProtocol.cs
@@ -460,6 +460,9 @@ namespace Org.BouncyCastle.Crypto.Tls
protected virtual void ReceiveCertificateVerifyMessage(MemoryStream buf)
{
+ if (mCertificateRequest == null)
+ throw new InvalidOperationException();
+
DigitallySigned clientCertificateVerify = DigitallySigned.Parse(Context, buf);
AssertEmpty(buf);
@@ -467,10 +470,13 @@ namespace Org.BouncyCastle.Crypto.Tls
// Verify the CertificateVerify message contains a correct signature.
try
{
+ SignatureAndHashAlgorithm signatureAlgorithm = clientCertificateVerify.Algorithm;
+
byte[] hash;
if (TlsUtilities.IsTlsV12(Context))
{
- hash = mPrepareFinishHash.GetFinalHash(clientCertificateVerify.Algorithm.Hash);
+ TlsUtilities.VerifySupportedSignatureAlgorithm(mCertificateRequest.SupportedSignatureAlgorithms, signatureAlgorithm);
+ hash = mPrepareFinishHash.GetFinalHash(signatureAlgorithm.Hash);
}
else
{
@@ -483,11 +489,12 @@ namespace Org.BouncyCastle.Crypto.Tls
TlsSigner tlsSigner = TlsUtilities.CreateTlsSigner((byte)mClientCertificateType);
tlsSigner.Init(Context);
- if (!tlsSigner.VerifyRawSignature(clientCertificateVerify.Algorithm,
- clientCertificateVerify.Signature, publicKey, hash))
- {
+ if (!tlsSigner.VerifyRawSignature(signatureAlgorithm, clientCertificateVerify.Signature, publicKey, hash))
throw new TlsFatalAlert(AlertDescription.decrypt_error);
- }
+ }
+ catch (TlsFatalAlert e)
+ {
+ throw e;
}
catch (Exception e)
{
diff --git a/crypto/src/crypto/tls/TlsUtilities.cs b/crypto/src/crypto/tls/TlsUtilities.cs
index 26fb0d5e8..7d1d488d7 100644
--- a/crypto/src/crypto/tls/TlsUtilities.cs
+++ b/crypto/src/crypto/tls/TlsUtilities.cs
@@ -129,14 +129,24 @@ namespace Org.BouncyCastle.Crypto.Tls
return context.ServerVersion.IsSsl;
}
+ public static bool IsTlsV11(ProtocolVersion version)
+ {
+ return ProtocolVersion.TLSv11.IsEqualOrEarlierVersionOf(version.GetEquivalentTLSVersion());
+ }
+
public static bool IsTlsV11(TlsContext context)
{
- return ProtocolVersion.TLSv11.IsEqualOrEarlierVersionOf(context.ServerVersion.GetEquivalentTLSVersion());
+ return IsTlsV11(context.ServerVersion);
+ }
+
+ public static bool IsTlsV12(ProtocolVersion version)
+ {
+ return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(version.GetEquivalentTLSVersion());
}
public static bool IsTlsV12(TlsContext context)
{
- return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(context.ServerVersion.GetEquivalentTLSVersion());
+ return IsTlsV12(context.ServerVersion);
}
public static void WriteUint8(byte i, Stream output)
@@ -712,11 +722,10 @@ namespace Org.BouncyCastle.Crypto.Tls
public static void EncodeSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms, bool allowAnonymous,
Stream output)
{
- if (supportedSignatureAlgorithms == null || supportedSignatureAlgorithms.Count < 1
- || supportedSignatureAlgorithms.Count >= (1 << 15))
- {
+ if (supportedSignatureAlgorithms == null)
+ throw new ArgumentNullException("supportedSignatureAlgorithms");
+ if (supportedSignatureAlgorithms.Count < 1 || supportedSignatureAlgorithms.Count >= (1 << 15))
throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms");
- }
// supported_signature_algorithms
int length = 2 * supportedSignatureAlgorithms.Count;
@@ -762,6 +771,27 @@ namespace Org.BouncyCastle.Crypto.Tls
return supportedSignatureAlgorithms;
}
+ public static void VerifySupportedSignatureAlgorithm(IList supportedSignatureAlgorithms, SignatureAndHashAlgorithm signatureAlgorithm)
+ {
+ if (supportedSignatureAlgorithms == null)
+ throw new ArgumentNullException("supportedSignatureAlgorithms");
+ if (supportedSignatureAlgorithms.Count < 1 || supportedSignatureAlgorithms.Count >= (1 << 15))
+ throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms");
+ if (signatureAlgorithm == null)
+ throw new ArgumentNullException("signatureAlgorithm");
+
+ if (signatureAlgorithm.Signature != SignatureAlgorithm.anonymous)
+ {
+ foreach (SignatureAndHashAlgorithm entry in supportedSignatureAlgorithms)
+ {
+ if (entry.Hash == signatureAlgorithm.Hash && entry.Signature == signatureAlgorithm.Signature)
+ return;
+ }
+ }
+
+ throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
+
public static byte[] PRF(TlsContext context, byte[] secret, string asciiLabel, byte[] seed, int size)
{
ProtocolVersion version = context.ServerVersion;
diff --git a/crypto/test/UnitTests.csproj b/crypto/test/UnitTests.csproj
index 71896d203..24a60346e 100644
--- a/crypto/test/UnitTests.csproj
+++ b/crypto/test/UnitTests.csproj
@@ -277,6 +277,8 @@
<Compile Include="src\crypto\tls\test\ByteQueueStreamTest.cs" />
<Compile Include="src\crypto\tls\test\DtlsProtocolTest.cs" />
<Compile Include="src\crypto\tls\test\DtlsTestCase.cs" />
+ <Compile Include="src\crypto\tls\test\DtlsTestClientProtocol.cs" />
+ <Compile Include="src\crypto\tls\test\DtlsTestServerProtocol.cs" />
<Compile Include="src\crypto\tls\test\DtlsTestSuite.cs" />
<Compile Include="src\crypto\tls\test\LoggingDatagramTransport.cs" />
<Compile Include="src\crypto\tls\test\MockDatagramAssociation.cs" />
@@ -299,8 +301,10 @@
<Compile Include="src\crypto\tls\test\TlsSrpProtocolTest.cs" />
<Compile Include="src\crypto\tls\test\TlsTestCase.cs" />
<Compile Include="src\crypto\tls\test\TlsTestClientImpl.cs" />
+ <Compile Include="src\crypto\tls\test\TlsTestClientProtocol.cs" />
<Compile Include="src\crypto\tls\test\TlsTestConfig.cs" />
<Compile Include="src\crypto\tls\test\TlsTestServerImpl.cs" />
+ <Compile Include="src\crypto\tls\test\TlsTestServerProtocol.cs" />
<Compile Include="src\crypto\tls\test\TlsTestSuite.cs" />
<Compile Include="src\crypto\tls\test\TlsTestUtilities.cs" />
<Compile Include="src\crypto\tls\test\UnreliableDatagramTransport.cs" />
diff --git a/crypto/test/src/crypto/tls/test/DtlsTestCase.cs b/crypto/test/src/crypto/tls/test/DtlsTestCase.cs
index d4af04fac..5e43337f4 100644
--- a/crypto/test/src/crypto/tls/test/DtlsTestCase.cs
+++ b/crypto/test/src/crypto/tls/test/DtlsTestCase.cs
@@ -28,8 +28,8 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
SecureRandom secureRandom = new SecureRandom();
- DtlsClientProtocol clientProtocol = new DtlsClientProtocol(secureRandom);
- DtlsServerProtocol serverProtocol = new DtlsServerProtocol(secureRandom);
+ DtlsTestClientProtocol clientProtocol = new DtlsTestClientProtocol(secureRandom, config);
+ DtlsTestServerProtocol serverProtocol = new DtlsTestServerProtocol(secureRandom, config);
MockDatagramAssociation network = new MockDatagramAssociation(1500);
@@ -101,14 +101,15 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
internal class Server
{
private readonly DtlsTestCase mOuter;
- private readonly DtlsServerProtocol mServerProtocol;
+ private readonly DtlsTestServerProtocol mServerProtocol;
private readonly DatagramTransport mServerTransport;
private readonly TlsTestServerImpl mServerImpl;
private volatile bool isShutdown = false;
internal Exception mCaught = null;
- internal Server(DtlsTestCase outer, DtlsServerProtocol serverProtocol, DatagramTransport serverTransport, TlsTestServerImpl serverImpl)
+ internal Server(DtlsTestCase outer, DtlsTestServerProtocol serverProtocol,
+ DatagramTransport serverTransport, TlsTestServerImpl serverImpl)
{
this.mOuter = outer;
this.mServerProtocol = serverProtocol;
diff --git a/crypto/test/src/crypto/tls/test/DtlsTestClientProtocol.cs b/crypto/test/src/crypto/tls/test/DtlsTestClientProtocol.cs
new file mode 100644
index 000000000..41ed93eb0
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/DtlsTestClientProtocol.cs
@@ -0,0 +1,28 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+ internal class DtlsTestClientProtocol
+ : DtlsClientProtocol
+ {
+ protected readonly TlsTestConfig config;
+
+ public DtlsTestClientProtocol(SecureRandom secureRandom, TlsTestConfig config)
+ : base(secureRandom)
+ {
+ this.config = config;
+ }
+
+ protected override byte[] GenerateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify)
+ {
+ if (certificateVerify.Algorithm != null && config.clientAuthSigAlgClaimed != null)
+ {
+ certificateVerify = new DigitallySigned(config.clientAuthSigAlgClaimed, certificateVerify.Signature);
+ }
+
+ return base.GenerateCertificateVerify(state, certificateVerify);
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/tls/test/DtlsTestServerProtocol.cs b/crypto/test/src/crypto/tls/test/DtlsTestServerProtocol.cs
new file mode 100644
index 000000000..006473cef
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/DtlsTestServerProtocol.cs
@@ -0,0 +1,18 @@
+using System;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+ internal class DtlsTestServerProtocol
+ : DtlsServerProtocol
+ {
+ protected readonly TlsTestConfig config;
+
+ public DtlsTestServerProtocol(SecureRandom secureRandom, TlsTestConfig config)
+ : base(secureRandom)
+ {
+ this.config = config;
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/tls/test/DtlsTestSuite.cs b/crypto/test/src/crypto/tls/test/DtlsTestSuite.cs
index eb9d42e5f..69ce36071 100644
--- a/crypto/test/src/crypto/tls/test/DtlsTestSuite.cs
+++ b/crypto/test/src/crypto/tls/test/DtlsTestSuite.cs
@@ -31,7 +31,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
TlsTestConfig c = CreateDtlsTestConfig(ProtocolVersion.DTLSv12);
c.clientFallback = true;
- testSuite.Add(new TestCaseData(c).SetName("FallbackGood"));
+ AddTestCase(testSuite, c, "FallbackGood");
}
/*
@@ -40,20 +40,22 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
* alerts being raised
*/
- //{
- // TlsTestConfig c = CreateDtlsTestConfig(ProtocolVersion.DTLSv12);
- // c.clientOfferVersion = ProtocolVersion.DTLSv10;
- // c.clientFallback = true;
- // c.ExpectServerFatalAlert(AlertDescription.inappropriate_fallback);
+#if false
+ {
+ TlsTestConfig c = CreateDtlsTestConfig(ProtocolVersion.DTLSv12);
+ c.clientOfferVersion = ProtocolVersion.DTLSv10;
+ c.clientFallback = true;
+ c.ExpectServerFatalAlert(AlertDescription.inappropriate_fallback);
- // testSuite.Add(new TestCaseData(c).SetName("FallbackBad"));
- //}
+ AddTestCase(testSuite, c, "FallbackBad");
+ }
+#endif
{
TlsTestConfig c = CreateDtlsTestConfig(ProtocolVersion.DTLSv12);
c.clientOfferVersion = ProtocolVersion.DTLSv10;
- testSuite.Add(new TestCaseData(c).SetName("FallbackNone"));
+ AddTestCase(testSuite, c, "FallbackNone");
}
}
@@ -71,52 +73,110 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
* alerts being raised
*/
- //{
- // TlsTestConfig c = CreateDtlsTestConfig(version);
- // c.clientAuth = C.CLIENT_AUTH_INVALID_VERIFY;
- // c.ExpectServerFatalAlert(AlertDescription.decrypt_error);
+#if false
+ /*
+ * Server only declares support for SHA1/RSA, client selects MD5/RSA. Since the client is
+ * NOT actually tracking MD5 over the handshake, we expect fatal alert from the client.
+ */
+ if (TlsUtilities.IsTlsV12(version))
+ {
+ TlsTestConfig c = CreateDtlsTestConfig(version);
+ c.clientAuth = C.CLIENT_AUTH_VALID;
+ c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.md5, SignatureAlgorithm.rsa);
+ c.serverCertReqSigAlgs = TlsUtilities.GetDefaultRsaSignatureAlgorithms();
+ c.ExpectClientFatalAlert(AlertDescription.internal_error);
- // testSuite.Add(new TestCaseData(c).SetName(prefix + "BadCertificateVerify"));
- //}
+ AddTestCase(testSuite, c, prefix + "BadCertificateVerifyHashAlg");
+ }
- //{
- // TlsTestConfig c = CreateDtlsTestConfig(version);
- // c.clientAuth = C.CLIENT_AUTH_INVALID_CERT;
- // c.ExpectServerFatalAlert(AlertDescription.bad_certificate);
+ /*
+ * Server only declares support for SHA1/ECDSA, client selects SHA1/RSA. Since the client is
+ * actually tracking SHA1 over the handshake, we expect fatal alert to come from the server
+ * when it verifies the selected algorithm against the CertificateRequest supported
+ * algorithms.
+ */
+ if (TlsUtilities.IsTlsV12(version))
+ {
+ TlsTestConfig c = CreateDtlsTestConfig(version);
+ c.clientAuth = C.CLIENT_AUTH_VALID;
+ c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa);
+ c.serverCertReqSigAlgs = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
+ c.ExpectServerFatalAlert(AlertDescription.illegal_parameter);
- // testSuite.Add(new TestCaseData(c).SetName(prefix + "BadClientCertificate"));
- //}
+ AddTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlg");
+ }
- //{
- // TlsTestConfig c = CreateDtlsTestConfig(version);
- // c.clientAuth = C.CLIENT_AUTH_NONE;
- // c.serverCertReq = C.SERVER_CERT_REQ_MANDATORY;
- // c.ExpectServerFatalAlert(AlertDescription.handshake_failure);
+ /*
+ * Server only declares support for SHA1/ECDSA, client signs with SHA1/RSA, but sends
+ * SHA1/ECDSA in the CertificateVerify. Since the client is actually tracking SHA1 over the
+ * handshake, and the claimed algorithm is in the CertificateRequest supported algorithms,
+ * we expect fatal alert to come from the server when it finds the claimed algorithm
+ * doesn't match the client certificate.
+ */
+ if (TlsUtilities.IsTlsV12(version))
+ {
+ TlsTestConfig c = CreateDtlsTestConfig(version);
+ c.clientAuth = C.CLIENT_AUTH_VALID;
+ c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa);
+ c.clientAuthSigAlgClaimed = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa);
+ c.serverCertReqSigAlgs = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
+ c.ExpectServerFatalAlert(AlertDescription.decrypt_error);
- // testSuite.Add(new TestCaseData(c).SetName(prefix + "BadMandatoryCertReqDeclined"));
- //}
+ AddTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlgMismatch");
+ }
{
TlsTestConfig c = CreateDtlsTestConfig(version);
+ c.clientAuth = C.CLIENT_AUTH_INVALID_VERIFY;
+ c.ExpectServerFatalAlert(AlertDescription.decrypt_error);
- testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodDefault"));
+ AddTestCase(testSuite, c, prefix + "BadCertificateVerifySignature");
+ }
+
+ {
+ TlsTestConfig c = CreateDtlsTestConfig(version);
+ c.clientAuth = C.CLIENT_AUTH_INVALID_CERT;
+ c.ExpectServerFatalAlert(AlertDescription.bad_certificate);
+
+ AddTestCase(testSuite, c, prefix + "BadClientCertificate");
+ }
+
+ {
+ TlsTestConfig c = CreateDtlsTestConfig(version);
+ c.clientAuth = C.CLIENT_AUTH_NONE;
+ c.serverCertReq = C.SERVER_CERT_REQ_MANDATORY;
+ c.ExpectServerFatalAlert(AlertDescription.handshake_failure);
+
+ AddTestCase(testSuite, c, prefix + "BadMandatoryCertReqDeclined");
+ }
+#endif
+
+ {
+ TlsTestConfig c = CreateDtlsTestConfig(version);
+
+ AddTestCase(testSuite, c, prefix + "GoodDefault");
}
{
TlsTestConfig c = CreateDtlsTestConfig(version);
c.serverCertReq = C.SERVER_CERT_REQ_NONE;
- testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodNoCertReq"));
+ AddTestCase(testSuite, c, prefix + "GoodNoCertReq");
}
{
TlsTestConfig c = CreateDtlsTestConfig(version);
c.clientAuth = C.CLIENT_AUTH_NONE;
- testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodOptionalCertReqDeclined"));
+ AddTestCase(testSuite, c, prefix + "GoodOptionalCertReqDeclined");
}
}
+ private static void AddTestCase(IList testSuite, TlsTestConfig config, String name)
+ {
+ testSuite.Add(new TestCaseData(config).SetName(name));
+ }
+
private static TlsTestConfig CreateDtlsTestConfig(ProtocolVersion version)
{
TlsTestConfig c = new TlsTestConfig();
diff --git a/crypto/test/src/crypto/tls/test/TlsTestCase.cs b/crypto/test/src/crypto/tls/test/TlsTestCase.cs
index 4b0c12710..7fb5db6ce 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestCase.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestCase.cs
@@ -35,8 +35,8 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
NetworkStream clientNet = new NetworkStream(clientPipe);
NetworkStream serverNet = new NetworkStream(serverPipe);
- TlsClientProtocol clientProtocol = new TlsClientProtocol(clientNet, secureRandom);
- TlsServerProtocol serverProtocol = new TlsServerProtocol(serverNet, secureRandom);
+ TlsTestClientProtocol clientProtocol = new TlsTestClientProtocol(clientNet, secureRandom, config);
+ TlsTestServerProtocol serverProtocol = new TlsTestServerProtocol(serverNet, secureRandom, config);
TlsTestClientImpl clientImpl = new TlsTestClientImpl(config);
TlsTestServerImpl serverImpl = new TlsTestServerImpl(config);
@@ -104,13 +104,13 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
internal class Server
{
protected readonly TlsTestCase mOuter;
- protected readonly TlsServerProtocol mServerProtocol;
+ protected readonly TlsTestServerProtocol mServerProtocol;
protected readonly TlsTestServerImpl mServerImpl;
internal bool mCanExit = false;
internal Exception mCaught = null;
- internal Server(TlsTestCase outer, TlsServerProtocol serverProtocol, TlsTestServerImpl serverImpl)
+ internal Server(TlsTestCase outer, TlsTestServerProtocol serverProtocol, TlsTestServerImpl serverImpl)
{
this.mOuter = outer;
this.mServerProtocol = serverProtocol;
diff --git a/crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs b/crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs
index 0cc1883ba..f313f75fe 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestClientImpl.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
using System.IO;
using Org.BouncyCastle.Asn1;
@@ -201,9 +202,15 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
return null;
}
+ IList supportedSigAlgs = certificateRequest.SupportedSignatureAlgorithms;
+ if (supportedSigAlgs != null && mOuter.mConfig.clientAuthSigAlg != null)
+ {
+ supportedSigAlgs = new ArrayList(1);
+ supportedSigAlgs.Add(mOuter.mConfig.clientAuthSigAlg);
+ }
+
TlsSignerCredentials signerCredentials = TlsTestUtilities.LoadSignerCredentials(mContext,
- certificateRequest.SupportedSignatureAlgorithms, SignatureAlgorithm.rsa,
- "x509-client.pem", "x509-client-key.pem");
+ supportedSigAlgs, SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem");
if (mOuter.mConfig.clientAuth == TlsTestConfig.CLIENT_AUTH_VALID)
{
diff --git a/crypto/test/src/crypto/tls/test/TlsTestClientProtocol.cs b/crypto/test/src/crypto/tls/test/TlsTestClientProtocol.cs
new file mode 100644
index 000000000..97b7c91bc
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsTestClientProtocol.cs
@@ -0,0 +1,29 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+ internal class TlsTestClientProtocol
+ : TlsClientProtocol
+ {
+ protected readonly TlsTestConfig config;
+
+ public TlsTestClientProtocol(Stream stream, SecureRandom secureRandom, TlsTestConfig config)
+ : base(stream, secureRandom)
+ {
+ this.config = config;
+ }
+
+ protected override void SendCertificateVerifyMessage(DigitallySigned certificateVerify)
+ {
+ if (certificateVerify.Algorithm != null && config.clientAuthSigAlgClaimed != null)
+ {
+ certificateVerify = new DigitallySigned(config.clientAuthSigAlgClaimed, certificateVerify.Signature);
+ }
+
+ base.SendCertificateVerifyMessage(certificateVerify);
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestConfig.cs b/crypto/test/src/crypto/tls/test/TlsTestConfig.cs
index 0d1e7badb..212d2b63c 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestConfig.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestConfig.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections;
namespace Org.BouncyCastle.Crypto.Tls.Tests
{
@@ -47,6 +48,18 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
public int clientAuth = CLIENT_AUTH_VALID;
/**
+ * If not null, and TLS 1.2 or higher is negotiated, selects a fixed signature/hash algorithm to
+ * be used for the CertificateVerify signature (if one is sent).
+ */
+ public SignatureAndHashAlgorithm clientAuthSigAlg = null;
+
+ /**
+ * If not null, and TLS 1.2 or higher is negotiated, selects a fixed signature/hash algorithm to
+ * be _claimed_ in the CertificateVerify (if one is sent), independently of what was actually used.
+ */
+ public SignatureAndHashAlgorithm clientAuthSigAlgClaimed = null;
+
+ /**
* Configures the minimum protocol version the client will accept. If null, uses the library's default.
*/
public ProtocolVersion clientMinimumVersion = null;
@@ -67,6 +80,12 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
public int serverCertReq = SERVER_CERT_REQ_OPTIONAL;
/**
+ * If TLS 1.2 or higher is negotiated, configures the set of supported signature algorithms in the
+ * CertificateRequest (if one is sent). If null, uses a default set.
+ */
+ public IList serverCertReqSigAlgs = null;
+
+ /**
* Configures the maximum protocol version the server will accept. If null, uses the library's default.
*/
public ProtocolVersion serverMaximumVersion = null;
diff --git a/crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs b/crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs
index 152d5dbdc..6f9d35b5c 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestServerImpl.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.IO;
+using System.Threading;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
@@ -72,11 +73,11 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
+ ", " + AlertDescription.GetText(alertDescription));
if (message != null)
{
- output.WriteLine("> " + message);
+ SafeWriteLine(output, "> " + message);
}
if (cause != null)
{
- output.WriteLine(cause);
+ SafeWriteLine(output, cause);
}
}
}
@@ -92,7 +93,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
if (TlsTestConfig.DEBUG)
{
TextWriter output = (alertLevel == AlertLevel.fatal) ? Console.Error : Console.Out;
- output.WriteLine("TLS server received alert: " + AlertLevel.GetText(alertLevel)
+ SafeWriteLine(output, "TLS server received alert: " + AlertLevel.GetText(alertLevel)
+ ", " + AlertDescription.GetText(alertDescription));
}
}
@@ -122,7 +123,11 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
IList serverSigAlgs = null;
if (TlsUtilities.IsSignatureAlgorithmsExtensionAllowed(mServerVersion))
{
- serverSigAlgs = TlsUtilities.GetDefaultSupportedSignatureAlgorithms();
+ serverSigAlgs = mConfig.serverCertReqSigAlgs;
+ if (serverSigAlgs == null)
+ {
+ serverSigAlgs = TlsUtilities.GetDefaultSupportedSignatureAlgorithms();
+ }
}
IList certificateAuthorities = new ArrayList();
@@ -190,5 +195,19 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
return TlsTestUtilities.LoadSignerCredentials(mContext, mSupportedSignatureAlgorithms, SignatureAlgorithm.rsa,
"x509-server.pem", "x509-server-key.pem");
}
+
+ private static void SafeWriteLine(TextWriter output, object line)
+ {
+ try
+ {
+ output.WriteLine(line);
+ }
+ catch (ThreadInterruptedException)
+ {
+ /*
+ * For some reason the NUnit plugin in Visual Studio started throwing these during alert logging
+ */
+ }
+ }
}
}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestServerProtocol.cs b/crypto/test/src/crypto/tls/test/TlsTestServerProtocol.cs
new file mode 100644
index 000000000..845b7f0b9
--- /dev/null
+++ b/crypto/test/src/crypto/tls/test/TlsTestServerProtocol.cs
@@ -0,0 +1,19 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Crypto.Tls.Tests
+{
+ internal class TlsTestServerProtocol
+ : TlsServerProtocol
+ {
+ protected readonly TlsTestConfig config;
+
+ public TlsTestServerProtocol(Stream stream, SecureRandom secureRandom, TlsTestConfig config)
+ : base(stream, secureRandom)
+ {
+ this.config = config;
+ }
+ }
+}
diff --git a/crypto/test/src/crypto/tls/test/TlsTestSuite.cs b/crypto/test/src/crypto/tls/test/TlsTestSuite.cs
index dfd09d06e..0770187d5 100644
--- a/crypto/test/src/crypto/tls/test/TlsTestSuite.cs
+++ b/crypto/test/src/crypto/tls/test/TlsTestSuite.cs
@@ -32,7 +32,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
TlsTestConfig c = CreateTlsTestConfig(ProtocolVersion.TLSv12);
c.clientFallback = true;
- testSuite.Add(new TestCaseData(c).SetName("FallbackGood"));
+ AddTestCase(testSuite, c, "FallbackGood");
}
{
@@ -41,14 +41,14 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
c.clientFallback = true;
c.ExpectServerFatalAlert(AlertDescription.inappropriate_fallback);
- testSuite.Add(new TestCaseData(c).SetName("FallbackBad"));
+ AddTestCase(testSuite, c, "FallbackBad");
}
{
TlsTestConfig c = CreateTlsTestConfig(ProtocolVersion.TLSv12);
c.clientOfferVersion = ProtocolVersion.TLSv11;
- testSuite.Add(new TestCaseData(c).SetName("FallbackNone"));
+ AddTestCase(testSuite, c, "FallbackNone");
}
}
@@ -63,7 +63,58 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
{
TlsTestConfig c = CreateTlsTestConfig(version);
- testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodDefault"));
+ AddTestCase(testSuite, c, prefix + "GoodDefault");
+ }
+
+ /*
+ * Server only declares support for SHA1/RSA, client selects MD5/RSA. Since the client is
+ * NOT actually tracking MD5 over the handshake, we expect fatal alert from the client.
+ */
+ if (TlsUtilities.IsTlsV12(version))
+ {
+ TlsTestConfig c = CreateTlsTestConfig(version);
+ c.clientAuth = C.CLIENT_AUTH_VALID;
+ c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.md5, SignatureAlgorithm.rsa);
+ c.serverCertReqSigAlgs = TlsUtilities.GetDefaultRsaSignatureAlgorithms();
+ c.ExpectClientFatalAlert(AlertDescription.internal_error);
+
+ AddTestCase(testSuite, c, prefix + "BadCertificateVerifyHashAlg");
+ }
+
+ /*
+ * Server only declares support for SHA1/ECDSA, client selects SHA1/RSA. Since the client is
+ * actually tracking SHA1 over the handshake, we expect fatal alert to come from the server
+ * when it verifies the selected algorithm against the CertificateRequest supported
+ * algorithms.
+ */
+ if (TlsUtilities.IsTlsV12(version))
+ {
+ TlsTestConfig c = CreateTlsTestConfig(version);
+ c.clientAuth = C.CLIENT_AUTH_VALID;
+ c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa);
+ c.serverCertReqSigAlgs = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
+ c.ExpectServerFatalAlert(AlertDescription.illegal_parameter);
+
+ AddTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlg");
+ }
+
+ /*
+ * Server only declares support for SHA1/ECDSA, client signs with SHA1/RSA, but sends
+ * SHA1/ECDSA in the CertificateVerify. Since the client is actually tracking SHA1 over the
+ * handshake, and the claimed algorithm is in the CertificateRequest supported algorithms,
+ * we expect fatal alert to come from the server when it finds the claimed algorithm
+ * doesn't match the client certificate.
+ */
+ if (TlsUtilities.IsTlsV12(version))
+ {
+ TlsTestConfig c = CreateTlsTestConfig(version);
+ c.clientAuth = C.CLIENT_AUTH_VALID;
+ c.clientAuthSigAlg = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.rsa);
+ c.clientAuthSigAlgClaimed = new SignatureAndHashAlgorithm(HashAlgorithm.sha1, SignatureAlgorithm.ecdsa);
+ c.serverCertReqSigAlgs = TlsUtilities.GetDefaultECDsaSignatureAlgorithms();
+ c.ExpectServerFatalAlert(AlertDescription.decrypt_error);
+
+ AddTestCase(testSuite, c, prefix + "BadCertificateVerifySigAlgMismatch");
}
{
@@ -71,7 +122,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
c.clientAuth = C.CLIENT_AUTH_INVALID_VERIFY;
c.ExpectServerFatalAlert(AlertDescription.decrypt_error);
- testSuite.Add(new TestCaseData(c).SetName(prefix + "BadCertificateVerify"));
+ AddTestCase(testSuite, c, prefix + "BadCertificateVerifySignature");
}
{
@@ -79,7 +130,7 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
c.clientAuth = C.CLIENT_AUTH_INVALID_CERT;
c.ExpectServerFatalAlert(AlertDescription.bad_certificate);
- testSuite.Add(new TestCaseData(c).SetName(prefix + "BadClientCertificate"));
+ AddTestCase(testSuite, c, prefix + "BadClientCertificate");
}
{
@@ -88,24 +139,29 @@ namespace Org.BouncyCastle.Crypto.Tls.Tests
c.serverCertReq = C.SERVER_CERT_REQ_MANDATORY;
c.ExpectServerFatalAlert(AlertDescription.handshake_failure);
- testSuite.Add(new TestCaseData(c).SetName(prefix + "BadMandatoryCertReqDeclined"));
+ AddTestCase(testSuite, c, prefix + "BadMandatoryCertReqDeclined");
}
{
TlsTestConfig c = CreateTlsTestConfig(version);
c.serverCertReq = C.SERVER_CERT_REQ_NONE;
- testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodNoCertReq"));
+ AddTestCase(testSuite, c, prefix + "GoodNoCertReq");
}
{
TlsTestConfig c = CreateTlsTestConfig(version);
c.clientAuth = C.CLIENT_AUTH_NONE;
- testSuite.Add(new TestCaseData(c).SetName(prefix + "GoodOptionalCertReqDeclined"));
+ AddTestCase(testSuite, c, prefix + "GoodOptionalCertReqDeclined");
}
}
+ private static void AddTestCase(IList testSuite, TlsTestConfig config, string name)
+ {
+ testSuite.Add(new TestCaseData(config).SetName(name));
+ }
+
private static TlsTestConfig CreateTlsTestConfig(ProtocolVersion version)
{
TlsTestConfig c = new TlsTestConfig();
|