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 <cert.h> // Must be included before certdb.h
15 #include "base/debug/leak_annotations.h"
16 #include "base/logging.h"
17 #include "base/memory/scoped_ptr.h"
18 #include "base/memory/singleton.h"
19 #include "base/pickle.h"
20 #include "base/strings/stringprintf.h"
21 #include "crypto/ec_private_key.h"
22 #include "crypto/nss_util.h"
23 #include "crypto/nss_util_internal.h"
24 #include "crypto/rsa_private_key.h"
25 #include "crypto/scoped_nss_types.h"
26 #include "crypto/third_party/nss/chromium-nss.h"
27 #include "net/cert/x509_certificate.h"
28 #include "net/cert/x509_util.h"
29 #include "net/cert/x509_util_nss.h"
35 // Callback for CERT_DecodeCertPackage(), used in
36 // CreateOSCertHandlesFromBytes().
38 CollectCertsCallback(void* arg
, SECItem
** certs
, int num_certs
) {
39 X509Certificate::OSCertHandles
* results
=
40 reinterpret_cast<X509Certificate::OSCertHandles
*>(arg
);
42 for (int i
= 0; i
< num_certs
; ++i
) {
43 X509Certificate::OSCertHandle handle
=
44 X509Certificate::CreateOSCertHandleFromBytes(
45 reinterpret_cast<char*>(certs
[i
]->data
), certs
[i
]->len
);
47 results
->push_back(handle
);
53 typedef scoped_ptr
<CERTName
, crypto::NSSDestroyer
<CERTName
, CERT_DestroyName
>>
56 // Create a new CERTName object from its encoded representation.
57 // |arena| is the allocation pool to use.
58 // |data| points to a DER-encoded X.509 DistinguishedName.
59 // Return a new CERTName pointer on success, or NULL.
60 CERTName
* CreateCertNameFromEncoded(PLArenaPool
* arena
,
61 const base::StringPiece
& data
) {
65 ScopedCERTName
name(PORT_ArenaZNew(arena
, CERTName
));
70 item
.len
= static_cast<unsigned int>(data
.length());
71 item
.data
= reinterpret_cast<unsigned char*>(const_cast<char*>(data
.data()));
73 SECStatus rv
= SEC_ASN1DecodeItem(arena
, name
.get(),
74 SEC_ASN1_GET(CERT_NameTemplate
), &item
);
78 return name
.release();
85 void ParsePrincipal(CERTName
* name
, CertPrincipal
* principal
) {
86 // Starting in NSS 3.15, CERTGetNameFunc takes a const CERTName* argument.
88 typedef char* (*CERTGetNameFunc
)(const CERTName
* name
);
90 typedef char* (*CERTGetNameFunc
)(CERTName
* name
);
93 // TODO(jcampan): add business_category and serial_number.
94 // TODO(wtc): NSS has the CERT_GetOrgName, CERT_GetOrgUnitName, and
95 // CERT_GetDomainComponentName functions, but they return only the most
96 // general (the first) RDN. NSS doesn't have a function for the street
98 static const SECOidTag kOIDs
[] = {SEC_OID_AVA_STREET_ADDRESS
,
99 SEC_OID_AVA_ORGANIZATION_NAME
,
100 SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME
,
103 std::vector
<std::string
>* values
[] = {&principal
->street_addresses
,
104 &principal
->organization_names
,
105 &principal
->organization_unit_names
,
106 &principal
->domain_components
};
107 DCHECK_EQ(arraysize(kOIDs
), arraysize(values
));
109 CERTRDN
** rdns
= name
->rdns
;
110 for (size_t rdn
= 0; rdns
[rdn
]; ++rdn
) {
111 CERTAVA
** avas
= rdns
[rdn
]->avas
;
112 for (size_t pair
= 0; avas
[pair
] != 0; ++pair
) {
113 SECOidTag tag
= CERT_GetAVATag(avas
[pair
]);
114 for (size_t oid
= 0; oid
< arraysize(kOIDs
); ++oid
) {
115 if (kOIDs
[oid
] == tag
) {
116 SECItem
* decode_item
= CERT_DecodeAVAValue(&avas
[pair
]->value
);
119 // TODO(wtc): Pass decode_item to CERT_RFC1485_EscapeAndQuote.
120 std::string
value(reinterpret_cast<char*>(decode_item
->data
),
122 values
[oid
]->push_back(value
);
123 SECITEM_FreeItem(decode_item
, PR_TRUE
);
130 // Get CN, L, S, and C.
131 CERTGetNameFunc get_name_funcs
[4] = {CERT_GetCommonName
,
132 CERT_GetLocalityName
,
134 CERT_GetCountryName
};
135 std::string
* single_values
[4] = {&principal
->common_name
,
136 &principal
->locality_name
,
137 &principal
->state_or_province_name
,
138 &principal
->country_name
};
139 for (size_t i
= 0; i
< arraysize(get_name_funcs
); ++i
) {
140 char* value
= get_name_funcs
[i
](name
);
142 single_values
[i
]->assign(value
);
148 void ParseDate(const SECItem
* der_date
, base::Time
* result
) {
150 SECStatus rv
= DER_DecodeTimeChoice(&prtime
, der_date
);
151 DCHECK_EQ(SECSuccess
, rv
);
152 *result
= crypto::PRTimeToBaseTime(prtime
);
155 std::string
ParseSerialNumber(const CERTCertificate
* certificate
) {
156 return std::string(reinterpret_cast<char*>(certificate
->serialNumber
.data
),
157 certificate
->serialNumber
.len
);
160 void GetSubjectAltName(CERTCertificate
* cert_handle
,
161 std::vector
<std::string
>* dns_names
,
162 std::vector
<std::string
>* ip_addrs
) {
169 SECStatus rv
= CERT_FindCertExtension(
170 cert_handle
, SEC_OID_X509_SUBJECT_ALT_NAME
, &alt_name
);
171 if (rv
!= SECSuccess
)
174 PLArenaPool
* arena
= PORT_NewArena(DER_DEFAULT_CHUNKSIZE
);
175 DCHECK(arena
!= NULL
);
177 CERTGeneralName
* alt_name_list
;
178 alt_name_list
= CERT_DecodeAltNameExtension(arena
, &alt_name
);
179 SECITEM_FreeItem(&alt_name
, PR_FALSE
);
181 CERTGeneralName
* name
= alt_name_list
;
183 // DNSName and IPAddress are encoded as IA5String and OCTET STRINGs
184 // respectively, both of which can be byte copied from
185 // SECItemType::data into the appropriate output vector.
186 if (dns_names
&& name
->type
== certDNSName
) {
187 dns_names
->push_back(
188 std::string(reinterpret_cast<char*>(name
->name
.other
.data
),
189 name
->name
.other
.len
));
190 } else if (ip_addrs
&& name
->type
== certIPAddress
) {
192 std::string(reinterpret_cast<char*>(name
->name
.other
.data
),
193 name
->name
.other
.len
));
195 name
= CERT_GetNextGeneralName(name
);
196 if (name
== alt_name_list
)
199 PORT_FreeArena(arena
, PR_FALSE
);
202 X509Certificate::OSCertHandles
CreateOSCertHandlesFromBytes(
205 X509Certificate::Format format
) {
206 X509Certificate::OSCertHandles results
;
210 crypto::EnsureNSSInit();
212 if (!NSS_IsInitialized())
216 case X509Certificate::FORMAT_SINGLE_CERTIFICATE
: {
217 X509Certificate::OSCertHandle handle
=
218 X509Certificate::CreateOSCertHandleFromBytes(data
, length
);
220 results
.push_back(handle
);
223 case X509Certificate::FORMAT_PKCS7
: {
224 // Make a copy since CERT_DecodeCertPackage may modify it
225 std::vector
<char> data_copy(data
, data
+ length
);
227 SECStatus result
= CERT_DecodeCertPackage(&data_copy
[0], length
,
228 CollectCertsCallback
, &results
);
229 if (result
!= SECSuccess
)
234 NOTREACHED() << "Certificate format " << format
<< " unimplemented";
241 X509Certificate::OSCertHandle
ReadOSCertHandleFromPickle(
242 base::PickleIterator
* pickle_iter
) {
245 if (!pickle_iter
->ReadData(&data
, &length
))
248 return X509Certificate::CreateOSCertHandleFromBytes(data
, length
);
251 void GetPublicKeyInfo(CERTCertificate
* handle
,
253 X509Certificate::PublicKeyType
* type
) {
254 // Since we might fail, set the output parameters to default values first.
255 *type
= X509Certificate::kPublicKeyTypeUnknown
;
258 crypto::ScopedSECKEYPublicKey
key(CERT_ExtractPublicKey(handle
));
262 *size_bits
= SECKEY_PublicKeyStrengthInBits(key
.get());
264 switch (key
->keyType
) {
266 *type
= X509Certificate::kPublicKeyTypeRSA
;
269 *type
= X509Certificate::kPublicKeyTypeDSA
;
272 *type
= X509Certificate::kPublicKeyTypeDH
;
275 *type
= X509Certificate::kPublicKeyTypeECDSA
;
278 *type
= X509Certificate::kPublicKeyTypeUnknown
;
284 bool GetIssuersFromEncodedList(const std::vector
<std::string
>& encoded_issuers
,
286 std::vector
<CERTName
*>* out
) {
287 std::vector
<CERTName
*> result
;
288 for (size_t n
= 0; n
< encoded_issuers
.size(); ++n
) {
289 CERTName
* name
= CreateCertNameFromEncoded(arena
, encoded_issuers
[n
]);
291 result
.push_back(name
);
294 if (result
.size() == encoded_issuers
.size()) {
299 for (size_t n
= 0; n
< result
.size(); ++n
)
300 CERT_DestroyName(result
[n
]);
304 bool IsCertificateIssuedBy(const std::vector
<CERTCertificate
*>& cert_chain
,
305 const std::vector
<CERTName
*>& valid_issuers
) {
306 for (size_t n
= 0; n
< cert_chain
.size(); ++n
) {
307 CERTName
* cert_issuer
= &cert_chain
[n
]->issuer
;
308 for (size_t i
= 0; i
< valid_issuers
.size(); ++i
) {
309 if (CERT_CompareName(valid_issuers
[i
], cert_issuer
) == SECEqual
)
316 std::string
GetUniqueNicknameForSlot(const std::string
& nickname
,
317 const SECItem
* subject
,
318 PK11SlotInfo
* slot
) {
320 std::string new_name
= nickname
;
321 std::string temp_nickname
= new_name
;
322 std::string token_name
;
327 if (!PK11_IsInternalKeySlot(slot
)) {
328 token_name
.assign(PK11_GetTokenName(slot
));
329 token_name
.append(":");
331 temp_nickname
= token_name
+ new_name
;
334 while (SEC_CertNicknameConflict(temp_nickname
.c_str(),
335 const_cast<SECItem
*>(subject
),
336 CERT_GetDefaultCertDB())) {
337 base::SStringPrintf(&new_name
, "%s #%d", nickname
.c_str(), index
++);
338 temp_nickname
= token_name
+ new_name
;
344 } // namespace x509_util