proxygen
Validator.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 #include <fizz/crypto/Sha256.h>
14 
15 using namespace folly;
16 using namespace folly::io;
17 using namespace folly::ssl;
18 
19 namespace fizz {
20 namespace extensions {
21 
22 Optional<TokenBindingID> Validator::validateTokenBinding(
24  const Buf& ekm,
25  const TokenBindingKeyParameters& negotiatedParameters) {
26  if (tokenBinding.tokenbindingid.key_parameters != negotiatedParameters) {
27  VLOG(2) << "sent parameters: "
28  << toString(tokenBinding.tokenbindingid.key_parameters)
29  << " don't match negotiated parameters: "
30  << toString(negotiatedParameters);
31  return folly::none;
32  }
33 
34  try {
35  auto message = TokenBindingUtils::constructMessage(
36  tokenBinding.tokenbinding_type,
37  tokenBinding.tokenbindingid.key_parameters,
38  ekm);
39  verify(
40  tokenBinding.tokenbindingid.key_parameters,
41  tokenBinding.tokenbindingid.key,
42  tokenBinding.signature,
43  message);
44  return std::move(tokenBinding.tokenbindingid);
45  } catch (const std::exception& e) {
46  VLOG(1) << "Token Binding Verification Failed: " << e.what();
47  return folly::none;
48  }
49 }
50 
52  const TokenBindingKeyParameters& keyParams,
53  const Buf& key,
54  const Buf& signature,
55  const Buf& message) {
56  if (keyParams == TokenBindingKeyParameters::ecdsap256) {
57  auto pkey = constructEcKeyFromBuf(key);
58  auto ecdsa = constructECDSASig(signature);
59 
60  std::array<uint8_t, fizz::Sha256::HashLen> hashedMessage;
62  *message,
63  folly::MutableByteRange(hashedMessage.data(), hashedMessage.size()));
64  if (ECDSA_do_verify(
65  hashedMessage.data(),
66  hashedMessage.size(),
67  ecdsa.get(),
68  pkey.get()) != 1) {
69  throw std::runtime_error(folly::to<std::string>(
70  "Verification failed: ", detail::getOpenSSLError()));
71  }
72  } else {
73  // rsa_pss and rsa_pkcs
74  throw std::runtime_error(
75  folly::to<std::string>("key params not implemented: ", keyParams));
76  }
77 }
78 
79 EcdsaSigUniquePtr Validator::constructECDSASig(const Buf& signature) {
80  EcdsaSigUniquePtr ecdsaSignature(ECDSA_SIG_new());
81  if (!ecdsaSignature) {
82  throw std::runtime_error("Unable to allocate ecdsaSignature");
83  }
84  Cursor signatureReader(signature.get());
85  Buf rBytes = folly::IOBuf::create(TokenBindingUtils::kP256EcKeySize / 2);
86  Buf sBytes = folly::IOBuf::create(TokenBindingUtils::kP256EcKeySize / 2);
87  signatureReader.clone(*rBytes, TokenBindingUtils::kP256EcKeySize / 2);
88  signatureReader.clone(*sBytes, TokenBindingUtils::kP256EcKeySize / 2);
89  auto rRange = rBytes->coalesce();
90  auto sRange = sBytes->coalesce();
91  BIGNUMUniquePtr r(BN_new());
92  BIGNUMUniquePtr s(BN_new());
93  if (!BN_bin2bn(
94  rRange.data(), TokenBindingUtils::kP256EcKeySize / 2, r.get()) ||
95  !BN_bin2bn(
96  sRange.data(), TokenBindingUtils::kP256EcKeySize / 2, s.get())) {
97  throw std::runtime_error("unable to create bnum");
98  }
99 
100  // ecdsaSignature will clean up Bignum ptrs,
101  // so unique ptr needs to release them to avoid double delete
102  if (ECDSA_SIG_set0(ecdsaSignature.get(), r.release(), s.release()) != 1) {
103  throw std::runtime_error("unable to set bnum on ecdsa_sig");
104  }
105  return ecdsaSignature;
106 }
107 
108 EcKeyUniquePtr Validator::constructEcKeyFromBuf(const Buf& key) {
109  // EC_point_oct2point expects the format to match the one described here:
110  // https://tlswg.github.io/tls13-spec/draft-ietf-tls-tls13.html#ecdhe-param
111  Buf combinedKey = folly::IOBuf::create(TokenBindingUtils::kP256EcKeySize + 1);
112  Appender keyAppender(combinedKey.get(), 20);
113  keyAppender.writeBE<uint8_t>(POINT_CONVERSION_UNCOMPRESSED);
114 
115  // Key string from the token binding message has key size as the first byte,
116  // so we need to retrieve the key without the size byte,
117  // and add it to the buf from earlier
118  Cursor keyReader(key.get());
119  auto keyLen = keyReader.readBE<uint8_t>();
120  if (keyLen != TokenBindingUtils::kP256EcKeySize) {
121  throw std::runtime_error(
122  folly::to<std::string>("incorrect key size: ", keyLen));
123  }
124  keyAppender.push(keyReader, keyLen);
125  auto combinedRange = combinedKey->coalesce();
126 
127  auto evpKey =
128  fizz::detail::decodeECPublicKey(combinedRange, NID_X9_62_prime256v1);
129  EcKeyUniquePtr publicKey(EVP_PKEY_get1_EC_KEY(evpKey.get()));
130  if (!publicKey) {
131  throw std::runtime_error("Error getting EC_key");
132  }
133  return publicKey;
134 }
135 } // namespace extensions
136 } // namespace fizz
Definition: test.c:42
folly::StringPiece toString(StateEnum state)
Definition: State.cpp:16
void verify(int extras)
static std::unique_ptr< IOBuf > create(std::size_t capacity)
Definition: IOBuf.cpp:229
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
TokenBindingType tokenbinding_type
Definition: Types.h:57
TokenBindingKeyParameters
Definition: Types.h:33
std::unique_ptr< BIGNUM, BIGNUMDeleter > BIGNUMUniquePtr
std::unique_ptr< ECDSA_SIG, EcdsaSigDeleter > EcdsaSigUniquePtr
folly::ssl::EvpPkeyUniquePtr decodeECPublicKey(folly::ByteRange range, int curveNid)
std::unique_ptr< EC_KEY, EcKeyDeleter > EcKeyUniquePtr
int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
Definition: OpenSSL.cpp:405
Definition: Actions.h:16
std::string getOpenSSLError()
StringPiece tokenBinding
static void hash(const folly::IOBuf &in, folly::MutableByteRange out)
TokenBindingKeyParameters key_parameters
Definition: Types.h:47
TokenBindingID tokenbindingid
Definition: Types.h:58
std::unique_ptr< folly::IOBuf > Buf
Definition: Types.h:22
static set< string > s
constexpr None none
Definition: Optional.h:87
void writeBE(T value)
Definition: Cursor.h:744