File: encryption_header_parsers.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 (158 lines) | stat: -rw-r--r-- 4,798 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
146
147
148
149
150
151
152
153
154
155
156
157
158
// Copyright 2015 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/gcm_driver/crypto/encryption_header_parsers.h"

#include <string_view>

#include "base/base64url.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"


namespace gcm {

namespace {

// The default record size in bytes, as defined in section two of
// https://tools.ietf.org/html/draft-thomson-http-encryption.
const uint64_t kDefaultRecordSizeBytes = 4096;

// Decodes the string in |value| using base64url and writes the decoded value to
// |*salt|. Returns whether the string is not empty and could be decoded.
bool ValueToDecodedString(std::string_view value, std::string* salt) {
  if (value.empty())
    return false;

  return base::Base64UrlDecode(
      value, base::Base64UrlDecodePolicy::IGNORE_PADDING, salt);
}

// Parses the record size in |value| and writes the value to |*rs|. The value
// must be a positive decimal integer greater than one that does not start
// with a plus. Returns whether the record size was valid.
bool RecordSizeToInt(std::string_view value, uint64_t* rs) {
  if (value.empty())
    return false;

  // Reject a leading plus, as the fact that the value must be positive is
  // dictated by the specification.
  if (value[0] == '+')
    return false;

  uint64_t candidate_rs;
  if (!base::StringToUint64(value, &candidate_rs))
    return false;

  // The record size MUST be greater than one byte.
  if (candidate_rs <= 1)
    return false;

  *rs = candidate_rs;
  return true;
}

}  // namespace

EncryptionHeaderIterator::EncryptionHeaderIterator(
    std::string::const_iterator header_begin,
    std::string::const_iterator header_end)
    : iterator_(std::string_view(header_begin, header_end), /*delimiter=*/','),
      rs_(kDefaultRecordSizeBytes) {}

EncryptionHeaderIterator::~EncryptionHeaderIterator() = default;

bool EncryptionHeaderIterator::GetNext() {
  keyid_.clear();
  salt_.clear();
  rs_ = kDefaultRecordSizeBytes;

  if (!iterator_.GetNext())
    return false;

  net::HttpUtil::NameValuePairsIterator name_value_pairs(
      iterator_.value(), /*delimiter=*/';',
      net::HttpUtil::NameValuePairsIterator::Values::REQUIRED,
      net::HttpUtil::NameValuePairsIterator::Quotes::NOT_STRICT);

  bool found_keyid = false;
  bool found_salt = false;
  bool found_rs = false;

  while (name_value_pairs.GetNext()) {
    const std::string_view name = name_value_pairs.name();
    const std::string_view value = name_value_pairs.value();

    if (base::EqualsCaseInsensitiveASCII(name, "keyid")) {
      if (found_keyid)
        return false;
      keyid_ = value;
      found_keyid = true;
    } else if (base::EqualsCaseInsensitiveASCII(name, "salt")) {
      if (found_salt || !ValueToDecodedString(value, &salt_))
        return false;
      found_salt = true;
    } else if (base::EqualsCaseInsensitiveASCII(name, "rs")) {
      if (found_rs || !RecordSizeToInt(value, &rs_))
        return false;
      found_rs = true;
    } else {
      // Silently ignore unknown directives for forward compatibility.
    }
  }

  return name_value_pairs.valid();
}

CryptoKeyHeaderIterator::CryptoKeyHeaderIterator(
    std::string::const_iterator header_begin,
    std::string::const_iterator header_end)
    : iterator_(std::string_view(header_begin, header_end), /*delimiter=*/',') {
}

CryptoKeyHeaderIterator::~CryptoKeyHeaderIterator() = default;

bool CryptoKeyHeaderIterator::GetNext() {
  keyid_.clear();
  aesgcm128_.clear();
  dh_.clear();

  if (!iterator_.GetNext())
    return false;

  net::HttpUtil::NameValuePairsIterator name_value_pairs(
      iterator_.value(), /*delimiter=*/';',
      net::HttpUtil::NameValuePairsIterator::Values::REQUIRED,
      net::HttpUtil::NameValuePairsIterator::Quotes::NOT_STRICT);

  bool found_keyid = false;
  bool found_aesgcm128 = false;
  bool found_dh = false;

  while (name_value_pairs.GetNext()) {
    const std::string_view name = name_value_pairs.name();
    const std::string_view value = name_value_pairs.value();

    if (base::EqualsCaseInsensitiveASCII(name, "keyid")) {
      if (found_keyid)
        return false;
      keyid_ = value;
      found_keyid = true;
    } else if (base::EqualsCaseInsensitiveASCII(name, "aesgcm128")) {
      if (found_aesgcm128 || !ValueToDecodedString(value, &aesgcm128_))
        return false;
      found_aesgcm128 = true;
    } else if (base::EqualsCaseInsensitiveASCII(name, "dh")) {
      if (found_dh || !ValueToDecodedString(value, &dh_))
        return false;
      found_dh = true;
    } else {
      // Silently ignore unknown directives for forward compatibility.
    }
  }

  return name_value_pairs.valid();
}

}  // namespace gcm