Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / net / der / parse_values.cc
blob93e99b76ff3f772faf066a43e5a8c20e00f88584
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/logging.h"
6 #include "base/numerics/safe_math.h"
7 #include "net/der/parse_values.h"
9 namespace net {
11 namespace der {
13 namespace {
15 bool ParseBoolInternal(const Input& in, bool* out, bool relaxed) {
16 // According to ITU-T X.690 section 8.2, a bool is encoded as a single octet
17 // where the octet of all zeroes is FALSE and a non-zero value for the octet
18 // is TRUE.
19 if (in.Length() != 1)
20 return false;
21 ByteReader data(in);
22 uint8_t byte;
23 if (!data.ReadByte(&byte))
24 return false;
25 if (byte == 0) {
26 *out = false;
27 return true;
29 // ITU-T X.690 section 11.1 specifies that for DER, the TRUE value must be
30 // encoded as an octet of all ones.
31 if (byte == 0xff || relaxed) {
32 *out = true;
33 return true;
35 return false;
38 // Reads a positive decimal number with |digits| digits and stores it in
39 // |*out|. This function does not check that the type of |*out| is large
40 // enough to hold 10^digits - 1; the caller must choose an appropriate type
41 // based on the number of digits they wish to parse.
42 template <typename UINT>
43 bool DecimalStringToUint(ByteReader& in, size_t digits, UINT* out) {
44 UINT value = 0;
45 for (size_t i = 0; i < digits; ++i) {
46 uint8_t digit;
47 if (!in.ReadByte(&digit)) {
48 return false;
50 if (digit < '0' || digit > '9') {
51 return false;
53 value = (value * 10) + (digit - '0');
55 *out = value;
56 return true;
59 // Checks that the values in a GeneralizedTime struct are valid. This involves
60 // checking that the year is 4 digits, the month is between 1 and 12, the day
61 // is a day that exists in that month (following current leap year rules),
62 // hours are between 0 and 23, minutes between 0 and 59, and seconds between
63 // 0 and 60 (to allow for leap seconds; no validation is done that a leap
64 // second is on a day that could be a leap second).
65 bool ValidateGeneralizedTime(const GeneralizedTime& time) {
66 CHECK(time.year > 0 && time.year < 9999);
67 if (time.month < 1 || time.month > 12)
68 return false;
69 if (time.day < 1)
70 return false;
71 if (time.hours < 0 || time.hours > 23)
72 return false;
73 if (time.minutes < 0 || time.minutes > 59)
74 return false;
75 // Leap seconds are allowed.
76 if (time.seconds < 0 || time.seconds > 60)
77 return false;
79 // validate upper bound for day of month
80 switch (time.month) {
81 case 4:
82 case 6:
83 case 9:
84 case 11:
85 if (time.day > 30)
86 return false;
87 break;
88 case 1:
89 case 3:
90 case 5:
91 case 7:
92 case 8:
93 case 10:
94 case 12:
95 if (time.day > 31)
96 return false;
97 break;
98 case 2:
99 if (time.year % 4 == 0 &&
100 (time.year % 100 != 0 || time.year % 400 == 0)) {
101 if (time.day > 29)
102 return false;
103 } else {
104 if (time.day > 28)
105 return false;
107 break;
108 default:
109 NOTREACHED();
110 return false;
112 return true;
115 } // namespace
117 bool ParseBool(const Input& in, bool* out) {
118 return ParseBoolInternal(in, out, false /* relaxed */);
121 // BER interprets any non-zero value as true, while DER requires a bool to
122 // have either all bits zero (false) or all bits one (true). To support
123 // malformed certs, we recognized the BER encoding instead of failing to
124 // parse.
125 bool ParseBoolRelaxed(const Input& in, bool* out) {
126 return ParseBoolInternal(in, out, true /* relaxed */);
129 bool ParseUint64(const Input& in, uint64_t* out) {
130 ByteReader reader(in);
131 size_t bytes_read = 0;
132 uint8_t data;
133 uint64_t value = 0;
134 // Note that for simplicity, this check only admits integers up to 2^63-1.
135 if (in.Length() > sizeof(uint64_t) || in.Length() == 0)
136 return false;
137 while (reader.ReadByte(&data)) {
138 if (bytes_read == 0 && (data & 0x80)) {
139 return false;
141 value <<= 8;
142 value |= data;
143 bytes_read++;
145 // ITU-T X.690 section 8.3.2 specifies that an integer value must be encoded
146 // in the smallest number of octets. If the encoding consists of more than
147 // one octet, then the bits of the first octet and the most significant bit
148 // of the second octet must not be all zeroes or all ones.
149 // Because this function only parses unsigned integers, there's no need to
150 // check for the all ones case.
151 if (bytes_read > 1) {
152 ByteReader first_bytes_reader(in);
153 uint8_t first_byte;
154 uint8_t second_byte;
155 if (!first_bytes_reader.ReadByte(&first_byte) ||
156 !first_bytes_reader.ReadByte(&second_byte)) {
157 return false;
159 if (first_byte == 0 && !(second_byte & 0x80)) {
160 return false;
163 *out = value;
164 return true;
167 BitString::BitString(const Input& bytes, uint8_t unused_bits)
168 : bytes_(bytes), unused_bits_(unused_bits) {
169 DCHECK_LT(unused_bits, 8);
170 DCHECK(unused_bits == 0 || bytes.Length() != 0);
173 bool ParseBitString(const Input& in, BitString* out) {
174 ByteReader reader(in);
176 // From ITU-T X.690, section 8.6.2.2 (applies to BER, CER, DER):
178 // The initial octet shall encode, as an unsigned binary integer with
179 // bit 1 as the least significant bit, the number of unused bits in the final
180 // subsequent octet. The number shall be in the range zero to seven.
181 uint8_t unused_bits;
182 if (!reader.ReadByte(&unused_bits))
183 return false;
184 if (unused_bits > 7)
185 return false;
187 Input bytes;
188 if (!reader.ReadBytes(reader.BytesLeft(), &bytes))
189 return false; // Not reachable.
191 // Ensure that unused bits in the last byte are set to 0.
192 if (unused_bits > 0) {
193 // From ITU-T X.690, section 8.6.2.3 (applies to BER, CER, DER):
195 // If the bitstring is empty, there shall be no subsequent octets,
196 // and the initial octet shall be zero.
197 if (bytes.Length() == 0)
198 return false;
199 uint8_t last_byte = bytes.UnsafeData()[bytes.Length() - 1];
201 // From ITU-T X.690, section 11.2.1 (applies to CER and DER, but not BER):
203 // Each unused bit in the final octet of the encoding of a bit string value
204 // shall be set to zero.
205 uint8_t mask = 0xFF >> (8 - unused_bits);
206 if ((mask & last_byte) != 0)
207 return false;
210 *out = BitString(bytes, unused_bits);
211 return true;
214 bool operator<(const GeneralizedTime& lhs, const GeneralizedTime& rhs) {
215 if (lhs.year != rhs.year)
216 return lhs.year < rhs.year;
217 if (lhs.month != rhs.month)
218 return lhs.month < rhs.month;
219 if (lhs.day != rhs.day)
220 return lhs.day < rhs.day;
221 if (lhs.hours != rhs.hours)
222 return lhs.hours < rhs.hours;
223 if (lhs.minutes != rhs.minutes)
224 return lhs.minutes < rhs.minutes;
225 return lhs.seconds < rhs.seconds;
228 // A UTC Time in DER encoding should be YYMMDDHHMMSSZ, but some CAs encode
229 // the time following BER rules, which allows for YYMMDDHHMMZ. If the length
230 // is 11, assume it's YYMMDDHHMMZ, and in converting it to a GeneralizedTime,
231 // add in the seconds (set to 0).
232 bool ParseUTCTimeRelaxed(const Input& in, GeneralizedTime* value) {
233 ByteReader reader(in);
234 GeneralizedTime time;
235 if (!DecimalStringToUint(reader, 2, &time.year) ||
236 !DecimalStringToUint(reader, 2, &time.month) ||
237 !DecimalStringToUint(reader, 2, &time.day) ||
238 !DecimalStringToUint(reader, 2, &time.hours) ||
239 !DecimalStringToUint(reader, 2, &time.minutes)) {
240 return false;
243 // Try to read the 'Z' at the end. If we read something else, then for it to
244 // be valid the next bytes should be seconds (and then followed by 'Z').
245 uint8_t zulu;
246 ByteReader zulu_reader = reader;
247 if (!zulu_reader.ReadByte(&zulu))
248 return false;
249 if (zulu == 'Z' && !zulu_reader.HasMore()) {
250 time.seconds = 0;
251 *value = time;
252 return true;
254 if (!DecimalStringToUint(reader, 2, &time.seconds))
255 return false;
256 if (!reader.ReadByte(&zulu) || zulu != 'Z' || reader.HasMore())
257 return false;
258 if (!ValidateGeneralizedTime(time))
259 return false;
260 if (time.year < 50) {
261 time.year += 2000;
262 } else {
263 time.year += 1900;
265 *value = time;
266 return true;
269 bool ParseUTCTime(const Input& in, GeneralizedTime* value) {
270 ByteReader reader(in);
271 GeneralizedTime time;
272 if (!DecimalStringToUint(reader, 2, &time.year) ||
273 !DecimalStringToUint(reader, 2, &time.month) ||
274 !DecimalStringToUint(reader, 2, &time.day) ||
275 !DecimalStringToUint(reader, 2, &time.hours) ||
276 !DecimalStringToUint(reader, 2, &time.minutes) ||
277 !DecimalStringToUint(reader, 2, &time.seconds)) {
278 return false;
280 uint8_t zulu;
281 if (!reader.ReadByte(&zulu) || zulu != 'Z' || reader.HasMore())
282 return false;
283 if (!ValidateGeneralizedTime(time))
284 return false;
285 if (time.year < 50) {
286 time.year += 2000;
287 } else {
288 time.year += 1900;
290 *value = time;
291 return true;
294 bool ParseGeneralizedTime(const Input& in, GeneralizedTime* value) {
295 ByteReader reader(in);
296 GeneralizedTime time;
297 if (!DecimalStringToUint(reader, 4, &time.year) ||
298 !DecimalStringToUint(reader, 2, &time.month) ||
299 !DecimalStringToUint(reader, 2, &time.day) ||
300 !DecimalStringToUint(reader, 2, &time.hours) ||
301 !DecimalStringToUint(reader, 2, &time.minutes) ||
302 !DecimalStringToUint(reader, 2, &time.seconds)) {
303 return false;
305 uint8_t zulu;
306 if (!reader.ReadByte(&zulu) || zulu != 'Z' || reader.HasMore())
307 return false;
308 if (!ValidateGeneralizedTime(time))
309 return false;
310 *value = time;
311 return true;
314 } // namespace der
316 } // namespace net