Project import generated by Copybara.

PiperOrigin-RevId: 237361882
Change-Id: I109a68f44db867b20f8c6a7732b0ce657133e52a
diff --git a/quic/core/crypto/channel_id.cc b/quic/core/crypto/channel_id.cc
new file mode 100644
index 0000000..0c4a3e9
--- /dev/null
+++ b/quic/core/crypto/channel_id.cc
@@ -0,0 +1,89 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/third_party/quiche/src/quic/core/crypto/channel_id.h"
+
+#include <cstdint>
+
+#include "third_party/boringssl/src/include/openssl/bn.h"
+#include "third_party/boringssl/src/include/openssl/ec.h"
+#include "third_party/boringssl/src/include/openssl/ecdsa.h"
+#include "third_party/boringssl/src/include/openssl/nid.h"
+#include "third_party/boringssl/src/include/openssl/sha.h"
+
+namespace quic {
+
+// static
+const char ChannelIDVerifier::kContextStr[] = "QUIC ChannelID";
+// static
+const char ChannelIDVerifier::kClientToServerStr[] = "client -> server";
+
+// static
+bool ChannelIDVerifier::Verify(QuicStringPiece key,
+                               QuicStringPiece signed_data,
+                               QuicStringPiece signature) {
+  return VerifyRaw(key, signed_data, signature, true);
+}
+
+// static
+bool ChannelIDVerifier::VerifyRaw(QuicStringPiece key,
+                                  QuicStringPiece signed_data,
+                                  QuicStringPiece signature,
+                                  bool is_channel_id_signature) {
+  if (key.size() != 32 * 2 || signature.size() != 32 * 2) {
+    return false;
+  }
+
+  bssl::UniquePtr<EC_GROUP> p256(
+      EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+  if (p256.get() == nullptr) {
+    return false;
+  }
+
+  bssl::UniquePtr<BIGNUM> x(BN_new()), y(BN_new()), r(BN_new()), s(BN_new());
+
+  ECDSA_SIG sig;
+  sig.r = r.get();
+  sig.s = s.get();
+
+  const uint8_t* key_bytes = reinterpret_cast<const uint8_t*>(key.data());
+  const uint8_t* signature_bytes =
+      reinterpret_cast<const uint8_t*>(signature.data());
+
+  if (BN_bin2bn(key_bytes + 0, 32, x.get()) == nullptr ||
+      BN_bin2bn(key_bytes + 32, 32, y.get()) == nullptr ||
+      BN_bin2bn(signature_bytes + 0, 32, sig.r) == nullptr ||
+      BN_bin2bn(signature_bytes + 32, 32, sig.s) == nullptr) {
+    return false;
+  }
+
+  bssl::UniquePtr<EC_POINT> point(EC_POINT_new(p256.get()));
+  if (point.get() == nullptr ||
+      !EC_POINT_set_affine_coordinates_GFp(p256.get(), point.get(), x.get(),
+                                           y.get(), nullptr)) {
+    return false;
+  }
+
+  bssl::UniquePtr<EC_KEY> ecdsa_key(EC_KEY_new());
+  if (ecdsa_key.get() == nullptr ||
+      !EC_KEY_set_group(ecdsa_key.get(), p256.get()) ||
+      !EC_KEY_set_public_key(ecdsa_key.get(), point.get())) {
+    return false;
+  }
+
+  SHA256_CTX sha256;
+  SHA256_Init(&sha256);
+  if (is_channel_id_signature) {
+    SHA256_Update(&sha256, kContextStr, strlen(kContextStr) + 1);
+    SHA256_Update(&sha256, kClientToServerStr, strlen(kClientToServerStr) + 1);
+  }
+  SHA256_Update(&sha256, signed_data.data(), signed_data.size());
+
+  unsigned char digest[SHA256_DIGEST_LENGTH];
+  SHA256_Final(digest, &sha256);
+
+  return ECDSA_do_verify(digest, sizeof(digest), &sig, ecdsa_key.get()) == 1;
+}
+
+}  // namespace quic