1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/cert/internal/parse_certificate.h"
7 #include "base/strings/stringprintf.h"
8 #include "net/cert/internal/test_helpers.h"
9 #include "net/der/input.h"
10 #include "testing/gtest/include/gtest/gtest.h"
16 // Pretty-prints a GeneralizedTime as a human-readable string for use in test
17 // expectations (it is more readable to specify the expected results as a
19 std::string
ToString(const der::GeneralizedTime
& time
) {
20 return base::StringPrintf(
21 "year=%d, month=%d, day=%d, hours=%d, minutes=%d, seconds=%d", time
.year
,
22 time
.month
, time
.day
, time
.hours
, time
.minutes
, time
.seconds
);
25 std::string
GetFilePath(const std::string file_name
) {
26 return std::string("net/data/parse_certificate_unittest/") + file_name
;
29 // Loads certificate data and expectations from the PEM file |file_name|.
30 // Verifies that parsing the Certificate succeeds, and each parsed field matches
32 void EnsureParsingCertificateSucceeds(const std::string
& file_name
) {
34 std::string expected_tbs_certificate
;
35 std::string expected_signature_algorithm
;
36 std::string expected_signature
;
38 // Read the certificate data and test expectations from a single PEM file.
39 const PemBlockMapping mappings
[] = {
40 {"CERTIFICATE", &data
},
41 {"SIGNATURE", &expected_signature
},
42 {"SIGNATURE ALGORITHM", &expected_signature_algorithm
},
43 {"TBS CERTIFICATE", &expected_tbs_certificate
},
45 ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name
), mappings
));
47 // Parsing the certificate should succeed.
48 ParsedCertificate parsed
;
49 ASSERT_TRUE(ParseCertificate(InputFromString(&data
), &parsed
));
51 // Ensure that the ParsedCertificate matches expectations.
52 EXPECT_EQ(0, parsed
.signature_value
.unused_bits());
53 EXPECT_EQ(InputFromString(&expected_signature
),
54 parsed
.signature_value
.bytes());
55 EXPECT_EQ(InputFromString(&expected_signature_algorithm
),
56 parsed
.signature_algorithm_tlv
);
57 EXPECT_EQ(InputFromString(&expected_tbs_certificate
),
58 parsed
.tbs_certificate_tlv
);
61 // Loads certificate data from the PEM file |file_name| and verifies that the
62 // Certificate parsing fails.
63 void EnsureParsingCertificateFails(const std::string
& file_name
) {
66 const PemBlockMapping mappings
[] = {
67 {"CERTIFICATE", &data
},
70 ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name
), mappings
));
72 // Parsing the Certificate should fail.
73 ParsedCertificate parsed
;
74 ASSERT_FALSE(ParseCertificate(InputFromString(&data
), &parsed
));
77 // Tests parsing a Certificate.
78 TEST(ParseCertificateTest
, Version3
) {
79 EnsureParsingCertificateSucceeds("cert_version3.pem");
82 // Tests parsing a simplified Certificate-like structure (the sub-fields for
83 // algorithm and tbsCertificate are not actually valid, but ParseCertificate()
84 // doesn't check them)
85 TEST(ParseCertificateTest
, Skeleton
) {
86 EnsureParsingCertificateSucceeds("cert_skeleton.pem");
89 // Tests parsing a Certificate that is not a sequence fails.
90 TEST(ParseCertificateTest
, NotSequence
) {
91 EnsureParsingCertificateFails("cert_not_sequence.pem");
94 // Tests that uncomsumed data is not allowed after the main SEQUENCE.
95 TEST(ParseCertificateTest
, DataAfterSignature
) {
96 EnsureParsingCertificateFails("cert_data_after_signature.pem");
99 // Tests that parsing fails if the signature BIT STRING is missing.
100 TEST(ParseCertificateTest
, MissingSignature
) {
101 EnsureParsingCertificateFails("cert_missing_signature.pem");
104 // Tests that parsing fails if the signature is present but not a BIT STRING.
105 TEST(ParseCertificateTest
, SignatureNotBitString
) {
106 EnsureParsingCertificateFails("cert_signature_not_bit_string.pem");
109 // Tests that parsing fails if the main SEQUENCE is empty (missing all the
111 TEST(ParseCertificateTest
, EmptySequence
) {
112 EnsureParsingCertificateFails("cert_empty_sequence.pem");
115 // Tests what happens when the signature algorithm is present, but has the wrong
117 TEST(ParseCertificateTest
, AlgorithmNotSequence
) {
118 EnsureParsingCertificateFails("cert_algorithm_not_sequence.pem");
121 // Loads tbsCertificate data and expectations from the PEM file |file_name|.
122 // Verifies that parsing the TBSCertificate succeeds, and each parsed field
123 // matches the expectations.
124 void EnsureParsingTbsSucceeds(const std::string
& file_name
,
125 CertificateVersion expected_version
) {
127 std::string expected_serial_number
;
128 std::string expected_signature_algorithm
;
129 std::string expected_issuer
;
130 std::string expected_validity_not_before
;
131 std::string expected_validity_not_after
;
132 std::string expected_subject
;
133 std::string expected_spki
;
134 std::string expected_issuer_unique_id
;
135 std::string expected_subject_unique_id
;
136 std::string expected_extensions
;
138 // Read the certificate data and test expectations from a single PEM file.
139 const PemBlockMapping mappings
[] = {
140 {"TBS CERTIFICATE", &data
},
141 {"SIGNATURE ALGORITHM", &expected_signature_algorithm
},
142 {"SERIAL NUMBER", &expected_serial_number
},
143 {"ISSUER", &expected_issuer
},
144 {"VALIDITY NOTBEFORE", &expected_validity_not_before
},
145 {"VALIDITY NOTAFTER", &expected_validity_not_after
},
146 {"SUBJECT", &expected_subject
},
147 {"SPKI", &expected_spki
},
148 {"ISSUER UNIQUE ID", &expected_issuer_unique_id
, true},
149 {"SUBJECT UNIQUE ID", &expected_subject_unique_id
, true},
150 {"EXTENSIONS", &expected_extensions
, true},
152 ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name
), mappings
));
154 // Parsing the TBSCertificate should succeed.
155 ParsedTbsCertificate parsed
;
156 ASSERT_TRUE(ParseTbsCertificate(InputFromString(&data
), &parsed
));
158 // Ensure that the ParsedTbsCertificate matches expectations.
159 EXPECT_EQ(expected_version
, parsed
.version
);
161 EXPECT_EQ(InputFromString(&expected_serial_number
), parsed
.serial_number
);
162 EXPECT_EQ(InputFromString(&expected_signature_algorithm
),
163 parsed
.signature_algorithm_tlv
);
165 EXPECT_EQ(InputFromString(&expected_issuer
), parsed
.issuer_tlv
);
167 // In the test expectations PEM file, validity is described as a
168 // textual string of the parsed value (rather than as DER).
169 EXPECT_EQ(expected_validity_not_before
, ToString(parsed
.validity_not_before
));
170 EXPECT_EQ(expected_validity_not_after
, ToString(parsed
.validity_not_after
));
172 EXPECT_EQ(InputFromString(&expected_subject
), parsed
.subject_tlv
);
173 EXPECT_EQ(InputFromString(&expected_spki
), parsed
.spki_tlv
);
175 EXPECT_EQ(InputFromString(&expected_issuer_unique_id
),
176 parsed
.issuer_unique_id
.bytes());
177 EXPECT_EQ(!expected_issuer_unique_id
.empty(), parsed
.has_issuer_unique_id
);
178 EXPECT_EQ(InputFromString(&expected_subject_unique_id
),
179 parsed
.subject_unique_id
.bytes());
180 EXPECT_EQ(!expected_subject_unique_id
.empty(), parsed
.has_subject_unique_id
);
182 EXPECT_EQ(InputFromString(&expected_extensions
), parsed
.extensions_tlv
);
183 EXPECT_EQ(!expected_extensions
.empty(), parsed
.has_extensions
);
186 // Loads certificate data from the PEM file |file_name| and verifies that the
187 // Certificate parsing succeed, however the TBSCertificate parsing fails.
188 void EnsureParsingTbsFails(const std::string
& file_name
) {
191 const PemBlockMapping mappings
[] = {
192 {"TBS CERTIFICATE", &data
},
195 ASSERT_TRUE(ReadTestDataFromPemFile(GetFilePath(file_name
), mappings
));
197 // Parsing the TBSCertificate should fail.
198 ParsedTbsCertificate parsed
;
199 ASSERT_FALSE(ParseTbsCertificate(InputFromString(&data
), &parsed
));
202 // Tests parsing a TBSCertificate for v3 that contains no optional fields.
203 TEST(ParseTbsCertificateTest
, Version3NoOptionals
) {
204 EnsureParsingTbsSucceeds("tbs_v3_no_optionals.pem", CertificateVersion::V3
);
207 // Tests parsing a TBSCertificate for v3 that contains extensions.
208 TEST(ParseTbsCertificateTest
, Version3WithExtensions
) {
209 EnsureParsingTbsSucceeds("tbs_v3_extensions.pem", CertificateVersion::V3
);
212 // Tests parsing a TBSCertificate for v3 that contains no optional fields, and
213 // has a negative serial number.
215 // CAs are not supposed to include negative serial numbers, however RFC 5280
216 // expects consumers to deal with it anyway).
217 TEST(ParseTbsCertificateTest
, NegativeSerialNumber
) {
218 EnsureParsingTbsSucceeds("tbs_negative_serial_number.pem",
219 CertificateVersion::V3
);
222 // Tests parsing a TBSCertificate with a serial number that is 21 octets long
223 // (and the first byte is 0).
224 TEST(ParseTbCertificateTest
, SerialNumber21OctetsLeading0
) {
225 EnsureParsingTbsFails("tbs_serial_number_21_octets_leading_0.pem");
228 // Tests parsing a TBSCertificate with a serial number that is 26 octets long
229 // (and does not contain a leading 0).
230 TEST(ParseTbsCertificateTest
, SerialNumber26Octets
) {
231 EnsureParsingTbsFails("tbs_serial_number_26_octets.pem");
234 // Tests parsing a TBSCertificate which lacks a version number (causing it to
236 TEST(ParseTbsCertificateTest
, Version1
) {
237 EnsureParsingTbsSucceeds("tbs_v1.pem", CertificateVersion::V1
);
240 // The version was set to v1 explicitly rather than omitting the version field.
241 TEST(ParseTbsCertificateTest
, ExplicitVersion1
) {
242 EnsureParsingTbsFails("tbs_explicit_v1.pem");
245 // Extensions are not defined in version 1.
246 TEST(ParseTbsCertificateTest
, Version1WithExtensions
) {
247 EnsureParsingTbsFails("tbs_v1_extensions.pem");
250 // Extensions are not defined in version 2.
251 TEST(ParseTbsCertificateTest
, Version2WithExtensions
) {
252 EnsureParsingTbsFails("tbs_v2_extensions.pem");
255 // A boring version 2 certificate with none of the optional fields.
256 TEST(ParseTbsCertificateTest
, Version2NoOptionals
) {
257 EnsureParsingTbsSucceeds("tbs_v2_no_optionals.pem", CertificateVersion::V2
);
260 // A version 2 certificate with an issuer unique ID field.
261 TEST(ParseTbsCertificateTest
, Version2IssuerUniqueId
) {
262 EnsureParsingTbsSucceeds("tbs_v2_issuer_unique_id.pem",
263 CertificateVersion::V2
);
266 // A version 2 certificate with both a issuer and subject unique ID field.
267 TEST(ParseTbsCertificateTest
, Version2IssuerAndSubjectUniqueId
) {
268 EnsureParsingTbsSucceeds("tbs_v2_issuer_and_subject_unique_id.pem",
269 CertificateVersion::V2
);
272 // A version 3 certificate with all of the optional fields (issuer unique id,
273 // subject unique id, and extensions).
274 TEST(ParseTbsCertificateTest
, Version3AllOptionals
) {
275 EnsureParsingTbsSucceeds("tbs_v3_all_optionals.pem", CertificateVersion::V3
);
278 // The version was set to v4, which is unrecognized.
279 TEST(ParseTbsCertificateTest
, Version4
) {
280 EnsureParsingTbsFails("tbs_v4.pem");
283 // Tests that extraneous data after extensions in a v3 is rejected.
284 TEST(ParseTbsCertificateTest
, Version3DataAfterExtensions
) {
285 EnsureParsingTbsFails("tbs_v3_data_after_extensions.pem");
288 // Tests using a real-world certificate (whereas the other tests are fabricated
289 // (and in fact invalid) data.
290 TEST(ParseTbsCertificateTest
, Version3Real
) {
291 EnsureParsingTbsSucceeds("tbs_v3_real.pem", CertificateVersion::V3
);
294 // Parses a TBSCertificate whose "validity" field expresses both notBefore
295 // and notAfter using UTCTime.
296 TEST(ParseTbsCertificateTest
, ValidityBothUtcTime
) {
297 EnsureParsingTbsSucceeds("tbs_validity_both_utc_time.pem",
298 CertificateVersion::V3
);
301 // Parses a TBSCertificate whose "validity" field expresses both notBefore
302 // and notAfter using GeneralizedTime.
303 TEST(ParseTbsCertificateTest
, ValidityBothGeneralizedTime
) {
304 EnsureParsingTbsSucceeds("tbs_validity_both_generalized_time.pem",
305 CertificateVersion::V3
);
308 // Parses a TBSCertificate whose "validity" field expresses notBefore using
309 // UTCTime and notAfter using GeneralizedTime.
310 TEST(ParseTbsCertificateTest
, ValidityUTCTimeAndGeneralizedTime
) {
311 EnsureParsingTbsSucceeds("tbs_validity_utc_time_and_generalized_time.pem",
312 CertificateVersion::V3
);
315 // Parses a TBSCertificate whose validity" field expresses notBefore using
316 // GeneralizedTime and notAfter using UTCTime. Also of interest, notBefore >
317 // notAfter. Parsing will succeed, however no time can satisfy this constraint.
318 TEST(ParseTbsCertificateTest
, ValidityGeneralizedTimeAndUTCTime
) {
319 EnsureParsingTbsSucceeds("tbs_validity_generalized_time_and_utc_time.pem",
320 CertificateVersion::V3
);
323 // Parses a TBSCertificate whose "validity" field does not strictly follow
324 // the DER rules (and fails to be parsed).
325 TEST(ParseTbsCertificateTest
, ValidityRelaxed
) {
326 EnsureParsingTbsFails("tbs_validity_relaxed.pem");