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