diff options
-rw-r--r-- | crypto/src/tls/SecurityParameters.cs | 13 | ||||
-rw-r--r-- | crypto/src/tls/TlsUtilities.cs | 93 | ||||
-rw-r--r-- | crypto/src/tls/crypto/TlsSecret.cs | 2 | ||||
-rw-r--r-- | crypto/src/tls/crypto/impl/AbstractTlsSecret.cs | 7 | ||||
-rw-r--r-- | crypto/src/tls/crypto/impl/bc/BcTlsSecret.cs | 29 | ||||
-rw-r--r-- | crypto/test/src/tls/crypto/test/BcTlsCryptoTest.cs | 11 |
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 { |