1// Copyright 2013 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. 4 5#include "net/cert/nss_profile_filter_chromeos.h" 6 7#include "base/strings/string_piece.h" 8#include "base/strings/stringprintf.h" 9#include "net/cert/x509_certificate.h" 10 11namespace net { 12 13namespace { 14 15std::string CertSlotsString(CERTCertificate* cert) { 16 std::string result; 17 crypto::ScopedPK11SlotList slots_for_cert( 18 PK11_GetAllSlotsForCert(cert, NULL)); 19 for (PK11SlotListElement* slot_element = 20 PK11_GetFirstSafe(slots_for_cert.get()); 21 slot_element; 22 slot_element = 23 PK11_GetNextSafe(slots_for_cert.get(), slot_element, PR_FALSE)) { 24 if (!result.empty()) 25 result += ','; 26 base::StringAppendF(&result, 27 "%lu:%lu", 28 PK11_GetModuleID(slot_element->slot), 29 PK11_GetSlotID(slot_element->slot)); 30 } 31 return result; 32} 33 34} // namespace 35 36NSSProfileFilterChromeOS::NSSProfileFilterChromeOS() {} 37 38NSSProfileFilterChromeOS::NSSProfileFilterChromeOS( 39 const NSSProfileFilterChromeOS& other) { 40 public_slot_.reset(other.public_slot_ ? 41 PK11_ReferenceSlot(other.public_slot_.get()) : 42 NULL); 43 private_slot_.reset(other.private_slot_ ? 44 PK11_ReferenceSlot(other.private_slot_.get()) : 45 NULL); 46 system_slot_.reset( 47 other.system_slot_ ? PK11_ReferenceSlot(other.system_slot_.get()) : NULL); 48} 49 50NSSProfileFilterChromeOS::~NSSProfileFilterChromeOS() {} 51 52NSSProfileFilterChromeOS& NSSProfileFilterChromeOS::operator=( 53 const NSSProfileFilterChromeOS& other) { 54 public_slot_.reset(other.public_slot_ ? 55 PK11_ReferenceSlot(other.public_slot_.get()) : 56 NULL); 57 private_slot_.reset(other.private_slot_ ? 58 PK11_ReferenceSlot(other.private_slot_.get()) : 59 NULL); 60 system_slot_.reset( 61 other.system_slot_ ? PK11_ReferenceSlot(other.system_slot_.get()) : NULL); 62 return *this; 63} 64 65void NSSProfileFilterChromeOS::Init(crypto::ScopedPK11Slot public_slot, 66 crypto::ScopedPK11Slot private_slot, 67 crypto::ScopedPK11Slot system_slot) { 68 // crypto::ScopedPK11Slot actually holds a reference counted object. 69 // Because scoped_ptr<T> assignment is a no-op if it already points to 70 // the same pointer, a reference would be leaked because .Pass() does 71 // not release its reference, and the receiving object won't free 72 // its copy. 73 if (public_slot_.get() != public_slot.get()) 74 public_slot_ = public_slot.Pass(); 75 if (private_slot_.get() != private_slot.get()) 76 private_slot_ = private_slot.Pass(); 77 if (system_slot_.get() != system_slot.get()) 78 system_slot_ = system_slot.Pass(); 79} 80 81bool NSSProfileFilterChromeOS::IsModuleAllowed(PK11SlotInfo* slot) const { 82 // If this is one of the public/private slots for this profile or the system 83 // slot, allow it. 84 if (slot == public_slot_.get() || slot == private_slot_.get() || 85 slot == system_slot_.get()) { 86 return true; 87 } 88 // Allow the root certs module. 89 if (PK11_HasRootCerts(slot)) 90 return true; 91 // If it's from the read-only slots, allow it. 92 if (PK11_IsInternal(slot) && !PK11_IsRemovable(slot)) 93 return true; 94 // If |public_slot_| or |private_slot_| is null, there isn't a way to get the 95 // modules to use in the final test. 96 if (!public_slot_.get() || !private_slot_.get()) 97 return false; 98 // If this is not the internal (file-system) module or the TPM module, allow 99 // it. This would allow smartcards/etc, although ChromeOS doesn't currently 100 // support that. (This assumes that private_slot_ and system_slot_ are on the 101 // same module.) 102 DCHECK(!system_slot_.get() || 103 PK11_GetModule(private_slot_.get()) == 104 PK11_GetModule(system_slot_.get())); 105 SECMODModule* module_for_slot = PK11_GetModule(slot); 106 if (module_for_slot != PK11_GetModule(public_slot_.get()) && 107 module_for_slot != PK11_GetModule(private_slot_.get())) { 108 return true; 109 } 110 return false; 111} 112 113bool NSSProfileFilterChromeOS::IsCertAllowed(CERTCertificate* cert) const { 114 crypto::ScopedPK11SlotList slots_for_cert( 115 PK11_GetAllSlotsForCert(cert, NULL)); 116 if (!slots_for_cert) { 117 DVLOG(2) << "cert no slots: " << base::StringPiece(cert->nickname); 118 return false; 119 } 120 121 for (PK11SlotListElement* slot_element = 122 PK11_GetFirstSafe(slots_for_cert.get()); 123 slot_element; 124 slot_element = 125 PK11_GetNextSafe(slots_for_cert.get(), slot_element, PR_FALSE)) { 126 if (IsModuleAllowed(slot_element->slot)) { 127 DVLOG(3) << "cert from " << CertSlotsString(cert) 128 << " allowed: " << base::StringPiece(cert->nickname); 129 PK11_FreeSlotListElement(slots_for_cert.get(), slot_element); 130 return true; 131 } 132 } 133 DVLOG(2) << "cert from " << CertSlotsString(cert) 134 << " filtered: " << base::StringPiece(cert->nickname); 135 return false; 136} 137 138NSSProfileFilterChromeOS::CertNotAllowedForProfilePredicate:: 139 CertNotAllowedForProfilePredicate(const NSSProfileFilterChromeOS& filter) 140 : filter_(filter) {} 141 142bool NSSProfileFilterChromeOS::CertNotAllowedForProfilePredicate::operator()( 143 const scoped_refptr<X509Certificate>& cert) const { 144 return !filter_.IsCertAllowed(cert->os_cert_handle()); 145} 146 147NSSProfileFilterChromeOS::ModuleNotAllowedForProfilePredicate:: 148 ModuleNotAllowedForProfilePredicate(const NSSProfileFilterChromeOS& filter) 149 : filter_(filter) {} 150 151bool NSSProfileFilterChromeOS::ModuleNotAllowedForProfilePredicate::operator()( 152 const scoped_refptr<CryptoModule>& module) const { 153 return !filter_.IsModuleAllowed(module->os_module_handle()); 154} 155 156} // namespace net 157 158