Skip to content

Commit ae227e6

Browse files
committed
Validate CertificateVerify signature algorithm (TLS 1.2+)
- check the algorithm is in the CertificateRequest list - add (D)TLS test scenarios for various failure modes
1 parent 0a6a5b9 commit ae227e6

18 files changed

+426
-74
lines changed

crypto/crypto.csproj

+20
Original file line numberDiff line numberDiff line change
@@ -11839,6 +11839,16 @@
1183911839
SubType = "Code"
1184011840
BuildAction = "Compile"
1184111841
/>
11842+
<File
11843+
RelPath = "test\src\crypto\tls\test\DtlsTestClientProtocol.cs"
11844+
SubType = "Code"
11845+
BuildAction = "Compile"
11846+
/>
11847+
<File
11848+
RelPath = "test\src\crypto\tls\test\DtlsTestServerProtocol.cs"
11849+
SubType = "Code"
11850+
BuildAction = "Compile"
11851+
/>
1184211852
<File
1184311853
RelPath = "test\src\crypto\tls\test\DtlsTestSuite.cs"
1184411854
SubType = "Code"
@@ -11949,6 +11959,11 @@
1194911959
SubType = "Code"
1195011960
BuildAction = "Compile"
1195111961
/>
11962+
<File
11963+
RelPath = "test\src\crypto\tls\test\TlsTestClientProtocol.cs"
11964+
SubType = "Code"
11965+
BuildAction = "Compile"
11966+
/>
1195211967
<File
1195311968
RelPath = "test\src\crypto\tls\test\TlsTestConfig.cs"
1195411969
SubType = "Code"
@@ -11959,6 +11974,11 @@
1195911974
SubType = "Code"
1196011975
BuildAction = "Compile"
1196111976
/>
11977+
<File
11978+
RelPath = "test\src\crypto\tls\test\TlsTestServerProtocol.cs"
11979+
SubType = "Code"
11980+
BuildAction = "Compile"
11981+
/>
1196211982
<File
1196311983
RelPath = "test\src\crypto\tls\test\TlsTestSuite.cs"
1196411984
SubType = "Code"

