summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Dettman <peter.dettman@bouncycastle.org>2021-07-25 00:12:25 +0700
committerPeter Dettman <peter.dettman@bouncycastle.org>2021-07-25 00:12:25 +0700
commit934e1a1047ef192cf2fb5b5b5822561118a10c20 (patch)
tree47dfadf8dd6e7a2675a16a347b1c6691bb2812e1
parentCalculate HMAC without extracting TlsSecret (diff)
downloadBouncyCastle.NET-ed25519-934e1a1047ef192cf2fb5b5b5822561118a10c20.tar.xz
Refactoring around TLS HKDF
-rw-r--r--crypto/src/tls/SecurityParameters.cs13
-rw-r--r--crypto/src/tls/TlsUtilities.cs93
-rw-r--r--crypto/src/tls/crypto/TlsSecret.cs2
-rw-r--r--crypto/src/tls/crypto/impl/AbstractTlsSecret.cs7
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsSecret.cs29
-rw-r--r--crypto/test/src/tls/crypto/test/BcTlsCryptoTest.cs11
6 files changed, 114 insertions, 41 deletions
diff --git a/crypto/src/tls/SecurityParameters.cs b/crypto/src/tls/SecurityParameters.cs
index 84c3b9f11..f4aa1ac5a 100644
--- a/crypto/src/tls/SecurityParameters.cs
+++ b/crypto/src/tls/SecurityParameters.cs
@@ -22,6 +22,7 @@ namespace Org.BouncyCastle.Tls
         internal TlsSecret m_exporterMasterSecret = null;
         internal TlsSecret m_handshakeSecret = null;
         internal TlsSecret m_masterSecret = null;
+        internal TlsSecret m_preSharedKey = null;
         internal TlsSecret m_sharedSecret = null;
         internal TlsSecret m_trafficSecretClient = null;
         internal TlsSecret m_trafficSecretServer = null;
@@ -29,7 +30,6 @@ namespace Org.BouncyCastle.Tls
         internal byte[] m_serverRandom = null;
         internal byte[] m_sessionHash = null;
         internal byte[] m_sessionID = null;
-        internal byte[] m_psk = null;
         internal byte[] m_pskIdentity = null;
         internal byte[] m_srpIdentity = null;
         internal byte[] m_tlsServerEndPoint = null;
@@ -79,6 +79,7 @@ namespace Org.BouncyCastle.Tls
             this.m_exporterMasterSecret = ClearSecret(m_exporterMasterSecret);
             this.m_handshakeSecret = ClearSecret(m_handshakeSecret);
             this.m_masterSecret = ClearSecret(m_masterSecret);
+            this.m_preSharedKey = null;
             this.m_sharedSecret = ClearSecret(m_sharedSecret);
         }
 
@@ -227,6 +228,11 @@ namespace Org.BouncyCastle.Tls
             get { return m_peerVerifyData; }
         }
 
+        public TlsSecret PreSharedKey
+        {
+            get { return m_preSharedKey; }
+        }
+
         public int PrfAlgorithm
         {
             get { return m_prfAlgorithm; }
@@ -242,11 +248,6 @@ namespace Org.BouncyCastle.Tls
             get { return m_prfHashLength; }
         }
 
-        public byte[] Psk
-        {
-            get { return m_psk; }
-        }
-
         public byte[] PskIdentity
         {
             get { return m_pskIdentity; }
diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs
index 52b554801..adead624b 100644
--- a/crypto/src/tls/TlsUtilities.cs
+++ b/crypto/src/tls/TlsUtilities.cs
@@ -1459,6 +1459,23 @@ namespace Org.BouncyCastle.Tls
             return Arrays.ConcatenateAll(cr, sr, contextLength, context);
         }
 
+        private static byte[] CalculateFinishedHmac(SecurityParameters securityParameters, TlsSecret baseKey,
+            byte[] transcriptHash)
+        {
+            int cryptoHashAlgorithm = TlsCryptoUtilities.GetHash(securityParameters.PrfHashAlgorithm);
+            TlsSecret finishedKey = TlsCryptoUtilities.HkdfExpandLabel(baseKey, cryptoHashAlgorithm, "finished",
+                EmptyBytes, securityParameters.PrfHashLength);
+
+            try
+            {
+                return finishedKey.CalculateHmac(cryptoHashAlgorithm, transcriptHash, 0, transcriptHash.Length);
+            }
+            finally
+            {
+                finishedKey.Destroy();
+            }
+        }
+
         internal static TlsSecret CalculateMasterSecret(TlsContext context, TlsSecret preMasterSecret)
         {
             SecurityParameters sp = context.SecurityParameters;
@@ -1479,6 +1496,28 @@ namespace Org.BouncyCastle.Tls
             return Prf(sp, preMasterSecret, asciiLabel, seed, 48);
         }
 
