File: signed_web_bundle_id.cc

package info (click to toggle)
chromium 139.0.7258.138-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 6,120,676 kB
  • sloc: cpp: 35,100,869; 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 (145 lines) | stat: -rw-r--r-- 5,599 bytes parent folder | download | duplicates (6)
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
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/web_package/signed_web_bundles/signed_web_bundle_id.h"

#include <algorithm>
#include <ostream>
#include <string_view>

#include "base/containers/span.h"
#include "base/functional/bind.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/types/expected.h"
#include "components/base32/base32.h"
#include "crypto/random.h"

namespace web_package {

// static
base::expected<SignedWebBundleId, std::string> SignedWebBundleId::Create(
    std::string_view encoded_id) {
  if (encoded_id.size() != kEd25519EncodedIdLength &&
      encoded_id.size() != kEcdsaP256EncodedIdLength) {
    return base::unexpected(base::StringPrintf(
        "The signed web bundle ID must be exactly %zu "
        "characters long (for Ed25519) or %zu characters long (for ECDSA "
        "P-256), but was %zu characters long.",
        kEd25519EncodedIdLength, kEcdsaP256EncodedIdLength, encoded_id.size()));
  }

  for (const char c : encoded_id) {
    if (!(base::IsAsciiLower(c) || (c >= '2' && c <= '7'))) {
      return base::unexpected(
          "The signed web bundle ID must only contain lowercase ASCII "
          "characters and digits between 2 and 7 (without any padding).");
    }
  }

  // Base32 decode the ID as an array.
  const std::vector<uint8_t> decoded_id =
      base32::Base32Decode(base::ToUpperASCII(encoded_id));
  if (decoded_id.size() < kTypeSuffixLength) {
    return base::unexpected(
        "The signed web bundle ID could not be decoded from its base32 "
        "representation.");
  }

  auto type_suffix = base::span(decoded_id).last<kTypeSuffixLength>();
  if (std::ranges::equal(type_suffix, kTypeProxyMode)) {
    if (decoded_id.size() == kProxyModeDecodedIdLength) {
      return SignedWebBundleId(Type::kProxyMode, encoded_id);
    } else {
      return base::unexpected(base::StringPrintf(
          "A ProxyMode signed web bundle ID must be exactly %zu "
          "characters long, but was %zu characters long.",
          kProxyModeEncodedIdLength, encoded_id.size()));
    }
  }
  if (std::ranges::equal(type_suffix, kTypeEd25519PublicKey)) {
    if (decoded_id.size() == kEd25519DecodedIdLength) {
      return SignedWebBundleId(Type::kEd25519PublicKey, encoded_id);
    } else {
      return base::unexpected(base::StringPrintf(
          "An Ed25519 signed web bundle ID must be exactly %zu "
          "characters long, but was %zu characters long.",
          kEd25519EncodedIdLength, encoded_id.size()));
    }
  }
  if (std::ranges::equal(type_suffix, kTypeEcdsaP256PublicKey)) {
    if (decoded_id.size() == kEcdsaP256DecodedIdLength) {
      return SignedWebBundleId(Type::kEcdsaP256PublicKey, encoded_id);
    } else {
      return base::unexpected(base::StringPrintf(
          "An ECDSA P-256 signed web bundle ID must be exactly %zu "
          "characters long, but was %zu characters long.",
          kEcdsaP256EncodedIdLength, encoded_id.size()));
    }
  }
  return base::unexpected("The signed web bundle ID has an unknown type.");
}

// static
SignedWebBundleId SignedWebBundleId::CreateForPublicKey(
    const Ed25519PublicKey& public_key) {
  std::array<uint8_t, kEd25519DecodedIdLength> decoded_id;
  std::ranges::copy(public_key.bytes(), decoded_id.begin());
  std::ranges::copy(kTypeEd25519PublicKey,
                    decoded_id.end() - kTypeSuffixLength);

  auto encoded_id_uppercase = base32::Base32Encode(
      decoded_id, base32::Base32EncodePolicy::OMIT_PADDING);
  auto encoded_id = base::ToLowerASCII(encoded_id_uppercase);
  return SignedWebBundleId(Type::kEd25519PublicKey, encoded_id);
}

// static
SignedWebBundleId SignedWebBundleId::CreateForPublicKey(
    const EcdsaP256PublicKey& public_key) {
  std::array<uint8_t, kEcdsaP256DecodedIdLength> decoded_id;
  std::ranges::copy(public_key.bytes(), decoded_id.begin());
  std::ranges::copy(kTypeEcdsaP256PublicKey,
                    decoded_id.end() - kTypeSuffixLength);

  auto encoded_id_uppercase = base32::Base32Encode(
      decoded_id, base32::Base32EncodePolicy::OMIT_PADDING);
  auto encoded_id = base::ToLowerASCII(encoded_id_uppercase);
  return SignedWebBundleId(Type::kEcdsaP256PublicKey, encoded_id);
}

// static
SignedWebBundleId SignedWebBundleId::CreateForProxyMode(
    base::span<const uint8_t, kProxyModeKeyLength> data) {
  std::array<uint8_t, kProxyModeKeyLength + kTypeSuffixLength> decoded_id;
  std::ranges::copy(data, decoded_id.begin());
  std::ranges::copy(kTypeProxyMode, decoded_id.end() - kTypeSuffixLength);

  auto encoded_id_uppercase = base32::Base32Encode(
      decoded_id, base32::Base32EncodePolicy::OMIT_PADDING);
  auto encoded_id = base::ToLowerASCII(encoded_id_uppercase);
  return SignedWebBundleId(Type::kProxyMode, encoded_id);
}

// static
SignedWebBundleId SignedWebBundleId::CreateRandomForProxyMode() {
  std::array<uint8_t, kProxyModeKeyLength> random_bytes;
  crypto::RandBytes(random_bytes);
  return CreateForProxyMode(random_bytes);
}

SignedWebBundleId::SignedWebBundleId(Type type, std::string_view encoded_id)
    : type_(type), encoded_id_(encoded_id) {}

SignedWebBundleId::SignedWebBundleId(const SignedWebBundleId& other) = default;
SignedWebBundleId& SignedWebBundleId::operator=(
    const SignedWebBundleId& other) = default;

SignedWebBundleId::~SignedWebBundleId() = default;

std::ostream& operator<<(std::ostream& os, const SignedWebBundleId& id) {
  return os << id.id();
}

}  // namespace web_package