|
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 /* Copyright 2013 Mozilla Foundation |
|
4 * |
|
5 * Licensed under the Apache License, Version 2.0 (the "License"); |
|
6 * you may not use this file except in compliance with the License. |
|
7 * You may obtain a copy of the License at |
|
8 * |
|
9 * http://www.apache.org/licenses/LICENSE-2.0 |
|
10 * |
|
11 * Unless required by applicable law or agreed to in writing, software |
|
12 * distributed under the License is distributed on an "AS IS" BASIS, |
|
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 * See the License for the specific language governing permissions and |
|
15 * limitations under the License. |
|
16 */ |
|
17 |
|
18 #ifndef mozilla_pkix__pkixder_h |
|
19 #define mozilla_pkix__pkixder_h |
|
20 |
|
21 #include "pkix/nullptr.h" |
|
22 |
|
23 #include "prerror.h" |
|
24 #include "prlog.h" |
|
25 #include "secder.h" |
|
26 #include "secerr.h" |
|
27 #include "secoidt.h" |
|
28 #include "stdint.h" |
|
29 |
|
30 namespace mozilla { namespace pkix { namespace der { |
|
31 |
|
32 enum Class |
|
33 { |
|
34 UNIVERSAL = 0 << 6, |
|
35 // APPLICATION = 1 << 6, // unused |
|
36 CONTEXT_SPECIFIC = 2 << 6, |
|
37 // PRIVATE = 3 << 6 // unused |
|
38 }; |
|
39 |
|
40 enum Constructed |
|
41 { |
|
42 CONSTRUCTED = 1 << 5 |
|
43 }; |
|
44 |
|
45 enum Tag |
|
46 { |
|
47 BOOLEAN = UNIVERSAL | 0x01, |
|
48 INTEGER = UNIVERSAL | 0x02, |
|
49 BIT_STRING = UNIVERSAL | 0x03, |
|
50 OCTET_STRING = UNIVERSAL | 0x04, |
|
51 NULLTag = UNIVERSAL | 0x05, |
|
52 OIDTag = UNIVERSAL | 0x06, |
|
53 ENUMERATED = UNIVERSAL | 0x0a, |
|
54 GENERALIZED_TIME = UNIVERSAL | 0x18, |
|
55 SEQUENCE = UNIVERSAL | CONSTRUCTED | 0x30, |
|
56 }; |
|
57 |
|
58 enum Result |
|
59 { |
|
60 Failure = -1, |
|
61 Success = 0 |
|
62 }; |
|
63 |
|
64 enum EmptyAllowed { MayBeEmpty = 0, MustNotBeEmpty = 1 }; |
|
65 |
|
66 Result Fail(PRErrorCode errorCode); |
|
67 |
|
68 class Input |
|
69 { |
|
70 public: |
|
71 Input() |
|
72 : input(nullptr) |
|
73 , end(nullptr) |
|
74 { |
|
75 } |
|
76 |
|
77 Result Init(const uint8_t* data, size_t len) |
|
78 { |
|
79 if (input) { |
|
80 // already initialized |
|
81 return Fail(SEC_ERROR_INVALID_ARGS); |
|
82 } |
|
83 if (!data || len > 0xffffu) { |
|
84 // input too large |
|
85 return Fail(SEC_ERROR_BAD_DER); |
|
86 } |
|
87 |
|
88 // XXX: this->input = input bug was not caught by tests! Why not? |
|
89 // this->end = end bug was not caught by tests! Why not? |
|
90 this->input = data; |
|
91 this->end = data + len; |
|
92 |
|
93 return Success; |
|
94 } |
|
95 |
|
96 Result Expect(const uint8_t* expected, uint16_t expectedLen) |
|
97 { |
|
98 if (EnsureLength(expectedLen) != Success) { |
|
99 return Fail(SEC_ERROR_BAD_DER); |
|
100 } |
|
101 if (memcmp(input, expected, expectedLen)) { |
|
102 return Fail(SEC_ERROR_BAD_DER); |
|
103 } |
|
104 input += expectedLen; |
|
105 return Success; |
|
106 } |
|
107 |
|
108 bool Peek(uint8_t expectedByte) const |
|
109 { |
|
110 return input < end && *input == expectedByte; |
|
111 } |
|
112 |
|
113 Result Read(uint8_t& out) |
|
114 { |
|
115 if (input == end) { |
|
116 return Fail(SEC_ERROR_BAD_DER); |
|
117 } |
|
118 out = *input++; |
|
119 return Success; |
|
120 } |
|
121 |
|
122 Result Read(uint16_t& out) |
|
123 { |
|
124 if (input == end || input + 1 == end) { |
|
125 return Fail(SEC_ERROR_BAD_DER); |
|
126 } |
|
127 out = *input++; |
|
128 out <<= 8u; |
|
129 out |= *input++; |
|
130 return Success; |
|
131 } |
|
132 |
|
133 Result Skip(uint16_t len) |
|
134 { |
|
135 if (EnsureLength(len) != Success) { |
|
136 return Fail(SEC_ERROR_BAD_DER); |
|
137 } |
|
138 input += len; |
|
139 return Success; |
|
140 } |
|
141 |
|
142 Result Skip(uint16_t len, Input& skippedInput) |
|
143 { |
|
144 if (EnsureLength(len) != Success) { |
|
145 return Fail(SEC_ERROR_BAD_DER); |
|
146 } |
|
147 if (skippedInput.Init(input, len) != Success) { |
|
148 return Failure; |
|
149 } |
|
150 input += len; |
|
151 return Success; |
|
152 } |
|
153 |
|
154 Result Skip(uint16_t len, SECItem& skippedItem) |
|
155 { |
|
156 if (EnsureLength(len) != Success) { |
|
157 return Fail(SEC_ERROR_BAD_DER); |
|
158 } |
|
159 skippedItem.type = siBuffer; |
|
160 skippedItem.data = const_cast<uint8_t*>(input); |
|
161 skippedItem.len = len; |
|
162 input += len; |
|
163 return Success; |
|
164 } |
|
165 |
|
166 void SkipToEnd() |
|
167 { |
|
168 input = end; |
|
169 } |
|
170 |
|
171 Result EnsureLength(uint16_t len) |
|
172 { |
|
173 if (static_cast<size_t>(end - input) < len) { |
|
174 return Fail(SEC_ERROR_BAD_DER); |
|
175 } |
|
176 return Success; |
|
177 } |
|
178 |
|
179 bool AtEnd() const { return input == end; } |
|
180 |
|
181 class Mark |
|
182 { |
|
183 private: |
|
184 friend class Input; |
|
185 explicit Mark(const uint8_t* mark) : mMark(mark) { } |
|
186 const uint8_t* const mMark; |
|
187 void operator=(const Mark&) /* = delete */; |
|
188 }; |
|
189 |
|
190 Mark GetMark() const { return Mark(input); } |
|
191 |
|
192 bool GetSECItem(SECItemType type, const Mark& mark, /*out*/ SECItem& item) |
|
193 { |
|
194 PR_ASSERT(mark.mMark < input); |
|
195 item.type = type; |
|
196 item.data = const_cast<uint8_t*>(mark.mMark); |
|
197 // TODO: Return false if bounds check fails |
|
198 item.len = input - mark.mMark; |
|
199 return true; |
|
200 } |
|
201 |
|
202 private: |
|
203 const uint8_t* input; |
|
204 const uint8_t* end; |
|
205 |
|
206 Input(const Input&) /* = delete */; |
|
207 void operator=(const Input&) /* = delete */; |
|
208 }; |
|
209 |
|
210 inline Result |
|
211 ExpectTagAndLength(Input& input, uint8_t expectedTag, uint8_t expectedLength) |
|
212 { |
|
213 PR_ASSERT((expectedTag & 0x1F) != 0x1F); // high tag number form not allowed |
|
214 PR_ASSERT(expectedLength < 128); // must be a single-byte length |
|
215 |
|
216 uint16_t tagAndLength; |
|
217 if (input.Read(tagAndLength) != Success) { |
|
218 return Failure; |
|
219 } |
|
220 |
|
221 uint16_t expectedTagAndLength = static_cast<uint16_t>(expectedTag << 8); |
|
222 expectedTagAndLength |= expectedLength; |
|
223 |
|
224 if (tagAndLength != expectedTagAndLength) { |
|
225 return Fail(SEC_ERROR_BAD_DER); |
|
226 } |
|
227 |
|
228 return Success; |
|
229 } |
|
230 |
|
231 Result |
|
232 ExpectTagAndGetLength(Input& input, uint8_t expectedTag, uint16_t& length); |
|
233 |
|
234 inline Result |
|
235 ExpectTagAndIgnoreLength(Input& input, uint8_t expectedTag) |
|
236 { |
|
237 uint16_t ignored; |
|
238 return ExpectTagAndGetLength(input, expectedTag, ignored); |
|
239 } |
|
240 |
|
241 inline Result |
|
242 ExpectTagAndGetValue(Input& input, uint8_t tag, /*out*/ Input& value) |
|
243 { |
|
244 uint16_t length; |
|
245 if (ExpectTagAndGetLength(input, tag, length) != Success) { |
|
246 return Failure; |
|
247 } |
|
248 return input.Skip(length, value); |
|
249 } |
|
250 |
|
251 inline Result |
|
252 End(Input& input) |
|
253 { |
|
254 if (!input.AtEnd()) { |
|
255 return Fail(SEC_ERROR_BAD_DER); |
|
256 } |
|
257 |
|
258 return Success; |
|
259 } |
|
260 |
|
261 template <typename Decoder> |
|
262 inline Result |
|
263 Nested(Input& input, uint8_t tag, Decoder decoder) |
|
264 { |
|
265 uint16_t length; |
|
266 if (ExpectTagAndGetLength(input, tag, length) != Success) { |
|
267 return Failure; |
|
268 } |
|
269 |
|
270 Input nested; |
|
271 if (input.Skip(length, nested) != Success) { |
|
272 return Failure; |
|
273 } |
|
274 |
|
275 if (decoder(nested) != Success) { |
|
276 return Failure; |
|
277 } |
|
278 |
|
279 return End(nested); |
|
280 } |
|
281 |
|
282 template <typename Decoder> |
|
283 inline Result |
|
284 Nested(Input& input, uint8_t outerTag, uint8_t innerTag, Decoder decoder) |
|
285 { |
|
286 // XXX: This doesn't work (in VS2010): |
|
287 // return Nested(input, outerTag, bind(Nested, _1, innerTag, decoder)); |
|
288 |
|
289 uint16_t length; |
|
290 if (ExpectTagAndGetLength(input, outerTag, length) != Success) { |
|
291 return Failure; |
|
292 } |
|
293 Input nestedInput; |
|
294 if (input.Skip(length, nestedInput) != Success) { |
|
295 return Failure; |
|
296 } |
|
297 if (Nested(nestedInput, innerTag, decoder) != Success) { |
|
298 return Failure; |
|
299 } |
|
300 |
|
301 return End(nestedInput); |
|
302 } |
|
303 |
|
304 // This can be used to decode constructs like this: |
|
305 // |
|
306 // ... |
|
307 // foos SEQUENCE OF Foo, |
|
308 // ... |
|
309 // Foo ::= SEQUENCE { |
|
310 // } |
|
311 // |
|
312 // using a call like this: |
|
313 // |
|
314 // rv = NestedOf(input, SEQEUENCE, SEQUENCE, bind(_1, Foo)); |
|
315 // |
|
316 // Result Foo(Input& input) { |
|
317 // } |
|
318 // |
|
319 // In this example, Foo will get called once for each element of foos. |
|
320 // |
|
321 template <typename Decoder> |
|
322 inline Result |
|
323 NestedOf(Input& input, uint8_t outerTag, uint8_t innerTag, |
|
324 EmptyAllowed mayBeEmpty, Decoder decoder) |
|
325 { |
|
326 uint16_t responsesLength; |
|
327 if (ExpectTagAndGetLength(input, outerTag, responsesLength) != Success) { |
|
328 return Failure; |
|
329 } |
|
330 |
|
331 Input inner; |
|
332 if (input.Skip(responsesLength, inner) != Success) { |
|
333 return Failure; |
|
334 } |
|
335 |
|
336 if (inner.AtEnd()) { |
|
337 if (mayBeEmpty != MayBeEmpty) { |
|
338 return Fail(SEC_ERROR_BAD_DER); |
|
339 } |
|
340 return Success; |
|
341 } |
|
342 |
|
343 do { |
|
344 if (Nested(inner, innerTag, decoder) != Success) { |
|
345 return Failure; |
|
346 } |
|
347 } while (!inner.AtEnd()); |
|
348 |
|
349 return Success; |
|
350 } |
|
351 |
|
352 inline Result |
|
353 Skip(Input& input, uint8_t tag) |
|
354 { |
|
355 uint16_t length; |
|
356 if (ExpectTagAndGetLength(input, tag, length) != Success) { |
|
357 return Failure; |
|
358 } |
|
359 return input.Skip(length); |
|
360 } |
|
361 |
|
362 inline Result |
|
363 Skip(Input& input, uint8_t tag, /*out*/ SECItem& value) |
|
364 { |
|
365 uint16_t length; |
|
366 if (ExpectTagAndGetLength(input, tag, length) != Success) { |
|
367 return Failure; |
|
368 } |
|
369 return input.Skip(length, value); |
|
370 } |
|
371 |
|
372 // Universal types |
|
373 |
|
374 inline Result |
|
375 Boolean(Input& input, /*out*/ bool& value) |
|
376 { |
|
377 if (ExpectTagAndLength(input, BOOLEAN, 1) != Success) { |
|
378 return Failure; |
|
379 } |
|
380 |
|
381 uint8_t intValue; |
|
382 if (input.Read(intValue) != Success) { |
|
383 return Failure; |
|
384 } |
|
385 switch (intValue) { |
|
386 case 0: value = false; return Success; |
|
387 case 0xFF: value = true; return Success; |
|
388 default: |
|
389 PR_SetError(SEC_ERROR_BAD_DER, 0); |
|
390 return Failure; |
|
391 } |
|
392 } |
|
393 |
|
394 // This is for any BOOLEAN DEFAULT FALSE. |
|
395 // (If it is present and false, this is a bad encoding.) |
|
396 // TODO(bug 989518): For compatibility reasons, in some places we allow |
|
397 // invalid encodings with the explicit default value. |
|
398 inline Result |
|
399 OptionalBoolean(Input& input, bool allowInvalidExplicitEncoding, |
|
400 /*out*/ bool& value) |
|
401 { |
|
402 value = false; |
|
403 if (input.Peek(BOOLEAN)) { |
|
404 if (Boolean(input, value) != Success) { |
|
405 return Failure; |
|
406 } |
|
407 if (!allowInvalidExplicitEncoding && !value) { |
|
408 return Fail(SEC_ERROR_BAD_DER); |
|
409 } |
|
410 } |
|
411 return Success; |
|
412 } |
|
413 |
|
414 inline Result |
|
415 Enumerated(Input& input, uint8_t& value) |
|
416 { |
|
417 if (ExpectTagAndLength(input, ENUMERATED | 0, 1) != Success) { |
|
418 return Failure; |
|
419 } |
|
420 return input.Read(value); |
|
421 } |
|
422 |
|
423 inline Result |
|
424 GeneralizedTime(Input& input, PRTime& time) |
|
425 { |
|
426 uint16_t length; |
|
427 SECItem encoded; |
|
428 if (ExpectTagAndGetLength(input, GENERALIZED_TIME, length) != Success) { |
|
429 return Failure; |
|
430 } |
|
431 if (input.Skip(length, encoded)) { |
|
432 return Failure; |
|
433 } |
|
434 if (DER_GeneralizedTimeToTime(&time, &encoded) != SECSuccess) { |
|
435 return Failure; |
|
436 } |
|
437 |
|
438 return Success; |
|
439 } |
|
440 |
|
441 inline Result |
|
442 Integer(Input& input, /*out*/ SECItem& value) |
|
443 { |
|
444 uint16_t length; |
|
445 if (ExpectTagAndGetLength(input, INTEGER, length) != Success) { |
|
446 return Failure; |
|
447 } |
|
448 |
|
449 if (input.Skip(length, value) != Success) { |
|
450 return Failure; |
|
451 } |
|
452 |
|
453 if (value.len == 0) { |
|
454 return Fail(SEC_ERROR_BAD_DER); |
|
455 } |
|
456 |
|
457 // Check for overly-long encodings. If the first byte is 0x00 then the high |
|
458 // bit on the second byte must be 1; otherwise the same *positive* value |
|
459 // could be encoded without the leading 0x00 byte. If the first byte is 0xFF |
|
460 // then the second byte must NOT have its high bit set; otherwise the same |
|
461 // *negative* value could be encoded without the leading 0xFF byte. |
|
462 if (value.len > 1) { |
|
463 if ((value.data[0] == 0x00 && (value.data[1] & 0x80) == 0) || |
|
464 (value.data[0] == 0xff && (value.data[1] & 0x80) != 0)) { |
|
465 return Fail(SEC_ERROR_BAD_DER); |
|
466 } |
|
467 } |
|
468 |
|
469 return Success; |
|
470 } |
|
471 |
|
472 inline Result |
|
473 Null(Input& input) |
|
474 { |
|
475 return ExpectTagAndLength(input, NULLTag, 0); |
|
476 } |
|
477 |
|
478 template <uint16_t Len> |
|
479 Result |
|
480 OID(Input& input, const uint8_t (&expectedOid)[Len]) |
|
481 { |
|
482 if (ExpectTagAndLength(input, OIDTag, Len) != Success) { |
|
483 return Failure; |
|
484 } |
|
485 |
|
486 return input.Expect(expectedOid, Len); |
|
487 } |
|
488 |
|
489 // PKI-specific types |
|
490 |
|
491 // AlgorithmIdentifier ::= SEQUENCE { |
|
492 // algorithm OBJECT IDENTIFIER, |
|
493 // parameters ANY DEFINED BY algorithm OPTIONAL } |
|
494 inline Result |
|
495 AlgorithmIdentifier(Input& input, SECAlgorithmID& algorithmID) |
|
496 { |
|
497 if (Skip(input, OIDTag, algorithmID.algorithm) != Success) { |
|
498 return Failure; |
|
499 } |
|
500 algorithmID.parameters.data = nullptr; |
|
501 algorithmID.parameters.len = 0; |
|
502 if (input.AtEnd()) { |
|
503 return Success; |
|
504 } |
|
505 return Null(input); |
|
506 } |
|
507 |
|
508 inline Result |
|
509 CertificateSerialNumber(Input& input, /*out*/ SECItem& serialNumber) |
|
510 { |
|
511 // http://tools.ietf.org/html/rfc5280#section-4.1.2.2: |
|
512 // |
|
513 // * "The serial number MUST be a positive integer assigned by the CA to |
|
514 // each certificate." |
|
515 // * "Certificate users MUST be able to handle serialNumber values up to 20 |
|
516 // octets. Conforming CAs MUST NOT use serialNumber values longer than 20 |
|
517 // octets." |
|
518 // * "Note: Non-conforming CAs may issue certificates with serial numbers |
|
519 // that are negative or zero. Certificate users SHOULD be prepared to |
|
520 // gracefully handle such certificates." |
|
521 |
|
522 return Integer(input, serialNumber); |
|
523 } |
|
524 |
|
525 // x.509 and OCSP both use this same version numbering scheme, though OCSP |
|
526 // only supports v1. |
|
527 enum Version { v1 = 0, v2 = 1, v3 = 2 }; |
|
528 |
|
529 // X.509 Certificate and OCSP ResponseData both use this |
|
530 // "[0] EXPLICIT Version DEFAULT <defaultVersion>" construct, but with |
|
531 // different default versions. |
|
532 inline Result |
|
533 OptionalVersion(Input& input, /*out*/ uint8_t& version) |
|
534 { |
|
535 const uint8_t tag = CONTEXT_SPECIFIC | CONSTRUCTED | 0; |
|
536 if (!input.Peek(tag)) { |
|
537 version = v1; |
|
538 return Success; |
|
539 } |
|
540 if (ExpectTagAndLength(input, tag, 3) != Success) { |
|
541 return Failure; |
|
542 } |
|
543 if (ExpectTagAndLength(input, INTEGER, 1) != Success) { |
|
544 return Failure; |
|
545 } |
|
546 if (input.Read(version) != Success) { |
|
547 return Failure; |
|
548 } |
|
549 if (version & 0x80) { // negative |
|
550 return Fail(SEC_ERROR_BAD_DER); |
|
551 } |
|
552 return Success; |
|
553 } |
|
554 |
|
555 } } } // namespace mozilla::pkix::der |
|
556 |
|
557 #endif // mozilla_pkix__pkixder_h |