blob: b5f7a153b4413df5f0aae1ee4a7b83d4cf292853 [file] [log] [blame]
Bruno Rocha7f9aea22011-09-12 14:31:24 -07001// Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Gilad Arnoldcf175a02014-07-10 16:48:47 -07005#ifndef UPDATE_ENGINE_CERTIFICATE_CHECKER_H_
6#define UPDATE_ENGINE_CERTIFICATE_CHECKER_H_
Bruno Rocha7f9aea22011-09-12 14:31:24 -07007
Ben Chan05735a12014-09-03 07:48:22 -07008#include <curl/curl.h>
9#include <openssl/ssl.h>
10
Bruno Rocha7f9aea22011-09-12 14:31:24 -070011#include <string>
12
Ben Chan05735a12014-09-03 07:48:22 -070013#include <base/macros.h>
Bruno Rocha7f9aea22011-09-12 14:31:24 -070014#include <gtest/gtest_prod.h> // for FRIEND_TEST
Bruno Rocha7f9aea22011-09-12 14:31:24 -070015
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080016#include "update_engine/system_state.h"
Bruno Rocha7f9aea22011-09-12 14:31:24 -070017
18namespace chromeos_update_engine {
19
20// Wrapper for openssl operations with the certificates.
21class OpenSSLWrapper {
22 public:
23 OpenSSLWrapper() {}
24 virtual ~OpenSSLWrapper() {}
25
26 // Takes an openssl X509_STORE_CTX, extracts the corresponding certificate
27 // from it and calculates its fingerprint (SHA256 digest). Returns true on
28 // success and false otherwise.
29 //
30 // |x509_ctx| is the pointer to the openssl object that holds the certificate.
31 // |out_depth| is the depth of the current certificate, in the certificate
32 // chain.
33 // |out_digest_length| is the length of the generated digest.
34 // |out_digest| is the byte array where the digest itself will be written.
35 // It should be big enough to hold a SHA1 digest (e.g. EVP_MAX_MD_SIZE).
36 virtual bool GetCertificateDigest(X509_STORE_CTX* x509_ctx,
37 int* out_depth,
38 unsigned int* out_digest_length,
39 unsigned char* out_digest) const;
40
41 private:
42 DISALLOW_COPY_AND_ASSIGN(OpenSSLWrapper);
43};
44
45// Responsible for checking whether update server certificates change, and
46// reporting to UMA when this happens. Since all state information is persisted,
47// and openssl forces us to use a static callback with no data pointer, this
48// class is entirely static.
49class CertificateChecker {
50 public:
51 // These values are used to generate the keys of files persisted via prefs.
52 // This means that changing these will cause loss of information on metrics
53 // reporting, during the transition.
54 enum ServerToCheck {
55 kUpdate = 0,
56 kDownload = 1,
57 kNone = 2 // This needs to be the last element. Changing its value is ok.
58 };
59
60 CertificateChecker() {}
61 virtual ~CertificateChecker() {}
62
63 // This callback is called by libcurl just before the initialization of an
64 // SSL connection after having processed all other SSL related options. Used
65 // to check if server certificates change. |ptr| is expected to be a
66 // pointer to a ServerToCheck.
67 static CURLcode ProcessSSLContext(CURL* curl_handle, SSL_CTX* ssl_ctx,
68 void* ptr);
69
70 // Flushes to UMA any certificate-related report that was persisted.
71 static void FlushReport();
72
73 // Setters.
Jay Srinivasan6f6ea002012-12-14 11:26:28 -080074 static void set_system_state(SystemState* system_state) {
75 system_state_ = system_state;
Bruno Rocha7f9aea22011-09-12 14:31:24 -070076 }
77
78 static void set_openssl_wrapper(OpenSSLWrapper* openssl_wrapper) {
79 openssl_wrapper_ = openssl_wrapper;
80 }
81
82 private:
83 FRIEND_TEST(CertificateCheckerTest, NewCertificate);
84 FRIEND_TEST(CertificateCheckerTest, SameCertificate);
85 FRIEND_TEST(CertificateCheckerTest, ChangedCertificate);
86 FRIEND_TEST(CertificateCheckerTest, FailedCertificate);
87 FRIEND_TEST(CertificateCheckerTest, FlushReport);
88 FRIEND_TEST(CertificateCheckerTest, FlushNothingToReport);
89
90 // These callbacks are called by openssl after initial SSL verification. They
91 // are used to perform any additional security verification on the connection,
92 // but we use them here to get hold of the server certificate, in order to
93 // determine if it has changed since the last connection. Since openssl forces
94 // us to do this statically, we define two different callbacks for the two
95 // different official update servers, and only assign the correspondent one.
96 // The assigned callback is then called once per each certificate on the
97 // server and returns 1 for success and 0 for failure.
98 static int VerifySSLCallbackUpdateCheck(int preverify_ok,
99 X509_STORE_CTX* x509_ctx);
100 static int VerifySSLCallbackDownload(int preverify_ok,
101 X509_STORE_CTX* x509_ctx);
102
103 // Checks if server certificate for |server_to_check|, stored in |x509_ctx|,
104 // has changed since last connection to that same server. This is called by
105 // one of the two callbacks defined above. If certificate fails to check or
106 // changes, a report is generated and persisted, to be later sent by
107 // FlushReport. Returns true on success and false otherwise.
108 static bool CheckCertificateChange(ServerToCheck server_to_check,
109 int preverify_ok,
110 X509_STORE_CTX* x509_ctx);
111
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800112 // Global system context.
113 static SystemState* system_state_;
Bruno Rocha7f9aea22011-09-12 14:31:24 -0700114
115 // The wrapper for openssl operations.
116 static OpenSSLWrapper* openssl_wrapper_;
117
118 DISALLOW_COPY_AND_ASSIGN(CertificateChecker);
119};
120
121} // namespace chromeos_update_engine
122
Gilad Arnoldcf175a02014-07-10 16:48:47 -0700123#endif // UPDATE_ENGINE_CERTIFICATE_CHECKER_H_