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