| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/cert/x509_util_nss.h" |
| |
| #include <cert.h> // Must be included before certdb.h |
| #include <certdb.h> |
| #include <cryptohi.h> |
| #include <nss.h> |
| #include <pk11pub.h> |
| #include <prerror.h> |
| #include <secder.h> |
| #include <secmod.h> |
| #include <secport.h> |
| |
| #include "base/logging.h" |
| #include "base/strings/stringprintf.h" |
| #include "crypto/scoped_nss_types.h" |
| |
| namespace net { |
| |
| namespace { |
| |
| // Microsoft User Principal Name: 1.3.6.1.4.1.311.20.2.3 |
| const uint8_t kUpnOid[] = {0x2b, 0x6, 0x1, 0x4, 0x1, |
| 0x82, 0x37, 0x14, 0x2, 0x3}; |
| |
| } // namespace |
| |
| namespace x509_util { |
| |
| |
| void GetRFC822SubjectAltNames(CERTCertificate* cert_handle, |
| std::vector<std::string>* names) { |
| crypto::ScopedSECItem alt_name(SECITEM_AllocItem(NULL, NULL, 0)); |
| DCHECK(alt_name.get()); |
| |
| names->clear(); |
| SECStatus rv = CERT_FindCertExtension( |
| cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, alt_name.get()); |
| if (rv != SECSuccess) |
| return; |
| |
| crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); |
| DCHECK(arena.get()); |
| |
| CERTGeneralName* alt_name_list; |
| alt_name_list = CERT_DecodeAltNameExtension(arena.get(), alt_name.get()); |
| |
| CERTGeneralName* name = alt_name_list; |
| while (name) { |
| if (name->type == certRFC822Name) { |
| names->push_back( |
| std::string(reinterpret_cast<char*>(name->name.other.data), |
| name->name.other.len)); |
| } |
| name = CERT_GetNextGeneralName(name); |
| if (name == alt_name_list) |
| break; |
| } |
| } |
| |
| void GetUPNSubjectAltNames(CERTCertificate* cert_handle, |
| std::vector<std::string>* names) { |
| crypto::ScopedSECItem alt_name(SECITEM_AllocItem(NULL, NULL, 0)); |
| DCHECK(alt_name.get()); |
| |
| names->clear(); |
| SECStatus rv = CERT_FindCertExtension( |
| cert_handle, SEC_OID_X509_SUBJECT_ALT_NAME, alt_name.get()); |
| if (rv != SECSuccess) |
| return; |
| |
| crypto::ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); |
| DCHECK(arena.get()); |
| |
| CERTGeneralName* alt_name_list; |
| alt_name_list = CERT_DecodeAltNameExtension(arena.get(), alt_name.get()); |
| |
| CERTGeneralName* name = alt_name_list; |
| while (name) { |
| if (name->type == certOtherName) { |
| OtherName* on = &name->name.OthName; |
| if (on->oid.len == sizeof(kUpnOid) && |
| memcmp(on->oid.data, kUpnOid, sizeof(kUpnOid)) == 0) { |
| SECItem decoded; |
| if (SEC_QuickDERDecodeItem(arena.get(), &decoded, |
| SEC_ASN1_GET(SEC_UTF8StringTemplate), |
| &name->name.OthName.name) == SECSuccess) { |
| names->push_back( |
| std::string(reinterpret_cast<char*>(decoded.data), decoded.len)); |
| } |
| } |
| } |
| name = CERT_GetNextGeneralName(name); |
| if (name == alt_name_list) |
| break; |
| } |
| } |
| |
| std::string GetUniqueNicknameForSlot(const std::string& nickname, |
| const SECItem* subject, |
| PK11SlotInfo* slot) { |
| int index = 2; |
| std::string new_name = nickname; |
| std::string temp_nickname = new_name; |
| std::string token_name; |
| |
| if (!slot) |
| return new_name; |
| |
| if (!PK11_IsInternalKeySlot(slot)) { |
| token_name.assign(PK11_GetTokenName(slot)); |
| token_name.append(":"); |
| |
| temp_nickname = token_name + new_name; |
| } |
| |
| while (SEC_CertNicknameConflict(temp_nickname.c_str(), |
| const_cast<SECItem*>(subject), |
| CERT_GetDefaultCertDB())) { |
| base::SStringPrintf(&new_name, "%s #%d", nickname.c_str(), index++); |
| temp_nickname = token_name + new_name; |
| } |
| |
| return new_name; |
| } |
| |
| } // namespace x509_util |
| |
| } // namespace net |