1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/cert/x509_util_nss.h"
6
7 #include <cert.h> // Must be included before certdb.h
8 #include <certdb.h>
9 #include <cryptohi.h>
10 #include <dlfcn.h>
11 #include <nss.h>
12 #include <pk11pub.h>
13 #include <prerror.h>
14 #include <seccomon.h>
15 #include <secder.h>
16 #include <sechash.h>
17 #include <secmod.h>
18 #include <secport.h>
19 #include <string.h>
20
21 #include "base/logging.h"
22 #include "base/strings/stringprintf.h"
23 #include "crypto/nss_util.h"
24 #include "crypto/scoped_nss_types.h"
25 #include "net/cert/x509_util.h"
26 #include "net/third_party/mozilla_security_manager/nsNSSCertificateDB.h"
27 #include "third_party/boringssl/src/include/openssl/pool.h"
28
29 namespace net::x509_util {
30
31 namespace {
32
33 // Microsoft User Principal Name: 1.3.6.1.4.1.311.20.2.3
34 const uint8_t kUpnOid[] = {0x2b, 0x6, 0x1, 0x4, 0x1,
35 0x82, 0x37, 0x14, 0x2, 0x3};
36
DecodeAVAValue(CERTAVA * ava)37 std::string DecodeAVAValue(CERTAVA* ava) {
38 SECItem* decode_item = CERT_DecodeAVAValue(&ava->value);
39 if (!decode_item)
40 return std::string();
41 std::string value(reinterpret_cast<char*>(decode_item->data),
42 decode_item->len);
43 SECITEM_FreeItem(decode_item, PR_TRUE);
44 return value;
45 }
46
47 // Generates a unique nickname for |slot|, returning |nickname| if it is
48 // already unique.
49 //
50 // Note: The nickname returned will NOT include the token name, thus the
51 // token name must be prepended if calling an NSS function that expects
52 // <token>:<nickname>.
53 // TODO(gspencer): Internationalize this: it's wrong to hard-code English.
GetUniqueNicknameForSlot(const std::string & nickname,const SECItem * subject,PK11SlotInfo * slot)54 std::string GetUniqueNicknameForSlot(const std::string& nickname,
55 const SECItem* subject,
56 PK11SlotInfo* slot) {
57 int index = 2;
58 std::string new_name = nickname;
59 std::string temp_nickname = new_name;
60 std::string token_name;
61
62 if (!slot)
63 return new_name;
64
65 if (!PK11_IsInternalKeySlot(slot)) {
66 token_name.assign(PK11_GetTokenName(slot));
67 token_name.append(":");
68
69 temp_nickname = token_name + new_name;
70 }
71
72 while (SEC_CertNicknameConflict(temp_nickname.c_str(),
73 const_cast<SECItem*>(subject),
74 CERT_GetDefaultCertDB())) {
75 new_name = base::StringPrintf("%s #%d", nickname.c_str(), index++);
76 temp_nickname = token_name + new_name;
77 }
78
79 return new_name;
80 }
81
82 // The default nickname of the certificate, based on the certificate type
83 // passed in.
GetDefaultNickname(CERTCertificate * nss_cert,CertType type)84 std::string GetDefaultNickname(CERTCertificate* nss_cert, CertType type) {
85 std::string result;
86 if (type == USER_CERT && nss_cert->slot) {
87 // Find the private key for this certificate and see if it has a
88 // nickname. If there is a private key, and it has a nickname, then
89 // return that nickname.
90 SECKEYPrivateKey* private_key = PK11_FindPrivateKeyFromCert(
91 nss_cert->slot, nss_cert, nullptr /*wincx*/);
92 if (private_key) {
93 char* private_key_nickname = PK11_GetPrivateKeyNickname(private_key);
94 if (private_key_nickname) {
95 result = private_key_nickname;
96 PORT_Free(private_key_nickname);
97 SECKEY_DestroyPrivateKey(private_key);
98 return result;
99 }
100 SECKEY_DestroyPrivateKey(private_key);
101 }
102 }
103
104 switch (type) {
105 case CA_CERT: {
106 char* nickname = CERT_MakeCANickname(nss_cert);
107 result = nickname;
108 PORT_Free(nickname);
109 break;
110 }
111 case USER_CERT: {
112 std::string subject_name = GetCERTNameDisplayName(&nss_cert->subject);
113 if (subject_name.empty()) {
114 const char* email = CERT_GetFirstEmailAddress(nss_cert);
115 if (email)
116 subject_name = email;
117 }
118 // TODO(gspencer): Internationalize this. It's wrong to assume English
119 // here.
120 result =
121 base::StringPrintf("%s's %s ID", subject_name.c_str(),
122 GetCERTNameDisplayName(&nss_cert->issuer).c_str());
123 break;
124 }
125 case SERVER_CERT: {
126 result = GetCERTNameDisplayName(&nss_cert->subject);
127 break;
128 }
129 case OTHER_CERT:
130 default:
131 break;
132 }
133 return result;
134 }
135
136 } // namespace
137
IsSameCertificate(CERTCertificate * a,CERTCertificate * b)138 bool IsSameCertificate(CERTCertificate* a, CERTCertificate* b) {
139 DCHECK(a && b);
140 if (a == b)
141 return true;
142 return a->derCert.len == b->derCert.len &&
143 memcmp(a->derCert.data, b->derCert.data, a->derCert.len) == 0;
144 }
145
IsSameCertificate(CERTCertificate * a,const X509Certificate * b)146 bool IsSameCertificate(CERTCertificate* a, const X509Certificate* b) {
147 return IsSameCertificate(a, b->cert_buffer());
148 }
IsSameCertificate(const X509Certificate * a,CERTCertificate * b)149 bool IsSameCertificate(const X509Certificate* a, CERTCertificate* b) {
150 return IsSameCertificate(b, a->cert_buffer());
151 }
152
IsSameCertificate(CERTCertificate * a,const CRYPTO_BUFFER * b)153 bool IsSameCertificate(CERTCertificate* a, const CRYPTO_BUFFER* b) {
154 return a->derCert.len == CRYPTO_BUFFER_len(b) &&
155 memcmp(a->derCert.data, CRYPTO_BUFFER_data(b), a->derCert.len) == 0;
156 }
IsSameCertificate(const CRYPTO_BUFFER * a,CERTCertificate * b)157 bool IsSameCertificate(const CRYPTO_BUFFER* a, CERTCertificate* b) {
158 return IsSameCertificate(b, a);
159 }
160
CreateCERTCertificateFromBytes(base::span<const uint8_t> data)161 ScopedCERTCertificate CreateCERTCertificateFromBytes(
162 base::span<const uint8_t> data) {
163 crypto::EnsureNSSInit();
164
165 if (!NSS_IsInitialized())
166 return nullptr;
167
168 SECItem der_cert;
169 der_cert.data = const_cast<uint8_t*>(data.data());
170 der_cert.len = base::checked_cast<unsigned>(data.size());
171 der_cert.type = siDERCertBuffer;
172
173 // Parse into a certificate structure.
174 return ScopedCERTCertificate(CERT_NewTempCertificate(
175 CERT_GetDefaultCertDB(), &der_cert, nullptr /* nickname */,
176 PR_FALSE /* is_perm */, PR_TRUE /* copyDER */));
177 }
178
CreateCERTCertificateFromX509Certificate(const X509Certificate * cert)179 ScopedCERTCertificate CreateCERTCertificateFromX509Certificate(
180 const X509Certificate* cert) {
181 return CreateCERTCertificateFromBytes(
182 base::make_span(CRYPTO_BUFFER_data(cert->cert_buffer()),
183 CRYPTO_BUFFER_len(cert->cert_buffer())));
184 }
185
CreateCERTCertificateListFromX509Certificate(const X509Certificate * cert)186 ScopedCERTCertificateList CreateCERTCertificateListFromX509Certificate(
187 const X509Certificate* cert) {
188 return x509_util::CreateCERTCertificateListFromX509Certificate(
189 cert, InvalidIntermediateBehavior::kFail);
190 }
191
CreateCERTCertificateListFromX509Certificate(const X509Certificate * cert,InvalidIntermediateBehavior invalid_intermediate_behavior)192 ScopedCERTCertificateList CreateCERTCertificateListFromX509Certificate(
193 const X509Certificate* cert,
194 InvalidIntermediateBehavior invalid_intermediate_behavior) {
195 ScopedCERTCertificateList nss_chain;
196 nss_chain.reserve(1 + cert->intermediate_buffers().size());
197 ScopedCERTCertificate nss_cert =
198 CreateCERTCertificateFromX509Certificate(cert);
199 if (!nss_cert)
200 return {};
201 nss_chain.push_back(std::move(nss_cert));
202 for (const auto& intermediate : cert->intermediate_buffers()) {
203 ScopedCERTCertificate nss_intermediate = CreateCERTCertificateFromBytes(
204 base::make_span(CRYPTO_BUFFER_data(intermediate.get()),
205 CRYPTO_BUFFER_len(intermediate.get())));
206 if (!nss_intermediate) {
207 if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail)
208 return {};
209 LOG(WARNING) << "error parsing intermediate";
210 continue;
211 }
212 nss_chain.push_back(std::move(nss_intermediate));
213 }
214 return nss_chain;
215 }
216
CreateCERTCertificateListFromBytes(const char * data,size_t length,int format)217 ScopedCERTCertificateList CreateCERTCertificateListFromBytes(const char* data,
218 size_t length,
219 int format) {
220 CertificateList certs = X509Certificate::CreateCertificateListFromBytes(
221 base::as_bytes(base::make_span(data, length)), format);
222 ScopedCERTCertificateList nss_chain;
223 nss_chain.reserve(certs.size());
224 for (const scoped_refptr<X509Certificate>& cert : certs) {
225 ScopedCERTCertificate nss_cert =
226 CreateCERTCertificateFromX509Certificate(cert.get());
227 if (!nss_cert)
228 return {};
229 nss_chain.push_back(std::move(nss_cert));
230 }
231 return nss_chain;
232 }
233
DupCERTCertificate(CERTCertificate * cert)234 ScopedCERTCertificate DupCERTCertificate(CERTCertificate* cert) {
235 return ScopedCERTCertificate(CERT_DupCertificate(cert));
236 }
237
DupCERTCertificateList(const ScopedCERTCertificateList & certs)238 ScopedCERTCertificateList DupCERTCertificateList(
239 const ScopedCERTCertificateList& certs) {
240 ScopedCERTCertificateList result;
241 result.reserve(certs.size());
242 for (const ScopedCERTCertificate& cert : certs)
243 result.push_back(DupCERTCertificate(cert.get()));
244 return result;
245 }
246
CreateX509CertificateFromCERTCertificate(CERTCertificate * nss_cert,const std::vector<CERTCertificate * > & nss_chain)247 scoped_refptr<X509Certificate> CreateX509CertificateFromCERTCertificate(
248 CERTCertificate* nss_cert,
249 const std::vector<CERTCertificate*>& nss_chain) {
250 return CreateX509CertificateFromCERTCertificate(nss_cert, nss_chain, {});
251 }
252
CreateX509CertificateFromCERTCertificate(CERTCertificate * nss_cert,const std::vector<CERTCertificate * > & nss_chain,X509Certificate::UnsafeCreateOptions options)253 scoped_refptr<X509Certificate> CreateX509CertificateFromCERTCertificate(
254 CERTCertificate* nss_cert,
255 const std::vector<CERTCertificate*>& nss_chain,
256 X509Certificate::UnsafeCreateOptions options) {
257 if (!nss_cert || !nss_cert->derCert.len) {
258 return nullptr;
259 }
260 bssl::UniquePtr<CRYPTO_BUFFER> cert_handle(x509_util::CreateCryptoBuffer(
261 base::make_span(nss_cert->derCert.data, nss_cert->derCert.len)));
262
263 std::vector<bssl::UniquePtr<CRYPTO_BUFFER>> intermediates;
264 intermediates.reserve(nss_chain.size());
265 for (const CERTCertificate* nss_intermediate : nss_chain) {
266 if (!nss_intermediate || !nss_intermediate->derCert.len) {
267 return nullptr;
268 }
269 intermediates.push_back(x509_util::CreateCryptoBuffer(base::make_span(
270 nss_intermediate->derCert.data, nss_intermediate->derCert.len)));
271 }
272
273 return X509Certificate::CreateFromBufferUnsafeOptions(
274 std::move(cert_handle), std::move(intermediates), options);
275 }
276
CreateX509CertificateFromCERTCertificate(CERTCertificate * cert)277 scoped_refptr<X509Certificate> CreateX509CertificateFromCERTCertificate(
278 CERTCertificate* cert) {
279 return CreateX509CertificateFromCERTCertificate(
280 cert, std::vector<CERTCertificate*>());
281 }
282
CreateX509CertificateListFromCERTCertificates(const ScopedCERTCertificateList & certs)283 CertificateList CreateX509CertificateListFromCERTCertificates(
284 const ScopedCERTCertificateList& certs) {
285 CertificateList result;
286 result.reserve(certs.size());
287 for (const ScopedCERTCertificate& cert : certs) {
288 scoped_refptr<X509Certificate> x509_cert(
289 CreateX509CertificateFromCERTCertificate(cert.get()));
290 if (!x509_cert)
291 return {};
292 result.push_back(std::move(x509_cert));
293 }
294 return result;
295 }
296
GetDEREncoded(CERTCertificate * cert,std::string * der_encoded)297 bool GetDEREncoded(CERTCertificate* cert, std::string* der_encoded) {
298 if (!cert || !cert->derCert.len)
299 return false;
300 der_encoded->assign(reinterpret_cast<char*>(cert->derCert.data),
301 cert->derCert.len);
302 return true;
303 }
304
GetPEMEncoded(CERTCertificate * cert,std::string * pem_encoded)305 bool GetPEMEncoded(CERTCertificate* cert, std::string* pem_encoded) {
306 if (!cert || !cert->derCert.len)
307 return false;
308 std::string der(reinterpret_cast<char*>(cert->derCert.data),
309 cert->derCert.len);
310 return X509Certificate::GetPEMEncodedFromDER(der, pem_encoded);
311 }
312
GetRFC822SubjectAltNames(CERTCertificate * cert_handle,std::vector<std::string> * names)313 void GetRFC822SubjectAltNames(CERTCertificate* cert_handle,
314 std::vector<std::string>* names) {
315 crypto::ScopedSECItem alt_name(SECITEM_AllocItem(nullptr, nullptr, 0));
316 DCHECK(alt_name.get());
317
318 names->clear();
319 SECStatus rv = CERT_FindCertExtension(
320 cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, alt_name.get());
321 if (rv != SECSuccess)
322 return;
323
324 crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
325 DCHECK(arena.get());
326
327 CERTGeneralName* alt_name_list;
328 alt_name_list = CERT_DecodeAltNameExtension(arena.get(), alt_name.get());
329
330 CERTGeneralName* name = alt_name_list;
331 while (name) {
332 if (name->type == certRFC822Name) {
333 names->push_back(
334 std::string(reinterpret_cast<char*>(name->name.other.data),
335 name->name.other.len));
336 }
337 name = CERT_GetNextGeneralName(name);
338 if (name == alt_name_list)
339 break;
340 }
341 }
342
GetUPNSubjectAltNames(CERTCertificate * cert_handle,std::vector<std::string> * names)343 void GetUPNSubjectAltNames(CERTCertificate* cert_handle,
344 std::vector<std::string>* names) {
345 crypto::ScopedSECItem alt_name(SECITEM_AllocItem(nullptr, nullptr, 0));
346 DCHECK(alt_name.get());
347
348 names->clear();
349 SECStatus rv = CERT_FindCertExtension(
350 cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, alt_name.get());
351 if (rv != SECSuccess)
352 return;
353
354 crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
355 DCHECK(arena.get());
356
357 CERTGeneralName* alt_name_list;
358 alt_name_list = CERT_DecodeAltNameExtension(arena.get(), alt_name.get());
359
360 CERTGeneralName* name = alt_name_list;
361 while (name) {
362 if (name->type == certOtherName) {
363 OtherName* on = &name->name.OthName;
364 if (on->oid.len == sizeof(kUpnOid) &&
365 memcmp(on->oid.data, kUpnOid, sizeof(kUpnOid)) == 0) {
366 SECItem decoded;
367 if (SEC_QuickDERDecodeItem(arena.get(), &decoded,
368 SEC_ASN1_GET(SEC_UTF8StringTemplate),
369 &name->name.OthName.name) == SECSuccess) {
370 names->push_back(
371 std::string(reinterpret_cast<char*>(decoded.data), decoded.len));
372 }
373 }
374 }
375 name = CERT_GetNextGeneralName(name);
376 if (name == alt_name_list)
377 break;
378 }
379 }
380
GetDefaultUniqueNickname(CERTCertificate * nss_cert,CertType type,PK11SlotInfo * slot)381 std::string GetDefaultUniqueNickname(CERTCertificate* nss_cert,
382 CertType type,
383 PK11SlotInfo* slot) {
384 return GetUniqueNicknameForSlot(GetDefaultNickname(nss_cert, type),
385 &nss_cert->derSubject, slot);
386 }
387
GetCERTNameDisplayName(CERTName * name)388 std::string GetCERTNameDisplayName(CERTName* name) {
389 // Search for attributes in the Name, in this order: CN, O and OU.
390 CERTAVA* ou_ava = nullptr;
391 CERTAVA* o_ava = nullptr;
392 CERTRDN** rdns = name->rdns;
393 for (size_t rdn = 0; rdns[rdn]; ++rdn) {
394 CERTAVA** avas = rdns[rdn]->avas;
395 for (size_t pair = 0; avas[pair] != nullptr; ++pair) {
396 SECOidTag tag = CERT_GetAVATag(avas[pair]);
397 if (tag == SEC_OID_AVA_COMMON_NAME) {
398 // If CN is found, return immediately.
399 return DecodeAVAValue(avas[pair]);
400 }
401 // If O or OU is found, save the first one of each so that it can be
402 // returned later if no CN attribute is found.
403 if (tag == SEC_OID_AVA_ORGANIZATION_NAME && !o_ava)
404 o_ava = avas[pair];
405 if (tag == SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME && !ou_ava)
406 ou_ava = avas[pair];
407 }
408 }
409 if (o_ava)
410 return DecodeAVAValue(o_ava);
411 if (ou_ava)
412 return DecodeAVAValue(ou_ava);
413 return std::string();
414 }
415
GetValidityTimes(CERTCertificate * cert,base::Time * not_before,base::Time * not_after)416 bool GetValidityTimes(CERTCertificate* cert,
417 base::Time* not_before,
418 base::Time* not_after) {
419 PRTime pr_not_before, pr_not_after;
420 if (CERT_GetCertTimes(cert, &pr_not_before, &pr_not_after) == SECSuccess) {
421 if (not_before)
422 *not_before = crypto::PRTimeToBaseTime(pr_not_before);
423 if (not_after)
424 *not_after = crypto::PRTimeToBaseTime(pr_not_after);
425 return true;
426 }
427 return false;
428 }
429
CalculateFingerprint256(CERTCertificate * cert)430 SHA256HashValue CalculateFingerprint256(CERTCertificate* cert) {
431 SHA256HashValue sha256;
432 memset(sha256.data, 0, sizeof(sha256.data));
433
434 DCHECK(cert->derCert.data);
435 DCHECK_NE(0U, cert->derCert.len);
436
437 SECStatus rv = HASH_HashBuf(HASH_AlgSHA256, sha256.data, cert->derCert.data,
438 cert->derCert.len);
439 DCHECK_EQ(SECSuccess, rv);
440
441 return sha256;
442 }
443
ImportUserCert(CERTCertificate * cert)444 int ImportUserCert(CERTCertificate* cert) {
445 return mozilla_security_manager::ImportUserCert(cert);
446 }
447
448 } // namespace net::x509_util
449