| OLD | NEW |
| (Empty) |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "net/ssl/token_binding.h" | |
| 6 | |
| 7 #include <openssl/bytestring.h> | |
| 8 #include <openssl/ec.h> | |
| 9 #include <openssl/evp.h> | |
| 10 #include <openssl/mem.h> | |
| 11 | |
| 12 #include "base/stl_util.h" | |
| 13 #include "crypto/scoped_openssl_types.h" | |
| 14 #include "net/base/net_errors.h" | |
| 15 #include "net/ssl/ssl_config.h" | |
| 16 | |
| 17 namespace net { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 bool BuildTokenBindingID(crypto::ECPrivateKey* key, CBB* out) { | |
| 22 EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(key->key()); | |
| 23 DCHECK(ec_key); | |
| 24 | |
| 25 CBB ec_point; | |
| 26 return CBB_add_u8(out, TB_PARAM_ECDSAP256) && | |
| 27 CBB_add_u8_length_prefixed(out, &ec_point) && | |
| 28 EC_POINT_point2cbb(&ec_point, EC_KEY_get0_group(ec_key), | |
| 29 EC_KEY_get0_public_key(ec_key), | |
| 30 POINT_CONVERSION_UNCOMPRESSED, nullptr) && | |
| 31 CBB_flush(out); | |
| 32 } | |
| 33 | |
| 34 } // namespace | |
| 35 | |
| 36 bool IsTokenBindingSupported() { | |
| 37 return true; | |
| 38 } | |
| 39 | |
| 40 bool SignTokenBindingEkm(base::StringPiece ekm, | |
| 41 crypto::ECPrivateKey* key, | |
| 42 std::vector<uint8_t>* out) { | |
| 43 size_t sig_len; | |
| 44 const uint8_t* ekm_data = reinterpret_cast<const uint8_t*>(ekm.data()); | |
| 45 crypto::ScopedEVP_PKEY_CTX pctx(EVP_PKEY_CTX_new(key->key(), nullptr)); | |
| 46 if (!EVP_PKEY_sign_init(pctx.get()) || | |
| 47 !EVP_PKEY_sign(pctx.get(), nullptr, &sig_len, ekm_data, ekm.size())) { | |
| 48 return false; | |
| 49 } | |
| 50 out->resize(sig_len); | |
| 51 if (!EVP_PKEY_sign(pctx.get(), out->data(), &sig_len, ekm_data, ekm.size())) | |
| 52 return false; | |
| 53 out->resize(sig_len); | |
| 54 return true; | |
| 55 } | |
| 56 | |
| 57 Error BuildTokenBindingMessageFromTokenBindings( | |
| 58 const std::vector<base::StringPiece>& token_bindings, | |
| 59 std::string* out) { | |
| 60 CBB tb_message, child; | |
| 61 if (!CBB_init(&tb_message, 0) || | |
| 62 !CBB_add_u16_length_prefixed(&tb_message, &child)) { | |
| 63 CBB_cleanup(&tb_message); | |
| 64 return ERR_FAILED; | |
| 65 } | |
| 66 for (const base::StringPiece& token_binding : token_bindings) { | |
| 67 if (!CBB_add_bytes(&child, | |
| 68 reinterpret_cast<const uint8_t*>(token_binding.data()), | |
| 69 token_binding.size())) { | |
| 70 CBB_cleanup(&tb_message); | |
| 71 return ERR_FAILED; | |
| 72 } | |
| 73 } | |
| 74 | |
| 75 uint8_t* out_data; | |
| 76 size_t out_len; | |
| 77 if (!CBB_finish(&tb_message, &out_data, &out_len)) { | |
| 78 CBB_cleanup(&tb_message); | |
| 79 return ERR_FAILED; | |
| 80 } | |
| 81 out->assign(reinterpret_cast<char*>(out_data), out_len); | |
| 82 OPENSSL_free(out_data); | |
| 83 return OK; | |
| 84 } | |
| 85 | |
| 86 Error BuildTokenBinding(TokenBindingType type, | |
| 87 crypto::ECPrivateKey* key, | |
| 88 const std::vector<uint8_t>& signed_ekm, | |
| 89 std::string* out) { | |
| 90 uint8_t* out_data; | |
| 91 size_t out_len; | |
| 92 CBB token_binding; | |
| 93 if (!CBB_init(&token_binding, 0) || | |
| 94 !CBB_add_u8(&token_binding, static_cast<uint8_t>(type)) || | |
| 95 !BuildTokenBindingID(key, &token_binding) || | |
| 96 !CBB_add_u16(&token_binding, signed_ekm.size()) || | |
| 97 !CBB_add_bytes(&token_binding, signed_ekm.data(), signed_ekm.size()) || | |
| 98 // 0-length extensions | |
| 99 !CBB_add_u16(&token_binding, 0) || | |
| 100 !CBB_finish(&token_binding, &out_data, &out_len)) { | |
| 101 CBB_cleanup(&token_binding); | |
| 102 return ERR_FAILED; | |
| 103 } | |
| 104 out->assign(reinterpret_cast<char*>(out_data), out_len); | |
| 105 OPENSSL_free(out_data); | |
| 106 return OK; | |
| 107 } | |
| 108 | |
| 109 TokenBinding::TokenBinding() {} | |
| 110 | |
| 111 bool ParseTokenBindingMessage(base::StringPiece token_binding_message, | |
| 112 std::vector<TokenBinding>* token_bindings) { | |
| 113 CBS tb_message, tb, ec_point, signature, extensions; | |
| 114 uint8_t tb_type, tb_param; | |
| 115 CBS_init(&tb_message, | |
| 116 reinterpret_cast<const uint8_t*>(token_binding_message.data()), | |
| 117 token_binding_message.size()); | |
| 118 if (!CBS_get_u16_length_prefixed(&tb_message, &tb)) | |
| 119 return false; | |
| 120 while (CBS_len(&tb)) { | |
| 121 if (!CBS_get_u8(&tb, &tb_type) || !CBS_get_u8(&tb, &tb_param) || | |
| 122 !CBS_get_u8_length_prefixed(&tb, &ec_point) || | |
| 123 !CBS_get_u16_length_prefixed(&tb, &signature) || | |
| 124 !CBS_get_u16_length_prefixed(&tb, &extensions) || | |
| 125 tb_param != TB_PARAM_ECDSAP256 || | |
| 126 (TokenBindingType(tb_type) != TokenBindingType::PROVIDED && | |
| 127 TokenBindingType(tb_type) != TokenBindingType::REFERRED)) { | |
| 128 return false; | |
| 129 } | |
| 130 | |
| 131 TokenBinding token_binding; | |
| 132 token_binding.type = TokenBindingType(tb_type); | |
| 133 token_binding.ec_point = std::string( | |
| 134 reinterpret_cast<const char*>(CBS_data(&ec_point)), CBS_len(&ec_point)); | |
| 135 token_binding.signature = | |
| 136 std::string(reinterpret_cast<const char*>(CBS_data(&signature)), | |
| 137 CBS_len(&signature)); | |
| 138 token_bindings->push_back(token_binding); | |
| 139 } | |
| 140 return true; | |
| 141 } | |
| 142 | |
| 143 bool VerifyEKMSignature(base::StringPiece ec_point, | |
| 144 base::StringPiece signature, | |
| 145 base::StringPiece ekm) { | |
| 146 crypto::ScopedEC_Key key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1)); | |
| 147 EC_KEY* keyp = key.get(); | |
| 148 const uint8_t* ec_point_data = | |
| 149 reinterpret_cast<const uint8_t*>(ec_point.data()); | |
| 150 if (o2i_ECPublicKey(&keyp, &ec_point_data, ec_point.size()) != key.get()) | |
| 151 return false; | |
| 152 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); | |
| 153 if (!EVP_PKEY_assign_EC_KEY(pkey.get(), key.release())) | |
| 154 return false; | |
| 155 crypto::ScopedEVP_PKEY_CTX pctx(EVP_PKEY_CTX_new(pkey.get(), nullptr)); | |
| 156 if (!EVP_PKEY_verify_init(pctx.get()) || | |
| 157 !EVP_PKEY_verify( | |
| 158 pctx.get(), reinterpret_cast<const uint8_t*>(signature.data()), | |
| 159 signature.size(), reinterpret_cast<const uint8_t*>(ekm.data()), | |
| 160 ekm.size())) { | |
| 161 return false; | |
| 162 } | |
| 163 return true; | |
| 164 } | |
| 165 | |
| 166 } // namespace net | |
| OLD | NEW |