• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The Chromium Authors
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/device_bound_sessions/jwk_utils.h"
6 
7 #include "base/base64url.h"
8 #include "third_party/boringssl/src/include/openssl/bn.h"
9 #include "third_party/boringssl/src/include/openssl/bytestring.h"
10 #include "third_party/boringssl/src/include/openssl/ec.h"
11 #include "third_party/boringssl/src/include/openssl/evp.h"
12 #include "third_party/boringssl/src/include/openssl/rsa.h"
13 
14 namespace net::device_bound_sessions {
15 
16 namespace {
17 // The format of JSON Web Key (JWK) is specified in the section 4 of RFC 7517:
18 // https://www.ietf.org/rfc/rfc7517.html#section-4
19 //
20 // The parameters of a particular key type are specified by the JWA spec:
21 // https://www.ietf.org/rfc/rfc7518.html#section-6
22 constexpr char kKeyTypeParam[] = "kty";
23 constexpr char kEcKeyType[] = "EC";
24 constexpr char kEcCurve[] = "crv";
25 constexpr char kEcCurveP256[] = "P-256";
26 constexpr char kEcCoordinateX[] = "x";
27 constexpr char kEcCoordinateY[] = "y";
28 constexpr char kRsaKeyType[] = "RSA";
29 constexpr char kRsaModulus[] = "n";
30 constexpr char kRsaExponent[] = "e";
31 
Base64UrlEncode(base::span<const uint8_t> input)32 std::string Base64UrlEncode(base::span<const uint8_t> input) {
33   std::string output;
34   base::Base64UrlEncode(input, base::Base64UrlEncodePolicy::OMIT_PADDING,
35                         &output);
36   return output;
37 }
38 
ParsePublicKey(base::span<const uint8_t> pkey_spki)39 bssl::UniquePtr<EVP_PKEY> ParsePublicKey(base::span<const uint8_t> pkey_spki) {
40   CBS cbs;
41   CBS_init(&cbs, pkey_spki.data(), pkey_spki.size());
42   bssl::UniquePtr<EVP_PKEY> pkey(EVP_parse_public_key(&cbs));
43   if (CBS_len(&cbs) != 0) {
44     return nullptr;
45   }
46   return pkey;
47 }
48 
ConvertES256PkeySpkiToJwk(base::span<const uint8_t> pkey_spki)49 base::Value::Dict ConvertES256PkeySpkiToJwk(
50     base::span<const uint8_t> pkey_spki) {
51   bssl::UniquePtr<EVP_PKEY> pkey = ParsePublicKey(pkey_spki);
52   if (!pkey || EVP_PKEY_id(pkey.get()) != EVP_PKEY_EC) {
53     return base::Value::Dict();
54   }
55 
56   EC_KEY* ec_key = EVP_PKEY_get0_EC_KEY(pkey.get());
57   if (!ec_key) {
58     return base::Value::Dict();
59   }
60 
61   const EC_GROUP* group = EC_KEY_get0_group(ec_key);
62   const EC_POINT* point = EC_KEY_get0_public_key(ec_key);
63   if (!group || !point) {
64     return base::Value::Dict();
65   }
66 
67   bssl::UniquePtr<BIGNUM> x(BN_new());
68   bssl::UniquePtr<BIGNUM> y(BN_new());
69   if (!x || !y) {
70     return base::Value::Dict();
71   }
72 
73   if (!EC_POINT_get_affine_coordinates_GFp(group, point, x.get(), y.get(),
74                                            nullptr)) {
75     return base::Value::Dict();
76   }
77 
78   std::vector<uint8_t> x_bytes(BN_num_bytes(x.get()));
79   std::vector<uint8_t> y_bytes(BN_num_bytes(y.get()));
80   BN_bn2bin(x.get(), x_bytes.data());
81   BN_bn2bin(y.get(), y_bytes.data());
82 
83   return base::Value::Dict()
84       .Set(kKeyTypeParam, kEcKeyType)
85       .Set(kEcCurve, kEcCurveP256)
86       .Set(kEcCoordinateX, Base64UrlEncode(x_bytes))
87       .Set(kEcCoordinateY, Base64UrlEncode(y_bytes));
88 }
89 
ConvertRS256PkeySpkiToJwk(base::span<const uint8_t> pkey_spki)90 base::Value::Dict ConvertRS256PkeySpkiToJwk(
91     base::span<const uint8_t> pkey_spki) {
92   bssl::UniquePtr<EVP_PKEY> pkey = ParsePublicKey(pkey_spki);
93   if (!pkey || EVP_PKEY_id(pkey.get()) != EVP_PKEY_RSA) {
94     return base::Value::Dict();
95   }
96 
97   RSA* rsa_key = EVP_PKEY_get0_RSA(pkey.get());
98   if (!rsa_key) {
99     return base::Value::Dict();
100   }
101 
102   const BIGNUM* n = RSA_get0_n(rsa_key);
103   const BIGNUM* e = RSA_get0_e(rsa_key);
104   if (!n || !e) {
105     return base::Value::Dict();
106   }
107 
108   std::vector<uint8_t> n_bytes(BN_num_bytes(n));
109   std::vector<uint8_t> e_bytes(BN_num_bytes(e));
110   BN_bn2bin(n, n_bytes.data());
111   BN_bn2bin(e, e_bytes.data());
112 
113   return base::Value::Dict()
114       .Set(kKeyTypeParam, kRsaKeyType)
115       .Set(kRsaModulus, Base64UrlEncode(n_bytes))
116       .Set(kRsaExponent, Base64UrlEncode(e_bytes));
117 }
118 }  // namespace
119 
ConvertPkeySpkiToJwk(crypto::SignatureVerifier::SignatureAlgorithm algorithm,base::span<const uint8_t> pkey_spki)120 base::Value::Dict ConvertPkeySpkiToJwk(
121     crypto::SignatureVerifier::SignatureAlgorithm algorithm,
122     base::span<const uint8_t> pkey_spki) {
123   // TODO(crbug.com/360756896): Support more algorithms.
124   switch (algorithm) {
125     case crypto::SignatureVerifier::SignatureAlgorithm::RSA_PKCS1_SHA256:
126       return ConvertRS256PkeySpkiToJwk(pkey_spki);
127     case crypto::SignatureVerifier::SignatureAlgorithm::ECDSA_SHA256:
128       return ConvertES256PkeySpkiToJwk(pkey_spki);
129     default:
130       return base::Value::Dict();
131   }
132 }
133 
134 }  // namespace net::device_bound_sessions
135