crypto/src/crypto/tls/DeferredHash.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public virtual byte[] GetFinalHash(byte hashAlgorithm)
103103
{
104104
IDigest d = (IDigest)mHashes[hashAlgorithm];
105105
if (d == null)
106-
throw new InvalidOperationException("HashAlgorithm " + hashAlgorithm + " is not being tracked");
106+
throw new InvalidOperationException("HashAlgorithm." + HashAlgorithm.GetText(hashAlgorithm) + " is not being tracked");
107107

108108
d = TlsUtilities.CloneHash(hashAlgorithm, d);
109109
if (mBuf != null)

crypto/src/crypto/tls/DtlsServerProtocol.cs

+15-8
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,9 @@ protected virtual void ProcessClientCertificate(ServerHandshakeState state, byte
458458

459459
protected virtual void ProcessCertificateVerify(ServerHandshakeState state, byte[] body, TlsHandshakeHash prepareFinishHash)
460460
{
461+
if (state.certificateRequest == null)
462+
throw new InvalidOperationException();
463+
461464
MemoryStream buf = new MemoryStream(body, false);
462465

463466
TlsServerContextImpl context = state.serverContext;
@@ -466,13 +469,15 @@ protected virtual void ProcessCertificateVerify(ServerHandshakeState state, byte
466469
TlsProtocol.AssertEmpty(buf);
467470

468471
// Verify the CertificateVerify message contains a correct signature.
469-
bool verified = false;
470472
try
471473
{
474+
SignatureAndHashAlgorithm signatureAlgorithm = clientCertificateVerify.Algorithm;
475+
472476
byte[] hash;
473477
if (TlsUtilities.IsTlsV12(context))
474478
{
475-
hash = prepareFinishHash.GetFinalHash(clientCertificateVerify.Algorithm.Hash);
479+
TlsUtilities.VerifySupportedSignatureAlgorithm(state.certificateRequest.SupportedSignatureAlgorithms, signatureAlgorithm);
480+
hash = prepareFinishHash.GetFinalHash(signatureAlgorithm.Hash);
476481
}
477482
else
478483
{
@@ -485,15 +490,17 @@ protected virtual void ProcessCertificateVerify(ServerHandshakeState state, byte
485490

486491
TlsSigner tlsSigner = TlsUtilities.CreateTlsSigner((byte)state.clientCertificateType);
487492
tlsSigner.Init(context);
488-
verified = tlsSigner.VerifyRawSignature(clientCertificateVerify.Algorithm,
489-
clientCertificateVerify.Signature, publicKey, hash);
493+
if (!tlsSigner.VerifyRawSignature(signatureAlgorithm, clientCertificateVerify.Signature, publicKey, hash))
494+
throw new TlsFatalAlert(AlertDescription.decrypt_error);
490495
}
491-
catch (Exception)
496+
catch (TlsFatalAlert e)
492497
{
498+
throw e;
499+
}
500+
catch (Exception e)
501+
{
502+
throw new TlsFatalAlert(AlertDescription.decrypt_error, e);
493503
}
494-
495-
if (!verified)
496-
throw new TlsFatalAlert(AlertDescription.decrypt_error);
497504
}
498505

499506
protected virtual void ProcessClientHello(ServerHandshakeState state, byte[] body)

crypto/src/crypto/tls/HashAlgorithm.cs

+28
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,33 @@ public abstract class HashAlgorithm
1212
public const byte sha256 = 4;
1313
public const byte sha384 = 5;
1414
public const byte sha512 = 6;
15+
16+
public static string GetName(byte hashAlgorithm)
17+
{
18+
switch (hashAlgorithm)
19+
{
20+
case none:
21+
return "none";
22+
case md5:
23+
return "md5";
24+
case sha1:
25+
return "sha1";
26+
case sha224:
27+
return "sha224";
28+
case sha256:
29+
return "sha256";
30+
case sha384:
31+
return "sha384";
32+
case sha512:
33+
return "sha512";
34+
default:
35+
return "UNKNOWN";
36+
}
37+
}
38+
39+
public static string GetText(byte hashAlgorithm)
40+
{
41+
return GetName(hashAlgorithm) + "(" + hashAlgorithm + ")";
42+
}
1543
}
1644
}

crypto/src/crypto/tls/TlsServerProtocol.cs

+12-5
Original file line numberDiff line numberDiff line change
@@ -460,17 +460,23 @@ protected virtual void ReceiveCertificateMessage(MemoryStream buf)
460460

461461
protected virtual void ReceiveCertificateVerifyMessage(MemoryStream buf)
462462
{
463+
if (mCertificateRequest == null)
464+
throw new InvalidOperationException();
465+
463466
DigitallySigned clientCertificateVerify = DigitallySigned.Parse(Context, buf);
464467

465468
AssertEmpty(buf);
466469

467470
// Verify the CertificateVerify message contains a correct signature.
468471
try
469472
{
473+
SignatureAndHashAlgorithm signatureAlgorithm = clientCertificateVerify.Algorithm;
474+
470475
byte[] hash;
471476
if (TlsUtilities.IsTlsV12(Context))
472477
{
473-
hash = mPrepareFinishHash.GetFinalHash(clientCertificateVerify.Algorithm.Hash);
478+
TlsUtilities.VerifySupportedSignatureAlgorithm(mCertificateRequest.SupportedSignatureAlgorithms, signatureAlgorithm);
479+
hash = mPrepareFinishHash.GetFinalHash(signatureAlgorithm.Hash);
474480
}
475481
else
476482
{
@@ -483,11 +489,12 @@ protected virtual void ReceiveCertificateVerifyMessage(MemoryStream buf)
483489

484490
TlsSigner tlsSigner = TlsUtilities.CreateTlsSigner((byte)mClientCertificateType);
485491
tlsSigner.Init(Context);
486-
if (!tlsSigner.VerifyRawSignature(clientCertificateVerify.Algorithm,
487-
clientCertificateVerify.Signature, publicKey, hash))
488-
{
492+
if (!tlsSigner.VerifyRawSignature(signatureAlgorithm, clientCertificateVerify.Signature, publicKey, hash))
489493
throw new TlsFatalAlert(AlertDescription.decrypt_error);
490-
}
494+
}
495+
catch (TlsFatalAlert e)
496+
{
497+
throw e;
491498
}
492499
catch (Exception e)
493500
{

crypto/src/crypto/tls/TlsUtilities.cs

+36-6
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,24 @@ public static bool IsSsl(TlsContext context)
129129
return context.ServerVersion.IsSsl;
130130
}
131131

132+
public static bool IsTlsV11(ProtocolVersion version)
133+
{
134+
return ProtocolVersion.TLSv11.IsEqualOrEarlierVersionOf(version.GetEquivalentTLSVersion());
135+
}
136+
132137
public static bool IsTlsV11(TlsContext context)
133138
{
134-
return ProtocolVersion.TLSv11.IsEqualOrEarlierVersionOf(context.ServerVersion.GetEquivalentTLSVersion());
139+
return IsTlsV11(context.ServerVersion);
140+
}
141+
142+
public static bool IsTlsV12(ProtocolVersion version)
143+
{
144+
return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(version.GetEquivalentTLSVersion());
135145
}
136146

137147
public static bool IsTlsV12(TlsContext context)
138148
{
139-
return ProtocolVersion.TLSv12.IsEqualOrEarlierVersionOf(context.ServerVersion.GetEquivalentTLSVersion());
149+
return IsTlsV12(context.ServerVersion);
140150
}
141151

142152
public static void WriteUint8(byte i, Stream output)
@@ -712,11 +722,10 @@ public static IList ReadSignatureAlgorithmsExtension(byte[] extensionData)
712722
public static void EncodeSupportedSignatureAlgorithms(IList supportedSignatureAlgorithms, bool allowAnonymous,
713723
Stream output)
714724
{
715-
if (supportedSignatureAlgorithms == null || supportedSignatureAlgorithms.Count < 1
716-
|| supportedSignatureAlgorithms.Count >= (1 << 15))
717-
{
725+
if (supportedSignatureAlgorithms == null)
726+
throw new ArgumentNullException("supportedSignatureAlgorithms");
727+
if (supportedSignatureAlgorithms.Count < 1 || supportedSignatureAlgorithms.Count >= (1 << 15))
718728
throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms");
719-
}
720729

721730
// supported_signature_algorithms
722731
int length = 2 * supportedSignatureAlgorithms.Count;
@@ -762,6 +771,27 @@ public static IList ParseSupportedSignatureAlgorithms(bool allowAnonymous, Strea
762771
return supportedSignatureAlgorithms;
763772
}
764773

774+
public static void VerifySupportedSignatureAlgorithm(IList supportedSignatureAlgorithms, SignatureAndHashAlgorithm signatureAlgorithm)
775+
{
776+
if (supportedSignatureAlgorithms == null)
777+
throw new ArgumentNullException("supportedSignatureAlgorithms");
778+
if (supportedSignatureAlgorithms.Count < 1 || supportedSignatureAlgorithms.Count >= (1 << 15))
779+
throw new ArgumentException("must have length from 1 to (2^15 - 1)", "supportedSignatureAlgorithms");
780+
if (signatureAlgorithm == null)
781+
throw new ArgumentNullException("signatureAlgorithm");
782+
783+
if (signatureAlgorithm.Signature != SignatureAlgorithm.anonymous)
784+
{
785+
foreach (SignatureAndHashAlgorithm entry in supportedSignatureAlgorithms)
786+
{
787+
if (entry.Hash == signatureAlgorithm.Hash && entry.Signature == signatureAlgorithm.Signature)
788+
return;
789+
}
790+
}
791+
792+
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
793+
}
794+
765795
public static byte[] PRF(TlsContext context, byte[] secret, string asciiLabel, byte[] seed, int size)
766796
{
767797
ProtocolVersion version = context.ServerVersion;

crypto/test/UnitTests.csproj

+4
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@
277277
<Compile Include="src\crypto\tls\test\ByteQueueStreamTest.cs" />
278278
<Compile Include="src\crypto\tls\test\DtlsProtocolTest.cs" />
279279
<Compile Include="src\crypto\tls\test\DtlsTestCase.cs" />
280+
<Compile Include="src\crypto\tls\test\DtlsTestClientProtocol.cs" />
281+
<Compile Include="src\crypto\tls\test\DtlsTestServerProtocol.cs" />
280282
<Compile Include="src\crypto\tls\test\DtlsTestSuite.cs" />
281283
<Compile Include="src\crypto\tls\test\LoggingDatagramTransport.cs" />
282284
<Compile Include="src\crypto\tls\test\MockDatagramAssociation.cs" />
@@ -299,8 +301,10 @@
299301
<Compile Include="src\crypto\tls\test\TlsSrpProtocolTest.cs" />
300302
<Compile Include="src\crypto\tls\test\TlsTestCase.cs" />
301303
<Compile Include="src\crypto\tls\test\TlsTestClientImpl.cs" />
304+
<Compile Include="src\crypto\tls\test\TlsTestClientProtocol.cs" />
302305
<Compile Include="src\crypto\tls\test\TlsTestConfig.cs" />
303306
<Compile Include="src\crypto\tls\test\TlsTestServerImpl.cs" />
307+
<Compile Include="src\crypto\tls\test\TlsTestServerProtocol.cs" />
304308
<Compile Include="src\crypto\tls\test\TlsTestSuite.cs" />
305309
<Compile Include="src\crypto\tls\test\TlsTestUtilities.cs" />
306310
<Compile Include="src\crypto\tls\test\UnreliableDatagramTransport.cs" />

crypto/test/src/crypto/tls/test/DtlsTestCase.cs

+5-4
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public void RunTest(TlsTestConfig config)
2828

2929
SecureRandom secureRandom = new SecureRandom();
3030

31-
DtlsClientProtocol clientProtocol = new DtlsClientProtocol(secureRandom);
32-
DtlsServerProtocol serverProtocol = new DtlsServerProtocol(secureRandom);
31+
DtlsTestClientProtocol clientProtocol = new DtlsTestClientProtocol(secureRandom, config);
32+
DtlsTestServerProtocol serverProtocol = new DtlsTestServerProtocol(secureRandom, config);
3333

3434
MockDatagramAssociation network = new MockDatagramAssociation(1500);
3535

@@ -101,14 +101,15 @@ protected void LogException(Exception e)
101101
internal class Server
102102
{
103103
private readonly DtlsTestCase mOuter;
104-
private readonly DtlsServerProtocol mServerProtocol;
104+
private readonly DtlsTestServerProtocol mServerProtocol;
105105
private readonly DatagramTransport mServerTransport;
106106
private readonly TlsTestServerImpl mServerImpl;
107107

108108
private volatile bool isShutdown = false;
109109
internal Exception mCaught = null;
110110

111-
internal Server(DtlsTestCase outer, DtlsServerProtocol serverProtocol, DatagramTransport serverTransport, TlsTestServerImpl serverImpl)
111+
internal Server(DtlsTestCase outer, DtlsTestServerProtocol serverProtocol,
112+
DatagramTransport serverTransport, TlsTestServerImpl serverImpl)
112113
{
113114
this.mOuter = outer;
114115
this.mServerProtocol = serverProtocol;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
3+
using Org.BouncyCastle.Security;
4+
5+
namespace Org.BouncyCastle.Crypto.Tls.Tests
6+
{
7+
internal class DtlsTestClientProtocol
8+
: DtlsClientProtocol
9+
{
10+
protected readonly TlsTestConfig config;
11+
12+
public DtlsTestClientProtocol(SecureRandom secureRandom, TlsTestConfig config)
13+
: base(secureRandom)
14+
{
15+
this.config = config;
16+
}
17+
18+
protected override byte[] GenerateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify)
19+
{
20+
if (certificateVerify.Algorithm != null && config.clientAuthSigAlgClaimed != null)
21+
{
22+
certificateVerify = new DigitallySigned(config.clientAuthSigAlgClaimed, certificateVerify.Signature);
23+
}
24+
25+
return base.GenerateCertificateVerify(state, certificateVerify);
26+
}
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
3+
using Org.BouncyCastle.Security;
4+
5+
namespace Org.BouncyCastle.Crypto.Tls.Tests
6+
{
7+
internal class DtlsTestServerProtocol
8+
: DtlsServerProtocol
9+
{
10+
protected readonly TlsTestConfig config;
11+
12+
public DtlsTestServerProtocol(SecureRandom secureRandom, TlsTestConfig config)
13+
: base(secureRandom)
14+
{
15+
this.config = config;
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)