summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2015-12-16 22:50:41 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2015-12-16 22:50:41 +0700
commitae227e65ab48b8747c80e1b336a3e6896e9e346e (patch)
treebff90e085f89872399328db0391f9e8b4f7368f0 /crypto/src
parentUpdate version for release (diff)
downloadBouncyCastle.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.cs2
-rw-r--r--crypto/src/crypto/tls/DtlsServerProtocol.cs23
-rw-r--r--crypto/src/crypto/tls/HashAlgorithm.cs28
-rw-r--r--crypto/src/crypto/tls/TlsServerProtocol.cs17
-rw-r--r--crypto/src/crypto/tls/TlsUtilities.cs42
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;