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