proxygen
DefaultCertificateVerifier.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-present, Facebook, Inc.
3  * All rights reserved.
4  *
5  * This source code is licensed under the BSD-style license found in the
6  * LICENSE file in the root directory of this source tree.
7  */
8 
11 
12 namespace fizz {
13 
14 struct STACK_OF_X509_deleter {
15  void operator()(STACK_OF(X509) * sk) {
16  sk_X509_free(sk);
17  }
18 };
19 
20 /* static */ std::unique_ptr<DefaultCertificateVerifier>
23  const std::string& caFile) {
25  return std::make_unique<DefaultCertificateVerifier>(
26  context, std::move(store));
27 }
28 
30  const std::vector<std::shared_ptr<const fizz::PeerCert>>& certs) const {
31  if (certs.empty()) {
32  throw std::runtime_error("no certificates to verify");
33  }
34 
35  auto leafCert = certs.front()->getX509();
36 
37  auto certChainStack = std::unique_ptr<STACK_OF(X509), STACK_OF_X509_deleter>(
38  sk_X509_new_null());
39  if (!certChainStack) {
40  throw std::bad_alloc();
41  }
42 
43  for (size_t i = 1; i < certs.size(); i++) {
44  sk_X509_push(certChainStack.get(), certs[i]->getX509().get());
45  }
46 
47  auto ctx = folly::ssl::X509StoreCtxUniquePtr(X509_STORE_CTX_new());
48  if (!ctx) {
49  throw std::bad_alloc();
50  }
51 
52  if (X509_STORE_CTX_init(
53  ctx.get(),
54  x509Store_ ? x509Store_.get() : getDefaultX509Store(),
55  leafCert.get(),
56  certChainStack.get()) != 1) {
57  throw std::runtime_error("failed to initialize store context");
58  }
59 
60  if (X509_STORE_CTX_set_default(
61  ctx.get(),
62  context_ == VerificationContext::Server ? "ssl_client"
63  : "ssl_server") != 1) {
64  throw std::runtime_error("failed to set default verification method");
65  }
66 
67  if (customVerifyCallback_) {
68  X509_STORE_CTX_set_verify_cb(ctx.get(), customVerifyCallback_);
69  }
70 
71  folly::ssl::X509VerifyParam param(X509_VERIFY_PARAM_new());
72  if (!param) {
73  throw std::bad_alloc();
74  }
75 
76  if (X509_VERIFY_PARAM_set_flags(param.get(), X509_V_FLAG_X509_STRICT) != 1) {
77  throw std::runtime_error("failed to set strict certificate checking");
78  }
79 
80  if (X509_VERIFY_PARAM_set1(
81  X509_STORE_CTX_get0_param(ctx.get()), param.get()) != 1) {
82  throw std::runtime_error("failed to apply verification parameters");
83  }
84 
85  if (X509_verify_cert(ctx.get()) != 1) {
86  const auto errorInt = X509_STORE_CTX_get_error(ctx.get());
87  std::string errorText =
88  std::string(X509_verify_cert_error_string(errorInt));
89  throw std::runtime_error("certificate verification failed: " + errorText);
90  }
91 }
92 
95  X509_STORE* store = x509Store_ ? x509Store_.get() : getDefaultX509Store();
96  // X509_STORE stores CA certs as objects in this stack.
97  STACK_OF(X509_OBJECT)* entries = X509_STORE_get0_objects(store);
98 
99  for (int i = 0; i < sk_X509_OBJECT_num(entries); i++) {
100  X509_OBJECT* obj = sk_X509_OBJECT_value(entries, i);
101  if (X509_OBJECT_get_type(obj) == X509_LU_X509) {
102  auto certIssuer = X509_get_subject_name(X509_OBJECT_get0_X509(obj));
103  int dnLength = i2d_X509_NAME(certIssuer, nullptr);
104  if (dnLength < 0) {
105  throw std::runtime_error("Error computing DN length");
106  }
108  dn.encoded_name = folly::IOBuf::create(dnLength);
109  auto dnData = dn.encoded_name->writableData();
110  dnLength = i2d_X509_NAME(certIssuer, &dnData);
111  if (dnLength < 0) {
112  throw std::runtime_error("Error encoding DN in DER format");
113  }
114  dn.encoded_name->append(dnLength);
115  auth.authorities.push_back(std::move(dn));
116  }
117  }
118  authorities_ = std::move(auth);
119 }
120 
122  static folly::ssl::X509StoreUniquePtr defaultStore([]() {
123  X509_STORE* store = X509_STORE_new();
124 
125  if (!store) {
126  throw std::bad_alloc();
127  }
128 
129  if (X509_STORE_set_default_paths(store) != 1) {
130  throw std::runtime_error("failed to set default paths");
131  }
132 
133  return store;
134  }());
135 
136  return defaultStore.get();
137 }
138 
139 std::vector<Extension>
141  std::vector<Extension> exts;
142  exts.push_back(encodeExtension(authorities_));
143  return exts;
144 }
145 
146 } // namespace fizz
void verify(const std::vector< std::shared_ptr< const fizz::PeerCert >> &certs) const override
X509 * X509_OBJECT_get0_X509(const X509_OBJECT *obj)
Definition: OpenSSL.cpp:487
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
context
Definition: CMakeCache.txt:563
STACK_OF(X509_OBJECT)*X509_STORE_get0_objects(X509_STORE *store)
Definition: OpenSSL.cpp:305
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
static X509StoreUniquePtr readStoreFromFile(std::string caFile)
static std::unique_ptr< DefaultCertificateVerifier > createFromCAFile(VerificationContext context, const std::string &caFile)
std::unique_ptr< X509_STORE, X509StoreDeleter > X509StoreUniquePtr
Definition: Actions.h:16
int X509_OBJECT_get_type(const X509_OBJECT *obj)
Definition: OpenSSL.cpp:483
const char * string
Definition: Conv.cpp:212
std::unique_ptr< X509_STORE_CTX, X509StoreCtxDeleter > X509StoreCtxUniquePtr
std::vector< Extension > getCertificateRequestExtensions() const override
std::vector< DistinguishedName > authorities
Definition: Extensions.h:137
Extension encodeExtension(const TokenBindingParameters &params)
Definition: Types.cpp:113
std::unique_ptr< X509_VERIFY_PARAM, X509VerifyParamDeleter > X509VerifyParam