proxygen
Certificate.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 
10 
11 namespace {
12 int getCurveName(EVP_PKEY* key) {
13  auto ecKey = EVP_PKEY_get0_EC_KEY(key);
14  if (ecKey) {
15  return EC_GROUP_get_curve_name(EC_KEY_get0_group(ecKey));
16  }
17  return 0;
18 }
19 } // namespace
20 
21 namespace fizz {
22 
25  folly::ByteRange toBeSigned) {
26  static constexpr folly::StringPiece kServerLabel =
27  "TLS 1.3, server CertificateVerify";
28  static constexpr folly::StringPiece kClientLabel =
29  "TLS 1.3, client CertificateVerify";
30  static constexpr folly::StringPiece kAuthLabel = "Exported Authenticator";
31  static constexpr size_t kSigPrefixLen = 64;
32  static constexpr uint8_t kSigPrefix = 32;
33 
35  if (context == CertificateVerifyContext::Server) {
36  label = kServerLabel;
37  } else if (context == CertificateVerifyContext::Client) {
38  label = kClientLabel;
39  } else {
40  label = kAuthLabel;
41  }
42 
43  size_t sigDataLen = kSigPrefixLen + label.size() + 1 + toBeSigned.size();
44  auto buf = folly::IOBuf::create(sigDataLen);
45  buf->append(sigDataLen);
46 
47  // Place bytes in the right order.
48  size_t offset = 0;
49  memset(buf->writableData(), kSigPrefix, kSigPrefixLen);
50  offset += kSigPrefixLen;
51  memcpy(buf->writableData() + offset, label.data(), label.size());
52  offset += label.size();
53  memset(buf->writableData() + offset, 0, 1);
54  offset += 1;
55  memcpy(buf->writableData() + offset, toBeSigned.data(), toBeSigned.size());
56  return buf;
57 }
58 
60  const std::vector<folly::ssl::X509UniquePtr>& certs,
61  Buf certificateRequestContext) {
62  // compose the cert entry list
63  std::vector<CertificateEntry> entries;
64  for (const auto& cert : certs) {
65  CertificateEntry entry;
66  int len = i2d_X509(cert.get(), nullptr);
67  if (len < 0) {
68  throw std::runtime_error("Error computing length");
69  }
70  entry.cert_data = folly::IOBuf::create(len);
71  auto dataPtr = entry.cert_data->writableData();
72  len = i2d_X509(cert.get(), &dataPtr);
73  if (len < 0) {
74  throw std::runtime_error("Error converting cert to DER");
75  }
76  entry.cert_data->append(len);
77  // TODO: add any extensions.
78  entries.push_back(std::move(entry));
79  }
80 
81  CertificateMsg msg;
82  msg.certificate_request_context = std::move(certificateRequestContext);
83  msg.certificate_list = std::move(entries);
84  return msg;
85 }
86 
87 std::unique_ptr<PeerCert> CertUtils::makePeerCert(Buf certData) {
88  if (certData->empty()) {
89  throw std::runtime_error("empty peer cert");
90  }
91 
92  auto range = certData->coalesce();
93  const unsigned char* begin = range.data();
94  folly::ssl::X509UniquePtr cert(d2i_X509(nullptr, &begin, range.size()));
95  if (!cert) {
96  throw std::runtime_error("could not read cert");
97  }
98  if (begin != range.data() + range.size()) {
99  VLOG(1) << "Did not read to end of certificate";
100  }
101 
102  folly::ssl::EvpPkeyUniquePtr pubKey(X509_get_pubkey(cert.get()));
103  if (!pubKey) {
104  throw std::runtime_error("couldn't get pubkey from peer cert");
105  }
106  if (EVP_PKEY_id(pubKey.get()) == EVP_PKEY_RSA) {
107  return std::make_unique<PeerCertImpl<KeyType::RSA>>(std::move(cert));
108  } else if (EVP_PKEY_id(pubKey.get()) == EVP_PKEY_EC) {
109  switch (getCurveName(pubKey.get())) {
110  case NID_X9_62_prime256v1:
111  return std::make_unique<PeerCertImpl<KeyType::P256>>(std::move(cert));
112  case NID_secp384r1:
113  return std::make_unique<PeerCertImpl<KeyType::P384>>(std::move(cert));
114  case NID_secp521r1:
115  return std::make_unique<PeerCertImpl<KeyType::P521>>(std::move(cert));
116  default:
117  break;
118  }
119  }
120  throw std::runtime_error("unknown peer cert type");
121 }
122 
123 namespace {
124 
125 std::unique_ptr<SelfCert> selfCertFromDataInternal(
126  std::string certData,
127  std::string keyData,
128  char* password,
129  const std::vector<std::shared_ptr<CertificateCompressor>>& compressors) {
131  folly::StringPiece(certData));
132  if (certs.empty()) {
133  throw std::runtime_error("no certificates read");
134  }
135 
136  folly::ssl::BioUniquePtr b(BIO_new_mem_buf(keyData.data(), keyData.size()));
137 
138  if (!b) {
139  throw std::runtime_error("failed to create BIO");
140  }
141 
143  PEM_read_bio_PrivateKey(b.get(), nullptr, nullptr, password));
144 
145  if (!key) {
146  throw std::runtime_error("Failed to read key");
147  }
148 
149  return CertUtils::makeSelfCert(std::move(certs), std::move(key), compressors);
150 }
151 
152 } // namespace
153 
154 std::unique_ptr<SelfCert> CertUtils::makeSelfCert(
155  std::string certData,
156  std::string keyData,
157  const std::vector<std::shared_ptr<CertificateCompressor>>& compressors) {
158  return selfCertFromDataInternal(
159  std::move(certData), std::move(keyData), nullptr, compressors);
160 }
161 
162 std::unique_ptr<SelfCert> CertUtils::makeSelfCert(
163  std::string certData,
164  std::string encryptedKeyData,
165  std::string password,
166  const std::vector<std::shared_ptr<CertificateCompressor>>& compressors) {
167  return selfCertFromDataInternal(
168  std::move(certData), std::move(encryptedKeyData), &password[0], compressors);
169 }
170 
171 std::unique_ptr<SelfCert> CertUtils::makeSelfCert(
172  std::vector<folly::ssl::X509UniquePtr> certs,
174  const std::vector<std::shared_ptr<CertificateCompressor>>& compressors) {
175  folly::ssl::EvpPkeyUniquePtr pubKey(X509_get_pubkey(certs.front().get()));
176  if (!pubKey) {
177  throw std::runtime_error("Failed to read public key");
178  }
179 
180  if (EVP_PKEY_id(pubKey.get()) == EVP_PKEY_RSA) {
181  return std::make_unique<SelfCertImpl<KeyType::RSA>>(
182  std::move(key), std::move(certs), compressors);
183  } else if (EVP_PKEY_id(pubKey.get()) == EVP_PKEY_EC) {
184  switch (getCurveName(pubKey.get())) {
185  case NID_X9_62_prime256v1:
186  return std::make_unique<SelfCertImpl<KeyType::P256>>(
187  std::move(key), std::move(certs), compressors);
188  case NID_secp384r1:
189  return std::make_unique<SelfCertImpl<KeyType::P384>>(
190  std::move(key), std::move(certs), compressors);
191  case NID_secp521r1:
192  return std::make_unique<SelfCertImpl<KeyType::P521>>(
193  std::move(key), std::move(certs), compressors);
194  default:
195  break;
196  }
197  }
198  throw std::runtime_error("unknown self cert type");
199 }
200 
202  const CompressedCertificate& src) {
204  ret.algorithm = src.algorithm;
206  src.compressed_certificate_message->clone();
208  return ret;
209 }
210 
211 IdentityCert::IdentityCert(std::string identity) : identity_(identity) {}
212 
214  return identity_;
215 }
216 
218  return nullptr;
219 }
220 } // namespace fizz
CertificateCompressionAlgorithm algorithm
Definition: Types.h:245
static std::unique_ptr< SelfCert > makeSelfCert(std::string certData, std::string keyData, const std::vector< std::shared_ptr< CertificateCompressor >> &compressors={})
std::unique_ptr< X509, X509Deleter > X509UniquePtr
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
char b
std::unique_ptr< BIO, BioDeleter > BioUniquePtr
std::string identity_
Definition: Certificate.h:34
context
Definition: CMakeCache.txt:563
IdentityCert(std::string identity)
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
constexpr size_type size() const
Definition: Range.h:431
auto begin(TestAdlIterable &instance)
Definition: ForeachTest.cpp:56
uint32_t uncompressed_length
Definition: Types.h:246
std::unique_ptr< EVP_PKEY, EvpPkeyDeleter > EvpPkeyUniquePtr
Buf certificate_request_context
Definition: Types.h:238
Gen range(Value begin, Value end)
Definition: Base.h:467
std::vector< CertificateEntry > certificate_list
Definition: Types.h:239
constexpr Iter data() const
Definition: Range.h:446
static CertificateMsg getCertMessage(const std::vector< folly::ssl::X509UniquePtr > &certs, Buf certificateRequestContext)
Definition: Certificate.cpp:59
Definition: Actions.h:16
CertificateVerifyContext
Definition: Certificate.h:20
folly::ssl::X509UniquePtr getX509() const override
static std::unique_ptr< PeerCert > makePeerCert(Buf certData)
Definition: Certificate.cpp:87
const char * string
Definition: Conv.cpp:212
std::unique_ptr< folly::IOBuf > Buf
Definition: Types.h:22
Container::value_type * dataPtr(Container &cont)
Definition: RangeTest.cpp:1082
static std::vector< X509UniquePtr > readCertsFromBuffer(ByteRange range)
std::string getIdentity() const override
static Buf prepareSignData(CertificateVerifyContext context, folly::ByteRange toBeSigned)
Definition: Certificate.cpp:23
static CompressedCertificate cloneCompressedCert(const CompressedCertificate &src)
StringPiece label