Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(276)

Side by Side Diff: net/der/parse_values.cc

Issue 1295943002: Add a function for validating a DER-encoded INTEGER. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@cert_parsing
Patch Set: remove numeric_length as an out-parameter of IsValidInteger Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/der/parse_values.h ('k') | net/der/parse_values_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/logging.h" 5 #include "base/logging.h"
6 #include "base/numerics/safe_math.h" 6 #include "base/numerics/safe_math.h"
7 #include "net/der/parse_values.h" 7 #include "net/der/parse_values.h"
8 8
9 namespace net { 9 namespace net {
10 10
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 return false; 104 return false;
105 } 105 }
106 break; 106 break;
107 default: 107 default:
108 NOTREACHED(); 108 NOTREACHED();
109 return false; 109 return false;
110 } 110 }
111 return true; 111 return true;
112 } 112 }
113 113
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.
116 //
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).
120 //
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 GetNumberOfBytesInInteger(const Input& in) {
davidben 2015/08/18 19:44:15 I would maybe call this GetUnsignedIntegerLength o
eroman 2015/08/18 19:54:13 Done.
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.
128
129 if (first_byte == 0 && in.Length() > 1)
130 return in.Length() - 1;
131 return in.Length();
132 }
133
114 } // namespace 134 } // namespace
115 135
116 bool ParseBool(const Input& in, bool* out) { 136 bool ParseBool(const Input& in, bool* out) {
117 return ParseBoolInternal(in, out, false /* relaxed */); 137 return ParseBoolInternal(in, out, false /* relaxed */);
118 } 138 }
119 139
120 // BER interprets any non-zero value as true, while DER requires a bool to 140 // BER interprets any non-zero value as true, while DER requires a bool to
121 // have either all bits zero (false) or all bits one (true). To support 141 // have either all bits zero (false) or all bits one (true). To support
122 // malformed certs, we recognized the BER encoding instead of failing to 142 // malformed certs, we recognized the BER encoding instead of failing to
123 // parse. 143 // parse.
124 bool ParseBoolRelaxed(const Input& in, bool* out) { 144 bool ParseBoolRelaxed(const Input& in, bool* out) {
125 return ParseBoolInternal(in, out, true /* relaxed */); 145 return ParseBoolInternal(in, out, true /* relaxed */);
126 } 146 }
127 147
128 bool ParseUint64(const Input& in, uint64_t* out) { 148 // ITU-T X.690 section 8.3.2 specifies that an integer value must be encoded
129 ByteReader reader(in); 149 // in the smallest number of octets. If the encoding consists of more than
130 size_t bytes_read = 0; 150 // one octet, then the bits of the first octet and the most significant bit
131 uint8_t data; 151 // of the second octet must not be all zeroes or all ones.
132 uint64_t value = 0; 152 bool IsValidInteger(const Input& in, bool* out_negative) {
davidben 2015/08/18 19:44:16 Nit: negative to match the header, now that you do
eroman 2015/08/18 19:54:13 Done.
133 // Note that for simplicity, this check only admits integers up to 2^63-1. 153 der::ByteReader reader(in);
134 if (in.Length() > sizeof(uint64_t) || in.Length() == 0) 154 uint8_t first_byte;
135 return false; 155
136 while (reader.ReadByte(&data)) { 156 if (!reader.ReadByte(&first_byte))
137 if (bytes_read == 0 && (data & 0x80)) { 157 return false; // Empty inputs are not allowed.
138 return false; 158
139 } 159 uint8_t second_byte;
140 value <<= 8; 160 if (reader.ReadByte(&second_byte)) {
141 value |= data; 161 if ((first_byte == 0x00 || first_byte == 0xFF) &&
142 bytes_read++; 162 (first_byte & 0x80) == (second_byte & 0x80)) {
143 } 163 // Not a minimal encoding.
144 // ITU-T X.690 section 8.3.2 specifies that an integer value must be encoded
145 // in the smallest number of octets. If the encoding consists of more than
146 // one octet, then the bits of the first octet and the most significant bit
147 // of the second octet must not be all zeroes or all ones.
148 // Because this function only parses unsigned integers, there's no need to
149 // check for the all ones case.
150 if (bytes_read > 1) {
151 ByteReader first_bytes_reader(in);
152 uint8_t first_byte;
153 uint8_t second_byte;
154 if (!first_bytes_reader.ReadByte(&first_byte) ||
155 !first_bytes_reader.ReadByte(&second_byte)) {
156 return false;
157 }
158 if (first_byte == 0 && !(second_byte & 0x80)) {
159 return false; 164 return false;
160 } 165 }
161 } 166 }
167
168 *out_negative = (first_byte & 0x80) == 0x80;
169 return true;
170 }
171
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;
177
178 // Reject (non-negative) integers whose value would overflow the output type.
179 if (GetNumberOfBytesInInteger(in) > sizeof(*out))
180 return false;
181
182 ByteReader reader(in);
183 uint8_t data;
184 uint64_t value = 0;
185
186 while (reader.ReadByte(&data)) {
187 value <<= 8;
188 value |= data;
189 }
162 *out = value; 190 *out = value;
163 return true; 191 return true;
164 } 192 }
165 193
166 BitString::BitString(const Input& bytes, uint8_t unused_bits) 194 BitString::BitString(const Input& bytes, uint8_t unused_bits)
167 : bytes_(bytes), unused_bits_(unused_bits) { 195 : bytes_(bytes), unused_bits_(unused_bits) {
168 DCHECK_LT(unused_bits, 8); 196 DCHECK_LT(unused_bits, 8);
169 DCHECK(unused_bits == 0 || bytes.Length() != 0); 197 DCHECK(unused_bits == 0 || bytes.Length() != 0);
170 } 198 }
171 199
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 return false; 335 return false;
308 if (!ValidateGeneralizedTime(time)) 336 if (!ValidateGeneralizedTime(time))
309 return false; 337 return false;
310 *value = time; 338 *value = time;
311 return true; 339 return true;
312 } 340 }
313 341
314 } // namespace der 342 } // namespace der
315 343
316 } // namespace net 344 } // namespace net
OLDNEW
« no previous file with comments | « net/der/parse_values.h ('k') | net/der/parse_values_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698