+        internal static byte[] CalculatePskBinder(TlsContext context, bool isExternalPsk, TlsSecret earlySecret,
+            byte[] transcriptHash)
+        {
+            TlsCrypto crypto = context.Crypto;
+            SecurityParameters securityParameters = context.SecurityParameters;
+            int cryptoHashAlgorithm = TlsCryptoUtilities.GetHash(securityParameters.PrfHashAlgorithm);
+
+            string label = isExternalPsk ? "ext binder" : "res binder";
+            byte[] emptyTranscriptHash = crypto.CreateHash(cryptoHashAlgorithm).CalculateHash();
+
+            TlsSecret baseKey = DeriveSecret(securityParameters, earlySecret, label, emptyTranscriptHash);
+
+            try
+            {
+                return CalculateFinishedHmac(securityParameters, baseKey, transcriptHash);
+            }
+            finally
+            {
+                baseKey.Destroy();
+            }
+        }
+
         internal static byte[] CalculateVerifyData(TlsContext context, TlsHandshakeHash handshakeHash, bool isServer)
         {
             SecurityParameters securityParameters = context.SecurityParameters;
@@ -1489,12 +1528,9 @@ namespace Org.BouncyCastle.Tls
                 TlsSecret baseKey = isServer
                     ?   securityParameters.BaseKeyServer
                     :   securityParameters.BaseKeyClient;
-
-                TlsSecret finishedKey = DeriveSecret(securityParameters, baseKey, "finished", EmptyBytes);
-                int cryptoHashAlgorithm = TlsCryptoUtilities.GetHash(securityParameters.PrfHashAlgorithm);
                 byte[] transcriptHash = GetCurrentPrfHash(handshakeHash);
 
-                return finishedKey.CalculateHmac(cryptoHashAlgorithm, transcriptHash, 0, transcriptHash.Length);
+                return CalculateFinishedHmac(securityParameters, baseKey, transcriptHash);
             }
 
             if (negotiatedVersion.IsSsl)
