Coverage Report

Created: 2018-09-25 14:53

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