diff --git a/crypto/src/tls/DtlsClientProtocol.cs b/crypto/src/tls/DtlsClientProtocol.cs
index cd2fff709..a4810b983 100644
--- a/crypto/src/tls/DtlsClientProtocol.cs
+++ b/crypto/src/tls/DtlsClientProtocol.cs
@@ -446,7 +446,7 @@ namespace Org.BouncyCastle.Tls
securityParameters.m_clientSupportedGroups = TlsExtensionsUtilities.GetSupportedGroupsExtension(
state.clientExtensions);
- state.clientAgreements = TlsUtilities.AddEarlyKeySharesToClientHello(state.clientContext, state.client,
+ state.clientAgreements = TlsUtilities.AddKeyShareToClientHello(state.clientContext, state.client,
state.clientExtensions);
if (TlsUtilities.IsExtendedMasterSecretOptionalDtls(context.ClientSupportedVersions)
diff --git a/crypto/src/tls/OfferedPsks.cs b/crypto/src/tls/OfferedPsks.cs
index dfa2be034..14b6448b4 100644
--- a/crypto/src/tls/OfferedPsks.cs
+++ b/crypto/src/tls/OfferedPsks.cs
@@ -9,15 +9,18 @@ namespace Org.BouncyCastle.Tls
{
public sealed class OfferedPsks
{
- internal class Config
+ internal class BindersConfig
{
internal readonly TlsPsk[] m_psks;
+ internal readonly short[] m_pskKeyExchangeModes;
internal readonly TlsSecret[] m_earlySecrets;
internal int m_bindersSize;
- internal Config(TlsPsk[] psks, TlsSecret[] earlySecrets, int bindersSize)
+ internal BindersConfig(TlsPsk[] psks, short[] pskKeyExchangeModes, TlsSecret[] earlySecrets,
+ int bindersSize)
{
this.m_psks = psks;
+ this.m_pskKeyExchangeModes = pskKeyExchangeModes;
this.m_earlySecrets = earlySecrets;
this.m_bindersSize = bindersSize;
}
@@ -93,11 +96,11 @@ namespace Org.BouncyCastle.Tls
/// <exception cref="IOException"/>
internal static void EncodeBinders(Stream output, TlsCrypto crypto, TlsHandshakeHash handshakeHash,
- Config config)
+ BindersConfig bindersConfig)
{
- TlsPsk[] psks = config.m_psks;
- TlsSecret[] earlySecrets = config.m_earlySecrets;
- int expectedLengthOfBindersList = config.m_bindersSize - 2;
+ TlsPsk[] psks = bindersConfig.m_psks;
+ TlsSecret[] earlySecrets = bindersConfig.m_earlySecrets;
+ int expectedLengthOfBindersList = bindersConfig.m_bindersSize - 2;
TlsUtilities.CheckUint16(expectedLengthOfBindersList);
TlsUtilities.WriteUint16(expectedLengthOfBindersList, output);
diff --git a/crypto/src/tls/SecurityParameters.cs b/crypto/src/tls/SecurityParameters.cs
index 23a83a65f..548e4a4ca 100644
--- a/crypto/src/tls/SecurityParameters.cs
+++ b/crypto/src/tls/SecurityParameters.cs
@@ -22,7 +22,6 @@ namespace Org.BouncyCastle.Tls
internal TlsSecret m_exporterMasterSecret = null;
internal TlsSecret m_handshakeSecret = null;
internal TlsSecret m_masterSecret = null;
- internal TlsSecret m_sharedSecret = null;
internal TlsSecret m_trafficSecretClient = null;
internal TlsSecret m_trafficSecretServer = null;
internal byte[] m_clientRandom = null;
@@ -78,7 +77,6 @@ namespace Org.BouncyCastle.Tls
this.m_exporterMasterSecret = ClearSecret(m_exporterMasterSecret);
this.m_handshakeSecret = ClearSecret(m_handshakeSecret);
this.m_masterSecret = ClearSecret(m_masterSecret);
- this.m_sharedSecret = ClearSecret(m_sharedSecret);
}
public ProtocolName ApplicationProtocol
@@ -276,11 +274,6 @@ namespace Org.BouncyCastle.Tls
get { return m_sessionID; }
}
- public TlsSecret SharedSecret
- {
- get { return m_sharedSecret; }
- }
-
public byte[] SrpIdentity
{
get { return m_srpIdentity; }
diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs
index 190a1927f..5356880ff 100644
--- a/crypto/src/tls/TlsClientProtocol.cs
+++ b/crypto/src/tls/TlsClientProtocol.cs
@@ -14,6 +14,7 @@ namespace Org.BouncyCastle.Tls
internal TlsClientContextImpl m_tlsClientContext = null;
protected IDictionary m_clientAgreements = null;
+ internal OfferedPsks.BindersConfig m_clientBinders = null;
protected ClientHello m_clientHello = null;
protected TlsKeyExchange m_keyExchange = null;
protected TlsAuthentication m_authentication = null;
@@ -90,6 +91,7 @@ namespace Org.BouncyCastle.Tls
base.CleanupHandshake();
this.m_clientAgreements = null;
+ this.m_clientBinders = null;
this.m_clientHello = null;
this.m_keyExchange = null;
this.m_authentication = null;
@@ -832,6 +834,15 @@ namespace Org.BouncyCastle.Tls
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
}
+ if (null != m_clientBinders)
+ {
+ if (!Arrays.Contains(m_clientBinders.m_pskKeyExchangeModes, PskKeyExchangeMode.psk_dhe_ke))
+ {
+ // TODO[tls13-psk] Notify client that no PSK was selected.
+ this.m_clientBinders = null;
+ }
+ }
+
/*
* RFC 8446 4.2.8. Upon receipt of this [Key Share] extension in a HelloRetryRequest, the
* client MUST verify that (1) the selected_group field corresponds to a group which was
@@ -939,10 +950,29 @@ namespace Org.BouncyCastle.Tls
*/
securityParameters.m_statusRequestVersion = m_clientExtensions.Contains(ExtensionType.status_request) ? 1 : 0;
+ // TODO[tls13-psk] Use PSK early secret if negotiated
+ TlsSecret pskEarlySecret = null;
+
+ if (null != m_clientBinders)
+ {
+ // TODO[tls13-psk] Process the server's pre_shared_key response, if any
+ //int selected_identity = TlsExtensionsUtilities.GetPreSharedKeyServerHello(extensions);
+
+ // TODO[tls13-psk] Notify client of selected PSK
+ // pskEarlySecret = ...;
+
+ this.m_clientBinders = null;
+ }
+
+ TlsSecret sharedSecret = null;
+
{
KeyShareEntry keyShareEntry = TlsExtensionsUtilities.GetKeyShareServerHello(extensions);
if (null == keyShareEntry)
+ {
+ // TODO[tls13-psk] This would be OK for PskKeyExchangeMode.psk_ke (and not after HRR)
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
+ }
if (!m_clientAgreements.Contains(keyShareEntry.NamedGroup))
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
@@ -952,14 +982,11 @@ namespace Org.BouncyCastle.Tls
this.m_clientAgreements = null;
agreement.ReceivePeerValue(keyShareEntry.KeyExchange);
- securityParameters.m_sharedSecret = agreement.CalculateSecret();
-
- // TODO[tls13-psk] Use PSK early secret if negotiated
- TlsSecret pskEarlySecret = null;
-
- TlsUtilities.Establish13PhaseSecrets(m_tlsClientContext, pskEarlySecret);
+ sharedSecret = agreement.CalculateSecret();
}
+ TlsUtilities.Establish13PhaseSecrets(m_tlsClientContext, pskEarlySecret, sharedSecret);
+
{
InvalidateSession();
@@ -1477,13 +1504,12 @@ namespace Org.BouncyCastle.Tls
/// <exception cref="IOException"/>
protected virtual void Send13ClientHelloRetry()
{
- // TODO[tls13-psk] Create a new ClientHello object and handle any changes to the bindersSize
-
IDictionary clientHelloExtensions = m_clientHello.Extensions;
clientHelloExtensions.Remove(ExtensionType.cookie);
clientHelloExtensions.Remove(ExtensionType.early_data);
clientHelloExtensions.Remove(ExtensionType.key_share);
+ clientHelloExtensions.Remove(ExtensionType.pre_shared_key);
/*
* RFC 4.2.2. When sending the new ClientHello, the client MUST copy the contents of the
@@ -1492,6 +1518,9 @@ namespace Org.BouncyCastle.Tls
*/
if (null != m_retryCookie)
{
+ /*
+ * - Including a "cookie" extension if one was provided in the HelloRetryRequest.
+ */
TlsExtensionsUtilities.AddCookieExtension(clientHelloExtensions, m_retryCookie);
this.m_retryCookie = null;
}
@@ -1504,14 +1533,24 @@ namespace Org.BouncyCastle.Tls
if (m_retryGroup < 0)
throw new TlsFatalAlert(AlertDescription.internal_error);
+ /*
+ * - If a "key_share" extension was supplied in the HelloRetryRequest, replacing the list of shares
+ * with a list containing a single KeyShareEntry from the indicated group
+ */
this.m_clientAgreements = TlsUtilities.AddKeyShareToClientHelloRetry(m_tlsClientContext,
clientHelloExtensions, m_retryGroup);
/*
- * TODO[tls13] Updating the "pre_shared_key" extension if present by recomputing the
- * "obfuscated_ticket_age" and binder values and (optionally) removing any PSKs which are
- * incompatible with the server's indicated cipher suite.
+ * - Updating the "pre_shared_key" extension if present by recomputing the "obfuscated_ticket_age"
+ * and binder values and (optionally) removing any PSKs which are incompatible with the server's
+ * indicated cipher suite.
*/
+ if (null != m_clientBinders)
+ {
+ // TODO[tls13-psk]
+ //this.m_clientBinders = TlsUtilities.AddPreSharedKeyToClientHelloRetry(m_tlsClientContext,
+ // m_clientBinders, clientHelloExtensions);
+ }
/*
* TODO[tls13] Optionally adding, removing, or changing the length of the "padding"
@@ -1627,7 +1666,11 @@ namespace Org.BouncyCastle.Tls
securityParameters.m_clientSupportedGroups = TlsExtensionsUtilities.GetSupportedGroupsExtension(
m_clientExtensions);
- this.m_clientAgreements = TlsUtilities.AddEarlyKeySharesToClientHello(m_tlsClientContext, m_tlsClient,
+ this.m_clientBinders = TlsUtilities.AddPreSharedKeyToClientHello(m_tlsClientContext, m_tlsClient,
+ m_clientExtensions, offeredCipherSuites);
+
+ // TODO[tls13-psk] Perhaps don't add key_share if external PSK(s) offered and 'psk_dhe_ke' not offered
+ this.m_clientAgreements = TlsUtilities.AddKeyShareToClientHello(m_tlsClientContext, m_tlsClient,
m_clientExtensions);
if (TlsUtilities.IsExtendedMasterSecretOptionalTls(supportedVersions)
@@ -1684,9 +1727,7 @@ namespace Org.BouncyCastle.Tls
- // TODO[tls13-psk] Calculate the total length of the binders that will be added.
- int bindersSize = 0;
- //int bindersSize = 2 + lengthOfBindersList;
+ int bindersSize = null == m_clientBinders ? 0 : m_clientBinders.m_bindersSize;
this.m_clientHello = new ClientHello(legacy_version, securityParameters.ClientRandom, legacy_session_id,
null, offeredCipherSuites, m_clientExtensions, bindersSize);
@@ -1702,7 +1743,10 @@ namespace Org.BouncyCastle.Tls
message.PrepareClientHello(m_handshakeHash, m_clientHello.BindersSize);
- // TODO[tls13-psk] Calculate any PSK binders and write them to 'message' here.
+ if (null != m_clientBinders)
+ {
+ OfferedPsks.EncodeBinders(message, Context.Crypto, m_handshakeHash, m_clientBinders);
+ }
message.SendClientHello(this, m_handshakeHash, m_clientHello.BindersSize);
}
diff --git a/crypto/src/tls/TlsServerProtocol.cs b/crypto/src/tls/TlsServerProtocol.cs
index 2afb625a8..89365afad 100644
--- a/crypto/src/tls/TlsServerProtocol.cs
+++ b/crypto/src/tls/TlsServerProtocol.cs
@@ -309,6 +309,11 @@ namespace Org.BouncyCastle.Tls
this.m_expectSessionTicket = false;
+ // TODO[tls13-psk] Use PSK early secret if negotiated
+ TlsSecret pskEarlySecret = null;
+
+ TlsSecret sharedSecret = null;
+
{
int namedGroup = clientShare.NamedGroup;
@@ -331,14 +336,11 @@ namespace Org.BouncyCastle.Tls
TlsExtensionsUtilities.AddKeyShareServerHello(serverHelloExtensions, serverShare);
agreement.ReceivePeerValue(clientShare.KeyExchange);
- securityParameters.m_sharedSecret = agreement.CalculateSecret();
-
- // TODO[tls13-psk] Use PSK early secret if negotiated
- TlsSecret pskEarlySecret = null;
-
- TlsUtilities.Establish13PhaseSecrets(m_tlsServerContext, pskEarlySecret);
+ sharedSecret = agreement.CalculateSecret();
}
+ TlsUtilities.Establish13PhaseSecrets(m_tlsServerContext, pskEarlySecret, sharedSecret);
+
this.m_serverExtensions = serverEncryptedExtensions;
ApplyMaxFragmentLengthExtension(securityParameters.MaxFragmentLength);
diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs
index a80e6da32..7f529d8c5 100644
--- a/crypto/src/tls/TlsUtilities.cs
+++ b/crypto/src/tls/TlsUtilities.cs
@@ -1559,7 +1559,8 @@ namespace Org.BouncyCastle.Tls
return Prf(securityParameters, master_secret, asciiLabel, prfHash, verify_data_length).Extract();
}
- internal static void Establish13PhaseSecrets(TlsContext context, TlsSecret pskEarlySecret)
+ internal static void Establish13PhaseSecrets(TlsContext context, TlsSecret pskEarlySecret,
+ TlsSecret sharedSecret)
{
TlsCrypto crypto = context.Crypto;
SecurityParameters securityParameters = context.SecurityParameters;
@@ -1575,7 +1576,6 @@ namespace Org.BouncyCastle.Tls
.HkdfExtract(cryptoHashAlgorithm, zeros);
}
- TlsSecret sharedSecret = securityParameters.SharedSecret;
if (null == sharedSecret)
{
sharedSecret = zeros;
@@ -1595,7 +1595,6 @@ namespace Org.BouncyCastle.Tls
securityParameters.m_earlySecret = earlySecret;
securityParameters.m_handshakeSecret = handshakeSecret;
securityParameters.m_masterSecret = masterSecret;
- securityParameters.m_sharedSecret = null;
}
private static void Establish13TrafficSecrets(TlsContext context, byte[] transcriptHash, TlsSecret phaseSecret,
@@ -4844,7 +4843,7 @@ namespace Org.BouncyCastle.Tls
return false;
}
- internal static IDictionary AddEarlyKeySharesToClientHello(TlsClientContext clientContext, TlsClient client,
+ internal static IDictionary AddKeyShareToClientHello(TlsClientContext clientContext, TlsClient client,
IDictionary clientExtensions)
{
/*
@@ -5435,17 +5434,40 @@ namespace Org.BouncyCastle.Tls
#endif
/// <exception cref="IOException"/>
- internal static OfferedPsks.Config GetOfferedPsksConfig(TlsClientContext clientContext, TlsClient client)
+ internal static OfferedPsks.BindersConfig AddPreSharedKeyToClientHello(TlsClientContext clientContext,
+ TlsClient client, IDictionary clientExtensions, int[] offeredCipherSuites)
{
- TlsPskExternal[] pskExternals = GetPskExternalsClient(client);
+ if (!IsTlsV13(clientContext.ClientVersion))
+ return null;
+
+ TlsPskExternal[] pskExternals = GetPskExternalsClient(client, offeredCipherSuites);
if (null == pskExternals)
return null;
+ short[] pskKeyExchangeModes = client.GetPskKeyExchangeModes();
+ if (IsNullOrEmpty(pskKeyExchangeModes))
+ throw new TlsFatalAlert(AlertDescription.internal_error,
+ "External PSKs configured but no PskKeyExchangeMode available");
+
+ // Add the pre_shared_key extension
+ {
+ IList identities = Platform.CreateArrayList(pskExternals.Length);
+ for (int i = 0; i < pskExternals.Length; ++i)
+ {
+ TlsPskExternal pskExternal = pskExternals[i];
+
+ // TODO[tls13-psk] Handle obfuscated_ticket_age for resumption PSKs
+ identities.Add(new PskIdentity(pskExternal.Identity, 0L));
+ }
+
+ TlsExtensionsUtilities.AddPreSharedKeyClientHello(clientExtensions, new OfferedPsks(identities));
+ }
+
TlsSecret[] pskEarlySecrets = GetPskEarlySecrets(clientContext.Crypto, pskExternals);
int bindersSize = OfferedPsks.GetBindersSize(pskExternals);
- return new OfferedPsks.Config(pskExternals, pskEarlySecrets, bindersSize);
+ return new OfferedPsks.BindersConfig(pskExternals, pskKeyExchangeModes, pskEarlySecrets, bindersSize);
}
internal static TlsSecret GetPskEarlySecret(TlsCrypto crypto, TlsPsk psk)
@@ -5469,24 +5491,29 @@ namespace Org.BouncyCastle.Tls
}
/// <exception cref="IOException"/>
- internal static TlsPskExternal[] GetPskExternalsClient(TlsClient client)
+ internal static TlsPskExternal[] GetPskExternalsClient(TlsClient client, int[] offeredCipherSuites)
{
- // TODO[tl13-psk] Ensure PSK hash algorithms are supported by cipher suites
-
IList externalPsks = client.GetExternalPsks();
if (IsNullOrEmpty(externalPsks))
return null;
+ int[] prfAlgorithms = GetPrfAlgorithms13(offeredCipherSuites);
+
int count = externalPsks.Count;
TlsPskExternal[] result = new TlsPskExternal[count];
for (int i = 0; i < count; ++i)
{
- TlsPskExternal element = externalPsks[i] as TlsPskExternal;
- if (null == element)
- throw new TlsFatalAlert(AlertDescription.internal_error);
+ TlsPskExternal pskExternal = externalPsks[i] as TlsPskExternal;
+ if (null == pskExternal)
+ throw new TlsFatalAlert(AlertDescription.internal_error,
+ "External PSKs element is not a TlsPSKExternal");
+
+ if (!Arrays.Contains(prfAlgorithms, pskExternal.PrfAlgorithm))
+ throw new TlsFatalAlert(AlertDescription.internal_error,
+ "External PSK incompatible with offered cipher suites");
- result[i] = element;
+ result[i] = pskExternal;
}
return result;
|