pkixder.cpp 18 KB

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