xref: /aosp_15_r20/system/update_engine/certificate_checker.h (revision 5a9231315b4521097b8dc3750bc806fcafe0c72f)
1*5a923131SAndroid Build Coastguard Worker //
2*5a923131SAndroid Build Coastguard Worker // Copyright (C) 2011 The Android Open Source Project
3*5a923131SAndroid Build Coastguard Worker //
4*5a923131SAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*5a923131SAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*5a923131SAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*5a923131SAndroid Build Coastguard Worker //
8*5a923131SAndroid Build Coastguard Worker //      http://www.apache.org/licenses/LICENSE-2.0
9*5a923131SAndroid Build Coastguard Worker //
10*5a923131SAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*5a923131SAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*5a923131SAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*5a923131SAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*5a923131SAndroid Build Coastguard Worker // limitations under the License.
15*5a923131SAndroid Build Coastguard Worker //
16*5a923131SAndroid Build Coastguard Worker 
17*5a923131SAndroid Build Coastguard Worker #ifndef UPDATE_ENGINE_CERTIFICATE_CHECKER_H_
18*5a923131SAndroid Build Coastguard Worker #define UPDATE_ENGINE_CERTIFICATE_CHECKER_H_
19*5a923131SAndroid Build Coastguard Worker 
20*5a923131SAndroid Build Coastguard Worker #include <curl/curl.h>
21*5a923131SAndroid Build Coastguard Worker #include <openssl/ssl.h>
22*5a923131SAndroid Build Coastguard Worker 
23*5a923131SAndroid Build Coastguard Worker #include <string>
24*5a923131SAndroid Build Coastguard Worker 
25*5a923131SAndroid Build Coastguard Worker #include <android-base/macros.h>
26*5a923131SAndroid Build Coastguard Worker #include <gtest/gtest_prod.h>  // for FRIEND_TEST
27*5a923131SAndroid Build Coastguard Worker 
28*5a923131SAndroid Build Coastguard Worker namespace chromeos_update_engine {
29*5a923131SAndroid Build Coastguard Worker 
30*5a923131SAndroid Build Coastguard Worker class PrefsInterface;
31*5a923131SAndroid Build Coastguard Worker 
32*5a923131SAndroid Build Coastguard Worker // Wrapper for openssl operations with the certificates.
33*5a923131SAndroid Build Coastguard Worker class OpenSSLWrapper {
34*5a923131SAndroid Build Coastguard Worker  public:
35*5a923131SAndroid Build Coastguard Worker   OpenSSLWrapper() = default;
36*5a923131SAndroid Build Coastguard Worker   virtual ~OpenSSLWrapper() = default;
37*5a923131SAndroid Build Coastguard Worker 
38*5a923131SAndroid Build Coastguard Worker   // Takes an openssl X509_STORE_CTX, extracts the corresponding certificate
39*5a923131SAndroid Build Coastguard Worker   // from it and calculates its fingerprint (SHA256 digest). Returns true on
40*5a923131SAndroid Build Coastguard Worker   // success and false otherwise.
41*5a923131SAndroid Build Coastguard Worker   //
42*5a923131SAndroid Build Coastguard Worker   // |x509_ctx| is the pointer to the openssl object that holds the certificate.
43*5a923131SAndroid Build Coastguard Worker   // |out_depth| is the depth of the current certificate, in the certificate
44*5a923131SAndroid Build Coastguard Worker   // chain.
45*5a923131SAndroid Build Coastguard Worker   // |out_digest_length| is the length of the generated digest.
46*5a923131SAndroid Build Coastguard Worker   // |out_digest| is the byte array where the digest itself will be written.
47*5a923131SAndroid Build Coastguard Worker   // It should be big enough to hold a SHA1 digest (e.g. EVP_MAX_MD_SIZE).
48*5a923131SAndroid Build Coastguard Worker   virtual bool GetCertificateDigest(X509_STORE_CTX* x509_ctx,
49*5a923131SAndroid Build Coastguard Worker                                     int* out_depth,
50*5a923131SAndroid Build Coastguard Worker                                     unsigned int* out_digest_length,
51*5a923131SAndroid Build Coastguard Worker                                     uint8_t* out_digest) const;
52*5a923131SAndroid Build Coastguard Worker 
53*5a923131SAndroid Build Coastguard Worker  private:
54*5a923131SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(OpenSSLWrapper);
55*5a923131SAndroid Build Coastguard Worker };
56*5a923131SAndroid Build Coastguard Worker 
57*5a923131SAndroid Build Coastguard Worker // The values in this enum are replicated in the metrics server. See metrics.h
58*5a923131SAndroid Build Coastguard Worker // for instructions on how to update these values in the server side.
59*5a923131SAndroid Build Coastguard Worker enum class CertificateCheckResult {
60*5a923131SAndroid Build Coastguard Worker   // The certificate is valid and the same as seen before or the first time we
61*5a923131SAndroid Build Coastguard Worker   // see a certificate.
62*5a923131SAndroid Build Coastguard Worker   kValid,
63*5a923131SAndroid Build Coastguard Worker   // The certificate is valid, but is different than a previously seen
64*5a923131SAndroid Build Coastguard Worker   // certificate for the selected server.
65*5a923131SAndroid Build Coastguard Worker   kValidChanged,
66*5a923131SAndroid Build Coastguard Worker   // The certificate validation failed.
67*5a923131SAndroid Build Coastguard Worker   kFailed,
68*5a923131SAndroid Build Coastguard Worker 
69*5a923131SAndroid Build Coastguard Worker   // This value must be the last entry.
70*5a923131SAndroid Build Coastguard Worker   kNumConstants
71*5a923131SAndroid Build Coastguard Worker };
72*5a923131SAndroid Build Coastguard Worker 
73*5a923131SAndroid Build Coastguard Worker // These values are used to generate the keys of files persisted via prefs.
74*5a923131SAndroid Build Coastguard Worker // This means that changing these will cause loss of information on metrics
75*5a923131SAndroid Build Coastguard Worker // reporting, during the transition. These values are also mapped to a metric
76*5a923131SAndroid Build Coastguard Worker // name in metrics.cc, so adding values here requires to assign a new metric
77*5a923131SAndroid Build Coastguard Worker // name in that file.
78*5a923131SAndroid Build Coastguard Worker enum class ServerToCheck {
79*5a923131SAndroid Build Coastguard Worker   kUpdate = 0,
80*5a923131SAndroid Build Coastguard Worker   kDownload,
81*5a923131SAndroid Build Coastguard Worker 
82*5a923131SAndroid Build Coastguard Worker   // Ignore this server.
83*5a923131SAndroid Build Coastguard Worker   kNone,
84*5a923131SAndroid Build Coastguard Worker };
85*5a923131SAndroid Build Coastguard Worker 
86*5a923131SAndroid Build Coastguard Worker // Responsible for checking whether update server certificates change, and
87*5a923131SAndroid Build Coastguard Worker // reporting to UMA when this happens. Since all state information is persisted,
88*5a923131SAndroid Build Coastguard Worker // and openssl forces us to use a static callback with no data pointer, this
89*5a923131SAndroid Build Coastguard Worker // class is entirely static.
90*5a923131SAndroid Build Coastguard Worker class CertificateChecker {
91*5a923131SAndroid Build Coastguard Worker  public:
92*5a923131SAndroid Build Coastguard Worker   class Observer {
93*5a923131SAndroid Build Coastguard Worker    public:
94*5a923131SAndroid Build Coastguard Worker     virtual ~Observer() = default;
95*5a923131SAndroid Build Coastguard Worker 
96*5a923131SAndroid Build Coastguard Worker     // Called whenever a certificate is checked for the server |server_to_check|
97*5a923131SAndroid Build Coastguard Worker     // passing the result of said certificate check.
98*5a923131SAndroid Build Coastguard Worker     virtual void CertificateChecked(ServerToCheck server_to_check,
99*5a923131SAndroid Build Coastguard Worker                                     CertificateCheckResult result) = 0;
100*5a923131SAndroid Build Coastguard Worker   };
101*5a923131SAndroid Build Coastguard Worker 
102*5a923131SAndroid Build Coastguard Worker   CertificateChecker(PrefsInterface* prefs, OpenSSLWrapper* openssl_wrapper);
103*5a923131SAndroid Build Coastguard Worker   ~CertificateChecker();
104*5a923131SAndroid Build Coastguard Worker 
105*5a923131SAndroid Build Coastguard Worker   // This callback is called by libcurl just before the initialization of an
106*5a923131SAndroid Build Coastguard Worker   // SSL connection after having processed all other SSL related options. Used
107*5a923131SAndroid Build Coastguard Worker   // to check if server certificates change. |cert_checker| is expected to be a
108*5a923131SAndroid Build Coastguard Worker   // pointer to the CertificateChecker instance.
109*5a923131SAndroid Build Coastguard Worker   static CURLcode ProcessSSLContext(CURL* curl_handle,
110*5a923131SAndroid Build Coastguard Worker                                     SSL_CTX* ssl_ctx,
111*5a923131SAndroid Build Coastguard Worker                                     void* cert_checker);
112*5a923131SAndroid Build Coastguard Worker 
113*5a923131SAndroid Build Coastguard Worker   // Initialize this class as the singleton instance. Only one instance can be
114*5a923131SAndroid Build Coastguard Worker   // initialized at a time and it should be initialized before other methods
115*5a923131SAndroid Build Coastguard Worker   // can be used.
116*5a923131SAndroid Build Coastguard Worker   void Init();
117*5a923131SAndroid Build Coastguard Worker 
118*5a923131SAndroid Build Coastguard Worker   // Set the certificate observer to the passed instance. To remove the
119*5a923131SAndroid Build Coastguard Worker   // observer, pass a nullptr. The |observer| instance must be valid while this
120*5a923131SAndroid Build Coastguard Worker   // CertificateChecker verifies certificates.
SetObserver(Observer * observer)121*5a923131SAndroid Build Coastguard Worker   void SetObserver(Observer* observer) { observer_ = observer; }
122*5a923131SAndroid Build Coastguard Worker 
123*5a923131SAndroid Build Coastguard Worker  private:
124*5a923131SAndroid Build Coastguard Worker   FRIEND_TEST(CertificateCheckerTest, NewCertificate);
125*5a923131SAndroid Build Coastguard Worker   FRIEND_TEST(CertificateCheckerTest, SameCertificate);
126*5a923131SAndroid Build Coastguard Worker   FRIEND_TEST(CertificateCheckerTest, ChangedCertificate);
127*5a923131SAndroid Build Coastguard Worker   FRIEND_TEST(CertificateCheckerTest, FailedCertificate);
128*5a923131SAndroid Build Coastguard Worker 
129*5a923131SAndroid Build Coastguard Worker   // These callbacks are asynchronously called by openssl after initial SSL
130*5a923131SAndroid Build Coastguard Worker   // verification. They are used to perform any additional security verification
131*5a923131SAndroid Build Coastguard Worker   // on the connection, but we use them here to get hold of the server
132*5a923131SAndroid Build Coastguard Worker   // certificate, in order to determine if it has changed since the last
133*5a923131SAndroid Build Coastguard Worker   // connection. Since openssl forces us to do this statically, we define two
134*5a923131SAndroid Build Coastguard Worker   // different callbacks for the two different official update servers, and only
135*5a923131SAndroid Build Coastguard Worker   // assign the correspondent one. The assigned callback is then called once per
136*5a923131SAndroid Build Coastguard Worker   // each certificate on the server and returns 1 for success and 0 for failure.
137*5a923131SAndroid Build Coastguard Worker   static int VerifySSLCallbackDownload(int preverify_ok,
138*5a923131SAndroid Build Coastguard Worker                                        X509_STORE_CTX* x509_ctx);
139*5a923131SAndroid Build Coastguard Worker   static int VerifySSLCallbackUpdate(int preverify_ok,
140*5a923131SAndroid Build Coastguard Worker                                      X509_STORE_CTX* x509_ctx);
141*5a923131SAndroid Build Coastguard Worker   static int VerifySSLCallback(int preverify_ok,
142*5a923131SAndroid Build Coastguard Worker                                X509_STORE_CTX* x509_ctx,
143*5a923131SAndroid Build Coastguard Worker                                ServerToCheck server_to_check);
144*5a923131SAndroid Build Coastguard Worker 
145*5a923131SAndroid Build Coastguard Worker   // Checks if server certificate stored in |x509_ctx| has changed since last
146*5a923131SAndroid Build Coastguard Worker   // connection to that same server, specified by |server_to_check|.
147*5a923131SAndroid Build Coastguard Worker   // This is called by the callbacks defined above. The result of the
148*5a923131SAndroid Build Coastguard Worker   // certificate check is passed to the observer, if any. Returns true on
149*5a923131SAndroid Build Coastguard Worker   // success and false otherwise.
150*5a923131SAndroid Build Coastguard Worker   bool CheckCertificateChange(int preverify_ok,
151*5a923131SAndroid Build Coastguard Worker                               X509_STORE_CTX* x509_ctx,
152*5a923131SAndroid Build Coastguard Worker                               ServerToCheck server_to_check);
153*5a923131SAndroid Build Coastguard Worker 
154*5a923131SAndroid Build Coastguard Worker   // Notifies the observer, if any, of a certificate checking.
155*5a923131SAndroid Build Coastguard Worker   void NotifyCertificateChecked(ServerToCheck server_to_check,
156*5a923131SAndroid Build Coastguard Worker                                 CertificateCheckResult result);
157*5a923131SAndroid Build Coastguard Worker 
158*5a923131SAndroid Build Coastguard Worker   // The CertificateChecker singleton instance.
159*5a923131SAndroid Build Coastguard Worker   static CertificateChecker* cert_checker_singleton_;
160*5a923131SAndroid Build Coastguard Worker 
161*5a923131SAndroid Build Coastguard Worker   // Prefs instance used to store the certificates seen in the past.
162*5a923131SAndroid Build Coastguard Worker   PrefsInterface* prefs_;
163*5a923131SAndroid Build Coastguard Worker 
164*5a923131SAndroid Build Coastguard Worker   // The wrapper for openssl operations.
165*5a923131SAndroid Build Coastguard Worker   OpenSSLWrapper* openssl_wrapper_;
166*5a923131SAndroid Build Coastguard Worker 
167*5a923131SAndroid Build Coastguard Worker   // The observer called whenever a certificate is checked, if not null.
168*5a923131SAndroid Build Coastguard Worker   Observer* observer_{nullptr};
169*5a923131SAndroid Build Coastguard Worker 
170*5a923131SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(CertificateChecker);
171*5a923131SAndroid Build Coastguard Worker };
172*5a923131SAndroid Build Coastguard Worker 
173*5a923131SAndroid Build Coastguard Worker }  // namespace chromeos_update_engine
174*5a923131SAndroid Build Coastguard Worker 
175*5a923131SAndroid Build Coastguard Worker #endif  // UPDATE_ENGINE_CERTIFICATE_CHECKER_H_
176