Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This code is made available to you under your choice of the following sets
4 : * of licensing terms:
5 : */
6 : /* This Source Code Form is subject to the terms of the Mozilla Public
7 : * License, v. 2.0. If a copy of the MPL was not distributed with this
8 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 : */
10 : /* Copyright 2013 Mozilla Contributors
11 : *
12 : * Licensed under the Apache License, Version 2.0 (the "License");
13 : * you may not use this file except in compliance with the License.
14 : * You may obtain a copy of the License at
15 : *
16 : * http://www.apache.org/licenses/LICENSE-2.0
17 : *
18 : * Unless required by applicable law or agreed to in writing, software
19 : * distributed under the License is distributed on an "AS IS" BASIS,
20 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 : * See the License for the specific language governing permissions and
22 : * limitations under the License.
23 : */
24 :
25 : #include "pkixder.h"
26 :
27 : #include "pkixutil.h"
28 :
29 : namespace mozilla { namespace pkix { namespace der {
30 :
31 : // Too complicated to be inline
32 : Result
33 87 : ReadTagAndGetValue(Reader& input, /*out*/ uint8_t& tag, /*out*/ Input& value)
34 : {
35 : Result rv;
36 :
37 87 : rv = input.Read(tag);
38 87 : if (rv != Success) {
39 0 : return rv;
40 : }
41 87 : if ((tag & 0x1F) == 0x1F) {
42 0 : return Result::ERROR_BAD_DER; // high tag number form not allowed
43 : }
44 :
45 : uint16_t length;
46 :
47 : // The short form of length is a single byte with the high order bit set
48 : // to zero. The long form of length is one byte with the high order bit
49 : // set, followed by N bytes, where N is encoded in the lowest 7 bits of
50 : // the first byte.
51 : uint8_t length1;
52 87 : rv = input.Read(length1);
53 87 : if (rv != Success) {
54 0 : return rv;
55 : }
56 87 : if (!(length1 & 0x80)) {
57 71 : length = length1;
58 16 : } else if (length1 == 0x81) {
59 : uint8_t length2;
60 0 : rv = input.Read(length2);
61 0 : if (rv != Success) {
62 0 : return rv;
63 : }
64 0 : if (length2 < 128) {
65 : // Not shortest possible encoding
66 0 : return Result::ERROR_BAD_DER;
67 : }
68 0 : length = length2;
69 16 : } else if (length1 == 0x82) {
70 16 : rv = input.Read(length);
71 16 : if (rv != Success) {
72 0 : return rv;
73 : }
74 16 : if (length < 256) {
75 : // Not shortest possible encoding
76 0 : return Result::ERROR_BAD_DER;
77 : }
78 : } else {
79 : // We don't support lengths larger than 2^16 - 1.
80 0 : return Result::ERROR_BAD_DER;
81 : }
82 :
83 87 : return input.Skip(length, value);
84 : }
85 :
86 : static Result
87 0 : OptionalNull(Reader& input)
88 : {
89 0 : if (input.Peek(NULLTag)) {
90 0 : return Null(input);
91 : }
92 0 : return Success;
93 : }
94 :
95 : namespace {
96 :
97 : Result
98 0 : AlgorithmIdentifierValue(Reader& input, /*out*/ Reader& algorithmOIDValue)
99 : {
100 0 : Result rv = ExpectTagAndGetValue(input, der::OIDTag, algorithmOIDValue);
101 0 : if (rv != Success) {
102 0 : return rv;
103 : }
104 0 : return OptionalNull(input);
105 : }
106 :
107 : } // namespace
108 :
109 : Result
110 0 : SignatureAlgorithmIdentifierValue(Reader& input,
111 : /*out*/ PublicKeyAlgorithm& publicKeyAlgorithm,
112 : /*out*/ DigestAlgorithm& digestAlgorithm)
113 : {
114 : // RFC 5758 Section 3.2 (ECDSA with SHA-2), and RFC 3279 Section 2.2.3
115 : // (ECDSA with SHA-1) say that parameters must be omitted.
116 : //
117 : // RFC 4055 Section 5 and RFC 3279 Section 2.2.1 both say that parameters for
118 : // RSA must be encoded as NULL; we relax that requirement by allowing the
119 : // NULL to be omitted, to match all the other signature algorithms we support
120 : // and for compatibility.
121 0 : Reader algorithmID;
122 0 : Result rv = AlgorithmIdentifierValue(input, algorithmID);
123 0 : if (rv != Success) {
124 0 : return rv;
125 : }
126 :
127 : // RFC 5758 Section 3.2 (ecdsa-with-SHA224 is intentionally excluded)
128 : // python DottedOIDToCode.py ecdsa-with-SHA256 1.2.840.10045.4.3.2
129 : static const uint8_t ecdsa_with_SHA256[] = {
130 : 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02
131 : };
132 : // python DottedOIDToCode.py ecdsa-with-SHA384 1.2.840.10045.4.3.3
133 : static const uint8_t ecdsa_with_SHA384[] = {
134 : 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x03
135 : };
136 : // python DottedOIDToCode.py ecdsa-with-SHA512 1.2.840.10045.4.3.4
137 : static const uint8_t ecdsa_with_SHA512[] = {
138 : 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04
139 : };
140 :
141 : // RFC 4055 Section 5 (sha224WithRSAEncryption is intentionally excluded)
142 : // python DottedOIDToCode.py sha256WithRSAEncryption 1.2.840.113549.1.1.11
143 : static const uint8_t sha256WithRSAEncryption[] = {
144 : 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
145 : };
146 : // python DottedOIDToCode.py sha384WithRSAEncryption 1.2.840.113549.1.1.12
147 : static const uint8_t sha384WithRSAEncryption[] = {
148 : 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0c
149 : };
150 : // python DottedOIDToCode.py sha512WithRSAEncryption 1.2.840.113549.1.1.13
151 : static const uint8_t sha512WithRSAEncryption[] = {
152 : 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d
153 : };
154 :
155 : // RFC 3279 Section 2.2.1
156 : // python DottedOIDToCode.py sha-1WithRSAEncryption 1.2.840.113549.1.1.5
157 : static const uint8_t sha_1WithRSAEncryption[] = {
158 : 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05
159 : };
160 :
161 : // NIST Open Systems Environment (OSE) Implementor's Workshop (OIW)
162 : // http://www.oiw.org/agreements/stable/12s-9412.txt (no longer works).
163 : // http://www.imc.org/ietf-pkix/old-archive-97/msg01166.html
164 : // We need to support this this non-PKIX OID for compatibility.
165 : // python DottedOIDToCode.py sha1WithRSASignature 1.3.14.3.2.29
166 : static const uint8_t sha1WithRSASignature[] = {
167 : 0x2b, 0x0e, 0x03, 0x02, 0x1d
168 : };
169 :
170 : // RFC 3279 Section 2.2.3
171 : // python DottedOIDToCode.py ecdsa-with-SHA1 1.2.840.10045.4.1
172 : static const uint8_t ecdsa_with_SHA1[] = {
173 : 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x01
174 : };
175 :
176 : // Matching is attempted based on a rough estimate of the commonality of the
177 : // algorithm, to minimize the number of MatchRest calls.
178 0 : if (algorithmID.MatchRest(sha256WithRSAEncryption)) {
179 0 : publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
180 0 : digestAlgorithm = DigestAlgorithm::sha256;
181 0 : } else if (algorithmID.MatchRest(ecdsa_with_SHA256)) {
182 0 : publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
183 0 : digestAlgorithm = DigestAlgorithm::sha256;
184 0 : } else if (algorithmID.MatchRest(sha_1WithRSAEncryption)) {
185 0 : publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
186 0 : digestAlgorithm = DigestAlgorithm::sha1;
187 0 : } else if (algorithmID.MatchRest(ecdsa_with_SHA1)) {
188 0 : publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
189 0 : digestAlgorithm = DigestAlgorithm::sha1;
190 0 : } else if (algorithmID.MatchRest(ecdsa_with_SHA384)) {
191 0 : publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
192 0 : digestAlgorithm = DigestAlgorithm::sha384;
193 0 : } else if (algorithmID.MatchRest(ecdsa_with_SHA512)) {
194 0 : publicKeyAlgorithm = PublicKeyAlgorithm::ECDSA;
195 0 : digestAlgorithm = DigestAlgorithm::sha512;
196 0 : } else if (algorithmID.MatchRest(sha384WithRSAEncryption)) {
197 0 : publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
198 0 : digestAlgorithm = DigestAlgorithm::sha384;
199 0 : } else if (algorithmID.MatchRest(sha512WithRSAEncryption)) {
200 0 : publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
201 0 : digestAlgorithm = DigestAlgorithm::sha512;
202 0 : } else if (algorithmID.MatchRest(sha1WithRSASignature)) {
203 : // XXX(bug 1042479): recognize this old OID for compatibility.
204 0 : publicKeyAlgorithm = PublicKeyAlgorithm::RSA_PKCS1;
205 0 : digestAlgorithm = DigestAlgorithm::sha1;
206 : } else {
207 0 : return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
208 : }
209 :
210 0 : return Success;
211 : }
212 :
213 : Result
214 0 : DigestAlgorithmIdentifier(Reader& input, /*out*/ DigestAlgorithm& algorithm)
215 : {
216 0 : Reader r;
217 0 : return der::Nested(input, SEQUENCE, [&algorithm](Reader& r) -> Result {
218 0 : Reader algorithmID;
219 0 : Result rv = AlgorithmIdentifierValue(r, algorithmID);
220 0 : if (rv != Success) {
221 0 : return rv;
222 : }
223 :
224 : // RFC 4055 Section 2.1
225 : // python DottedOIDToCode.py id-sha1 1.3.14.3.2.26
226 : static const uint8_t id_sha1[] = {
227 : 0x2b, 0x0e, 0x03, 0x02, 0x1a
228 : };
229 : // python DottedOIDToCode.py id-sha256 2.16.840.1.101.3.4.2.1
230 : static const uint8_t id_sha256[] = {
231 : 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
232 : };
233 : // python DottedOIDToCode.py id-sha384 2.16.840.1.101.3.4.2.2
234 : static const uint8_t id_sha384[] = {
235 : 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
236 : };
237 : // python DottedOIDToCode.py id-sha512 2.16.840.1.101.3.4.2.3
238 : static const uint8_t id_sha512[] = {
239 : 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
240 : };
241 :
242 : // Matching is attempted based on a rough estimate of the commonality of the
243 : // algorithm, to minimize the number of MatchRest calls.
244 0 : if (algorithmID.MatchRest(id_sha1)) {
245 0 : algorithm = DigestAlgorithm::sha1;
246 0 : } else if (algorithmID.MatchRest(id_sha256)) {
247 0 : algorithm = DigestAlgorithm::sha256;
248 0 : } else if (algorithmID.MatchRest(id_sha384)) {
249 0 : algorithm = DigestAlgorithm::sha384;
250 0 : } else if (algorithmID.MatchRest(id_sha512)) {
251 0 : algorithm = DigestAlgorithm::sha512;
252 : } else {
253 0 : return Result::ERROR_INVALID_ALGORITHM;
254 : }
255 :
256 0 : return Success;
257 0 : });
258 : }
259 :
260 : Result
261 0 : SignedData(Reader& input, /*out*/ Reader& tbs,
262 : /*out*/ SignedDataWithSignature& signedData)
263 : {
264 0 : Reader::Mark mark(input.GetMark());
265 :
266 : Result rv;
267 0 : rv = ExpectTagAndGetValue(input, SEQUENCE, tbs);
268 0 : if (rv != Success) {
269 0 : return rv;
270 : }
271 :
272 0 : rv = input.GetInput(mark, signedData.data);
273 0 : if (rv != Success) {
274 0 : return rv;
275 : }
276 :
277 0 : rv = ExpectTagAndGetValue(input, der::SEQUENCE, signedData.algorithm);
278 0 : if (rv != Success) {
279 0 : return rv;
280 : }
281 :
282 0 : rv = BitStringWithNoUnusedBits(input, signedData.signature);
283 0 : if (rv == Result::ERROR_BAD_DER) {
284 0 : rv = Result::ERROR_BAD_SIGNATURE;
285 : }
286 0 : return rv;
287 : }
288 :
289 : Result
290 15 : BitStringWithNoUnusedBits(Reader& input, /*out*/ Input& value)
291 : {
292 15 : Reader valueWithUnusedBits;
293 15 : Result rv = ExpectTagAndGetValue(input, BIT_STRING, valueWithUnusedBits);
294 15 : if (rv != Success) {
295 0 : return rv;
296 : }
297 :
298 : uint8_t unusedBitsAtEnd;
299 15 : if (valueWithUnusedBits.Read(unusedBitsAtEnd) != Success) {
300 0 : return Result::ERROR_BAD_DER;
301 : }
302 : // XXX: Really the constraint should be that unusedBitsAtEnd must be less
303 : // than 7. But, we suspect there are no real-world values in OCSP responses
304 : // or certificates with non-zero unused bits. It seems like NSS assumes this
305 : // in various places, so we enforce it too in order to simplify this code. If
306 : // we find compatibility issues, we'll know we're wrong and we'll have to
307 : // figure out how to shift the bits around.
308 15 : if (unusedBitsAtEnd != 0) {
309 0 : return Result::ERROR_BAD_DER;
310 : }
311 15 : return valueWithUnusedBits.SkipToEnd(value);
312 : }
313 :
314 : static inline Result
315 0 : ReadDigit(Reader& input, /*out*/ unsigned int& value)
316 : {
317 : uint8_t b;
318 0 : if (input.Read(b) != Success) {
319 0 : return Result::ERROR_INVALID_DER_TIME;
320 : }
321 0 : if (b < '0' || b > '9') {
322 0 : return Result::ERROR_INVALID_DER_TIME;
323 : }
324 0 : value = static_cast<unsigned int>(b - static_cast<uint8_t>('0'));
325 0 : return Success;
326 : }
327 :
328 : static inline Result
329 0 : ReadTwoDigits(Reader& input, unsigned int minValue, unsigned int maxValue,
330 : /*out*/ unsigned int& value)
331 : {
332 : unsigned int hi;
333 0 : Result rv = ReadDigit(input, hi);
334 0 : if (rv != Success) {
335 0 : return rv;
336 : }
337 : unsigned int lo;
338 0 : rv = ReadDigit(input, lo);
339 0 : if (rv != Success) {
340 0 : return rv;
341 : }
342 0 : value = (hi * 10) + lo;
343 0 : if (value < minValue || value > maxValue) {
344 0 : return Result::ERROR_INVALID_DER_TIME;
345 : }
346 0 : return Success;
347 : }
348 :
349 : namespace internal {
350 :
351 : // We parse GeneralizedTime and UTCTime according to RFC 5280 and we do not
352 : // accept all time formats allowed in the ASN.1 spec. That is,
353 : // GeneralizedTime must always be in the format YYYYMMDDHHMMSSZ and UTCTime
354 : // must always be in the format YYMMDDHHMMSSZ. Timezone formats of the form
355 : // +HH:MM or -HH:MM or NOT accepted.
356 : Result
357 0 : TimeChoice(Reader& tagged, uint8_t expectedTag, /*out*/ Time& time)
358 : {
359 : unsigned int days;
360 :
361 0 : Reader input;
362 0 : Result rv = ExpectTagAndGetValue(tagged, expectedTag, input);
363 0 : if (rv != Success) {
364 0 : return rv;
365 : }
366 :
367 : unsigned int yearHi;
368 : unsigned int yearLo;
369 0 : if (expectedTag == GENERALIZED_TIME) {
370 0 : rv = ReadTwoDigits(input, 0, 99, yearHi);
371 0 : if (rv != Success) {
372 0 : return rv;
373 : }
374 0 : rv = ReadTwoDigits(input, 0, 99, yearLo);
375 0 : if (rv != Success) {
376 0 : return rv;
377 : }
378 0 : } else if (expectedTag == UTCTime) {
379 0 : rv = ReadTwoDigits(input, 0, 99, yearLo);
380 0 : if (rv != Success) {
381 0 : return rv;
382 : }
383 0 : yearHi = yearLo >= 50u ? 19u : 20u;
384 : } else {
385 : return NotReached("invalid tag given to TimeChoice",
386 0 : Result::ERROR_INVALID_DER_TIME);
387 : }
388 0 : unsigned int year = (yearHi * 100u) + yearLo;
389 0 : if (year < 1970u) {
390 : // We don't support dates before January 1, 1970 because that is the epoch.
391 0 : return Result::ERROR_INVALID_DER_TIME;
392 : }
393 0 : days = DaysBeforeYear(year);
394 :
395 : unsigned int month;
396 0 : rv = ReadTwoDigits(input, 1u, 12u, month);
397 0 : if (rv != Success) {
398 0 : return rv;
399 : }
400 : unsigned int daysInMonth;
401 : static const unsigned int jan = 31u;
402 0 : const unsigned int feb = ((year % 4u == 0u) &&
403 0 : ((year % 100u != 0u) || (year % 400u == 0u)))
404 0 : ? 29u
405 0 : : 28u;
406 : static const unsigned int mar = 31u;
407 : static const unsigned int apr = 30u;
408 : static const unsigned int may = 31u;
409 : static const unsigned int jun = 30u;
410 : static const unsigned int jul = 31u;
411 : static const unsigned int aug = 31u;
412 : static const unsigned int sep = 30u;
413 : static const unsigned int oct = 31u;
414 : static const unsigned int nov = 30u;
415 : static const unsigned int dec = 31u;
416 0 : switch (month) {
417 0 : case 1: daysInMonth = jan; break;
418 0 : case 2: daysInMonth = feb; days += jan; break;
419 0 : case 3: daysInMonth = mar; days += jan + feb; break;
420 0 : case 4: daysInMonth = apr; days += jan + feb + mar; break;
421 0 : case 5: daysInMonth = may; days += jan + feb + mar + apr; break;
422 0 : case 6: daysInMonth = jun; days += jan + feb + mar + apr + may; break;
423 0 : case 7: daysInMonth = jul; days += jan + feb + mar + apr + may + jun;
424 0 : break;
425 0 : case 8: daysInMonth = aug; days += jan + feb + mar + apr + may + jun +
426 0 : jul;
427 0 : break;
428 0 : case 9: daysInMonth = sep; days += jan + feb + mar + apr + may + jun +
429 0 : jul + aug;
430 0 : break;
431 0 : case 10: daysInMonth = oct; days += jan + feb + mar + apr + may + jun +
432 0 : jul + aug + sep;
433 0 : break;
434 0 : case 11: daysInMonth = nov; days += jan + feb + mar + apr + may + jun +
435 0 : jul + aug + sep + oct;
436 0 : break;
437 0 : case 12: daysInMonth = dec; days += jan + feb + mar + apr + may + jun +
438 0 : jul + aug + sep + oct + nov;
439 0 : break;
440 : default:
441 : return NotReached("month already bounds-checked by ReadTwoDigits",
442 0 : Result::FATAL_ERROR_INVALID_STATE);
443 : }
444 :
445 : unsigned int dayOfMonth;
446 0 : rv = ReadTwoDigits(input, 1u, daysInMonth, dayOfMonth);
447 0 : if (rv != Success) {
448 0 : return rv;
449 : }
450 0 : days += dayOfMonth - 1;
451 :
452 : unsigned int hours;
453 0 : rv = ReadTwoDigits(input, 0u, 23u, hours);
454 0 : if (rv != Success) {
455 0 : return rv;
456 : }
457 : unsigned int minutes;
458 0 : rv = ReadTwoDigits(input, 0u, 59u, minutes);
459 0 : if (rv != Success) {
460 0 : return rv;
461 : }
462 : unsigned int seconds;
463 0 : rv = ReadTwoDigits(input, 0u, 59u, seconds);
464 0 : if (rv != Success) {
465 0 : return rv;
466 : }
467 :
468 : uint8_t b;
469 0 : if (input.Read(b) != Success) {
470 0 : return Result::ERROR_INVALID_DER_TIME;
471 : }
472 0 : if (b != 'Z') {
473 0 : return Result::ERROR_INVALID_DER_TIME;
474 : }
475 0 : if (End(input) != Success) {
476 0 : return Result::ERROR_INVALID_DER_TIME;
477 : }
478 :
479 0 : uint64_t totalSeconds = (static_cast<uint64_t>(days) * 24u * 60u * 60u) +
480 0 : (static_cast<uint64_t>(hours) * 60u * 60u) +
481 0 : (static_cast<uint64_t>(minutes) * 60u) +
482 0 : seconds;
483 :
484 0 : time = TimeFromElapsedSecondsAD(totalSeconds);
485 0 : return Success;
486 : }
487 :
488 : Result
489 8 : IntegralBytes(Reader& input, uint8_t tag,
490 : IntegralValueRestriction valueRestriction,
491 : /*out*/ Input& value,
492 : /*optional out*/ Input::size_type* significantBytes)
493 : {
494 8 : Result rv = ExpectTagAndGetValue(input, tag, value);
495 8 : if (rv != Success) {
496 0 : return rv;
497 : }
498 8 : Reader reader(value);
499 :
500 : // There must be at least one byte in the value. (Zero is encoded with a
501 : // single 0x00 value byte.)
502 : uint8_t firstByte;
503 8 : rv = reader.Read(firstByte);
504 8 : if (rv != Success) {
505 0 : if (rv == Result::ERROR_BAD_DER) {
506 0 : return Result::ERROR_INVALID_INTEGER_ENCODING;
507 : }
508 :
509 0 : return rv;
510 : }
511 :
512 : // If there is a byte after an initial 0x00/0xFF, then the initial byte
513 : // indicates a positive/negative integer value with its high bit set/unset.
514 8 : bool prefixed = !reader.AtEnd() && (firstByte == 0 || firstByte == 0xff);
515 :
516 8 : if (prefixed) {
517 : uint8_t nextByte;
518 4 : if (reader.Read(nextByte) != Success) {
519 : return NotReached("Read of one byte failed but not at end.",
520 0 : Result::FATAL_ERROR_LIBRARY_FAILURE);
521 : }
522 4 : if ((firstByte & 0x80) == (nextByte & 0x80)) {
523 0 : return Result::ERROR_INVALID_INTEGER_ENCODING;
524 : }
525 : }
526 :
527 8 : switch (valueRestriction) {
528 : case IntegralValueRestriction::MustBe0To127:
529 0 : if (value.GetLength() != 1 || (firstByte & 0x80) != 0) {
530 0 : return Result::ERROR_INVALID_INTEGER_ENCODING;
531 : }
532 0 : break;
533 :
534 : case IntegralValueRestriction::MustBePositive:
535 16 : if ((value.GetLength() == 1 && firstByte == 0) ||
536 8 : (firstByte & 0x80) != 0) {
537 0 : return Result::ERROR_INVALID_INTEGER_ENCODING;
538 : }
539 8 : break;
540 :
541 : case IntegralValueRestriction::NoRestriction:
542 0 : break;
543 : }
544 :
545 8 : if (significantBytes) {
546 4 : *significantBytes = value.GetLength();
547 4 : if (prefixed) {
548 4 : assert(*significantBytes > 1);
549 4 : --*significantBytes;
550 : }
551 :
552 4 : assert(*significantBytes > 0);
553 : }
554 :
555 8 : return Success;
556 : }
557 :
558 : // This parser will only parse values between 0..127. If this range is
559 : // increased then callers will need to be changed.
560 : Result
561 0 : IntegralValue(Reader& input, uint8_t tag, /*out*/ uint8_t& value)
562 : {
563 : // Conveniently, all the Integers that we actually have to be able to parse
564 : // are positive and very small. Consequently, this parser is *much* simpler
565 : // than a general Integer parser would need to be.
566 0 : Input valueBytes;
567 0 : Result rv = IntegralBytes(input, tag, IntegralValueRestriction::MustBe0To127,
568 0 : valueBytes, nullptr);
569 0 : if (rv != Success) {
570 0 : return rv;
571 : }
572 0 : Reader valueReader(valueBytes);
573 0 : rv = valueReader.Read(value);
574 0 : if (rv != Success) {
575 0 : return NotReached("IntegralBytes already validated the value.", rv);
576 : }
577 0 : rv = End(valueReader);
578 0 : assert(rv == Success); // guaranteed by IntegralBytes's range checks.
579 0 : return rv;
580 : }
581 :
582 : } // namespace internal
583 :
584 : Result
585 0 : OptionalVersion(Reader& input, /*out*/ Version& version)
586 : {
587 : static const uint8_t TAG = CONTEXT_SPECIFIC | CONSTRUCTED | 0;
588 0 : if (!input.Peek(TAG)) {
589 0 : version = Version::v1;
590 0 : return Success;
591 : }
592 0 : return Nested(input, TAG, [&version](Reader& value) -> Result {
593 : uint8_t integerValue;
594 0 : Result rv = Integer(value, integerValue);
595 0 : if (rv != Success) {
596 0 : return rv;
597 : }
598 : // XXX(bug 1031093): We shouldn't accept an explicit encoding of v1,
599 : // but we do here for compatibility reasons.
600 0 : switch (integerValue) {
601 0 : case static_cast<uint8_t>(Version::v3): version = Version::v3; break;
602 0 : case static_cast<uint8_t>(Version::v2): version = Version::v2; break;
603 0 : case static_cast<uint8_t>(Version::v1): version = Version::v1; break;
604 0 : case static_cast<uint8_t>(Version::v4): version = Version::v4; break;
605 : default:
606 0 : return Result::ERROR_BAD_DER;
607 : }
608 0 : return Success;
609 0 : });
610 : }
611 :
612 : } } } // namespace mozilla::pkix::der
|