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 "mozpkix/test/pkixtestutil.h"
26
27 #include <cerrno>
28 #include <cstdio>
29 #include <limits>
30 #include <new>
31 #include <sstream>
32 #include <cstdlib>
33
34 #include "mozpkix/pkixder.h"
35 #include "mozpkix/pkixutil.h"
36
37 using namespace std;
38
39 namespace mozilla { namespace pkix { namespace test {
40
41 namespace {
42
43 struct ScopedMaybeDeleteFile {
operator ()mozilla::pkix::test::__anon912d3d6e0111::ScopedMaybeDeleteFile44 void operator()(FILE* f) {
45 if (f) {
46 (void)fclose(f);
47 }
48 }
49 };
50 typedef std::unique_ptr<FILE, ScopedMaybeDeleteFile> ScopedFILE;
51
52 FILE*
OpenFile(const string & dir,const string & filename,const string & mode)53 OpenFile(const string& dir, const string& filename, const string& mode)
54 {
55 string path = dir + '/' + filename;
56
57 ScopedFILE file;
58 #ifdef _MSC_VER
59 {
60 FILE* rawFile;
61 errno_t error = fopen_s(&rawFile, path.c_str(), mode.c_str());
62 if (error) {
63 // TODO: map error to NSPR error code
64 rawFile = nullptr;
65 }
66 file.reset(rawFile);
67 }
68 #else
69 file.reset(fopen(path.c_str(), mode.c_str()));
70 #endif
71 return file.release();
72 }
73
74 } // namespace
75
76 bool
InputEqualsByteString(Input input,const ByteString & bs)77 InputEqualsByteString(Input input, const ByteString& bs)
78 {
79 Input bsInput;
80 if (bsInput.Init(bs.data(), bs.length()) != Success) {
81 // Init can only fail if it is given a bad pointer or if the input is too
82 // long, which won't ever happen. Plus, if it does, it is ok to call abort
83 // since this is only test code.
84 abort();
85 }
86 return InputsAreEqual(input, bsInput);
87 }
88
89 ByteString
InputToByteString(Input input)90 InputToByteString(Input input)
91 {
92 ByteString result;
93 Reader reader(input);
94 for (;;) {
95 uint8_t b;
96 if (reader.Read(b) != Success) {
97 return result;
98 }
99 result.push_back(b);
100 }
101 }
102
103 Result
TamperOnce(ByteString & item,const ByteString & from,const ByteString & to)104 TamperOnce(/*in/out*/ ByteString& item, const ByteString& from,
105 const ByteString& to)
106 {
107 if (from.length() < 8) {
108 return Result::FATAL_ERROR_INVALID_ARGS;
109 }
110 if (from.length() != to.length()) {
111 return Result::FATAL_ERROR_INVALID_ARGS;
112 }
113 size_t pos = item.find(from);
114 if (pos == string::npos) {
115 return Result::FATAL_ERROR_INVALID_ARGS; // No matches.
116 }
117 if (item.find(from, pos + from.length()) != string::npos) {
118 return Result::FATAL_ERROR_INVALID_ARGS; // More than once match.
119 }
120 item.replace(pos, from.length(), to);
121 return Success;
122 }
123
124 // Given a tag and a value, generates a DER-encoded tag-length-value item.
125 ByteString
TLV(uint8_t tag,size_t length,const ByteString & value)126 TLV(uint8_t tag, size_t length, const ByteString& value)
127 {
128 ByteString result;
129 result.push_back(tag);
130
131 if (value.length() < 128) {
132 result.push_back(static_cast<uint8_t>(length));
133 } else if (value.length() < 256) {
134 result.push_back(0x81u);
135 result.push_back(static_cast<uint8_t>(length));
136 } else if (value.length() < 65536) {
137 result.push_back(0x82u);
138 result.push_back(static_cast<uint8_t>(length / 256));
139 result.push_back(static_cast<uint8_t>(length % 256));
140 } else {
141 // It is MUCH more convenient for TLV to be infallible than for it to have
142 // "proper" error handling.
143 abort();
144 }
145 result.append(value);
146 return result;
147 }
148
OCSPResponseExtension()149 OCSPResponseExtension::OCSPResponseExtension()
150 : id()
151 , critical(false)
152 , value()
153 , next(nullptr)
154 {
155 }
156
OCSPResponseContext(const CertID & aCertID,time_t time)157 OCSPResponseContext::OCSPResponseContext(const CertID& aCertID, time_t time)
158 : certID(aCertID)
159 , certIDHashAlgorithm(DigestAlgorithm::sha1)
160 , certIDHashAlgorithmEncoded(ByteString())
161 , responseStatus(successful)
162 , skipResponseBytes(false)
163 , producedAt(time)
164 , singleExtensions(nullptr)
165 , responseExtensions(nullptr)
166 , includeEmptyExtensions(false)
167 , signatureAlgorithm(sha256WithRSAEncryption())
168 , badSignature(false)
169 , certs(nullptr)
170
171 , certStatus(good)
172 , revocationTime(0)
173 , thisUpdate(time)
174 , nextUpdate(time + static_cast<time_t>(Time::ONE_DAY_IN_SECONDS))
175 , includeNextUpdate(true)
176 {
177 }
178
179 static ByteString ResponseBytes(OCSPResponseContext& context);
180 static ByteString BasicOCSPResponse(OCSPResponseContext& context);
181 static ByteString ResponseData(OCSPResponseContext& context);
182 static ByteString ResponderID(OCSPResponseContext& context);
183 static ByteString KeyHash(const ByteString& subjectPublicKeyInfo);
184 static ByteString SingleResponse(OCSPResponseContext& context);
185 static ByteString CertID(OCSPResponseContext& context);
186 static ByteString CertStatus(OCSPResponseContext& context);
187
188 static ByteString
HASH(const ByteString & toHash,DigestAlgorithm digestAlgorithm)189 HASH(const ByteString& toHash, DigestAlgorithm digestAlgorithm)
190 {
191 uint8_t digestBuf[MAX_DIGEST_SIZE_IN_BYTES];
192 Input input;
193 if (input.Init(toHash.data(), toHash.length()) != Success) {
194 abort();
195 }
196 size_t digestLen = DigestAlgorithmToSizeInBytes(digestAlgorithm);
197 assert(digestLen <= sizeof(digestBuf));
198 Result rv = TestDigestBuf(input, digestAlgorithm, digestBuf, digestLen);
199 if (rv != Success) {
200 abort();
201 }
202 return ByteString(digestBuf, digestLen);
203 }
204
205 static ByteString
HashedOctetString(const ByteString & bytes,DigestAlgorithm digestAlgorithm)206 HashedOctetString(const ByteString& bytes, DigestAlgorithm digestAlgorithm)
207 {
208 ByteString digest(HASH(bytes, digestAlgorithm));
209 if (ENCODING_FAILED(digest)) {
210 return ByteString();
211 }
212 return TLV(der::OCTET_STRING, digest);
213 }
214
215 static ByteString
BitString(const ByteString & rawBytes,bool corrupt)216 BitString(const ByteString& rawBytes, bool corrupt)
217 {
218 ByteString prefixed;
219 // We have to add a byte at the beginning indicating no unused bits.
220 // TODO: add ability to have bit strings of bit length not divisible by 8,
221 // resulting in unused bits in the bitstring encoding
222 prefixed.push_back(0);
223 prefixed.append(rawBytes);
224 if (corrupt) {
225 assert(prefixed.length() > 8);
226 prefixed[8]++;
227 }
228 return TLV(der::BIT_STRING, prefixed);
229 }
230
231 ByteString
Boolean(bool value)232 Boolean(bool value)
233 {
234 ByteString encodedValue;
235 encodedValue.push_back(value ? 0xffu : 0x00u);
236 return TLV(der::BOOLEAN, encodedValue);
237 }
238
239 ByteString
Integer(long value)240 Integer(long value)
241 {
242 if (value < 0 || value > 127) {
243 // TODO: add encoding of larger values
244 // It is MUCH more convenient for Integer to be infallible than for it to
245 // have "proper" error handling.
246 abort();
247 }
248
249 ByteString encodedValue;
250 encodedValue.push_back(static_cast<uint8_t>(value));
251 return TLV(der::INTEGER, encodedValue);
252 }
253
254 enum TimeEncoding { UTCTime = 0, GeneralizedTime = 1 };
255
256 // Windows doesn't provide gmtime_r, but it provides something very similar.
257 #if defined(_WINDOWS) && (!defined(_POSIX_C_SOURCE) || !defined(_POSIX_THREAD_SAFE_FUNCTIONS))
258 static tm*
gmtime_r(const time_t * t,tm * exploded)259 gmtime_r(const time_t* t, /*out*/ tm* exploded)
260 {
261 if (gmtime_s(exploded, t) != 0) {
262 return nullptr;
263 }
264 return exploded;
265 }
266 #endif
267
268 // http://tools.ietf.org/html/rfc5280#section-4.1.2.5
269 // UTCTime: YYMMDDHHMMSSZ (years 1950-2049 only)
270 // GeneralizedTime: YYYYMMDDHHMMSSZ
271 //
272 // This assumes that time/time_t are POSIX-compliant in that time() returns
273 // the number of seconds since the Unix epoch.
274 static ByteString
TimeToEncodedTime(time_t time,TimeEncoding encoding)275 TimeToEncodedTime(time_t time, TimeEncoding encoding)
276 {
277 assert(encoding == UTCTime || encoding == GeneralizedTime);
278
279 tm exploded;
280 if (!gmtime_r(&time, &exploded)) {
281 return ByteString();
282 }
283
284 if (exploded.tm_sec >= 60) {
285 // round down for leap seconds
286 exploded.tm_sec = 59;
287 }
288
289 // exploded.tm_year is the year offset by 1900.
290 int year = exploded.tm_year + 1900;
291
292 if (encoding == UTCTime && (year < 1950 || year >= 2050)) {
293 return ByteString();
294 }
295
296 ByteString value;
297
298 if (encoding == GeneralizedTime) {
299 value.push_back(static_cast<uint8_t>('0' + (year / 1000)));
300 value.push_back(static_cast<uint8_t>('0' + ((year % 1000) / 100)));
301 }
302
303 value.push_back(static_cast<uint8_t>('0' + ((year % 100) / 10)));
304 value.push_back(static_cast<uint8_t>('0' + (year % 10)));
305 value.push_back(static_cast<uint8_t>('0' + ((exploded.tm_mon + 1) / 10)));
306 value.push_back(static_cast<uint8_t>('0' + ((exploded.tm_mon + 1) % 10)));
307 value.push_back(static_cast<uint8_t>('0' + (exploded.tm_mday / 10)));
308 value.push_back(static_cast<uint8_t>('0' + (exploded.tm_mday % 10)));
309 value.push_back(static_cast<uint8_t>('0' + (exploded.tm_hour / 10)));
310 value.push_back(static_cast<uint8_t>('0' + (exploded.tm_hour % 10)));
311 value.push_back(static_cast<uint8_t>('0' + (exploded.tm_min / 10)));
312 value.push_back(static_cast<uint8_t>('0' + (exploded.tm_min % 10)));
313 value.push_back(static_cast<uint8_t>('0' + (exploded.tm_sec / 10)));
314 value.push_back(static_cast<uint8_t>('0' + (exploded.tm_sec % 10)));
315 value.push_back('Z');
316
317 return TLV(encoding == GeneralizedTime ? der::GENERALIZED_TIME : der::UTCTime,
318 value);
319 }
320
321 static ByteString
TimeToGeneralizedTime(time_t time)322 TimeToGeneralizedTime(time_t time)
323 {
324 return TimeToEncodedTime(time, GeneralizedTime);
325 }
326
327 // http://tools.ietf.org/html/rfc5280#section-4.1.2.5: "CAs conforming to this
328 // profile MUST always encode certificate validity dates through the year 2049
329 // as UTCTime; certificate validity dates in 2050 or later MUST be encoded as
330 // GeneralizedTime." (This is a special case of the rule that we must always
331 // use the shortest possible encoding.)
332 static ByteString
TimeToTimeChoice(time_t time)333 TimeToTimeChoice(time_t time)
334 {
335 tm exploded;
336 if (!gmtime_r(&time, &exploded)) {
337 return ByteString();
338 }
339 TimeEncoding encoding = (exploded.tm_year + 1900 >= 1950 &&
340 exploded.tm_year + 1900 < 2050)
341 ? UTCTime
342 : GeneralizedTime;
343
344 return TimeToEncodedTime(time, encoding);
345 }
346
347 Time
YMDHMS(uint16_t year,uint16_t month,uint16_t day,uint16_t hour,uint16_t minutes,uint16_t seconds)348 YMDHMS(uint16_t year, uint16_t month, uint16_t day,
349 uint16_t hour, uint16_t minutes, uint16_t seconds)
350 {
351 assert(year <= 9999);
352 assert(month >= 1);
353 assert(month <= 12);
354 assert(day >= 1);
355 assert(hour < 24);
356 assert(minutes < 60);
357 assert(seconds < 60);
358
359 uint64_t days = DaysBeforeYear(year);
360
361 {
362 static const int16_t DAYS_IN_MONTH[] = {
363 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
364 };
365
366 int16_t i = 1;
367 for (;;) {
368 int16_t daysInMonth = DAYS_IN_MONTH[i - 1];
369 if (i == 2 &&
370 ((year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)))) {
371 // Add leap day
372 ++daysInMonth;
373 }
374 if (i == month) {
375 assert(day <= daysInMonth);
376 break;
377 }
378 days += daysInMonth;
379 ++i;
380 }
381 }
382
383 days += (day - 1);
384
385 uint64_t totalSeconds = days * Time::ONE_DAY_IN_SECONDS;
386 totalSeconds += hour * 60 * 60;
387 totalSeconds += minutes * 60;
388 totalSeconds += seconds;
389 return TimeFromElapsedSecondsAD(totalSeconds);
390 }
391
392 static ByteString
SignedData(const ByteString & tbsData,const TestKeyPair & keyPair,const TestSignatureAlgorithm & signatureAlgorithm,bool corrupt,const ByteString * certs)393 SignedData(const ByteString& tbsData,
394 const TestKeyPair& keyPair,
395 const TestSignatureAlgorithm& signatureAlgorithm,
396 bool corrupt, /*optional*/ const ByteString* certs)
397 {
398 ByteString signature;
399 if (keyPair.SignData(tbsData, signatureAlgorithm, signature) != Success) {
400 return ByteString();
401 }
402
403 // TODO: add ability to have signatures of bit length not divisible by 8,
404 // resulting in unused bits in the bitstring encoding
405 ByteString signatureNested(BitString(signature, corrupt));
406 if (ENCODING_FAILED(signatureNested)) {
407 return ByteString();
408 }
409
410 ByteString certsNested;
411 if (certs) {
412 ByteString certsSequenceValue;
413 while (!(*certs).empty()) {
414 certsSequenceValue.append(*certs);
415 ++certs;
416 }
417 ByteString certsSequence(TLV(der::SEQUENCE, certsSequenceValue));
418 certsNested = TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
419 certsSequence);
420 }
421
422 ByteString value;
423 value.append(tbsData);
424 value.append(signatureAlgorithm.algorithmIdentifier);
425 value.append(signatureNested);
426 value.append(certsNested);
427 return TLV(der::SEQUENCE, value);
428 }
429
430 // Extension ::= SEQUENCE {
431 // extnID OBJECT IDENTIFIER,
432 // critical BOOLEAN DEFAULT FALSE,
433 // extnValue OCTET STRING
434 // -- contains the DER encoding of an ASN.1 value
435 // -- corresponding to the extension type identified
436 // -- by extnID
437 // }
438 static ByteString
Extension(Input extnID,Critical critical,const ByteString & extnValueBytes)439 Extension(Input extnID, Critical critical, const ByteString& extnValueBytes)
440 {
441 ByteString encoded;
442
443 encoded.append(ByteString(extnID.UnsafeGetData(), extnID.GetLength()));
444
445 if (critical == Critical::Yes) {
446 encoded.append(Boolean(true));
447 }
448
449 ByteString extnValueSequence(TLV(der::SEQUENCE, extnValueBytes));
450 ByteString extnValue(TLV(der::OCTET_STRING, extnValueSequence));
451 encoded.append(extnValue);
452 return TLV(der::SEQUENCE, encoded);
453 }
454
455 static ByteString
EmptyExtension(Input extnID,Critical critical)456 EmptyExtension(Input extnID, Critical critical)
457 {
458 ByteString encoded(extnID.UnsafeGetData(), extnID.GetLength());
459
460 if (critical == Critical::Yes) {
461 encoded.append(Boolean(true));
462 }
463
464 ByteString extnValue(TLV(der::OCTET_STRING, ByteString()));
465 encoded.append(extnValue);
466 return TLV(der::SEQUENCE, encoded);
467 }
468
469 std::string
GetEnv(const char * name)470 GetEnv(const char* name)
471 {
472 std::string result;
473
474 #ifndef _MSC_VER
475 // XXX: Not thread safe.
476 const char* value = getenv(name);
477 if (value) {
478 result = value;
479 }
480 #else
481 char* value = nullptr;
482 size_t valueLength = 0;
483 if (_dupenv_s(&value, &valueLength, name) != 0) {
484 abort();
485 }
486 if (value) {
487 result = value;
488 free(value);
489 }
490 #endif
491 return result;
492 }
493
494 void
MaybeLogOutput(const ByteString & result,const char * suffix)495 MaybeLogOutput(const ByteString& result, const char* suffix)
496 {
497 assert(suffix);
498
499 // This allows us to more easily debug the generated output, by creating a
500 // file in the directory given by MOZILLA_PKIX_TEST_LOG_DIR for each
501 // NOT THREAD-SAFE!!!
502 std::string logPath(GetEnv("MOZILLA_PKIX_TEST_LOG_DIR"));
503 if (!logPath.empty()) {
504 static int counter = 0;
505
506 std::ostringstream counterStream;
507 counterStream << counter;
508 if (!counterStream) {
509 assert(false);
510 return;
511 }
512 string filename = counterStream.str() + '-' + suffix + ".der";
513
514 ++counter;
515 ScopedFILE file(OpenFile(logPath, filename, "wb"));
516 if (file) {
517 (void) fwrite(result.data(), result.length(), 1, file.get());
518 }
519 }
520 }
521
522 ///////////////////////////////////////////////////////////////////////////////
523 // Certificates
524
525 static ByteString TBSCertificate(long version, const ByteString& serialNumber,
526 const ByteString& signature,
527 const ByteString& issuer,
528 time_t notBefore, time_t notAfter,
529 const ByteString& subject,
530 const ByteString& subjectPublicKeyInfo,
531 /*optional*/ const ByteString* extensions);
532
533 // Certificate ::= SEQUENCE {
534 // tbsCertificate TBSCertificate,
535 // signatureAlgorithm AlgorithmIdentifier,
536 // signatureValue BIT STRING }
537 ByteString
CreateEncodedCertificate(long version,const TestSignatureAlgorithm & signature,const ByteString & serialNumber,const ByteString & issuerNameDER,time_t notBefore,time_t notAfter,const ByteString & subjectNameDER,const TestKeyPair & subjectKeyPair,const ByteString * extensions,const TestKeyPair & issuerKeyPair,const TestSignatureAlgorithm & signatureAlgorithm)538 CreateEncodedCertificate(long version,
539 const TestSignatureAlgorithm& signature,
540 const ByteString& serialNumber,
541 const ByteString& issuerNameDER,
542 time_t notBefore, time_t notAfter,
543 const ByteString& subjectNameDER,
544 const TestKeyPair& subjectKeyPair,
545 /*optional*/ const ByteString* extensions,
546 const TestKeyPair& issuerKeyPair,
547 const TestSignatureAlgorithm& signatureAlgorithm)
548 {
549 ByteString tbsCertificate(TBSCertificate(version, serialNumber,
550 signature.algorithmIdentifier,
551 issuerNameDER, notBefore,
552 notAfter, subjectNameDER,
553 subjectKeyPair.subjectPublicKeyInfo,
554 extensions));
555 if (ENCODING_FAILED(tbsCertificate)) {
556 return ByteString();
557 }
558
559 ByteString result(SignedData(tbsCertificate, issuerKeyPair,
560 signatureAlgorithm, false, nullptr));
561 if (ENCODING_FAILED(result)) {
562 return ByteString();
563 }
564
565 MaybeLogOutput(result, "cert");
566
567 return result;
568 }
569
570 // TBSCertificate ::= SEQUENCE {
571 // version [0] Version DEFAULT v1,
572 // serialNumber CertificateSerialNumber,
573 // signature AlgorithmIdentifier,
574 // issuer Name,
575 // validity Validity,
576 // subject Name,
577 // subjectPublicKeyInfo SubjectPublicKeyInfo,
578 // issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
579 // -- If present, version MUST be v2 or v3
580 // subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
581 // -- If present, version MUST be v2 or v3
582 // extensions [3] Extensions OPTIONAL
583 // -- If present, version MUST be v3 -- }
584 static ByteString
TBSCertificate(long versionValue,const ByteString & serialNumber,const ByteString & signature,const ByteString & issuer,time_t notBeforeTime,time_t notAfterTime,const ByteString & subject,const ByteString & subjectPublicKeyInfo,const ByteString * extensions)585 TBSCertificate(long versionValue,
586 const ByteString& serialNumber, const ByteString& signature,
587 const ByteString& issuer, time_t notBeforeTime,
588 time_t notAfterTime, const ByteString& subject,
589 const ByteString& subjectPublicKeyInfo,
590 /*optional*/ const ByteString* extensions)
591 {
592 ByteString value;
593
594 if (versionValue != static_cast<long>(der::Version::v1)) {
595 ByteString versionInteger(Integer(versionValue));
596 ByteString version(TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
597 versionInteger));
598 value.append(version);
599 }
600
601 value.append(serialNumber);
602 value.append(signature);
603 value.append(issuer);
604
605 // Validity ::= SEQUENCE {
606 // notBefore Time,
607 // notAfter Time }
608 ByteString validity;
609 {
610 ByteString notBefore(TimeToTimeChoice(notBeforeTime));
611 if (ENCODING_FAILED(notBefore)) {
612 return ByteString();
613 }
614 ByteString notAfter(TimeToTimeChoice(notAfterTime));
615 if (ENCODING_FAILED(notAfter)) {
616 return ByteString();
617 }
618 ByteString validityValue;
619 validityValue.append(notBefore);
620 validityValue.append(notAfter);
621 validity = TLV(der::SEQUENCE, validityValue);
622 if (ENCODING_FAILED(validity)) {
623 return ByteString();
624 }
625 }
626 value.append(validity);
627
628 value.append(subject);
629
630 value.append(subjectPublicKeyInfo);
631
632 if (extensions) {
633 ByteString extensionsValue;
634 while (!(*extensions).empty()) {
635 extensionsValue.append(*extensions);
636 ++extensions;
637 }
638 ByteString extensionsSequence(TLV(der::SEQUENCE, extensionsValue));
639 if (ENCODING_FAILED(extensionsSequence)) {
640 return ByteString();
641 }
642 ByteString extensionsWrapped(
643 TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 3, extensionsSequence));
644 if (ENCODING_FAILED(extensionsWrapped)) {
645 return ByteString();
646 }
647 value.append(extensionsWrapped);
648 }
649
650 return TLV(der::SEQUENCE, value);
651 }
652
653 // AttributeTypeAndValue ::= SEQUENCE {
654 // type AttributeType,
655 // value AttributeValue }
656 //
657 // AttributeType ::= OBJECT IDENTIFIER
658 //
659 // AttributeValue ::= ANY -- DEFINED BY AttributeType
660 //
661 // DirectoryString ::= CHOICE {
662 // teletexString TeletexString (SIZE (1..MAX)),
663 // printableString PrintableString (SIZE (1..MAX)),
664 // universalString UniversalString (SIZE (1..MAX)),
665 // utf8String UTF8String (SIZE (1..MAX)),
666 // bmpString BMPString (SIZE (1..MAX)) }
667 template <size_t N>
668 static ByteString
AVA(const uint8_t (& type)[N],uint8_t directoryStringType,const ByteString & value)669 AVA(const uint8_t (&type)[N], uint8_t directoryStringType,
670 const ByteString& value)
671 {
672 ByteString wrappedValue(TLV(directoryStringType, value));
673 ByteString ava;
674 ava.append(type, N);
675 ava.append(wrappedValue);
676 return TLV(der::SEQUENCE, ava);
677 }
678
679 ByteString
CN(const ByteString & value,uint8_t encodingTag)680 CN(const ByteString& value, uint8_t encodingTag)
681 {
682 // id-at OBJECT IDENTIFIER ::= { joint-iso-ccitt(2) ds(5) 4 }
683 // id-at-commonName AttributeType ::= { id-at 3 }
684 // python DottedOIDToCode.py --tlv id-at-commonName 2.5.4.3
685 static const uint8_t tlv_id_at_commonName[] = {
686 0x06, 0x03, 0x55, 0x04, 0x03
687 };
688 return AVA(tlv_id_at_commonName, encodingTag, value);
689 }
690
691 ByteString
OU(const ByteString & value,uint8_t encodingTag)692 OU(const ByteString& value, uint8_t encodingTag)
693 {
694 // id-at OBJECT IDENTIFIER ::= { joint-iso-ccitt(2) ds(5) 4 }
695 // id-at-organizationalUnitName AttributeType ::= { id-at 11 }
696 // python DottedOIDToCode.py --tlv id-at-organizationalUnitName 2.5.4.11
697 static const uint8_t tlv_id_at_organizationalUnitName[] = {
698 0x06, 0x03, 0x55, 0x04, 0x0b
699 };
700
701 return AVA(tlv_id_at_organizationalUnitName, encodingTag, value);
702 }
703
704 ByteString
emailAddress(const ByteString & value)705 emailAddress(const ByteString& value)
706 {
707 // id-emailAddress AttributeType ::= { pkcs-9 1 }
708 // python DottedOIDToCode.py --tlv id-emailAddress 1.2.840.113549.1.9.1
709 static const uint8_t tlv_id_emailAddress[] = {
710 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01
711 };
712
713 return AVA(tlv_id_emailAddress, der::IA5String, value);
714 }
715
716 // RelativeDistinguishedName ::=
717 // SET SIZE (1..MAX) OF AttributeTypeAndValue
718 //
719 ByteString
RDN(const ByteString & avas)720 RDN(const ByteString& avas)
721 {
722 return TLV(der::SET, avas);
723 }
724
725 // Name ::= CHOICE { -- only one possibility for now --
726 // rdnSequence RDNSequence }
727 //
728 // RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
729 //
730 ByteString
Name(const ByteString & rdns)731 Name(const ByteString& rdns)
732 {
733 return TLV(der::SEQUENCE, rdns);
734 }
735
736 ByteString
CreateEncodedSerialNumber(long serialNumberValue)737 CreateEncodedSerialNumber(long serialNumberValue)
738 {
739 return Integer(serialNumberValue);
740 }
741
742 // BasicConstraints ::= SEQUENCE {
743 // cA BOOLEAN DEFAULT FALSE,
744 // pathLenConstraint INTEGER (0..MAX) OPTIONAL }
745 ByteString
CreateEncodedBasicConstraints(bool isCA,const long * pathLenConstraintValue,Critical critical)746 CreateEncodedBasicConstraints(bool isCA,
747 /*optional in*/ const long* pathLenConstraintValue,
748 Critical critical)
749 {
750 ByteString value;
751
752 if (isCA) {
753 ByteString cA(Boolean(true));
754 value.append(cA);
755 }
756
757 if (pathLenConstraintValue) {
758 ByteString pathLenConstraint(Integer(*pathLenConstraintValue));
759 value.append(pathLenConstraint);
760 }
761
762 // python DottedOIDToCode.py --tlv id-ce-basicConstraints 2.5.29.19
763 static const uint8_t tlv_id_ce_basicConstraints[] = {
764 0x06, 0x03, 0x55, 0x1d, 0x13
765 };
766 return Extension(Input(tlv_id_ce_basicConstraints), critical, value);
767 }
768
769 // ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
770 // KeyPurposeId ::= OBJECT IDENTIFIER
771 ByteString
CreateEncodedEKUExtension(Input ekuOID,Critical critical)772 CreateEncodedEKUExtension(Input ekuOID, Critical critical)
773 {
774 ByteString value(ekuOID.UnsafeGetData(), ekuOID.GetLength());
775
776 // python DottedOIDToCode.py --tlv id-ce-extKeyUsage 2.5.29.37
777 static const uint8_t tlv_id_ce_extKeyUsage[] = {
778 0x06, 0x03, 0x55, 0x1d, 0x25
779 };
780
781 return Extension(Input(tlv_id_ce_extKeyUsage), critical, value);
782 }
783
784 // python DottedOIDToCode.py --tlv id-ce-subjectAltName 2.5.29.17
785 static const uint8_t tlv_id_ce_subjectAltName[] = {
786 0x06, 0x03, 0x55, 0x1d, 0x11
787 };
788
789 ByteString
CreateEncodedSubjectAltName(const ByteString & names)790 CreateEncodedSubjectAltName(const ByteString& names)
791 {
792 return Extension(Input(tlv_id_ce_subjectAltName), Critical::No, names);
793 }
794
795 ByteString
CreateEncodedEmptySubjectAltName()796 CreateEncodedEmptySubjectAltName()
797 {
798 return EmptyExtension(Input(tlv_id_ce_subjectAltName), Critical::No);
799 }
800
801 ///////////////////////////////////////////////////////////////////////////////
802 // OCSP responses
803
804 ByteString
CreateEncodedOCSPResponse(OCSPResponseContext & context)805 CreateEncodedOCSPResponse(OCSPResponseContext& context)
806 {
807 if (!context.skipResponseBytes) {
808 if (!context.signerKeyPair) {
809 return ByteString();
810 }
811 }
812
813 // OCSPResponse ::= SEQUENCE {
814 // responseStatus OCSPResponseStatus,
815 // responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
816
817 // OCSPResponseStatus ::= ENUMERATED {
818 // successful (0), -- Response has valid confirmations
819 // malformedRequest (1), -- Illegal confirmation request
820 // internalError (2), -- Internal error in issuer
821 // tryLater (3), -- Try again later
822 // -- (4) is not used
823 // sigRequired (5), -- Must sign the request
824 // unauthorized (6) -- Request unauthorized
825 // }
826 ByteString reponseStatusValue;
827 reponseStatusValue.push_back(context.responseStatus);
828 ByteString responseStatus(TLV(der::ENUMERATED, reponseStatusValue));
829
830 ByteString responseBytesNested;
831 if (!context.skipResponseBytes) {
832 ByteString responseBytes(ResponseBytes(context));
833 if (ENCODING_FAILED(responseBytes)) {
834 return ByteString();
835 }
836
837 responseBytesNested = TLV(der::CONSTRUCTED | der::CONTEXT_SPECIFIC,
838 responseBytes);
839 }
840
841 ByteString value;
842 value.append(responseStatus);
843 value.append(responseBytesNested);
844 ByteString result(TLV(der::SEQUENCE, value));
845
846 MaybeLogOutput(result, "ocsp");
847
848 return result;
849 }
850
851 // ResponseBytes ::= SEQUENCE {
852 // responseType OBJECT IDENTIFIER,
853 // response OCTET STRING }
854 ByteString
ResponseBytes(OCSPResponseContext & context)855 ResponseBytes(OCSPResponseContext& context)
856 {
857 // Includes tag and length
858 static const uint8_t id_pkix_ocsp_basic_encoded[] = {
859 0x06, 0x09, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
860 };
861 ByteString response(BasicOCSPResponse(context));
862 if (ENCODING_FAILED(response)) {
863 return ByteString();
864 }
865 ByteString responseNested = TLV(der::OCTET_STRING, response);
866
867 ByteString value;
868 value.append(id_pkix_ocsp_basic_encoded,
869 sizeof(id_pkix_ocsp_basic_encoded));
870 value.append(responseNested);
871 return TLV(der::SEQUENCE, value);
872 }
873
874 // BasicOCSPResponse ::= SEQUENCE {
875 // tbsResponseData ResponseData,
876 // signatureAlgorithm AlgorithmIdentifier,
877 // signature BIT STRING,
878 // certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
879 ByteString
BasicOCSPResponse(OCSPResponseContext & context)880 BasicOCSPResponse(OCSPResponseContext& context)
881 {
882 ByteString tbsResponseData(ResponseData(context));
883 if (ENCODING_FAILED(tbsResponseData)) {
884 return ByteString();
885 }
886
887 return SignedData(tbsResponseData, *context.signerKeyPair,
888 context.signatureAlgorithm, context.badSignature,
889 context.certs);
890 }
891
892 // Extension ::= SEQUENCE {
893 // id OBJECT IDENTIFIER,
894 // critical BOOLEAN DEFAULT FALSE
895 // value OCTET STRING
896 // }
897 static ByteString
OCSPExtension(OCSPResponseExtension & extension)898 OCSPExtension(OCSPResponseExtension& extension)
899 {
900 ByteString encoded;
901 encoded.append(extension.id);
902 if (extension.critical) {
903 encoded.append(Boolean(true));
904 }
905 ByteString value(TLV(der::OCTET_STRING, extension.value));
906 encoded.append(value);
907 return TLV(der::SEQUENCE, encoded);
908 }
909
910 // Extensions ::= [1] {
911 // SEQUENCE OF Extension
912 // }
913 static ByteString
OCSPExtensions(OCSPResponseExtension * extensions)914 OCSPExtensions(OCSPResponseExtension* extensions)
915 {
916 ByteString value;
917 for (OCSPResponseExtension* extension = extensions;
918 extension; extension = extension->next) {
919 ByteString extensionEncoded(OCSPExtension(*extension));
920 if (ENCODING_FAILED(extensionEncoded)) {
921 return ByteString();
922 }
923 value.append(extensionEncoded);
924 }
925 ByteString sequence(TLV(der::SEQUENCE, value));
926 return TLV(der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 1, sequence);
927 }
928
929 // ResponseData ::= SEQUENCE {
930 // version [0] EXPLICIT Version DEFAULT v1,
931 // responderID ResponderID,
932 // producedAt GeneralizedTime,
933 // responses SEQUENCE OF SingleResponse,
934 // responseExtensions [1] EXPLICIT Extensions OPTIONAL }
935 ByteString
ResponseData(OCSPResponseContext & context)936 ResponseData(OCSPResponseContext& context)
937 {
938 ByteString responderID(ResponderID(context));
939 if (ENCODING_FAILED(responderID)) {
940 return ByteString();
941 }
942 ByteString producedAtEncoded(TimeToGeneralizedTime(context.producedAt));
943 if (ENCODING_FAILED(producedAtEncoded)) {
944 return ByteString();
945 }
946 ByteString response(SingleResponse(context));
947 if (ENCODING_FAILED(response)) {
948 return ByteString();
949 }
950 ByteString responses(TLV(der::SEQUENCE, response));
951 ByteString responseExtensions;
952 if (context.responseExtensions || context.includeEmptyExtensions) {
953 responseExtensions = OCSPExtensions(context.responseExtensions);
954 }
955
956 ByteString value;
957 value.append(responderID);
958 value.append(producedAtEncoded);
959 value.append(responses);
960 value.append(responseExtensions);
961 return TLV(der::SEQUENCE, value);
962 }
963
964 // ResponderID ::= CHOICE {
965 // byName [1] Name,
966 // byKey [2] KeyHash }
967 // }
968 ByteString
ResponderID(OCSPResponseContext & context)969 ResponderID(OCSPResponseContext& context)
970 {
971 ByteString contents;
972 uint8_t responderIDType;
973 if (!context.signerNameDER.empty()) {
974 contents = context.signerNameDER;
975 responderIDType = 1; // byName
976 } else {
977 contents = KeyHash(context.signerKeyPair->subjectPublicKey);
978 if (ENCODING_FAILED(contents)) {
979 return ByteString();
980 }
981 responderIDType = 2; // byKey
982 }
983
984 // XXX: MSVC 2015 wrongly warns about signed/unsigned conversion without the
985 // static_cast.
986 uint8_t tag = static_cast<uint8_t>(der::CONSTRUCTED | der::CONTEXT_SPECIFIC |
987 responderIDType);
988 return TLV(tag, contents);
989 }
990
991 // KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
992 // -- (i.e., the SHA-1 hash of the value of the
993 // -- BIT STRING subjectPublicKey [excluding
994 // -- the tag, length, and number of unused
995 // -- bits] in the responder's certificate)
996 ByteString
KeyHash(const ByteString & subjectPublicKey)997 KeyHash(const ByteString& subjectPublicKey)
998 {
999 return HashedOctetString(subjectPublicKey, DigestAlgorithm::sha1);
1000 }
1001
1002 // SingleResponse ::= SEQUENCE {
1003 // certID CertID,
1004 // certStatus CertStatus,
1005 // thisUpdate GeneralizedTime,
1006 // nextUpdate [0] EXPLICIT GeneralizedTime OPTIONAL,
1007 // singleExtensions [1] EXPLICIT Extensions OPTIONAL }
1008 ByteString
SingleResponse(OCSPResponseContext & context)1009 SingleResponse(OCSPResponseContext& context)
1010 {
1011 ByteString certID(CertID(context));
1012 if (ENCODING_FAILED(certID)) {
1013 return ByteString();
1014 }
1015 ByteString certStatus(CertStatus(context));
1016 if (ENCODING_FAILED(certStatus)) {
1017 return ByteString();
1018 }
1019 ByteString thisUpdateEncoded(TimeToGeneralizedTime(context.thisUpdate));
1020 if (ENCODING_FAILED(thisUpdateEncoded)) {
1021 return ByteString();
1022 }
1023 ByteString nextUpdateEncodedNested;
1024 if (context.includeNextUpdate) {
1025 ByteString nextUpdateEncoded(TimeToGeneralizedTime(context.nextUpdate));
1026 if (ENCODING_FAILED(nextUpdateEncoded)) {
1027 return ByteString();
1028 }
1029 nextUpdateEncodedNested = TLV(der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0,
1030 nextUpdateEncoded);
1031 }
1032 ByteString singleExtensions;
1033 if (context.singleExtensions || context.includeEmptyExtensions) {
1034 singleExtensions = OCSPExtensions(context.singleExtensions);
1035 }
1036
1037 ByteString value;
1038 value.append(certID);
1039 value.append(certStatus);
1040 value.append(thisUpdateEncoded);
1041 value.append(nextUpdateEncodedNested);
1042 value.append(singleExtensions);
1043 return TLV(der::SEQUENCE, value);
1044 }
1045
1046 // CertID ::= SEQUENCE {
1047 // hashAlgorithm AlgorithmIdentifier,
1048 // issuerNameHash OCTET STRING, -- Hash of issuer's DN
1049 // issuerKeyHash OCTET STRING, -- Hash of issuer's public key
1050 // serialNumber CertificateSerialNumber }
1051 ByteString
CertID(OCSPResponseContext & context)1052 CertID(OCSPResponseContext& context)
1053 {
1054 ByteString issuerName(context.certID.issuer.UnsafeGetData(),
1055 context.certID.issuer.GetLength());
1056 ByteString issuerNameHash(HashedOctetString(issuerName, context.certIDHashAlgorithm));
1057 if (ENCODING_FAILED(issuerNameHash)) {
1058 return ByteString();
1059 }
1060
1061 ByteString issuerKeyHash;
1062 {
1063 // context.certID.issuerSubjectPublicKeyInfo is the entire
1064 // SubjectPublicKeyInfo structure, but we need just the subjectPublicKey
1065 // part.
1066 Reader input(context.certID.issuerSubjectPublicKeyInfo);
1067 Reader contents;
1068 if (der::ExpectTagAndGetValue(input, der::SEQUENCE, contents) != Success) {
1069 return ByteString();
1070 }
1071 // Skip AlgorithmIdentifier
1072 if (der::ExpectTagAndSkipValue(contents, der::SEQUENCE) != Success) {
1073 return ByteString();
1074 }
1075 Input subjectPublicKey;
1076 if (der::BitStringWithNoUnusedBits(contents, subjectPublicKey)
1077 != Success) {
1078 return ByteString();
1079 }
1080 issuerKeyHash = HashedOctetString(ByteString(subjectPublicKey.UnsafeGetData(),
1081 subjectPublicKey.GetLength()), context.certIDHashAlgorithm);
1082 if (ENCODING_FAILED(issuerKeyHash)) {
1083 return ByteString();
1084 }
1085 }
1086
1087 ByteString serialNumberValue(context.certID.serialNumber.UnsafeGetData(),
1088 context.certID.serialNumber.GetLength());
1089 ByteString serialNumber(TLV(der::INTEGER, serialNumberValue));
1090
1091 // python DottedOIDToCode.py --alg id-sha1 1.3.14.3.2.26
1092 static const uint8_t alg_id_sha1[] = {
1093 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a
1094 };
1095 // python DottedOIDToCode.py --alg id-sha256 2.16.840.1.101.3.4.2.1
1096 static const uint8_t alg_id_sha256[] = {
1097 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
1098 };
1099 // python DottedOIDToCode.py --alg id-sha384 2.16.840.1.101.3.4.2.2
1100 static const uint8_t alg_id_sha384[] = {
1101 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
1102 };
1103 // python DottedOIDToCode.py --alg id-sha512 2.16.840.1.101.3.4.2.3
1104 static const uint8_t alg_id_sha512[] = {
1105 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
1106 };
1107
1108 ByteString value;
1109 if (!context.certIDHashAlgorithmEncoded.empty()) {
1110 value.append(context.certIDHashAlgorithmEncoded);
1111 } else {
1112 switch (context.certIDHashAlgorithm) {
1113 case DigestAlgorithm::sha1:
1114 value.append(alg_id_sha1, sizeof(alg_id_sha1));
1115 break;
1116 case DigestAlgorithm::sha256:
1117 value.append(alg_id_sha256, sizeof(alg_id_sha256));
1118 break;
1119 case DigestAlgorithm::sha384:
1120 value.append(alg_id_sha384, sizeof(alg_id_sha384));
1121 break;
1122 case DigestAlgorithm::sha512:
1123 value.append(alg_id_sha512, sizeof(alg_id_sha512));
1124 break;
1125 MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
1126 }
1127 }
1128 value.append(issuerNameHash);
1129 value.append(issuerKeyHash);
1130 value.append(serialNumber);
1131 return TLV(der::SEQUENCE, value);
1132 }
1133
1134 // CertStatus ::= CHOICE {
1135 // good [0] IMPLICIT NULL,
1136 // revoked [1] IMPLICIT RevokedInfo,
1137 // unknown [2] IMPLICIT UnknownInfo }
1138 //
1139 // RevokedInfo ::= SEQUENCE {
1140 // revocationTime GeneralizedTime,
1141 // revocationReason [0] EXPLICIT CRLReason OPTIONAL }
1142 //
1143 // UnknownInfo ::= NULL
1144 //
1145 ByteString
CertStatus(OCSPResponseContext & context)1146 CertStatus(OCSPResponseContext& context)
1147 {
1148 switch (context.certStatus) {
1149 // Both good and unknown are ultimately represented as NULL - the only
1150 // difference is in the tag that identifies them.
1151 case 0:
1152 case 2:
1153 {
1154 // XXX: MSVC 2015 wrongly warns about signed/unsigned conversion without
1155 // the static cast.
1156 return TLV(static_cast<uint8_t>(der::CONTEXT_SPECIFIC |
1157 context.certStatus), ByteString());
1158 }
1159 case 1:
1160 {
1161 ByteString revocationTime(TimeToGeneralizedTime(context.revocationTime));
1162 if (ENCODING_FAILED(revocationTime)) {
1163 return ByteString();
1164 }
1165 // TODO(bug 980536): add support for revocationReason
1166 return TLV(der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1, revocationTime);
1167 }
1168 default:
1169 assert(false);
1170 // fall through
1171 }
1172 return ByteString();
1173 }
1174
1175 static const ByteString NO_UNUSED_BITS(1, 0x00);
1176
1177 // The SubjectPublicKeyInfo syntax is specified in RFC 5280 Section 4.1.
TestKeyPair(const TestPublicKeyAlgorithm & aPublicKeyAlg,const ByteString & spk)1178 TestKeyPair::TestKeyPair(const TestPublicKeyAlgorithm& aPublicKeyAlg,
1179 const ByteString& spk)
1180 : publicKeyAlg(aPublicKeyAlg)
1181 , subjectPublicKeyInfo(TLV(der::SEQUENCE,
1182 aPublicKeyAlg.algorithmIdentifier +
1183 TLV(der::BIT_STRING, NO_UNUSED_BITS + spk)))
1184 , subjectPublicKey(spk)
1185 {
1186 }
1187
1188 } } } // namespace mozilla::pkix::test
1189