1
#include "source/extensions/common/aws/signers/sigv4a_key_derivation.h"
2

            
3
#include "source/common/crypto/utility.h"
4
#include "source/extensions/common/aws/signers/sigv4a_common.h"
5

            
6
namespace Envoy {
7
namespace Extensions {
8
namespace Common {
9
namespace Aws {
10

            
11
absl::StatusOr<EC_KEY*> SigV4AKeyDerivation::derivePrivateKey(absl::string_view access_key_id,
12
254
                                                              absl::string_view secret_access_key) {
13

            
14
254
  auto& crypto_util = Envoy::Common::Crypto::UtilitySingleton::get();
15

            
16
254
  const uint8_t key_length = 32; // AWS_CAL_ECDSA_P256
17
254
  std::vector<uint8_t> private_key_buf(key_length);
18

            
19
254
  const uint8_t access_key_length = access_key_id.length();
20
254
  const uint8_t required_fixed_input_length = 32 + access_key_length;
21
254
  std::vector<uint8_t> fixed_input(required_fixed_input_length);
22

            
23
254
  const auto secret_key =
24
254
      absl::StrCat(SigV4ASignatureConstants::SigV4ASignatureVersion, secret_access_key);
25

            
26
254
  enum SigV4AKeyDerivationResult result = AkdrNextCounter;
27
254
  uint8_t external_counter = 1;
28

            
29
254
  BIGNUM* priv_key_num;
30
254
  EC_KEY* ec_key;
31

            
32
509
  while ((result == AkdrNextCounter) &&
33
509
         (external_counter <= 254)) // MAX_KEY_DERIVATION_COUNTER_VALUE
34
255
  {
35
255
    fixed_input.clear();
36
255
    fixed_input.insert(fixed_input.begin(), {0x00, 0x00, 0x00, 0x01});
37
    // Workaround for asan optimization issue described here
38
    // https://github.com/envoyproxy/envoy/pull/34377
39
255
    absl::string_view s(SigV4ASignatureConstants::SigV4AAlgorithm);
40
255
    fixed_input.insert(fixed_input.end(), s.begin(), s.end());
41
255
    fixed_input.insert(fixed_input.end(), 0x00);
42
255
    fixed_input.insert(fixed_input.end(), access_key_id.begin(), access_key_id.end());
43
255
    fixed_input.insert(fixed_input.end(), external_counter);
44
255
    fixed_input.insert(fixed_input.end(), {0x00, 0x00, 0x01, 0x00});
45

            
46
255
    auto k0 = crypto_util.getSha256Hmac(
47
255
        std::vector<uint8_t>(secret_key.begin(), secret_key.end()),
48
255
        absl::string_view(reinterpret_cast<char*>(fixed_input.data()), fixed_input.size()));
49

            
50
    // ECDSA q - 2
51
255
    std::vector<uint8_t> s_n_minus_2 = {
52
255
        0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF,
53
255
        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0xE6, 0xFA, 0xAD, 0xA7, 0x17,
54
255
        0x9E, 0x84, 0xF3, 0xB9, 0xCA, 0xC2, 0xFC, 0x63, 0x25, 0x4F,
55
255
    };
56

            
57
    // check that k0 < s_n_minus_2
58
255
    bool lt_result = constantTimeLessThanOrEqualTo(k0, s_n_minus_2);
59

            
60
255
    if (!lt_result) {
61
      // Loop if k0 >= s_n_minus_2 and the counter will cause a new hmac to be generated
62
1
      external_counter++;
63
254
    } else {
64
254
      result = SigV4AKeyDerivationResult::AkdrSuccess;
65
      // PrivateKey d = c+1
66
254
      constantTimeAddOne(&k0);
67
254
      priv_key_num = BN_bin2bn(k0.data(), k0.size(), nullptr);
68

            
69
      // Create a new OpenSSL EC_KEY by curve nid for secp256r1 (NIST P-256)
70
254
      ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
71

            
72
      // And set the private key we calculated above
73
254
      if (!EC_KEY_set_private_key(ec_key, priv_key_num)) {
74
        BN_free(priv_key_num);
75
        OPENSSL_free(ec_key);
76
        return absl::InvalidArgumentError("SigV4a private key could not be set");
77
      }
78
254
      BN_free(priv_key_num);
79
254
    }
80
255
  }
81

            
82
254
  return (result == SigV4AKeyDerivationResult::AkdrNextCounter)
83
254
             ? absl::StatusOr<EC_KEY*>(absl::InvalidArgumentError("Key derivation tries excepted"))
84
254
             : absl::StatusOr<EC_KEY*>(ec_key);
85
254
}
86

            
87
156
bool SigV4AKeyDerivation::derivePublicKey(EC_KEY* ec_key) {
88

            
89
156
  const BIGNUM* priv_key_num = EC_KEY_get0_private_key(ec_key);
90
156
  const EC_GROUP* group = EC_KEY_get0_group(ec_key);
91
156
  EC_POINT* point = EC_POINT_new(group);
92

            
93
156
  EC_POINT_mul(group, point, priv_key_num, nullptr, nullptr, nullptr);
94

            
95
156
  EC_KEY_set_public_key(ec_key, point);
96

            
97
156
  EC_POINT_free(point);
98
156
  return true;
99
156
}
100

            
101
// code based on aws sdk key derivation constant time implementations
102
// https://github.com/awslabs/aws-c-auth/blob/baeffa791d9d1cf61460662a6d9ac2186aaf05df/source/key_derivation.c#L152
103

            
104
bool SigV4AKeyDerivation::constantTimeLessThanOrEqualTo(std::vector<uint8_t> lhs_raw_be_bigint,
105
255
                                                        std::vector<uint8_t> rhs_raw_be_bigint) {
106

            
107
255
  volatile uint8_t gt = 0;
108
255
  volatile uint8_t eq = 1;
109

            
110
8415
  for (uint8_t i = 0; i < lhs_raw_be_bigint.size(); ++i) {
111
8160
    volatile int32_t lhs_digit = lhs_raw_be_bigint[i];
112
8160
    volatile int32_t rhs_digit = rhs_raw_be_bigint[i];
113

            
114
8160
    gt = gt | (((rhs_digit - lhs_digit) >> 31) & eq);
115
8160
    eq = eq & ((((lhs_digit ^ rhs_digit) - 1) >> 31) & 0x01);
116
8160
  }
117
255
  return (gt + gt + eq - 1) <= 0;
118
255
}
119

            
120
254
void SigV4AKeyDerivation::constantTimeAddOne(std::vector<uint8_t>* raw_be_bigint) {
121

            
122
254
  const uint8_t byte_count = raw_be_bigint->size();
123

            
124
254
  volatile uint32_t carry = 1;
125

            
126
8382
  for (size_t i = 0; i < byte_count; ++i) {
127
8128
    const size_t index = byte_count - i - 1;
128

            
129
8128
    volatile uint32_t current_digit = (*raw_be_bigint)[index];
130
8128
    current_digit = current_digit + carry;
131

            
132
8128
    carry = (current_digit >> 8) & 0x01;
133

            
134
8128
    (*raw_be_bigint)[index] = (current_digit & 0xFF);
135
8128
  }
136
254
}
137

            
138
} // namespace Aws
139
} // namespace Common
140
} // namespace Extensions
141
} // namespace Envoy