Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AES-GCM runtime availability check, Advertise / initialize AES-GCM cipher only if supported #197

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1037,14 +1037,17 @@ void CSteamNetworkConnectionBase::ClearCrypto()
void CSteamNetworkConnectionBase::ClearLocalCrypto()
{
AssertLocksHeldByCurrentThread();
m_eNegotiatedCipher = k_ESteamNetworkingSocketsCipher_INVALID;
m_cbEncryptionOverhead = k_cbAESGCMTagSize;
m_keyExchangePrivateKeyLocal.Wipe();
m_msgCryptLocal.Clear();
m_msgSignedCryptLocal.Clear();
m_bCryptKeysValid = false;
m_cryptContextSend.Wipe();
m_cryptContextRecv.Wipe();
if (m_eNegotiatedCipher != k_ESteamNetworkingSocketsCipher_NULL)
{
m_cryptContextSend.Wipe();
m_cryptContextRecv.Wipe();
}
m_eNegotiatedCipher = k_ESteamNetworkingSocketsCipher_INVALID;
m_cbEncryptionOverhead = k_cbAESGCMTagSize;
Copy link
Contributor

@zpostfacto zpostfacto Oct 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be legal to always wipe these, even if they aren't initialized?

Stepping back:

If we're going to support more than one cipher we need to refactor this. because m_cryptContextSend is too generic of a name if it is always going to be an instance of AES-GCM. We probably should add a new abstract interface ISymmetricEncryptContext, with two virtual methods, Encrypt() and the destructor. We would never "wipe" a context, we would just delete it, and the destructor would always securely wipe it. AES_GCM_EncryptContext would implement this interface. (The old mix-in interface design pattern --- yes, multiple-base classes.) So then we would have std::unique_ptr<ISymmetricEncryptContext> m_pEncryptContext. (And the same for decrypt.) So you would deal in concrete types when you were initializing, but once initialization was complete, you would just have the abstract type.

There's a lot of stuff going on in the Steam branch that needs to be merged and cleaned up in crypto land (recently upgraded to a new version of OpenSSL), but if you want to take a stab at it, I can pull that and then I can clean this up when I get back in sync with Steam.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd debated that, but I wasn't sure how extensive a refactor would be eagerly welcomed. 😄

Will take a look when I have a moment. 👍

m_cryptIVSend.Wipe();
m_cryptIVRecv.Wipe();
}
Expand Down Expand Up @@ -1219,19 +1222,29 @@ void CSteamNetworkConnectionBase::SetCryptoCipherList()
// V
case 0:
// Not allowed
m_msgCryptLocal.add_ciphers( k_ESteamNetworkingSocketsCipher_AES_256_GCM );
if (AES_GCM_CipherContext::IsAvailable())
{
m_msgCryptLocal.add_ciphers( k_ESteamNetworkingSocketsCipher_AES_256_GCM );
}
Assert( m_msgCryptLocal.ciphers_size() > 0 );
break;
Copy link
Contributor

@zpostfacto zpostfacto Oct 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this situation should be fatal to the connection. (If the connection is configured to require encryption, it should be fatal if encryption is not available.)


case 1:
// Allowed, but prefer encrypted
m_msgCryptLocal.add_ciphers( k_ESteamNetworkingSocketsCipher_AES_256_GCM );
if (AES_GCM_CipherContext::IsAvailable())
{
m_msgCryptLocal.add_ciphers( k_ESteamNetworkingSocketsCipher_AES_256_GCM );
}
m_msgCryptLocal.add_ciphers( k_ESteamNetworkingSocketsCipher_NULL );
break;

case 2:
// Allowed, preferred
m_msgCryptLocal.add_ciphers( k_ESteamNetworkingSocketsCipher_NULL );
m_msgCryptLocal.add_ciphers( k_ESteamNetworkingSocketsCipher_AES_256_GCM );
if (AES_GCM_CipherContext::IsAvailable())
{
m_msgCryptLocal.add_ciphers( k_ESteamNetworkingSocketsCipher_AES_256_GCM );
}
break;

case 3:
Expand Down Expand Up @@ -1693,13 +1706,16 @@ bool CSteamNetworkConnectionBase::BFinishCryptoHandshake( bool bServer )
V_memcpy( pStart, &expandTemp, sizeof(SHA256Digest_t) );
}

// Set encryption keys into the contexts, and set parameters
if (
!m_cryptContextSend.Init( cryptKeySend.m_buf, cryptKeySend.k_nSize, m_cryptIVSend.k_nSize, k_cbAESGCMTagSize )
|| !m_cryptContextRecv.Init( cryptKeyRecv.m_buf, cryptKeyRecv.k_nSize, m_cryptIVRecv.k_nSize, k_cbAESGCMTagSize ) )
if (m_eNegotiatedCipher != k_ESteamNetworkingSocketsCipher_NULL)
{
ConnectionState_ProblemDetectedLocally( k_ESteamNetConnectionEnd_Remote_BadCrypt, "Error initializing crypto" );
return false;
// Set encryption keys into the contexts, and set parameters
if (
!m_cryptContextSend.Init( cryptKeySend.m_buf, cryptKeySend.k_nSize, m_cryptIVSend.k_nSize, k_cbAESGCMTagSize )
|| !m_cryptContextRecv.Init( cryptKeyRecv.m_buf, cryptKeyRecv.k_nSize, m_cryptIVRecv.k_nSize, k_cbAESGCMTagSize ) )
{
ConnectionState_ProblemDetectedLocally( k_ESteamNetConnectionEnd_Remote_BadCrypt, "Error initializing crypto" );
return false;
}
}

//
Expand Down