@@ -1513,43 +1549,43 @@ namespace Org.BouncyCastle.Tls
 
         internal static void Establish13PhaseSecrets(TlsContext context)
         {
+            TlsCrypto crypto = context.Crypto;
             SecurityParameters securityParameters = context.SecurityParameters;
             int cryptoHashAlgorithm = TlsCryptoUtilities.GetHash(securityParameters.PrfHashAlgorithm);
-            int hashLen = securityParameters.PrfHashLength;
-            byte[] zeroes = new byte[hashLen];
+            TlsSecret zeros = crypto.HkdfInit(cryptoHashAlgorithm);
+            byte[] emptyTranscriptHash = crypto.CreateHash(cryptoHashAlgorithm).CalculateHash();
 
-            byte[] psk = securityParameters.Psk;
-            if (null == psk)
-            {
-                psk = zeroes;
-            }
-            else
+            TlsSecret preSharedKey = securityParameters.PreSharedKey;
+            if (null == preSharedKey)
             {
-                securityParameters.m_psk = null;
+                preSharedKey = zeros;
             }
 
-            byte[] ecdhe = zeroes;
+            TlsSecret earlySecret = crypto.HkdfInit(cryptoHashAlgorithm)
+                .HkdfExtract(cryptoHashAlgorithm, preSharedKey);
+
             TlsSecret sharedSecret = securityParameters.SharedSecret;
-            if (null != sharedSecret)
+            if (null == sharedSecret)
             {
-                securityParameters.m_sharedSecret = null;
-                ecdhe = sharedSecret.Extract();
+                sharedSecret = zeros;
             }
 
-            TlsCrypto crypto = context.Crypto;
+            TlsSecret handshakeSecret = DeriveSecret(securityParameters, earlySecret, "derived", emptyTranscriptHash)
+                .HkdfExtract(cryptoHashAlgorithm, sharedSecret);
 
-            byte[] emptyTranscriptHash = crypto.CreateHash(cryptoHashAlgorithm).CalculateHash();
+            if (sharedSecret != zeros)
+            {
+                sharedSecret.Destroy();
+            }
 
-            TlsSecret earlySecret = crypto.HkdfInit(cryptoHashAlgorithm)
-                .HkdfExtract(cryptoHashAlgorithm, psk);
-            TlsSecret handshakeSecret = DeriveSecret(securityParameters, earlySecret, "derived", emptyTranscriptHash)
-                .HkdfExtract(cryptoHashAlgorithm, ecdhe);
             TlsSecret masterSecret = DeriveSecret(securityParameters, handshakeSecret, "derived", emptyTranscriptHash)
-                .HkdfExtract(cryptoHashAlgorithm, zeroes);
+                .HkdfExtract(cryptoHashAlgorithm, zeros);
 
             securityParameters.m_earlySecret = earlySecret;
             securityParameters.m_handshakeSecret = handshakeSecret;
             securityParameters.m_masterSecret = masterSecret;
+            securityParameters.m_preSharedKey = null;
+            securityParameters.m_sharedSecret = null;
         }
 
         private static void Establish13TrafficSecrets(TlsContext context, byte[] transcriptHash, TlsSecret phaseSecret,
@@ -5170,8 +5206,13 @@ namespace Org.BouncyCastle.Tls
         internal static TlsSecret DeriveSecret(SecurityParameters securityParameters, TlsSecret secret, string label,
             byte[] transcriptHash)
         {
-            return TlsCryptoUtilities.HkdfExpandLabel(secret, securityParameters.PrfHashAlgorithm, label,
-                transcriptHash, securityParameters.PrfHashLength);
+            short prfHashAlgorithm = securityParameters.PrfHashAlgorithm;
+            int prfHashLength = securityParameters.PrfHashLength;
+
+            if (transcriptHash.Length != prfHashLength)
+                throw new TlsFatalAlert(AlertDescription.internal_error);
+
+            return TlsCryptoUtilities.HkdfExpandLabel(secret, prfHashAlgorithm, label, transcriptHash, prfHashLength);
         }
 
         internal static TlsSecret GetSessionMasterSecret(TlsCrypto crypto, TlsSecret masterSecret)
diff --git a/crypto/src/tls/crypto/TlsSecret.cs b/crypto/src/tls/crypto/TlsSecret.cs
index 8c39c56f7..8aea34bcf 100644
--- a/crypto/src/tls/crypto/TlsSecret.cs
+++ b/crypto/src/tls/crypto/TlsSecret.cs
@@ -61,7 +61,7 @@ namespace Org.BouncyCastle.Tls.Crypto
         /// <see cref="CryptoHashAlgorithm"/> for values.</param>
         /// <param name="ikm">input keying material.</param>
         /// <returns>a pseudo-random key (of HashLen octets).</returns>
-        TlsSecret HkdfExtract(int cryptoHashAlgorithm, byte[] ikm);
+        TlsSecret HkdfExtract(int cryptoHashAlgorithm, TlsSecret ikm);
 
         bool IsAlive();
     }
