Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / net / der / parse_values.cc
blob7920d9fc89d88e24f266a8bf022995ebeb41af10
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 if (time.month < 1 || time.month > 12)
67 return false;
68 if (time.day < 1)
69 return false;
70 if (time.hours < 0 || time.hours > 23)
71 return false;
72 if (time.minutes < 0 || time.minutes > 59)
73 return false;
74 // Leap seconds are allowed.
75 if (time.seconds < 0 || time.seconds > 60)
76 return false;
78 // validate upper bound for day of month
79 switch (time.month) {
80 case 4:
81 case 6:
82 case 9:
83 case 11:
84 if (time.day > 30)
85 return false;
86 break;
87 case 1:
88 case 3:
89 case 5:
90 case 7:
91 case 8:
92 case 10:
93 case 12:
94 if (time.day > 31)
95 return false;
96 break;
97 case 2:
98 if (time.year % 4 == 0 &&
99 (time.year % 100 != 0 || time.year % 400 == 0)) {
100 if (time.day > 29)
101 return false;
102 } else {
103 if (time.day > 28)
104 return false;
106 break;
107 default:
108 NOTREACHED();
109 return false;
111 return true;
114 // Returns the number of bytes of numeric precision in a DER encoded INTEGER
115 // value. |in| must be a valid DER encoding of an INTEGER for this to work.
117 // Normally the precision of the number is exactly in.Length(). However when
118 // encoding positive numbers using DER it is possible to have a leading zero
119 // (to prevent number from being interpreted as negative).
121 // For instance a 160-bit positive number might take 21 bytes to encode. This
122 // function will return 20 in such a case.
123 size_t GetUnsignedIntegerLength(const Input& in) {
124 der::ByteReader reader(in);
125 uint8_t first_byte;
126 if (!reader.ReadByte(&first_byte))
127 return 0; // Not valid DER as |in| was empty.
129 if (first_byte == 0 && in.Length() > 1)
130 return in.Length() - 1;
131 return in.Length();
134 } // namespace
136 bool ParseBool(const Input& in, bool* out) {
137 return ParseBoolInternal(in, out, false /* relaxed */);
140 // BER interprets any non-zero value as true, while DER requires a bool to
141 // have either all bits zero (false) or all bits one (true). To support
142 // malformed certs, we recognized the BER encoding instead of failing to
143 // parse.
144 bool ParseBoolRelaxed(const Input& in, bool* out) {
145 return ParseBoolInternal(in, out, true /* relaxed */);
148 // ITU-T X.690 section 8.3.2 specifies that an integer value must be encoded
149 // in the smallest number of octets. If the encoding consists of more than
150 // one octet, then the bits of the first octet and the most significant bit
151 // of the second octet must not be all zeroes or all ones.
152 bool IsValidInteger(const Input& in, bool* negative) {
153 der::ByteReader reader(in);
154 uint8_t first_byte;
156 if (!reader.ReadByte(&first_byte))
157 return false; // Empty inputs are not allowed.
159 uint8_t second_byte;
160 if (reader.ReadByte(&second_byte)) {
161 if ((first_byte == 0x00 || first_byte == 0xFF) &&
162 (first_byte & 0x80) == (second_byte & 0x80)) {
163 // Not a minimal encoding.
164 return false;
168 *negative = (first_byte & 0x80) == 0x80;
169 return true;
172 bool ParseUint64(const Input& in, uint64_t* out) {
173 // Reject non-minimally encoded numbers and negative numbers.
174 bool negative;
175 if (!IsValidInteger(in, &negative) || negative)
176 return false;
178 // Reject (non-negative) integers whose value would overflow the output type.
179 if (GetUnsignedIntegerLength(in) > sizeof(*out))
180 return false;
182 ByteReader reader(in);
183 uint8_t data;
184 uint64_t value = 0;
186 while (reader.ReadByte(&data)) {
187 value <<= 8;
188 value |= data;
190 *out = value;
191 return true;
194 BitString::BitString(const Input& bytes, uint8_t unused_bits)
195 : bytes_(bytes), unused_bits_(unused_bits) {
196 DCHECK_LT(unused_bits, 8);
197 DCHECK(unused_bits == 0 || bytes.Length() != 0);
200 bool ParseBitString(const Input& in, BitString* out) {
201 ByteReader reader(in);
203 // From ITU-T X.690, section 8.6.2.2 (applies to BER, CER, DER):
205 // The initial octet shall encode, as an unsigned binary integer with
206 // bit 1 as the least significant bit, the number of unused bits in the final
207 // subsequent octet. The number shall be in the range zero to seven.
208 uint8_t unused_bits;
209 if (!reader.ReadByte(&unused_bits))
210 return false;
211 if (unused_bits > 7)
212 return false;
214 Input bytes;
215 if (!reader.ReadBytes(reader.BytesLeft(), &bytes))
216 return false; // Not reachable.
218 // Ensure that unused bits in the last byte are set to 0.
219 if (unused_bits > 0) {
220 // From ITU-T X.690, section 8.6.2.3 (applies to BER, CER, DER):
222 // If the bitstring is empty, there shall be no subsequent octets,
223 // and the initial octet shall be zero.
224 if (bytes.Length() == 0)
225 return false;
226 uint8_t last_byte = bytes.UnsafeData()[bytes.Length() - 1];
228 // From ITU-T X.690, section 11.2.1 (applies to CER and DER, but not BER):
230 // Each unused bit in the final octet of the encoding of a bit string value
231 // shall be set to zero.
232 uint8_t mask = 0xFF >> (8 - unused_bits);
233 if ((mask & last_byte) != 0)
234 return false;
237 *out = BitString(bytes, unused_bits);
238 return true;
241 bool operator<(const GeneralizedTime& lhs, const GeneralizedTime& rhs) {
242 if (lhs.year != rhs.year)
243 return lhs.year < rhs.year;
244 if (lhs.month != rhs.month)
245 return lhs.month < rhs.month;
246 if (lhs.day != rhs.day)
247 return lhs.day < rhs.day;
248 if (lhs.hours != rhs.hours)
249 return lhs.hours < rhs.hours;
250 if (lhs.minutes != rhs.minutes)
251 return lhs.minutes < rhs.minutes;
252 return lhs.seconds < rhs.seconds;
255 // A UTC Time in DER encoding should be YYMMDDHHMMSSZ, but some CAs encode
256 // the time following BER rules, which allows for YYMMDDHHMMZ. If the length
257 // is 11, assume it's YYMMDDHHMMZ, and in converting it to a GeneralizedTime,
258 // add in the seconds (set to 0).
259 bool ParseUTCTimeRelaxed(const Input& in, GeneralizedTime* value) {
260 ByteReader reader(in);
261 GeneralizedTime time;
262 if (!DecimalStringToUint(reader, 2, &time.year) ||
263 !DecimalStringToUint(reader, 2, &time.month) ||
264 !DecimalStringToUint(reader, 2, &time.day) ||
265 !DecimalStringToUint(reader, 2, &time.hours) ||
266 !DecimalStringToUint(reader, 2, &time.minutes)) {
267 return false;
270 // Try to read the 'Z' at the end. If we read something else, then for it to
271 // be valid the next bytes should be seconds (and then followed by 'Z').
272 uint8_t zulu;
273 ByteReader zulu_reader = reader;
274 if (!zulu_reader.ReadByte(&zulu))
275 return false;
276 if (zulu == 'Z' && !zulu_reader.HasMore()) {
277 time.seconds = 0;
278 *value = time;
279 } else {
280 if (!DecimalStringToUint(reader, 2, &time.seconds))
281 return false;
282 if (!reader.ReadByte(&zulu) || zulu != 'Z' || reader.HasMore())
283 return false;
286 if (time.year < 50) {
287 time.year += 2000;
288 } else {
289 time.year += 1900;
291 if (!ValidateGeneralizedTime(time))
292 return false;
293 *value = time;
294 return true;
297 bool ParseUTCTime(const Input& in, GeneralizedTime* value) {
298 ByteReader reader(in);
299 GeneralizedTime time;
300 if (!DecimalStringToUint(reader, 2, &time.year) ||
301 !DecimalStringToUint(reader, 2, &time.month) ||
302 !DecimalStringToUint(reader, 2, &time.day) ||
303 !DecimalStringToUint(reader, 2, &time.hours) ||
304 !DecimalStringToUint(reader, 2, &time.minutes) ||
305 !DecimalStringToUint(reader, 2, &time.seconds)) {
306 return false;
308 uint8_t zulu;
309 if (!reader.ReadByte(&zulu) || zulu != 'Z' || reader.HasMore())
310 return false;
311 if (time.year < 50) {
312 time.year += 2000;
313 } else {
314 time.year += 1900;
316 if (!ValidateGeneralizedTime(time))
317 return false;
318 *value = time;
319 return true;
322 bool ParseGeneralizedTime(const Input& in, GeneralizedTime* value) {
323 ByteReader reader(in);
324 GeneralizedTime time;
325 if (!DecimalStringToUint(reader, 4, &time.year) ||
326 !DecimalStringToUint(reader, 2, &time.month) ||
327 !DecimalStringToUint(reader, 2, &time.day) ||
328 !DecimalStringToUint(reader, 2, &time.hours) ||
329 !DecimalStringToUint(reader, 2, &time.minutes) ||
330 !DecimalStringToUint(reader, 2, &time.seconds)) {
331 return false;
333 uint8_t zulu;
334 if (!reader.ReadByte(&zulu) || zulu != 'Z' || reader.HasMore())
335 return false;
336 if (!ValidateGeneralizedTime(time))
337 return false;
338 *value = time;
339 return true;
342 } // namespace der
344 } // namespace net