Backed out changeset a93095760b1f (bug 1658042) for causing Bug 1658576 a=backout

This commit is contained in:
Noemi Erli 2020-08-11 18:44:29 +03:00
Родитель 8df04ff073
Коммит 54c193f6bc
5 изменённых файлов: 63 добавлений и 159 удалений

Просмотреть файл

@ -26,7 +26,6 @@ use core_foundation::string::*;
// etc.. This is easier.
include!("bindings_macos.rs");
use crate::manager::SlotType;
use crate::util::*;
#[repr(C)]
@ -815,17 +814,7 @@ pub enum Object {
}
impl Object {
pub fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
// The modern/legacy slot distinction in theory enables differentiation
// between keys that are from modules that can use modern cryptography
// (namely EC keys and RSA-PSS signatures) and those that cannot.
// However, the function that would enable this
// (SecKeyIsAlgorithmSupported) causes a password dialog to appear on
// our test machines, so this backend pretends that everything supports
// modern crypto for now.
if slot_type != SlotType::Modern {
return false;
}
pub fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
match self {
Object::Cert(cert) => cert.matches(attrs),
Object::Key(key) => key.matches(attrs),

Просмотреть файл

@ -17,7 +17,6 @@ use winapi::um::errhandlingapi::GetLastError;
use winapi::um::ncrypt::*;
use winapi::um::wincrypt::{HCRYPTHASH, HCRYPTPROV, *};
use crate::manager::SlotType;
use crate::util::*;
// winapi has some support for ncrypt.h, but not for this function.
@ -65,25 +64,6 @@ fn get_cert_subject_dn(cert_info: &CERT_INFO) -> Result<Vec<u8>, ()> {
Ok(subject_dn_string_bytes)
}
/// Helper function to determine which slot to expose a certificate/key on.
/// Certificates with keys that are available via the CNG APIs are exposed on the modern slot.
/// Certificates with keys that are only available via the CryptoAPI APIs are exposed on the legacy
/// slot.
fn get_slot_type_for_cert(cert: PCCERT_CONTEXT) -> SlotType {
if unsafe {
CryptFindCertificateKeyProvInfo(
cert,
CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG,
std::ptr::null_mut(),
)
} != 0
{
SlotType::Modern
} else {
SlotType::Legacy
}
}
/// Represents a certificate for which there exists a corresponding private key.
pub struct Cert {
/// PKCS #11 object class. Will be `CKO_CERTIFICATE`.
@ -102,13 +82,11 @@ pub struct Cert {
serial_number: Vec<u8>,
/// The DER bytes of the subject distinguished name of the certificate.
subject: Vec<u8>,
/// Which slot this certificate should be exposed on.
slot_type: SlotType,
}
impl Cert {
fn new(cert_context: PCCERT_CONTEXT) -> Result<Cert, ()> {
let cert = unsafe { &*cert_context };
fn new(cert: PCCERT_CONTEXT) -> Result<Cert, ()> {
let cert = unsafe { &*cert };
let cert_info = unsafe { &*cert.pCertInfo };
let value =
unsafe { slice::from_raw_parts(cert.pbCertEncoded, cert.cbCertEncoded as usize) };
@ -133,7 +111,6 @@ impl Cert {
issuer,
serial_number,
subject,
slot_type: get_slot_type_for_cert(cert_context),
})
}
@ -169,10 +146,7 @@ impl Cert {
&self.subject
}
fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
if slot_type != self.slot_type {
return false;
}
fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
for (attr_type, attr_value) in attrs {
let comparison = match *attr_type {
CKA_CLASS => self.class(),
@ -589,8 +563,6 @@ pub struct Key {
ec_params: Option<Vec<u8>>,
/// An enum identifying this key's type.
key_type_enum: KeyType,
/// Which slot this key should be exposed on.
slot_type: SlotType,
}
impl Key {
@ -637,7 +609,6 @@ impl Key {
modulus,
ec_params,
key_type_enum,
slot_type: get_slot_type_for_cert(cert_context),
})
}
@ -675,10 +646,7 @@ impl Key {
}
}
fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
if slot_type != self.slot_type {
return false;
}
fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
for (attr_type, attr_value) in attrs {
let comparison = match *attr_type {
CKA_CLASS => self.class(),
@ -765,10 +733,10 @@ pub enum Object {
}
impl Object {
pub fn matches(&self, slot_type: SlotType, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
pub fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
match self {
Object::Cert(cert) => cert.matches(slot_type, attrs),
Object::Key(key) => key.matches(slot_type, attrs),
Object::Cert(cert) => cert.matches(attrs),
Object::Key(key) => key.matches(attrs),
}
}

Просмотреть файл

@ -35,7 +35,7 @@ mod backend_macos;
#[cfg(target_os = "windows")]
mod backend_windows;
use manager::{ManagerProxy, SlotType};
use manager::ManagerProxy;
lazy_static! {
/// The singleton `ManagerProxy` that handles state with respect to PKCS #11. Only one thread
@ -144,12 +144,8 @@ extern "C" fn C_GetInfo(pInfo: CK_INFO_PTR) -> CK_RV {
CKR_OK
}
/// This module has two slots.
const SLOT_COUNT: CK_ULONG = 2;
/// The slot with ID 1 supports modern mechanisms like RSA-PSS.
const SLOT_ID_MODERN: CK_SLOT_ID = 1;
/// The slot with ID 2 only supports legacy mechanisms.
const SLOT_ID_LEGACY: CK_SLOT_ID = 2;
/// This module only has one slot. Its ID is 1.
const SLOT_ID: CK_SLOT_ID = 1;
/// This gets called twice: once with a null `pSlotList` to get the number of slots (returned via
/// `pulCount`) and a second time to get the ID for each slot.
@ -162,42 +158,35 @@ extern "C" fn C_GetSlotList(
error!("C_GetSlotList: CKR_ARGUMENTS_BAD");
return CKR_ARGUMENTS_BAD;
}
unsafe {
*pulCount = 1;
}
if !pSlotList.is_null() {
if unsafe { *pulCount } < SLOT_COUNT {
let slotCount = unsafe { *pulCount };
if slotCount < 1 {
error!("C_GetSlotList: CKR_BUFFER_TOO_SMALL");
return CKR_BUFFER_TOO_SMALL;
}
unsafe {
*pSlotList = SLOT_ID_MODERN;
*pSlotList.offset(1) = SLOT_ID_LEGACY;
*pSlotList = SLOT_ID;
}
};
unsafe {
*pulCount = SLOT_COUNT;
}
debug!("C_GetSlotList: CKR_OK");
CKR_OK
}
const SLOT_DESCRIPTION_MODERN_BYTES: &[u8; 64] =
b"OS Client Cert Slot (Modern) ";
const SLOT_DESCRIPTION_LEGACY_BYTES: &[u8; 64] =
b"OS Client Cert Slot (Legacy) ";
const SLOT_DESCRIPTION_BYTES: &[u8; 64] =
b"OS Client Cert Slot ";
/// This gets called to obtain information about slots. In this implementation, the tokens are
/// always present in the slots.
/// This gets called to obtain information about slots. In this implementation, the token is always
/// present in the slot.
extern "C" fn C_GetSlotInfo(slotID: CK_SLOT_ID, pInfo: CK_SLOT_INFO_PTR) -> CK_RV {
if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pInfo.is_null() {
if slotID != SLOT_ID || pInfo.is_null() {
error!("C_GetSlotInfo: CKR_ARGUMENTS_BAD");
return CKR_ARGUMENTS_BAD;
}
let description = if slotID == SLOT_ID_MODERN {
SLOT_DESCRIPTION_MODERN_BYTES
} else {
SLOT_DESCRIPTION_LEGACY_BYTES
};
let slot_info = CK_SLOT_INFO {
slotDescription: *description,
slotDescription: *SLOT_DESCRIPTION_BYTES,
manufacturerID: *MANUFACTURER_ID_BYTES,
flags: CKF_TOKEN_PRESENT,
hardwareVersion: CK_VERSION::default(),
@ -210,25 +199,19 @@ extern "C" fn C_GetSlotInfo(slotID: CK_SLOT_ID, pInfo: CK_SLOT_INFO_PTR) -> CK_R
CKR_OK
}
const TOKEN_LABEL_MODERN_BYTES: &[u8; 32] = b"OS Client Cert Token (Modern) ";
const TOKEN_LABEL_LEGACY_BYTES: &[u8; 32] = b"OS Client Cert Token (Legacy) ";
const TOKEN_LABEL_BYTES: &[u8; 32] = b"OS Client Cert Token ";
const TOKEN_MODEL_BYTES: &[u8; 16] = b"osclientcerts ";
const TOKEN_SERIAL_NUMBER_BYTES: &[u8; 16] = b"0000000000000000";
/// This gets called to obtain some information about tokens. This implementation has two slots,
/// so it has two tokens. This information is primarily for display purposes.
/// This gets called to obtain some information about tokens. This implementation only has one slot,
/// so it only has one token. This information is primarily for display purposes.
extern "C" fn C_GetTokenInfo(slotID: CK_SLOT_ID, pInfo: CK_TOKEN_INFO_PTR) -> CK_RV {
if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pInfo.is_null() {
if slotID != SLOT_ID || pInfo.is_null() {
error!("C_GetTokenInfo: CKR_ARGUMENTS_BAD");
return CKR_ARGUMENTS_BAD;
}
let mut token_info = CK_TOKEN_INFO::default();
let label = if slotID == SLOT_ID_MODERN {
TOKEN_LABEL_MODERN_BYTES
} else {
TOKEN_LABEL_LEGACY_BYTES
};
token_info.label = *label;
token_info.label = *TOKEN_LABEL_BYTES;
token_info.manufacturerID = *MANUFACTURER_ID_BYTES;
token_info.model = *TOKEN_MODEL_BYTES;
token_info.serialNumber = *TOKEN_SERIAL_NUMBER_BYTES;
@ -239,22 +222,18 @@ extern "C" fn C_GetTokenInfo(slotID: CK_SLOT_ID, pInfo: CK_TOKEN_INFO_PTR) -> CK
CKR_OK
}
/// This gets called to determine what mechanisms a slot supports. The modern slot supports ECDSA,
/// RSA PKCS, and RSA PSS. The legacy slot only supports RSA PKCS.
/// This gets called to determine what mechanisms a slot supports. This implementation supports
/// ECDSA, RSA PKCS, and RSA PSS.
extern "C" fn C_GetMechanismList(
slotID: CK_SLOT_ID,
pMechanismList: CK_MECHANISM_TYPE_PTR,
pulCount: CK_ULONG_PTR,
) -> CK_RV {
if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || pulCount.is_null() {
if slotID != SLOT_ID || pulCount.is_null() {
error!("C_GetMechanismList: CKR_ARGUMENTS_BAD");
return CKR_ARGUMENTS_BAD;
}
let mechanisms = if slotID == SLOT_ID_MODERN {
vec![CKM_ECDSA, CKM_RSA_PKCS, CKM_RSA_PKCS_PSS]
} else {
vec![CKM_RSA_PKCS]
};
let mechanisms = [CKM_ECDSA, CKM_RSA_PKCS, CKM_RSA_PKCS_PSS];
if !pMechanismList.is_null() {
if unsafe { *pulCount as usize } < mechanisms.len() {
error!("C_GetMechanismList: CKR_ARGUMENTS_BAD");
@ -321,18 +300,13 @@ extern "C" fn C_OpenSession(
_Notify: CK_NOTIFY,
phSession: CK_SESSION_HANDLE_PTR,
) -> CK_RV {
if (slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY) || phSession.is_null() {
if slotID != SLOT_ID || phSession.is_null() {
error!("C_OpenSession: CKR_ARGUMENTS_BAD");
return CKR_ARGUMENTS_BAD;
}
let mut manager_guard = try_to_get_manager_guard!();
let manager = manager_guard_to_manager!(manager_guard);
let slot_type = if slotID == SLOT_ID_MODERN {
SlotType::Modern
} else {
SlotType::Legacy
};
let session_handle = match manager.open_session(slot_type) {
let session_handle = match manager.open_session() {
Ok(session_handle) => session_handle,
Err(()) => {
error!("C_OpenSession: open_session failed");
@ -360,18 +334,13 @@ extern "C" fn C_CloseSession(hSession: CK_SESSION_HANDLE) -> CK_RV {
/// This gets called to close all open sessions at once. This is handled by the `ManagerProxy`.
extern "C" fn C_CloseAllSessions(slotID: CK_SLOT_ID) -> CK_RV {
if slotID != SLOT_ID_MODERN && slotID != SLOT_ID_LEGACY {
if slotID != SLOT_ID {
error!("C_CloseAllSessions: CKR_ARGUMENTS_BAD");
return CKR_ARGUMENTS_BAD;
}
let mut manager_guard = try_to_get_manager_guard!();
let manager = manager_guard_to_manager!(manager_guard);
let slot_type = if slotID == SLOT_ID_MODERN {
SlotType::Modern
} else {
SlotType::Legacy
};
match manager.close_all_sessions(slot_type) {
match manager.close_all_sessions() {
Ok(()) => {
debug!("C_CloseAllSessions: CKR_OK");
CKR_OK

Просмотреть файл

@ -18,15 +18,6 @@ use std::thread;
use std::thread::JoinHandle;
use std::time::{Duration, Instant};
/// Helper enum to differentiate between sessions on the modern slot and sessions on the legacy
/// slot. The former is for EC keys and RSA keys that can be used with RSA-PSS whereas the latter is
/// for RSA keys that cannot be used with RSA-PSS.
#[derive(Clone, Copy, PartialEq)]
pub enum SlotType {
Modern,
Legacy,
}
/// Helper type for sending `ManagerArguments` to the real `Manager`.
type ManagerArgumentsSender = Sender<ManagerArguments>;
/// Helper type for receiving `ManagerReturnValue`s from the real `Manager`.
@ -36,9 +27,9 @@ type ManagerReturnValueReceiver = Receiver<ManagerReturnValue>;
/// `ManagerArguments::Stop` is a special variant that stops the background thread and drops the
/// `Manager`.
enum ManagerArguments {
OpenSession(SlotType),
OpenSession,
CloseSession(CK_SESSION_HANDLE),
CloseAllSessions(SlotType),
CloseAllSessions,
StartSearch(CK_SESSION_HANDLE, Vec<(CK_ATTRIBUTE_TYPE, Vec<u8>)>),
Search(CK_SESSION_HANDLE, usize),
ClearSearch(CK_SESSION_HANDLE),
@ -112,16 +103,14 @@ impl ManagerProxy {
}
};
let results = match arguments {
ManagerArguments::OpenSession(slot_type) => {
ManagerReturnValue::OpenSession(real_manager.open_session(slot_type))
ManagerArguments::OpenSession => {
ManagerReturnValue::OpenSession(real_manager.open_session())
}
ManagerArguments::CloseSession(session_handle) => {
ManagerReturnValue::CloseSession(real_manager.close_session(session_handle))
}
ManagerArguments::CloseAllSessions(slot_type) => {
ManagerReturnValue::CloseAllSessions(
real_manager.close_all_sessions(slot_type),
)
ManagerArguments::CloseAllSessions => {
ManagerReturnValue::CloseAllSessions(real_manager.close_all_sessions())
}
ManagerArguments::StartSearch(session, attrs) => {
ManagerReturnValue::StartSearch(real_manager.start_search(session, &attrs))
@ -196,10 +185,10 @@ impl ManagerProxy {
Ok(result)
}
pub fn open_session(&mut self, slot_type: SlotType) -> Result<CK_SESSION_HANDLE, ()> {
pub fn open_session(&mut self) -> Result<CK_SESSION_HANDLE, ()> {
manager_proxy_fn_impl!(
self,
ManagerArguments::OpenSession(slot_type),
ManagerArguments::OpenSession,
ManagerReturnValue::OpenSession
)
}
@ -212,10 +201,10 @@ impl ManagerProxy {
)
}
pub fn close_all_sessions(&mut self, slot_type: SlotType) -> Result<(), ()> {
pub fn close_all_sessions(&mut self) -> Result<(), ()> {
manager_proxy_fn_impl!(
self,
ManagerArguments::CloseAllSessions(slot_type),
ManagerArguments::CloseAllSessions,
ManagerReturnValue::CloseAllSessions
)
}
@ -352,9 +341,8 @@ fn search_is_for_all_certificates_or_keys(
/// specification. This includes what sessions are open, which search and sign operations are
/// ongoing, and what objects are known and by what handle.
struct Manager {
/// A map of session to session type (modern or legacy). Sessions can be created (opened) and
/// later closed.
sessions: BTreeMap<CK_SESSION_HANDLE, SlotType>,
/// A set of sessions. Sessions can be created (opened) and later closed.
sessions: BTreeSet<CK_SESSION_HANDLE>,
/// A map of searches to PKCS #11 object handles that match those searches.
searches: BTreeMap<CK_SESSION_HANDLE, Vec<CK_OBJECT_HANDLE>>,
/// A map of sign operations to a pair of the object handle and optionally some params being
@ -379,7 +367,7 @@ struct Manager {
impl Manager {
pub fn new() -> Manager {
let mut manager = Manager {
sessions: BTreeMap::new(),
sessions: BTreeSet::new(),
searches: BTreeMap::new(),
signs: BTreeMap::new(),
objects: BTreeMap::new(),
@ -432,29 +420,23 @@ impl Manager {
}
}
pub fn open_session(&mut self, slot_type: SlotType) -> Result<CK_SESSION_HANDLE, ()> {
pub fn open_session(&mut self) -> Result<CK_SESSION_HANDLE, ()> {
let next_session = self.next_session;
self.next_session += 1;
self.sessions.insert(next_session, slot_type);
self.sessions.insert(next_session);
Ok(next_session)
}
pub fn close_session(&mut self, session: CK_SESSION_HANDLE) -> Result<(), ()> {
self.sessions.remove(&session).ok_or(()).map(|_| ())
if self.sessions.remove(&session) {
Ok(())
} else {
Err(())
}
}
pub fn close_all_sessions(&mut self, slot_type: SlotType) -> Result<(), ()> {
let mut to_remove = Vec::new();
for (session, open_slot_type) in self.sessions.iter() {
if slot_type == *open_slot_type {
to_remove.push(*session);
}
}
for session in to_remove {
if self.sessions.remove(&session).is_none() {
return Err(());
}
}
pub fn close_all_sessions(&mut self) -> Result<(), ()> {
self.sessions.clear();
Ok(())
}
@ -473,10 +455,9 @@ impl Manager {
session: CK_SESSION_HANDLE,
attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)],
) -> Result<(), ()> {
let slot_type = match self.sessions.get(&session) {
Some(slot_type) => *slot_type,
None => return Err(()),
};
if self.searches.contains_key(&session) {
return Err(());
}
// If the search is for an attribute we don't support, no objects will match. This check
// saves us having to look through all of our objects.
for (attr, _) in attrs {
@ -495,7 +476,7 @@ impl Manager {
}
let mut handles = Vec::new();
for (handle, object) in &self.objects {
if object.matches(slot_type, attrs) {
if object.matches(attrs) {
handles.push(*handle);
}
}

Просмотреть файл

@ -27,10 +27,7 @@ async function check_osclientcerts_module_loaded() {
slot => slot.name
);
testModuleSlotNames.sort();
const expectedSlotNames = [
"OS Client Cert Slot (Legacy)",
"OS Client Cert Slot (Modern)",
];
const expectedSlotNames = ["OS Client Cert Slot"];
deepEqual(
testModuleSlotNames,
expectedSlotNames,