summary refs log tree commit diff
path: root/crypto/src/tls
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 /crypto/src/tls
parentCalculate HMAC without extracting TlsSecret (diff)
downloadBouncyCastle.NET-ed25519-934e1a1047ef192cf2fb5b5b5822561118a10c20.tar.xz
Refactoring around TLS HKDF
Diffstat (limited to 'crypto/src/tls')
-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
5 files changed, 108 insertions, 36 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);
+            }
+        }
     }
 }