proxygen
JavaCryptoCertificateVerifier.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 
15  void operator()(STACK_OF(X509) * sk) {
16  sk_X509_free(sk);
17  }
18 };
19 
20 /* static */ std::unique_ptr<JavaCryptoCertificateVerifier>
23  const std::string& caFile) {
25  return std::make_unique<JavaCryptoCertificateVerifier>(
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  folly::ssl::X509VerifyParam param(X509_VERIFY_PARAM_new());
68  if (!param) {
69  throw std::bad_alloc();
70  }
71 
72  if (X509_VERIFY_PARAM_set_flags(param.get(), X509_V_FLAG_X509_STRICT) != 1) {
73  throw std::runtime_error("failed to set strict certificate checking");
74  }
75 
76  if (X509_VERIFY_PARAM_set1(
77  X509_STORE_CTX_get0_param(ctx.get()), param.get()) != 1) {
78  throw std::runtime_error("failed to apply verification parameters");
79  }
80 
81  if (X509_verify_cert(ctx.get()) != 1) {
82  const auto errorInt = X509_STORE_CTX_get_error(ctx.get());
83  std::string errorText =
84  std::string(X509_verify_cert_error_string(errorInt));
85  throw std::runtime_error("certificate verification failed: " + errorText);
86  }
87 }
88 
91  X509_STORE* store = x509Store_ ? x509Store_.get() : getDefaultX509Store();
92  // X509_STORE stores CA certs as objects in this stack.
93  STACK_OF(X509_OBJECT)* entries = X509_STORE_get0_objects(store);
94 
95  for (int i = 0; i < sk_X509_OBJECT_num(entries); i++) {
96  X509_OBJECT* obj = sk_X509_OBJECT_value(entries, i);
97  if (X509_OBJECT_get_type(obj) == X509_LU_X509) {
98  auto certIssuer = X509_get_subject_name(X509_OBJECT_get0_X509(obj));
99  int dnLength = i2d_X509_NAME(certIssuer, nullptr);
100  if (dnLength < 0) {
101  throw std::runtime_error("Error computing DN length");
102  }
104  dn.encoded_name = folly::IOBuf::create(dnLength);
105  auto dnData = dn.encoded_name->writableData();
106  dnLength = i2d_X509_NAME(certIssuer, &dnData);
107  if (dnLength < 0) {
108  throw std::runtime_error("Error encoding DN in DER format");
109  }
110  dn.encoded_name->append(dnLength);
111  auth.authorities.push_back(std::move(dn));
112  }
113  }
114  authorities_ = std::move(auth);
115 }
116 
118  static folly::ssl::X509StoreUniquePtr defaultStore([]() {
119  X509_STORE* store = X509_STORE_new();
120 
121  if (!store) {
122  throw std::bad_alloc();
123  }
124 
125  if (X509_STORE_set_default_paths(store) != 1) {
126  throw std::runtime_error("failed to set default paths");
127  }
128 
129  return store;
130  }());
131 
132  return defaultStore.get();
133 }
134 
135 std::vector<Extension>
137  std::vector<Extension> exts;
138  exts.push_back(encodeExtension(authorities_));
139  return exts;
140 }
141 } // 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
std::vector< Extension > getCertificateRequestExtensions() const override
static X509StoreUniquePtr readStoreFromFile(std::string caFile)
static std::unique_ptr< JavaCryptoCertificateVerifier > 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< DistinguishedName > authorities
Definition: Extensions.h:137
Extension encodeExtension(const TokenBindingParameters &params)
Definition: Types.cpp:113
std::unique_ptr< X509_VERIFY_PARAM, X509VerifyParamDeleter > X509VerifyParam