File: two_qwac_cert_binding_builder.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (151 lines) | stat: -rw-r--r-- 5,376 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/test/two_qwac_cert_binding_builder.h"

#include "base/base64.h"
#include "base/base64url.h"
#include "base/json/json_string_value_serializer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/boringssl/src/include/openssl/rsa.h"

namespace net {

TwoQwacCertBindingBuilder::TwoQwacCertBindingBuilder()
    : cert_chain_(CertBuilder::CreateSimpleChain(2)) {
  GetLeafBuilder()->SetCertificatePolicies({"0.4.0.194112.1.6"});  // QNCP-w-gen
  GetLeafBuilder()->SetQwacQcStatements({bssl::der::Input(kEtsiQctWebOid)});
  GetLeafBuilder()->SetExtendedKeyUsages({bssl::der::Input(kIdKpTlsBinding)});
  GenerateKeyForSigAlg();
  // set bound_certs_ to two bogus values
  bound_certs_ = {"one", "two"};
}

TwoQwacCertBindingBuilder::~TwoQwacCertBindingBuilder() = default;

void TwoQwacCertBindingBuilder::GenerateKeyForSigAlg() {
  switch (sig_alg_) {
    case JwsSigAlg::kRsaPkcs1Sha256:
    case JwsSigAlg::kRsaPssSha256:
      cert_chain_[0]->GenerateRSAKey();
      break;
    case JwsSigAlg::kEcdsaP256Sha256:
      cert_chain_[0]->GenerateECKey();
  }
  Invalidate();
}

std::string TwoQwacCertBindingBuilder::SigAlg() const {
  switch (sig_alg_) {
    case JwsSigAlg::kRsaPkcs1Sha256:
      return "RS256";
    case JwsSigAlg::kRsaPssSha256:
      return "PS256";
    case JwsSigAlg::kEcdsaP256Sha256:
      return "ES256";
  }
  return "";
}

std::string TwoQwacCertBindingBuilder::HashAlg() const {
  switch (hash_alg_) {
    case crypto::hash::kSha256:
      return "S256";
    case crypto::hash::kSha384:
      return "S384";
    case crypto::hash::kSha512:
      return "S512";
    default:
      return "";
  }
}

base::ListValue TwoQwacCertBindingBuilder::GenerateX5cHeaderValue() {
  base::ListValue x5c_list;
  for (const auto& cert : cert_chain_) {
    x5c_list.Append(base::Base64Encode(cert->GetDER()));
  }
  return x5c_list;
}

base::DictValue TwoQwacCertBindingBuilder::GenerateSigDHeaderValue() {
  base::DictValue sig_d =
      base::Value::Dict()
          .Set("mId", "http://uri.etsi.org/19182/ObjectIdByURIHash")
          .Set("hashM", HashAlg());
  base::ListValue pars;
  base::ListValue hash_v;
  for (const auto& bound_cert : bound_certs_) {
    // ETSI TS 119 182-1 clause 5.2.8.1: Each element of the "hashV" array
    // shall contain the base64url-encoded digest value of the
    // base64url-encoded data object.
    std::string cert_b64;
    base::Base64UrlEncode(bound_cert, base::Base64UrlEncodePolicy::OMIT_PADDING,
                          &cert_b64);
    std::vector<uint8_t> cert_hash(
        crypto::hash::DigestSizeForHashKind(hash_alg_));
    crypto::hash::Hash(hash_alg_, cert_b64, cert_hash);
    std::string hash_b64;
    base::Base64UrlEncode(cert_hash, base::Base64UrlEncodePolicy::OMIT_PADDING,
                          &hash_b64);
    hash_v.Append(hash_b64);
    pars.Append("");
  }
  sig_d.Set("pars", std::move(pars));
  sig_d.Set("hashV", std::move(hash_v));
  return sig_d;
}

void TwoQwacCertBindingBuilder::GenerateHeader() {
  // Build the minimal JWS header needed for a 2-QWAC TLS certificate binding.
  base::DictValue header = base::DictValue()
                               .Set("alg", SigAlg())
                               .Set("cty", "TLS-Certificate-Binding-v1")
                               .Set("x5c", GenerateX5cHeaderValue())
                               .Set("sigD", GenerateSigDHeaderValue());
  // Add/override values in the header
  header.Merge(header_overrides_.Clone());

  std::string header_string;
  ASSERT_TRUE(JSONStringValueSerializer(&header_string).Serialize(header));
  header_b64_ = std::string();
  base::Base64UrlEncode(
      header_string, base::Base64UrlEncodePolicy::OMIT_PADDING, &*header_b64_);
}

void TwoQwacCertBindingBuilder::GenerateSignature() {
  // All JWS signature algorithms that we support use SHA-256 as their digest.
  const EVP_MD* digest = EVP_sha256();
  bssl::ScopedEVP_MD_CTX ctx;
  EVP_PKEY_CTX* pkey_ctx;
  EVP_PKEY* key = cert_chain_[0]->GetKey();
  ASSERT_TRUE(
      EVP_DigestSignInit(ctx.get(), &pkey_ctx, EVP_sha256(), nullptr, key));
  if (sig_alg_ == JwsSigAlg::kRsaPssSha256) {
    ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, RSA_PKCS1_PSS_PADDING));
    ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, digest));
    ASSERT_TRUE(EVP_PKEY_CTX_set_rsa_pss_saltlen(
        pkey_ctx, -1 /* match digest and salt length */));
  }

  // The JWS signing input is the the (base64url-encoded) header and payload
  // concatenated and separated by a '.'. For a 2-QWAC cert binding, the
  // payload is always empty.
  const std::string& header = GetHeader();
  const std::array<uint8_t, 1> separator = {'.'};
  ASSERT_TRUE(EVP_DigestSignUpdate(ctx.get(), header.data(), header.size()));
  ASSERT_TRUE(
      EVP_DigestSignUpdate(ctx.get(), separator.data(), separator.size()));
  size_t len = 0;
  std::vector<uint8_t> sig;
  ASSERT_TRUE(EVP_DigestSignFinal(ctx.get(), nullptr, &len));
  sig.resize(len);
  ASSERT_TRUE(EVP_DigestSignFinal(ctx.get(), sig.data(), &len));
  sig.resize(len);
  signature_b64_ = std::string();
  base::Base64UrlEncode(sig, base::Base64UrlEncodePolicy::OMIT_PADDING,
                        &*signature_b64_);
}

}  // namespace net