1 //====== Copyright Valve Corporation, All rights reserved. ==================== 2 // 3 // Implements a store of CA certificates, e.g. certificates that are not 4 // assigned to a particular identity. Also contains functions for checking 5 // the chain of trust. 6 7 #ifndef STEAMNETWORKINGSOCKETS_CERTSTORE_H 8 #define STEAMNETWORKINGSOCKETS_CERTSTORE_H 9 #pragma once 10 11 #include <ostream> 12 #include "steamnetworkingsockets_internal.h" 13 14 // Use a hardcoded root CA key? It's just a key, not the cert here, because there are no additional relevant 15 // details that the cert might specify. We assume any such cert would be self-signed and not have any 16 // restrictions, and we also act as if it doesn't expire. 17 #if !defined( STEAMNETWORKINGSOCKETS_HARDCODED_ROOT_CA_KEY ) && !defined( STEAMNETWORKINGSOCKETS_ALLOW_DYNAMIC_SELFSIGNED_CERTS ) 18 19 // Master Valve Key 20 #define STEAMNETWORKINGSOCKETS_HARDCODED_ROOT_CA_KEY "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJrsoE4XUc5iaNVpACyh4fobLbwm02tOo6AIOtNygpuE ID18220590129359924542" 21 #endif 22 23 // Internal stuff goes in a private namespace 24 namespace SteamNetworkingSocketsLib { 25 26 /// Certificates are granted limited authority. A CertAuthParameter is a 27 /// list items of items of a certain type (AppID, PopID, etc) that are 28 /// authorized. The concept of "none" and "all" are also possible to 29 /// represent. 30 /// 31 /// Internally, this is represented using a simple sorted array. 32 /// "All" is represented as a list with a single special "invalid" item. 33 template <typename T, T kInvalidItem = T(-1)> 34 struct CertAuthParameter 35 { 36 /// Set the list to authorize nothing. SetEmptyCertAuthParameter37 inline void SetEmpty() { m_vecItems.clear(); } IsEmptyCertAuthParameter38 inline bool IsEmpty() const { return m_vecItems.empty(); } 39 40 /// Set the list to be "all items". SetAllCertAuthParameter41 inline void SetAll() { m_vecItems.clear(); m_vecItems.push_back( kInvalidItem );} IsAllCertAuthParameter42 inline bool IsAll() const { return m_vecItems.size() == 1 && m_vecItems[0] == kInvalidItem; } 43 44 /// Return true if the item is in the list. (Or if we are set to "all".) HasItemCertAuthParameter45 bool HasItem( T x ) const 46 { 47 Assert( x != kInvalidItem ); 48 if ( IsAll() ) 49 return true; 50 return std::binary_search( m_vecItems.begin(), m_vecItems.end(), x ); 51 } 52 53 /// Set this list to be the intersection of the two lists 54 void SetIntersection( const CertAuthParameter<T,kInvalidItem> &a, const CertAuthParameter<T,kInvalidItem> &b ); 55 void Setup( const T *pItems, int n ); 56 void Print( std::ostream &out, void (*ItemPrint)( std::ostream &out, const T &x ) ) const; 57 58 private: 59 60 // Usually very few items here, use a static list; overflow 61 // to heap 62 vstd::small_vector<T,8> m_vecItems; 63 }; 64 65 /// Describe the rights that a cert is authorized to grant, 66 /// and its expiry. This is also used to describe the authority 67 /// granted by a *chain* of certs --- it is the intersection 68 /// of all the certs on the chain. (E.g. a cert may claim certain 69 /// rights, but those assertions are not valid if the signing 70 /// key does not have rights to grant them). 71 struct CertAuthScope 72 { 73 CertAuthParameter<SteamNetworkingPOPID> m_pops; 74 CertAuthParameter<AppId_t> m_apps; 75 time_t m_timeExpiry = 0; 76 SetAllCertAuthScope77 void SetAll() 78 { 79 m_pops.SetAll(); 80 m_apps.SetAll(); 81 m_timeExpiry = std::numeric_limits<time_t>::max(); 82 } 83 SetEmptyCertAuthScope84 void SetEmpty() 85 { 86 m_pops.SetEmpty(); 87 m_apps.SetEmpty(); 88 m_timeExpiry = 0; 89 } 90 91 // Return true if we don't grant authorization to anything IsEmptyCertAuthScope92 bool IsEmpty() const 93 { 94 return m_timeExpiry == 0 || m_apps.IsEmpty() || m_pops.IsEmpty(); 95 } 96 SetIntersectionCertAuthScope97 void SetIntersection( const CertAuthScope &a, const CertAuthScope &b ) 98 { 99 m_pops.SetIntersection( a.m_pops, b.m_pops ); 100 m_apps.SetIntersection( a.m_apps, b.m_apps ); 101 m_timeExpiry = std::min( a.m_timeExpiry, b.m_timeExpiry ); 102 } 103 104 void Print( std::ostream &out, const char *pszIndent ) const; 105 }; 106 107 /// Nuke all certs and start over from scratch 108 extern void CertStore_Reset(); 109 110 /// Add a cert to the store from a base-64 blob (the body of the PEM-like blob). Returns false 111 /// only if there was a parse error. DOES NOT check for expiry or validate any signatures, etc. 112 extern bool CertStore_AddCertFromBase64( const char *pszBase64, SteamNetworkingErrMsg &errMsg ); 113 114 /// Adds a key revocation entry. 115 extern void CertStore_AddKeyRevocation( uint64 key_id ); 116 117 /// Given a signed blob of data, locate the CA public key, make sure it is trusted, 118 /// and verify the signature. Also checks that none of the certs in the chain 119 /// have expired at the current time (which you must supply). 120 /// 121 /// If the signed data should be trusted, the scope of the authorization granted 122 /// to that public key is returned. Otherwise, NULL is returned and errMsg is 123 /// populated. 124 extern const CertAuthScope *CertStore_CheckCASignature( const std::string &signed_data, uint64 nCAKeyID, const std::string &signature, time_t timeNow, SteamNetworkingErrMsg &errMsg ); 125 126 /// Check a CA signature and chain of trust for a signed cert. 127 /// Also deserializes the cert and make sure it is not expired. 128 /// DOES NOT CHECK that the appid, pops, etc in the cert 129 /// are granted by the CA chain. You need to do that! 130 extern const CertAuthScope *CertStore_CheckCert( const CMsgSteamDatagramCertificateSigned &msgCertSigned, CMsgSteamDatagramCertificate &outMsgCert, time_t timeNow, SteamNetworkingErrMsg &errMsg ); 131 132 /// Check if a cert gives permission to access a certain app. 133 extern bool CheckCertAppID( const CMsgSteamDatagramCertificate &msgCert, const CertAuthScope *pCertAuthScope, AppId_t nAppID, SteamNetworkingErrMsg &errMsg ); 134 135 /// Check if a cert gives permission to access a certain PoPID. 136 extern bool CheckCertPOPID( const CMsgSteamDatagramCertificate &msgCert, const CertAuthScope *pCertAuthScope, SteamNetworkingPOPID popID, SteamNetworkingErrMsg &errMsg ); 137 138 /// Print all of the certs in the cert storef 139 extern void CertStore_Print( std::ostream &out ); 140 141 /// Check the cert store, asserting if any keys are not trusted 142 extern void CertStore_Check(); 143 144 /// Steam memory validation 145 #ifdef DBGFLAG_VALIDATE 146 extern void CertStore_ValidateStatics( CValidator &validator ); 147 #endif 148 149 } 150 151 #endif // STEAMNETWORKINGSOCKETS_CERTSTORE_H 152