diff options
author | Peter Dettman <peter.dettman@bouncycastle.org> | 2015-12-16 22:50:41 +0700 |
---|---|---|
committer | Peter Dettman <peter.dettman@bouncycastle.org> | 2015-12-16 22:50:41 +0700 |
commit | ae227e65ab48b8747c80e1b336a3e6896e9e346e (patch) | |
tree | bff90e085f89872399328db0391f9e8b4f7368f0 /crypto/src | |
parent | Update version for release (diff) | |
download | BouncyCastle.NET-ed25519-ae227e65ab48b8747c80e1b336a3e6896e9e346e.tar.xz |
Validate CertificateVerify signature algorithm (TLS 1.2+)
- check the algorithm is in the CertificateRequest list - add (D)TLS test scenarios for various failure modes
Diffstat (limited to 'crypto/src')
-rw-r--r-- | crypto/src/crypto/tls/DeferredHash.cs | 2 | ||||
-rw-r--r-- | crypto/src/crypto/tls/DtlsServerProtocol.cs | 23 | ||||
-rw-r--r-- | crypto/src/crypto/tls/HashAlgorithm.cs | 28 | ||||
-rw-r--r-- | crypto/src/crypto/tls/TlsServerProtocol.cs | 17 | ||||
-rw-r--r-- | crypto/src/crypto/tls/TlsUtilities.cs | 42 |
5 files changed, 92 insertions, 20 deletions
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; |