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