diff --git a/crypto/src/tls/crypto/impl/AbstractTlsSecret.cs b/crypto/src/tls/crypto/impl/AbstractTlsSecret.cs
index 1ea25344d..cc07f978f 100644
--- a/crypto/src/tls/crypto/impl/AbstractTlsSecret.cs
+++ b/crypto/src/tls/crypto/impl/AbstractTlsSecret.cs
@@ -9,6 +9,11 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl
     public abstract class AbstractTlsSecret
         : TlsSecret
     {
+        protected static byte[] CopyData(AbstractTlsSecret other)
+        {
+            return other.CopyData();
+        }
+
         protected byte[] m_data;
 
         /// <summary>Base constructor.</summary>
@@ -79,7 +84,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl
 
         public abstract TlsSecret HkdfExpand(int cryptoHashAlgorithm, byte[] info, int length);
 
-        public abstract TlsSecret HkdfExtract(int cryptoHashAlgorithm, byte[] ikm);
+        public abstract TlsSecret HkdfExtract(int cryptoHashAlgorithm, TlsSecret ikm);
 
         public virtual bool IsAlive()
         {
diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsSecret.cs b/crypto/src/tls/crypto/impl/bc/BcTlsSecret.cs
index b76c1612a..47a3d1212 100644
--- a/crypto/src/tls/crypto/impl/bc/BcTlsSecret.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcTlsSecret.cs
@@ -12,6 +12,21 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
     public class BcTlsSecret
         : AbstractTlsSecret
     {
+        public static BcTlsSecret Convert(BcTlsCrypto crypto, TlsSecret secret)
+        {
+            if (secret is BcTlsSecret)
+                return (BcTlsSecret)secret;
+
+            if (secret is AbstractTlsSecret)
+            {
+                AbstractTlsSecret abstractTlsSecret = (AbstractTlsSecret)secret;
+
+                return crypto.AdoptLocalSecret(CopyData(abstractTlsSecret));
+            }
+
+            throw new ArgumentException("unrecognized TlsSecret - cannot copy data: " + Platform.GetTypeName(secret));
+        }
+
         // SSL3 magic mix constants ("A", "BB", "CCC", ...)
         private static readonly byte[] Ssl3Const = GenerateSsl3Constants();
 
@@ -105,7 +120,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             }
         }
 
-        public override TlsSecret HkdfExtract(int cryptoHashAlgorithm, byte[] ikm)
+        public override TlsSecret HkdfExtract(int cryptoHashAlgorithm, TlsSecret ikm)
         {
             lock (this)
             {
@@ -117,7 +132,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
                 HMac hmac = new HMac(m_crypto.CreateDigest(cryptoHashAlgorithm));
                 hmac.Init(new KeyParameter(salt));
 
-                hmac.BlockUpdate(ikm, 0, ikm.Length);
+                Convert(m_crypto, ikm).UpdateMac(hmac);
 
                 byte[] prk = new byte[hmac.GetMacSize()];
                 hmac.DoFinal(prk, 0);
@@ -238,5 +253,15 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             HmacHash(digest, m_data, 0, m_data.Length, labelSeed, result);
             return result;
         }
+
+        protected virtual void UpdateMac(IMac mac)
+        {
+            lock (this)
+            {
+                CheckAlive();
+
+                mac.BlockUpdate(m_data, 0, m_data.Length);
+            }
+        }
     }
 }
diff --git a/crypto/test/src/tls/crypto/test/BcTlsCryptoTest.cs b/crypto/test/src/tls/crypto/test/BcTlsCryptoTest.cs
index cf1397ef2..75a3d1e00 100644
--- a/crypto/test/src/tls/crypto/test/BcTlsCryptoTest.cs
+++ b/crypto/test/src/tls/crypto/test/BcTlsCryptoTest.cs
@@ -236,7 +236,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Tests
 
             // {server}  extract secret "early":
             {
-                byte[] ikm = new byte[32];
+                TlsSecret ikm = m_crypto.HkdfInit(hash);
                 early = init.HkdfExtract(hash, ikm);
                 Expect(early, "33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a");
             }
@@ -250,7 +250,8 @@ namespace Org.BouncyCastle.Tls.Crypto.Tests
 
             // {server}  extract secret "handshake":
             {
-                byte[] ikm = Hex("8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d");
+                TlsSecret ikm = m_crypto.CreateSecret(
+                    Hex("8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d"));
                 handshake = handshake.HkdfExtract(hash, ikm);
                 Expect(handshake, "1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac");
             }
@@ -284,7 +285,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Tests
 
             // {server}  extract secret "master":
             {
-                byte[] ikm = new byte[32];
+                TlsSecret ikm = m_crypto.HkdfInit(hash);
                 master = master.HkdfExtract(hash, ikm);
                 Expect(master, "18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19");
             }
@@ -408,11 +409,11 @@ namespace Org.BouncyCastle.Tls.Crypto.Tests
             {
                 int hash = hashes[i];
                 int hashLen = TlsCryptoUtilities.GetHashOutputSize(hash);
-                byte[] zeroes = new byte[hashLen];
+                TlsSecret zeros = m_crypto.HkdfInit(hash);
 
                 int limit = 255 * hashLen;
 
-                TlsSecret secret = m_crypto.HkdfInit(hash).HkdfExtract(hash, zeroes);
+                TlsSecret secret = m_crypto.HkdfInit(hash).HkdfExtract(hash, zeros);
 
                 try
                 {