Index: net/socket/ssl_client_socket_openssl.cc |
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc |
index bcf23eaf9c63c1411a4d982b13035e1bcc484b67..774b41666cec20be23be7b180d81b8fb18b2bb4b 100644 |
--- a/net/socket/ssl_client_socket_openssl.cc |
+++ b/net/socket/ssl_client_socket_openssl.cc |
@@ -521,8 +521,129 @@ int SSLClientSocketOpenSSL::ExportKeyingMaterial( |
} |
int SSLClientSocketOpenSSL::GetTLSUniqueChannelBinding(std::string* out) { |
- NOTIMPLEMENTED(); |
- return ERR_NOT_IMPLEMENTED; |
+ uint8_t buf[64]; |
+ size_t len; |
+ if (!SSL_get_tls_unique(ssl_, buf, &len, arraysize(buf))) |
+ return ERR_FAILED; |
+ out->assign(reinterpret_cast<char*>(buf), len); |
+ return OK; |
+} |
+ |
+// BuildProvidedTokenBindingID builds the serialized TokenBindingID struct as |
+// defined in draft-ietf-tokbind-protocol-02. It only builds provided token |
+// bindings, and only supports ECDSA P256 keys. The TokenBindingID struct |
+// definition (and related structs and enums) is provided below. |
+// |
+// enum { |
+// rsa2048_pkcs1.5_sha256(0), |
+// rsa2048_pss_sha256(1), |
+// ecdsap256_sha256(2), (255) |
+// } TokenBindingKeyParameters; |
+// |
+// enum { |
+// secp256r1 (23), (0xFFFF) |
+// } NamedCurve; |
+// |
+// struct { |
+// opaque point <1..2^8-1>; |
+// } ECPoint; |
+// |
+// struct { |
+// NamedCurve namedcurve; |
+// ECPoint point; // Uncompressed format |
+// } ECDSAParams; |
+// |
+// enum { |
+// provided_token_binding(0), referred_token_binding(1), (255) |
+// } TokenBindingType; |
+// |
+// struct { |
+// TokenBindingType tokenbinding_type; |
+// TokenBindingKeyParameters key_parameters; |
+// select (key_parameters) { |
+// case rsa2048_pkcs1.5_sha256: |
+// case rsa2048_pss_sha256: |
+// RSAPublicKey rsapubkey; |
+// case ecdsap256_sha256: |
+// ECDSAParams ecdsaparams; |
+// } |
+// } TokenBindingID; |
+bool BuildProvidedTokenBindingID(crypto::ECPrivateKey* key, CBB* out) { |
+ CBB ec_point; |
+ if (!CBB_add_u8(out, 0) || // provided_token_binding(0) |
+ !CBB_add_u8(out, TB_PARAM_ECDSAP256_SHA256) || |
+ !CBB_add_u16(out, 23) || // NamedCurve secp256r1(23) |
+ !CBB_add_u8_length_prefixed(out, &ec_point)) { |
+ return false; |
+ } |
+ std::string raw_key; |
+ if (!key->ExportRawPublicKey(&raw_key)) { |
+ return false; |
+ } |
+ if (!CBB_add_bytes(&ec_point, reinterpret_cast<uint8*>( |
+ const_cast<char*>(raw_key.data())), |
+ raw_key.size()) || |
+ !CBB_flush(out)) { |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+int SSLClientSocketOpenSSL::BuildProvidedTokenBinding() { |
+ size_t tb_ekm_size = 32; |
+ uint8_t tb_ekm_buf[32]; |
+ const char tb_ekm_label[] = "EXPORTER-Token-Binding"; |
+ // The EKM label does not include a null terminating byte. Calling arraysize |
+ // on a char array includes the null terminator in the length, so subtract 1 |
+ // to account for that. |
+ size_t ekm_label_length = arraysize(tb_ekm_label) - 1; |
+ if (!SSL_export_keying_material(ssl_, tb_ekm_buf, tb_ekm_size, tb_ekm_label, |
+ ekm_label_length, nullptr, 0, false)) { |
+ return ERR_FAILED; |
+ } |
+ |
+ crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create()); |
+ size_t sig_len; |
+ if (!EVP_DigestSignInit(ctx.get(), nullptr, EVP_sha256(), nullptr, |
+ channel_id_key_->key()) || |
+ !EVP_DigestSignUpdate(ctx.get(), tb_ekm_buf, tb_ekm_size) || |
+ !EVP_DigestSignFinal(ctx.get(), nullptr, &sig_len)) { |
+ return ERR_FAILED; |
+ } |
+ std::vector<uint8> signature; |
+ signature.resize(sig_len); |
+ if (!EVP_DigestSignFinal(ctx.get(), &signature.front(), &sig_len)) |
+ return ERR_FAILED; |
+ |
+ // Build in |token_binding| the serialization of the TokenBinding struct, |
+ // defined as follows: |
+ // |
+ // struct { |
+ // TokenBindingID tokenbindingid; |
+ // opaque signature<0..2^16-1>;// Signature over the exported keying |
+ // material value |
+ // Extension extensions<0..2^16-1>; |
+ // } TokenBinding; |
+ CBB token_binding; |
+ uint8_t* out_data; |
+ size_t out_len; |
+ if (!CBB_init(&token_binding, 0) || |
+ !BuildProvidedTokenBindingID(channel_id_key_.get(), &token_binding) || |
+ !CBB_add_u16(&token_binding, sig_len) || |
+ !CBB_add_bytes(&token_binding, &signature.front(), sig_len) || |
+ // 0-length extensions |
+ !CBB_add_u16(&token_binding, 0) || |
+ !CBB_finish(&token_binding, &out_data, &out_len)) { |
+ CBB_cleanup(&token_binding); |
+ return ERR_FAILED; |
+ } |
+ provided_token_binding_.assign(reinterpret_cast<char*>(out_data), out_len); |
+ OPENSSL_free(out_data); |
+ return OK; |
+} |
+ |
+std::string SSLClientSocketOpenSSL::GetProvidedTokenBinding() { |
+ return provided_token_binding_; |
} |
int SSLClientSocketOpenSSL::Connect(const CompletionCallback& callback) { |
@@ -1114,16 +1235,19 @@ int SSLClientSocketOpenSSL::DoHandshakeComplete(int result) { |
return ERR_SSL_FALLBACK_BEYOND_MINIMUM_VERSION; |
} |
- // Check that if token binding was negotiated, then extended master secret |
- // must also be negotiated. |
- if (token_binding_extension_.WasNegotiated() && |
- !ssl_->session->extended_master_secret) { |
- return ERR_SSL_PROTOCOL_ERROR; |
- } |
- |
- if (token_binding_extension_.WasNegotiated() && !channel_id_key_) { |
- GotoState(STATE_TOKEN_BINDING_LOOKUP); |
- return OK; |
+ if (token_binding_extension_.WasNegotiated()) { |
+ // Check that if token binding was negotiated, then extended master secret |
+ // must also be negotiated. |
+ if (!ssl_->session->extended_master_secret) |
+ return ERR_SSL_PROTOCOL_ERROR; |
+ if (!channel_id_key_) { |
+ GotoState(STATE_TOKEN_BINDING_LOOKUP); |
+ return OK; |
+ } |
+ if (BuildProvidedTokenBinding() != OK) { |
+ NOTREACHED(); |
+ return ERR_FAILED; |
+ } |
} |
// SSL handshake is completed. If NPN wasn't negotiated, see if ALPN was. |
@@ -2245,9 +2369,9 @@ void SSLClientSocketOpenSSL::TokenBindingExtension::SetParams( |
bool SSLClientSocketOpenSSL::TokenBindingExtension::RegisterCallbacks( |
SSL_CTX* ssl_ctx) { |
return SSL_CTX_add_client_custom_ext( |
- ssl_ctx, kExtNum, &TokenBindingExtension::ClientAddCallback, |
- &TokenBindingExtension::ClientFreeCallback, nullptr, |
- &TokenBindingExtension::ClientParseCallback, nullptr); |
+ ssl_ctx, kExtNum, &TokenBindingExtension::ClientAddCallback, |
+ &TokenBindingExtension::ClientFreeCallback, nullptr, |
+ &TokenBindingExtension::ClientParseCallback, nullptr) != 0; |
mattm
2015/10/01 01:53:01
should this change be in the parent CL?
nharper
2015/10/01 20:25:46
Done.
|
} |
int SSLClientSocketOpenSSL::TokenBindingExtension::ClientAdd( |