#include #include #include #include #include #include #include using namespace SteamNetworkingSocketsLib; // Time as I write this. So that the tests will still work even after these generated keys expire. time_t k_timeTestNow = 1555374048; void GenerateCert( CMsgSteamDatagramCertificateSigned &msgOut, const char *certData, const CECSigningPrivateKey &keyCAPrivateKey, uint64 nCAKeyID ) { msgOut.Clear(); // Generate a dummy cert with the requested fields and give it a keypair { CMsgSteamDatagramCertificate msgCert; DbgVerify( google::protobuf::TextFormat::ParseFromString( std::string( certData ), &msgCert ) ); msgCert.set_time_expiry( k_timeTestNow + 3600*8 ); CECSigningPrivateKey tempIdentityPrivateKey; CECSigningPublicKey tempIdentityPublicKey; CCrypto::GenerateSigningKeyPair( &tempIdentityPublicKey, &tempIdentityPrivateKey ); DbgVerify( tempIdentityPublicKey.GetRawDataAsStdString( msgCert.mutable_key_data() ) ); msgCert.set_key_type( CMsgSteamDatagramCertificate_EKeyType_ED25519 ); DbgVerify( msgCert.SerializeToString( msgOut.mutable_cert() ) ); } // Sign it CryptoSignature_t sig; keyCAPrivateKey.GenerateSignature( msgOut.cert().c_str(), msgOut.cert().length(), &sig ); msgOut.set_ca_key_id( nCAKeyID ); msgOut.set_ca_signature( &sig, sizeof(sig) ); } int main() { SteamNetworkingErrMsg errMsg; // // Populate our cert store with some certs. // See make_test_certs.py // // Dynamic (not-hardcoded) self-signed cert // KeyID . . . .: 8112647883641536425 // Public key . : ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBkU/enzJscDJp0N1RbYkL0E9wXVO5krNr8rm4JDrNBE CECSigningPrivateKey privkey_dynamic_root; DbgVerify( privkey_dynamic_root.ParsePEM( "-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZWQy NTUxOQAAACAZFP3p8ybHAyadDdUW2JC9BPcF1TuZKza/K5uCQ6zQRAAAAH8SNFZ4EjRWeAAA AAtzc2gtZWQyNTUxOQAAACAZFP3p8ybHAyadDdUW2JC9BPcF1TuZKza/K5uCQ6zQRAAAAEDq vSVEpg9EZkMej6Fw1EFCuiAnNtMCTKmf8ZRXSwzrXRkU/enzJscDJp0N1RbYkL0E9wXVO5kr Nr8rm4JDrNBE -----END OPENSSH PRIVATE KEY----- ", 375 ) ); // CA KeyID . . : 8112647883641536425 //const uint64 k_key_dynamic_root = 8112647883641536425ull; DbgVerify( CertStore_AddCertFromBase64( "Ii4IARIgGRT96fMmxwMmnQ3VFtiQvQT3BdU7mSs2vyubgkOs0ERFmSm1XE2ZkHdgKak/R3xE6pVwMkBlDV+UgOQHEwEg5GnlKLxK5aqKAWl8J0Eo2pl6+grtk5fitu9U15EXtkHhw1o7q8+sZFvRJw8/zXuohkzVB1AC", errMsg ) ); // Intermediate cert for app (CSGO), signed by hardcoded key // KeyID . . . .: 1790264268120135407 // Public key . : ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILumwWENaKq+n5xzAvfLgOOaeLvQqky4LzU0HI0qBnU/ CECSigningPrivateKey privkey_csgo; DbgVerify( privkey_csgo.ParsePEM( "-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZWQy NTUxOQAAACC7psFhDWiqvp+ccwL3y4Djmni70KpMuC81NByNKgZ1PwAAAH8SNFZ4EjRWeAAA AAtzc2gtZWQyNTUxOQAAACC7psFhDWiqvp+ccwL3y4Djmni70KpMuC81NByNKgZ1PwAAAEAs mu57b1o/lDSwUKD4LvIM/kQMwFIbzEbFIoyuyDEf3bumwWENaKq+n5xzAvfLgOOaeLvQqky4 LzU0HI0qBnU/ -----END OPENSSH PRIVATE KEY----- ", 375 ) ); // CA KeyID . . : 9417917822780561193 // Apps . . . . : [730] const uint64 k_key_csgo = 1790264268120135407ull; DbgVerify( CertStore_AddCertFromBase64( "IjEIARIgu6bBYQ1oqr6fnHMC98uA45p4u9CqTLgvNTQcjSoGdT9FmSm1XE2ZkHdgUNoFKSnXp45cKrOCMkCPs0eTzHWsN0oDNrxnAvvi3MiDv6Tv4CudquT4D/nss3usW6xUPD3YIbbISWxL8YE1HGYVRILCYWDCqxoBOK4M", errMsg ) ); // Cert for particular data center. Not specifically scoped to app, but signed by CSGO cert, so should effectively be scoped. // KeyID . . . .: 10851291850214533835 // Public key . : ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKd+8wfN8OYAQ+P4fdiC+7xwakeqOlDSqKY5/9wtkUim CECSigningPrivateKey privkey_csgo_eatmwh; DbgVerify( privkey_csgo_eatmwh.ParsePEM( "-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZWQy NTUxOQAAACCnfvMHzfDmAEPj+H3Ygvu8cGpHqjpQ0qimOf/cLZFIpgAAAH8SNFZ4EjRWeAAA AAtzc2gtZWQyNTUxOQAAACCnfvMHzfDmAEPj+H3Ygvu8cGpHqjpQ0qimOf/cLZFIpgAAAEA0 pWdXwJgrvazaE/69qtE0zsjQJfzshriDJxfC467ktqd+8wfN8OYAQ+P4fdiC+7xwakeqOlDS qKY5/9wtkUim -----END OPENSSH PRIVATE KEY----- ", 375 ) ); // CA KeyID . . : 1790264268120135407 // POPs . . . . : [u'eat', u'mwh'] const uint64 k_key_csgo_eatmwh = 10851291850214533835ull; DbgVerify( CertStore_AddCertFromBase64( "IjgIARIgp37zB83w5gBD4/h92IL7vHBqR6o6UNKopjn/3C2RSKYtdGFlAC1od20ARZkptVxNmZB3YCnvFmDb3UvYGDJAYXfYn+ofbs5Fz4EYiMYNh4SFD302+S/xXsAzmk8awH7nuasCV+RUWjoOshkKMK6ONCYzmkMiD0so7tOR+7zsDQ==", errMsg ) ); // Intermediate cert for app (TF2), signed by self-signed cert // KeyID . . . .: 12206663272037732248 // Public key . : ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIC/nkdg+La27cA2ptQj1t0buCYoo2OAQI+lf2P/QaRq4 CECSigningPrivateKey privkey_tf2; DbgVerify( privkey_tf2.ParsePEM( "-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZWQy NTUxOQAAACAv55HYPi2tu3ANqbUI9bdG7gmKKNjgECPpX9j/0GkauAAAAH8SNFZ4EjRWeAAA AAtzc2gtZWQyNTUxOQAAACAv55HYPi2tu3ANqbUI9bdG7gmKKNjgECPpX9j/0GkauAAAAEDf 8k3ME+Xapo2rNSUTO7SLog3hNCGP4cWcvM4bnEBkwC/nkdg+La27cA2ptQj1t0buCYoo2OAQ I+lf2P/QaRq4 -----END OPENSSH PRIVATE KEY----- ", 375 ) ); // CA KeyID . . : 8112647883641536425 // Apps . . . . : [440] const uint64 k_key_tf2 = 12206663272037732248ull; DbgVerify( CertStore_AddCertFromBase64( "IjEIARIgL+eR2D4trbtwDam1CPW3Ru4JiijY4BAj6V/Y/9BpGrhFmSm1XE2ZkHdgULgDKak/R3xE6pVwMkBCdDdDrAn6IkpuRwksFtXHUTgJNtColLLNPdoEhfyg/Fb5EDnTcOmaNzfoJbv2aFGmjPv2CUzYg+G8qKJv09wN", errMsg ) ); // Another intermediate cert signed by hardcoded root // KeyID . . . .: 15210429824691730624 // Public key . : ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO+dnkgm1SI2UAMbGkrotrHeTe30Mu4mhne9s7kb+knI CECSigningPrivateKey privkey_dota_revoked; DbgVerify( privkey_dota_revoked.ParsePEM( "-----BEGIN OPENSSH PRIVATE KEY----- b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZWQy NTUxOQAAACDvnZ5IJtUiNlADGxpK6Lax3k3t9DLuJoZ3vbO5G/pJyAAAAH8SNFZ4EjRWeAAA AAtzc2gtZWQyNTUxOQAAACDvnZ5IJtUiNlADGxpK6Lax3k3t9DLuJoZ3vbO5G/pJyAAAAEB8 CNRDPePmSmm66c7QyeOSiQyMHtrcouvxqzNq6GnRz++dnkgm1SI2UAMbGkrotrHeTe30Mu4m hne9s7kb+knI -----END OPENSSH PRIVATE KEY----- ", 375 ) ); // CA KeyID . . : 9417917822780561193 // Apps . . . . : [570] const uint64 k_key_dota_revoked = 15210429824691730624ull; DbgVerify( CertStore_AddCertFromBase64( "IjEIARIg752eSCbVIjZQAxsaSui2sd5N7fQy7iaGd72zuRv6SchFmSm1XE2ZkHdgULoEKSnXp45cKrOCMkCzt988yidn25C8fBC47EyW35w6SA9GbhPx6CUVeI5h8c/GGHrE4d/Mwvm5t3gv37xUg/uSquFhqWuERmUO4xAP", errMsg ) ); // Revoke a key CertStore_AddKeyRevocation( k_key_dota_revoked ); CMsgSteamDatagramCertificateSigned msgCertSigned; CMsgSteamDatagramCertificate msgCert; const CertAuthScope *pCertScope; const SteamNetworkingPOPID iad = CalculateSteamNetworkingPOPIDFromString( "iad" ); const SteamNetworkingPOPID sto = CalculateSteamNetworkingPOPIDFromString( "sto" ); // 7566447 const SteamNetworkingPOPID mwh = CalculateSteamNetworkingPOPIDFromString( "mwh" ); const SteamNetworkingPOPID eat = CalculateSteamNetworkingPOPIDFromString( "eat" ); // // Basic check for an identity cert issued by an intermediary. // GenerateCert( msgCertSigned, "app_ids: 730 identity: { generic_string: \"Hercule Poirot\" }", privkey_csgo, k_key_csgo ); pCertScope = CertStore_CheckCert( msgCertSigned, msgCert, k_timeTestNow, errMsg ); Assert( pCertScope ); DbgVerify( CheckCertAppID( msgCert, pCertScope, 730, errMsg ) ); // Shouldn't work for wrong app DbgVerify( !CheckCertAppID( msgCert, pCertScope, 570, errMsg ) ); // Should work for any POPID DbgVerify( CheckCertPOPID( msgCert, pCertScope, iad, errMsg ) ); DbgVerify( CheckCertPOPID( msgCert, pCertScope, sto, errMsg ) ); // // Try to use CSGO CA cert to authorize for Dota // GenerateCert( msgCertSigned, "app_ids: 570 identity: { generic_string: \"Hercule Poirot\" }", privkey_csgo, k_key_csgo ); // Signature should check out here. pCertScope = CertStore_CheckCert( msgCertSigned, msgCert, k_timeTestNow, errMsg ); Assert( pCertScope ); // But app check should fail DbgVerify( !CheckCertAppID( msgCert, pCertScope, 570, errMsg ) ); // // Cert for data center, signed directly by global app intermediary, // with the POP restriction in the issued cert // Assert( iad == 6906212 ); GenerateCert( msgCertSigned, "app_ids: 730 gameserver_datacenter_ids: 6906212", privkey_csgo, k_key_csgo ); pCertScope = CertStore_CheckCert( msgCertSigned, msgCert, k_timeTestNow, errMsg ); Assert( pCertScope ); DbgVerify( CheckCertAppID( msgCert, pCertScope, 730, errMsg ) ); // Should only work for the authorized POP DbgVerify( CheckCertPOPID( msgCert, pCertScope, iad, errMsg ) ); DbgVerify( !CheckCertPOPID( msgCert, pCertScope, sto, errMsg ) ); // // Cert for data center, signed by app that is further restricted by POPID // Assert( iad == 6906212 ); Assert( mwh == 7173992 ); GenerateCert( msgCertSigned, "app_ids: 730 gameserver_datacenter_ids: 6906212 gameserver_datacenter_ids: 7173992", privkey_csgo_eatmwh, k_key_csgo_eatmwh ); pCertScope = CertStore_CheckCert( msgCertSigned, msgCert, k_timeTestNow, errMsg ); Assert( pCertScope ); DbgVerify( CheckCertAppID( msgCert, pCertScope, 730, errMsg ) ); DbgVerify( !CheckCertPOPID( msgCert, pCertScope, iad, errMsg ) ); // Not in CA chain DbgVerify( CheckCertPOPID( msgCert, pCertScope, mwh, errMsg ) ); // In both CA chain and cert DbgVerify( !CheckCertPOPID( msgCert, pCertScope, eat, errMsg ) ); // In CA chain but not cert // // Try to use a cert where only cert is from root that isn't hardcoded // GenerateCert( msgCertSigned, "app_ids: 440 identity: { generic_string: \"Hercule Poirot\" }", privkey_tf2, k_key_tf2 ); pCertScope = CertStore_CheckCert( msgCertSigned, msgCert, k_timeTestNow, errMsg ); Assert( !pCertScope ); // // Try to use a cert signed by a revoked key // GenerateCert( msgCertSigned, "app_ids: 570 identity: { generic_string: \"Hercule Poirot\" }", privkey_dota_revoked, k_key_dota_revoked ); // Should fail pCertScope = CertStore_CheckCert( msgCertSigned, msgCert, k_timeTestNow, errMsg ); Assert( !pCertScope ); return 0; }