mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1789520 - rust implementation of nssckbi. r=keeler,supply-chain-reviewers
Differential Revision: https://phabricator.services.mozilla.com/D156612
This commit is contained in:
parent
d11dd7596d
commit
479f9ec25e
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -574,6 +574,16 @@ dependencies = [
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "builtins-static"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
"nom 7.1.1",
|
||||
"pkcs11-bindings",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.10.0"
|
||||
@ -4094,9 +4104,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkcs11-bindings"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "054f65db435bb7cf99db2f38bbcf568dfa66c342201df54e700c772b178e2f20"
|
||||
checksum = "780bf71a814823f87d50b5bfbfd4ba5f2af46819a01f0ac31238f650693eb592"
|
||||
dependencies = [
|
||||
"bindgen",
|
||||
]
|
||||
|
@ -8,12 +8,13 @@ members = [
|
||||
"js/src/frontend/smoosh",
|
||||
"js/src/rust",
|
||||
"netwerk/test/http3server",
|
||||
"security/manager/ssl/builtins",
|
||||
"security/manager/ssl/ipcclientcerts",
|
||||
"security/manager/ssl/osclientcerts",
|
||||
"testing/geckodriver",
|
||||
"toolkit/components/uniffi-bindgen-gecko-js",
|
||||
"toolkit/crashreporter/rust_minidump_writer_linux",
|
||||
"toolkit/crashreporter/mozwer-rust",
|
||||
"toolkit/crashreporter/rust_minidump_writer_linux",
|
||||
"toolkit/library/gtest/rust",
|
||||
"toolkit/library/rust/",
|
||||
"toolkit/mozapps/defaultagent/rust",
|
||||
|
16
security/manager/ssl/builtins/Cargo.toml
Normal file
16
security/manager/ssl/builtins/Cargo.toml
Normal file
@ -0,0 +1,16 @@
|
||||
[package]
|
||||
name = "builtins-static"
|
||||
version = "0.1.0"
|
||||
authors = ["John Schanck <jschanck@mozilla.com>"]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
pkcs11-bindings = "0.1.1"
|
||||
smallvec = { version = "1.9.0", features = ["const_new"] }
|
||||
|
||||
[build-dependencies]
|
||||
bindgen = { default-features = false, features = ["runtime"], version = "0.59" }
|
||||
nom = "7.1.1"
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
495
security/manager/ssl/builtins/build.rs
Normal file
495
security/manager/ssl/builtins/build.rs
Normal file
@ -0,0 +1,495 @@
|
||||
/* -*- Mode: rust; rust-indent-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
extern crate bindgen;
|
||||
extern crate nom;
|
||||
|
||||
use bindgen::callbacks::*;
|
||||
use bindgen::*;
|
||||
|
||||
use nom::branch::alt;
|
||||
use nom::bytes::complete::{tag, take_until};
|
||||
use nom::character::complete::{
|
||||
char, multispace0, newline, not_line_ending, one_of, space0, space1,
|
||||
};
|
||||
use nom::combinator::{fail, recognize};
|
||||
use nom::multi::{many1, separated_list0};
|
||||
use nom::sequence::{delimited, separated_pair, terminated, tuple};
|
||||
use nom::IResult;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::env;
|
||||
use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io::{BufWriter, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn octal_block_to_vec_u8(octal_block: &str) -> Vec<u8> {
|
||||
octal_block
|
||||
.lines()
|
||||
.flat_map(|x| x.split('\\').skip(1))
|
||||
.map(|x| u8::from_str_radix(x, 8).expect("octal value out of range."))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn octal_block_to_hex_string(octal: &str) -> String {
|
||||
octal_block_to_vec_u8(octal)
|
||||
.iter()
|
||||
.map(|x| format!("0x{:02X}, ", x))
|
||||
.collect()
|
||||
}
|
||||
|
||||
// Wrapper around values parsed out of certdata.txt
|
||||
enum Ck<'a> {
|
||||
Class(&'a str),
|
||||
Comment(&'a str),
|
||||
DistrustAfter(Option<&'a str>),
|
||||
Empty,
|
||||
MultilineOctal(&'a str),
|
||||
OptionBool(&'a str),
|
||||
Trust(&'a str),
|
||||
Utf8(&'a str),
|
||||
}
|
||||
|
||||
// Translation of parsed values into the output rust code
|
||||
impl fmt::Display for Ck<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Ck::Class(s) => write!(f, "{s}_BYTES"),
|
||||
Ck::Comment(s) => write!(f, "{}", s.replace('#', "//")),
|
||||
Ck::DistrustAfter(None) => write!(f, "Some(CK_FALSE_BYTES)"),
|
||||
Ck::DistrustAfter(Some(s)) => write!(f, "Some(&[{}])", octal_block_to_hex_string(s)),
|
||||
Ck::Empty => write!(f, "None"),
|
||||
Ck::MultilineOctal(s) => write!(f, "&[{}]", octal_block_to_hex_string(s)),
|
||||
Ck::OptionBool(s) => write!(f, "Some({s}_BYTES)"),
|
||||
Ck::Trust(s) => write!(f, "{s}_BYTES"),
|
||||
Ck::Utf8(s) => write!(f, "\"{s}\\0\""),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Ck<'_> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Ck::Class(s), Ck::Class(t)) => s.eq(t),
|
||||
(Ck::Comment(s), Ck::Comment(t)) => s.eq(t),
|
||||
(Ck::DistrustAfter(None), Ck::DistrustAfter(None)) => true,
|
||||
(Ck::DistrustAfter(Some(s)), Ck::DistrustAfter(Some(t))) => {
|
||||
// compare the data rather than the presentation
|
||||
let vec_s = octal_block_to_vec_u8(s);
|
||||
let vec_t = octal_block_to_vec_u8(t);
|
||||
vec_s.eq(&vec_t)
|
||||
}
|
||||
(Ck::Empty, Ck::Empty) => true,
|
||||
(Ck::MultilineOctal(s), Ck::MultilineOctal(t)) => {
|
||||
// compare the data rather than the presentation
|
||||
let vec_s = octal_block_to_vec_u8(s);
|
||||
let vec_t = octal_block_to_vec_u8(t);
|
||||
vec_s.eq(&vec_t)
|
||||
}
|
||||
(Ck::Trust(s), Ck::Trust(t)) => s.eq(t),
|
||||
(Ck::Utf8(s), Ck::Utf8(t)) => s.eq(t),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn class(i: &str) -> IResult<&str, Ck> {
|
||||
let (i, _) = tag("CK_OBJECT_CLASS")(i)?;
|
||||
let (i, _) = space1(i)?;
|
||||
let (i, class) = alt((
|
||||
tag("CKO_NSS_BUILTIN_ROOT_LIST"),
|
||||
tag("CKO_CERTIFICATE"),
|
||||
tag("CKO_NSS_TRUST"),
|
||||
))(i)?;
|
||||
let (i, _) = space0(i)?;
|
||||
let (i, _) = newline(i)?;
|
||||
Ok((i, Ck::Class(class)))
|
||||
}
|
||||
|
||||
fn trust(i: &str) -> IResult<&str, Ck> {
|
||||
let (i, _) = tag("CK_TRUST")(i)?;
|
||||
let (i, _) = space1(i)?;
|
||||
let (i, trust) = alt((
|
||||
tag("CKT_NSS_TRUSTED_DELEGATOR"),
|
||||
tag("CKT_NSS_MUST_VERIFY_TRUST"),
|
||||
tag("CKT_NSS_NOT_TRUSTED"),
|
||||
))(i)?;
|
||||
let (i, _) = space0(i)?;
|
||||
let (i, _) = newline(i)?;
|
||||
Ok((i, Ck::Trust(trust)))
|
||||
}
|
||||
|
||||
// Parses a CK_BBOOL and wraps it with Ck::OptionBool so that it gets printed as
|
||||
// "Some(CK_TRUE_BYTES)" instead of "CK_TRUE_BYTES".
|
||||
fn option_bbool(i: &str) -> IResult<&str, Ck> {
|
||||
let (i, _) = tag("CK_BBOOL")(i)?;
|
||||
let (i, _) = space1(i)?;
|
||||
let (i, b) = alt((tag("CK_TRUE"), tag("CK_FALSE")))(i)?;
|
||||
let (i, _) = space0(i)?;
|
||||
let (i, _) = newline(i)?;
|
||||
Ok((i, Ck::OptionBool(b)))
|
||||
}
|
||||
|
||||
fn bbool_true(i: &str) -> IResult<&str, Ck> {
|
||||
let (i, _) = tag("CK_BBOOL")(i)?;
|
||||
let (i, _) = space1(i)?;
|
||||
let (i, _) = tag("CK_TRUE")(i)?;
|
||||
let (i, _) = space0(i)?;
|
||||
let (i, _) = newline(i)?;
|
||||
Ok((i, Ck::Empty))
|
||||
}
|
||||
|
||||
fn bbool_false(i: &str) -> IResult<&str, Ck> {
|
||||
let (i, _) = tag("CK_BBOOL")(i)?;
|
||||
let (i, _) = space1(i)?;
|
||||
let (i, _) = tag("CK_FALSE")(i)?;
|
||||
let (i, _) = space0(i)?;
|
||||
let (i, _) = newline(i)?;
|
||||
Ok((i, Ck::Empty))
|
||||
}
|
||||
|
||||
fn utf8(i: &str) -> IResult<&str, Ck> {
|
||||
let (i, _) = tag("UTF8")(i)?;
|
||||
let (i, _) = space1(i)?;
|
||||
let (i, _) = char('"')(i)?;
|
||||
let (i, utf8) = take_until("\"")(i)?;
|
||||
let (i, _) = char('"')(i)?;
|
||||
let (i, _) = space0(i)?;
|
||||
let (i, _) = newline(i)?;
|
||||
Ok((i, Ck::Utf8(utf8)))
|
||||
}
|
||||
|
||||
fn certificate_type(i: &str) -> IResult<&str, Ck> {
|
||||
let (i, _) = tag("CK_CERTIFICATE_TYPE")(i)?;
|
||||
let (i, _) = space1(i)?;
|
||||
let (i, _) = tag("CKC_X_509")(i)?;
|
||||
let (i, _) = space0(i)?;
|
||||
let (i, _) = newline(i)?;
|
||||
Ok((i, Ck::Empty))
|
||||
}
|
||||
|
||||
// A CKA_NSS_{EMAIL,SERVER}_DISTRUST_AFTER line in certdata.txt is encoded either as a CK_BBOOL
|
||||
// with value CK_FALSE (when there is no distrust after date) or as a MULTILINE_OCTAL block.
|
||||
fn distrust_after(i: &str) -> IResult<&str, Ck> {
|
||||
let (i, value) = alt((multiline_octal, bbool_false))(i)?;
|
||||
match value {
|
||||
Ck::Empty => Ok((i, Ck::DistrustAfter(None))),
|
||||
Ck::MultilineOctal(data) => Ok((i, Ck::DistrustAfter(Some(data)))),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn octal_octet(i: &str) -> IResult<&str, &str> {
|
||||
recognize(tuple((
|
||||
tag("\\"),
|
||||
one_of("0123"), // 255 = \377
|
||||
one_of("01234567"),
|
||||
one_of("01234567"),
|
||||
)))(i)
|
||||
}
|
||||
|
||||
fn multiline_octal(i: &str) -> IResult<&str, Ck> {
|
||||
let (i, _) = tag("MULTILINE_OCTAL")(i)?;
|
||||
let (i, _) = space0(i)?;
|
||||
let (i, _) = newline(i)?;
|
||||
let (i, lines) = recognize(many1(terminated(many1(octal_octet), newline)))(i)?;
|
||||
let (i, _) = tag("END")(i)?;
|
||||
let (i, _) = space0(i)?;
|
||||
let (i, _) = newline(i)?;
|
||||
return Ok((i, Ck::MultilineOctal(lines)));
|
||||
}
|
||||
|
||||
fn distrust_comment(i: &str) -> IResult<&str, (&str, Ck)> {
|
||||
let (i, comment) = recognize(delimited(
|
||||
alt((
|
||||
tag("# For Email Distrust After: "),
|
||||
tag("# For Server Distrust After: "),
|
||||
)),
|
||||
not_line_ending,
|
||||
newline,
|
||||
))(i)?;
|
||||
Ok((i, ("DISTRUST_COMMENT", Ck::Comment(comment))))
|
||||
}
|
||||
|
||||
fn comment(i: &str) -> IResult<&str, (&str, Ck)> {
|
||||
let (i, comment) = recognize(many1(delimited(char('#'), not_line_ending, newline)))(i)?;
|
||||
Ok((i, ("COMMENT", Ck::Comment(comment))))
|
||||
}
|
||||
|
||||
fn certdata_line(i: &str) -> IResult<&str, (&str, Ck)> {
|
||||
let (i, (attr, value)) = alt((
|
||||
distrust_comment, // must be listed before `comment`
|
||||
comment,
|
||||
separated_pair(tag("CKA_CLASS"), space1, class),
|
||||
separated_pair(tag("CKA_CERTIFICATE_TYPE"), space1, certificate_type),
|
||||
separated_pair(alt((tag("CKA_ID"), tag("CKA_LABEL"))), space1, utf8),
|
||||
separated_pair(
|
||||
alt((
|
||||
tag("CKA_ISSUER"),
|
||||
tag("CKA_CERT_SHA1_HASH"),
|
||||
tag("CKA_CERT_MD5_HASH"),
|
||||
tag("CKA_SERIAL_NUMBER"),
|
||||
tag("CKA_SUBJECT"),
|
||||
tag("CKA_VALUE"),
|
||||
)),
|
||||
space1,
|
||||
multiline_octal,
|
||||
),
|
||||
separated_pair(
|
||||
alt((
|
||||
tag("CKA_NSS_SERVER_DISTRUST_AFTER"),
|
||||
tag("CKA_NSS_EMAIL_DISTRUST_AFTER"),
|
||||
)),
|
||||
space1,
|
||||
distrust_after,
|
||||
),
|
||||
separated_pair(
|
||||
alt((
|
||||
tag("CKA_TRUST_EMAIL_PROTECTION"),
|
||||
tag("CKA_TRUST_CODE_SIGNING"),
|
||||
tag("CKA_TRUST_SERVER_AUTH"),
|
||||
)),
|
||||
space1,
|
||||
trust,
|
||||
),
|
||||
separated_pair(tag("CKA_NSS_MOZILLA_CA_POLICY"), space1, option_bbool),
|
||||
separated_pair(tag("CKA_TOKEN"), space1, bbool_true),
|
||||
separated_pair(
|
||||
alt((
|
||||
tag("CKA_TRUST_STEP_UP_APPROVED"),
|
||||
tag("CKA_PRIVATE"),
|
||||
tag("CKA_MODIFIABLE"),
|
||||
)),
|
||||
space1,
|
||||
bbool_false,
|
||||
),
|
||||
))(i)?;
|
||||
Ok((i, (attr, value)))
|
||||
}
|
||||
|
||||
type Block<'a> = HashMap<&'a str, Ck<'a>>;
|
||||
|
||||
fn attr<'a>(block: &'a Block, attr: &str) -> &'a Ck<'a> {
|
||||
block.get(attr).unwrap_or(&Ck::Empty)
|
||||
}
|
||||
|
||||
fn parse(i: &str) -> IResult<&str, Vec<Block>> {
|
||||
let mut out: Vec<Block> = vec![];
|
||||
let (i, _) = take_until("BEGINDATA\n")(i)?;
|
||||
let (i, _) = tag("BEGINDATA\n")(i)?;
|
||||
let (i, mut raw_blocks) = separated_list0(many1(char('\n')), many1(certdata_line))(i)?;
|
||||
let (i, _) = multispace0(i)?; // allow trailing whitespace
|
||||
if !i.is_empty() {
|
||||
// The first line of i contains an error.
|
||||
let (line, _) = i.split_once('\n').unwrap_or((i, ""));
|
||||
fail::<_, &str, _>(line)?;
|
||||
}
|
||||
for raw_block in raw_blocks.drain(..) {
|
||||
out.push(raw_block.into_iter().collect())
|
||||
}
|
||||
Ok((i, out))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PKCS11TypesParseCallbacks;
|
||||
|
||||
impl ParseCallbacks for PKCS11TypesParseCallbacks {
|
||||
fn int_macro(&self, _name: &str, _value: i64) -> Option<IntKind> {
|
||||
Some(IntKind::U8)
|
||||
}
|
||||
}
|
||||
|
||||
// If we encounter a problem parsing certdata.txt we'll try to turn it into a compile time
|
||||
// error in builtins.rs. We need to output definitions for ROOT_LIST_LABEL and BUILTINS to
|
||||
// cut down on the number of errors the compiler produces.
|
||||
macro_rules! emit_build_error {
|
||||
($out:ident, $err:expr) => {
|
||||
writeln!($out, "std::compile_error!(\"{}\");", $err)?;
|
||||
writeln!($out, "pub static ROOT_LIST_LABEL: &[u8] = b\"\";")?;
|
||||
writeln!($out, "pub static BUILTINS: &[Root] = &[];")?;
|
||||
};
|
||||
}
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
println!("cargo:rerun-if-changed=../../../nss/lib/ckfw/builtins/certdata.txt");
|
||||
println!("cargo:rerun-if-changed=../../../nss/lib/ckfw/builtins/nssckbi.h");
|
||||
|
||||
let bindings = Builder::default()
|
||||
.header("../../../nss/lib/ckfw/builtins/nssckbi.h")
|
||||
.allowlist_var("NSS_BUILTINS_CRYPTOKI_VERSION_MAJOR")
|
||||
.allowlist_var("NSS_BUILTINS_CRYPTOKI_VERSION_MINOR")
|
||||
.allowlist_var("NSS_BUILTINS_LIBRARY_VERSION_MAJOR")
|
||||
.allowlist_var("NSS_BUILTINS_LIBRARY_VERSION_MINOR")
|
||||
.allowlist_var("NSS_BUILTINS_HARDWARE_VERSION_MAJOR")
|
||||
.allowlist_var("NSS_BUILTINS_HARDWARE_VERSION_MINOR")
|
||||
.allowlist_var("NSS_BUILTINS_FIRMWARE_VERSION_MAJOR")
|
||||
.allowlist_var("NSS_BUILTINS_FIRMWARE_VERSION_MINOR")
|
||||
.parse_callbacks(Box::new(PKCS11TypesParseCallbacks))
|
||||
.generate()
|
||||
.expect("Unable to generate bindings.");
|
||||
|
||||
let out_path = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR should be set in env."));
|
||||
bindings
|
||||
.write_to_file(out_path.join("version.rs"))
|
||||
.expect("Could not write version.rs.");
|
||||
|
||||
let mut out = BufWriter::new(
|
||||
File::create(out_path.join("builtins.rs")).expect("Could not write builtins.rs."),
|
||||
);
|
||||
|
||||
let input: &str = &std::fs::read_to_string("../../../nss/lib/ckfw/builtins/certdata.txt")
|
||||
.expect("Unable to read certdata.txt.");
|
||||
|
||||
let blocks = match parse(input) {
|
||||
Ok((_, blocks)) => blocks,
|
||||
Err(e) => {
|
||||
let input = match e {
|
||||
nom::Err::Error(nom::error::Error { input, .. }) => input,
|
||||
_ => "Unknown",
|
||||
};
|
||||
emit_build_error!(
|
||||
out,
|
||||
&format!(
|
||||
"Could not parse certdata.txt. Failed at: \'{}\'\");",
|
||||
input.escape_debug().to_string().escape_debug()
|
||||
)
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
let root_lists: Vec<&Block> = blocks
|
||||
.iter()
|
||||
.filter(|x| attr(x, "CKA_CLASS") == &Ck::Class("CKO_NSS_BUILTIN_ROOT_LIST"))
|
||||
.collect();
|
||||
|
||||
if root_lists.len() != 1 {
|
||||
emit_build_error!(
|
||||
out,
|
||||
"certdata.txt does not define a CKO_NSS_BUILTIN_ROOT_LIST object."
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut certs: Vec<&Block> = blocks
|
||||
.iter()
|
||||
.filter(|x| attr(x, "CKA_CLASS") == &Ck::Class("CKO_CERTIFICATE"))
|
||||
.collect();
|
||||
|
||||
let trusts: Vec<&Block> = blocks
|
||||
.iter()
|
||||
.filter(|x| attr(x, "CKA_CLASS") == &Ck::Class("CKO_NSS_TRUST"))
|
||||
.collect();
|
||||
|
||||
if certs.len() != trusts.len() {
|
||||
emit_build_error!(
|
||||
out,
|
||||
"certdata.txt has a mismatched number of certificate and trust objects"
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Ensure that every certificate has a CKA_SUBJECT attribute for the sort
|
||||
for (i, cert) in certs.iter().enumerate() {
|
||||
match cert.get("CKA_SUBJECT") {
|
||||
Some(Ck::MultilineOctal(_)) => (),
|
||||
_ => {
|
||||
emit_build_error!(
|
||||
out,
|
||||
format!(
|
||||
"Certificate {} in certdata.txt has no CKA_SUBJECT attribute.",
|
||||
i
|
||||
)
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
certs.sort_by_cached_key(|x| match x.get("CKA_SUBJECT") {
|
||||
Some(Ck::MultilineOctal(data)) => octal_block_to_vec_u8(data),
|
||||
_ => unreachable!(),
|
||||
});
|
||||
|
||||
let root_list_label = attr(root_lists[0], "CKA_LABEL");
|
||||
writeln!(
|
||||
out,
|
||||
"pub const ROOT_LIST_LABEL: &[u8] = b{root_list_label};"
|
||||
)?;
|
||||
|
||||
// Output all of the certificates, so we can take take sub-slices for
|
||||
// components of the Root structs later.
|
||||
for (i, cert) in certs.iter().enumerate() {
|
||||
let comment = match attr(cert, "COMMENT") {
|
||||
Ck::Empty => &Ck::Comment(""),
|
||||
comment => comment,
|
||||
};
|
||||
let der = attr(cert, "CKA_VALUE");
|
||||
writeln!(out, "{comment}static ROOT_{i}: &[u8] = {der};")?;
|
||||
}
|
||||
|
||||
writeln!(out, "pub static BUILTINS: &[Root] = &[")?;
|
||||
for (i, cert) in certs.iter().enumerate() {
|
||||
let subject = attr(cert, "CKA_SUBJECT");
|
||||
let issuer = attr(cert, "CKA_ISSUER");
|
||||
let label = attr(cert, "CKA_LABEL");
|
||||
if !subject.eq(issuer) {
|
||||
writeln!(out, "];")?; // end the definition of BUILTINS
|
||||
let label = format!("{}", label);
|
||||
writeln!(
|
||||
out,
|
||||
"std::compile_error!(\"Certificate with label {} is not self-signed\");",
|
||||
label.escape_debug()
|
||||
)?;
|
||||
return Ok(());
|
||||
}
|
||||
let serial = attr(cert, "CKA_SERIAL_NUMBER");
|
||||
let mozpol = attr(cert, "CKA_NSS_MOZILLA_CA_POLICY");
|
||||
let server_distrust = attr(cert, "CKA_NSS_SERVER_DISTRUST_AFTER");
|
||||
let email_distrust = attr(cert, "CKA_NSS_EMAIL_DISTRUST_AFTER");
|
||||
let matching_trusts: Vec<&&Block> = trusts
|
||||
.iter()
|
||||
.filter(|trust| {
|
||||
(attr(cert, "CKA_ISSUER") == attr(trust, "CKA_ISSUER"))
|
||||
&& (attr(cert, "CKA_SERIAL_NUMBER") == attr(trust, "CKA_SERIAL_NUMBER"))
|
||||
})
|
||||
.collect();
|
||||
if matching_trusts.len() != 1 {
|
||||
writeln!(out, "];")?; // end the definition of BUILTINS
|
||||
let label = format!("{}", label);
|
||||
writeln!(out, "std::compile_error!(\"Could not find unique trust object for {} in certdata.txt\");", label.escape_debug())?;
|
||||
return Ok(());
|
||||
}
|
||||
let trust = *matching_trusts[0];
|
||||
let sha1 = attr(trust, "CKA_CERT_SHA1_HASH");
|
||||
let md5 = attr(trust, "CKA_CERT_MD5_HASH");
|
||||
let server = attr(trust, "CKA_TRUST_SERVER_AUTH");
|
||||
let email = attr(trust, "CKA_TRUST_EMAIL_PROTECTION");
|
||||
|
||||
// TODO(Bug 1794045): We could make the library smaller by encoding der_name and der_serial
|
||||
// as subslices of ROOT_i. Should be possible in rust 1.64 using slice::from_raw_parts.
|
||||
writeln!(
|
||||
out,
|
||||
" Root {{
|
||||
label: {label},
|
||||
der_name: {subject},
|
||||
der_serial: {serial},
|
||||
der_cert: ROOT_{i},
|
||||
mozilla_ca_policy: {mozpol},
|
||||
server_distrust_after: {server_distrust},
|
||||
email_distrust_after: {email_distrust},
|
||||
sha1: {sha1},
|
||||
md5: {md5},
|
||||
trust_server: {server},
|
||||
trust_email: {email},
|
||||
}},"
|
||||
)?;
|
||||
}
|
||||
writeln!(out, "];")?;
|
||||
|
||||
let _ = out.flush();
|
||||
Ok(())
|
||||
}
|
@ -0,0 +1 @@
|
||||
C_GetFunctionList
|
37
security/manager/ssl/builtins/dynamic-library/moz.build
Normal file
37
security/manager/ssl/builtins/dynamic-library/moz.build
Normal file
@ -0,0 +1,37 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
USE_LIBS += ["builtins-static"]
|
||||
|
||||
# see notes in ipcclientcerts/dynamic-library/moz.build
|
||||
|
||||
if CONFIG["OS_ARCH"] == "Linux" and CONFIG["OS_TARGET"] != "Android":
|
||||
SOURCES += [
|
||||
"stub.cpp",
|
||||
]
|
||||
else:
|
||||
SOURCES += [
|
||||
"stub.c",
|
||||
]
|
||||
|
||||
if CONFIG["OS_TARGET"] == "Android":
|
||||
OS_LIBS += ["m"]
|
||||
|
||||
if CONFIG["OS_ARCH"] == "WINNT":
|
||||
OS_LIBS += [
|
||||
"advapi32",
|
||||
"userenv",
|
||||
"ws2_32",
|
||||
]
|
||||
OS_LIBS += [
|
||||
"bcrypt",
|
||||
]
|
||||
|
||||
|
||||
SharedLibrary("nssckbi")
|
||||
|
||||
NoVisibilityFlags()
|
||||
SYMBOLS_FILE = "builtins.symbols"
|
19
security/manager/ssl/builtins/dynamic-library/stub.c
Normal file
19
security/manager/ssl/builtins/dynamic-library/stub.c
Normal file
@ -0,0 +1,19 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "pkcs11.h"
|
||||
|
||||
// see notes in ipcclientcerts/dynamic-library/stub.c
|
||||
|
||||
CK_RV BUILTINSC_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList);
|
||||
|
||||
CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) {
|
||||
return BUILTINSC_GetFunctionList(ppFunctionList);
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
# include "mozilla/Assertions.h"
|
||||
void _Unwind_Resume() { MOZ_CRASH("Unexpected call to _Unwind_Resume"); }
|
||||
#endif
|
17
security/manager/ssl/builtins/dynamic-library/stub.cpp
Normal file
17
security/manager/ssl/builtins/dynamic-library/stub.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "pkcs11.h"
|
||||
|
||||
// see notes in ipcclientcerts/dynamic-library/stub.cpp
|
||||
|
||||
extern "C" {
|
||||
|
||||
CK_RV BUILTINSC_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList);
|
||||
|
||||
CK_RV C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList) {
|
||||
return BUILTINSC_GetFunctionList(ppFunctionList);
|
||||
}
|
||||
}
|
9
security/manager/ssl/builtins/moz.build
Normal file
9
security/manager/ssl/builtins/moz.build
Normal file
@ -0,0 +1,9 @@
|
||||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DIRS += ["dynamic-library"]
|
||||
|
||||
RustLibrary("builtins-static")
|
43
security/manager/ssl/builtins/src/certdata.rs
Normal file
43
security/manager/ssl/builtins/src/certdata.rs
Normal file
@ -0,0 +1,43 @@
|
||||
/* -*- Mode: rust; rust-indent-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use pkcs11_bindings::nss::*;
|
||||
use pkcs11_bindings::*;
|
||||
|
||||
// We need to expand some PKCS#11 / NSS constants as byte arrays for pattern matching and
|
||||
// C_GetAttributeValue queries. We use native endianness, because PKCS#11 sits between an
|
||||
// application and a device driver that are running on the same machine.
|
||||
pub const CKC_X_509_BYTES: &[u8] = &CKC_X_509.to_ne_bytes();
|
||||
pub const CKO_CERTIFICATE_BYTES: &[u8] = &CKO_CERTIFICATE.to_ne_bytes();
|
||||
pub const CKO_NSS_BUILTIN_ROOT_LIST_BYTES: &[u8] = &CKO_NSS_BUILTIN_ROOT_LIST.to_ne_bytes();
|
||||
pub const CKO_NSS_TRUST_BYTES: &[u8] = &CKO_NSS_TRUST.to_ne_bytes();
|
||||
pub const CKT_NSS_MUST_VERIFY_TRUST_BYTES: &[u8] = &CKT_NSS_MUST_VERIFY_TRUST.to_ne_bytes();
|
||||
pub const CKT_NSS_NOT_TRUSTED_BYTES: &[u8] = &CKT_NSS_NOT_TRUSTED.to_ne_bytes();
|
||||
pub const CKT_NSS_TRUSTED_DELEGATOR_BYTES: &[u8] = &CKT_NSS_TRUSTED_DELEGATOR.to_ne_bytes();
|
||||
pub const CK_FALSE_BYTES: &[u8] = &CK_FALSE.to_ne_bytes();
|
||||
pub const CK_TRUE_BYTES: &[u8] = &CK_TRUE.to_ne_bytes();
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct Root {
|
||||
pub label: &'static str,
|
||||
pub der_name: &'static [u8],
|
||||
pub der_serial: &'static [u8],
|
||||
pub der_cert: &'static [u8],
|
||||
pub mozilla_ca_policy: Option<&'static [u8]>,
|
||||
pub server_distrust_after: Option<&'static [u8]>,
|
||||
pub email_distrust_after: Option<&'static [u8]>,
|
||||
pub sha1: &'static [u8],
|
||||
pub md5: &'static [u8],
|
||||
pub trust_server: &'static [u8],
|
||||
pub trust_email: &'static [u8],
|
||||
}
|
||||
|
||||
impl PartialOrd for Root {
|
||||
fn partial_cmp(&self, other: &Root) -> Option<std::cmp::Ordering> {
|
||||
self.der_name.partial_cmp(other.der_name)
|
||||
}
|
||||
}
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/builtins.rs"));
|
344
security/manager/ssl/builtins/src/internal.rs
Normal file
344
security/manager/ssl/builtins/src/internal.rs
Normal file
@ -0,0 +1,344 @@
|
||||
/* -*- Mode: rust; rust-indent-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use pkcs11_bindings::nss::*;
|
||||
use pkcs11_bindings::*;
|
||||
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::certdata::*;
|
||||
|
||||
// The token stores 2N+1 objects: one NSS root list object, N certificate objects, and N trust
|
||||
// objects.
|
||||
//
|
||||
// Internally, the token identifies each object by its ObjectClass (RootList, Certificate,
|
||||
// or Trust) and its index in the list of objects of the same class.
|
||||
//
|
||||
// The PKCS#11 interface, on the other hand, identifies each object with a unique, non-zero,
|
||||
// unsigned long. This ulong is referred to as the object's CK_OBJECT_HANDLE.
|
||||
//
|
||||
// We're free to choose the mapping between ObjectHandles and CK_OBJECT_HANDLEs. Currently we
|
||||
// encode the ObjectClass in the low 2 bits of the CK_OBJECT_HANDLE and the index in the higher
|
||||
// bits. We use the values 1, 2, and 3 for ObjectClass to avoid using 0 as a CK_OBJECT_HANDLE.
|
||||
//
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ObjectClass {
|
||||
RootList = 1,
|
||||
Certificate = 2,
|
||||
Trust = 3,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ObjectHandle {
|
||||
class: ObjectClass,
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl TryFrom<CK_OBJECT_HANDLE> for ObjectHandle {
|
||||
type Error = ();
|
||||
fn try_from(handle: CK_OBJECT_HANDLE) -> Result<Self, Self::Error> {
|
||||
if let Ok(handle) = usize::try_from(handle) {
|
||||
let index = handle >> 2;
|
||||
let class = match handle & 3 {
|
||||
1 if index == 0 => ObjectClass::RootList,
|
||||
2 if index < BUILTINS.len() => ObjectClass::Certificate,
|
||||
3 if index < BUILTINS.len() => ObjectClass::Trust,
|
||||
_ => return Err(()),
|
||||
};
|
||||
Ok(ObjectHandle { class, index })
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ObjectHandle> for CK_OBJECT_HANDLE {
|
||||
fn from(object_handle: ObjectHandle) -> CK_OBJECT_HANDLE {
|
||||
match CK_OBJECT_HANDLE::try_from(object_handle.index) {
|
||||
Ok(index) => (index << 2) | (object_handle.class as CK_OBJECT_HANDLE),
|
||||
Err(_) => 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_attribute(attribute: CK_ATTRIBUTE_TYPE, object: &ObjectHandle) -> Option<&'static [u8]> {
|
||||
match object.class {
|
||||
ObjectClass::RootList => get_root_list_attribute(attribute),
|
||||
ObjectClass::Certificate => get_cert_attribute(attribute, &BUILTINS[object.index]),
|
||||
ObjectClass::Trust => get_trust_attribute(attribute, &BUILTINS[object.index]),
|
||||
}
|
||||
}
|
||||
|
||||
// Every attribute that appears in certdata.txt must have a corresponding match arm in one of the
|
||||
// get_*_attribute functions.
|
||||
//
|
||||
fn get_root_list_attribute(attribute: CK_ATTRIBUTE_TYPE) -> Option<&'static [u8]> {
|
||||
match attribute {
|
||||
CKA_CLASS => Some(CKO_NSS_BUILTIN_ROOT_LIST_BYTES),
|
||||
CKA_TOKEN => Some(CK_TRUE_BYTES),
|
||||
CKA_PRIVATE => Some(CK_FALSE_BYTES),
|
||||
CKA_MODIFIABLE => Some(CK_FALSE_BYTES),
|
||||
CKA_LABEL => Some(ROOT_LIST_LABEL),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_cert_attribute(attribute: CK_ATTRIBUTE_TYPE, cert: &Root) -> Option<&'static [u8]> {
|
||||
match attribute {
|
||||
CKA_CLASS => Some(CKO_CERTIFICATE_BYTES),
|
||||
CKA_TOKEN => Some(CK_TRUE_BYTES),
|
||||
CKA_PRIVATE => Some(CK_FALSE_BYTES),
|
||||
CKA_MODIFIABLE => Some(CK_FALSE_BYTES),
|
||||
CKA_LABEL => Some(cert.label.as_bytes()),
|
||||
CKA_CERTIFICATE_TYPE => Some(CKC_X_509_BYTES),
|
||||
CKA_SUBJECT => Some(cert.der_name),
|
||||
CKA_ID => Some(b"0\0"), // null terminated to match C implementation
|
||||
CKA_ISSUER => Some(cert.der_name),
|
||||
CKA_SERIAL_NUMBER => Some(cert.der_serial),
|
||||
CKA_VALUE => Some(cert.der_cert),
|
||||
CKA_NSS_MOZILLA_CA_POLICY => cert.mozilla_ca_policy,
|
||||
CKA_NSS_SERVER_DISTRUST_AFTER => cert.server_distrust_after,
|
||||
CKA_NSS_EMAIL_DISTRUST_AFTER => cert.email_distrust_after,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_trust_attribute(attribute: CK_ATTRIBUTE_TYPE, cert: &Root) -> Option<&'static [u8]> {
|
||||
match attribute {
|
||||
CKA_CLASS => Some(CKO_NSS_TRUST_BYTES),
|
||||
CKA_TOKEN => Some(CK_TRUE_BYTES),
|
||||
CKA_PRIVATE => Some(CK_FALSE_BYTES),
|
||||
CKA_MODIFIABLE => Some(CK_FALSE_BYTES),
|
||||
CKA_LABEL => Some(cert.label.as_bytes()),
|
||||
CKA_CERT_SHA1_HASH => Some(cert.sha1),
|
||||
CKA_CERT_MD5_HASH => Some(cert.md5),
|
||||
CKA_ISSUER => Some(cert.der_name),
|
||||
CKA_SERIAL_NUMBER => Some(cert.der_serial),
|
||||
CKA_TRUST_STEP_UP_APPROVED => Some(CK_FALSE_BYTES),
|
||||
CKA_TRUST_SERVER_AUTH => Some(cert.trust_server),
|
||||
CKA_TRUST_EMAIL_PROTECTION => Some(cert.trust_email),
|
||||
CKA_TRUST_CODE_SIGNING => Some(CKT_NSS_MUST_VERIFY_TRUST_BYTES),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
// A query matches an object if each term matches some attribute of the object. A search result is
|
||||
// a list of object handles. Typical queries yield zero or one results, so we optimize for this
|
||||
// case.
|
||||
//
|
||||
pub type Query<'a> = [(CK_ATTRIBUTE_TYPE, &'a [u8])];
|
||||
pub type SearchResult = SmallVec<[ObjectHandle; 1]>;
|
||||
|
||||
pub fn search(query: &Query) -> SearchResult {
|
||||
// The BUILTINS list is sorted by name. So if the query includes a CKA_SUBJECT or CKA_ISSUER
|
||||
// field we can binary search.
|
||||
for &(attr, value) in query {
|
||||
if attr == CKA_SUBJECT || attr == CKA_ISSUER {
|
||||
return search_by_name(value, query);
|
||||
}
|
||||
}
|
||||
|
||||
let mut results: SearchResult = SearchResult::default();
|
||||
|
||||
// A query with no name term might match the root list object
|
||||
if match_root_list(query) {
|
||||
results.push(ObjectHandle {
|
||||
class: ObjectClass::RootList,
|
||||
index: 0,
|
||||
});
|
||||
}
|
||||
|
||||
// A query with a CKA_CLASS term matches exactly one type of object, and we should avoid
|
||||
// iterating over BUILTINS when CKO_CLASS is neither CKO_CERTIFICATE_BYTES nor
|
||||
// CKO_NSS_TRUST_BYTES.
|
||||
let mut maybe_cert = true;
|
||||
let mut maybe_trust = true;
|
||||
for &(attr, value) in query {
|
||||
if attr == CKA_CLASS {
|
||||
maybe_cert = value.eq(CKO_CERTIFICATE_BYTES);
|
||||
maybe_trust = value.eq(CKO_NSS_TRUST_BYTES);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if !(maybe_cert || maybe_trust) {
|
||||
return results; // The root list or nothing.
|
||||
}
|
||||
|
||||
for (index, builtin) in BUILTINS.iter().enumerate() {
|
||||
if maybe_cert && match_cert(query, builtin) {
|
||||
results.push(ObjectHandle {
|
||||
class: ObjectClass::Certificate,
|
||||
index,
|
||||
});
|
||||
}
|
||||
if maybe_trust && match_trust(query, builtin) {
|
||||
results.push(ObjectHandle {
|
||||
class: ObjectClass::Trust,
|
||||
index,
|
||||
});
|
||||
}
|
||||
}
|
||||
results
|
||||
}
|
||||
|
||||
fn search_by_name(name: &[u8], query: &Query) -> SearchResult {
|
||||
let mut results: SearchResult = SearchResult::default();
|
||||
|
||||
let index = match BUILTINS.binary_search_by_key(&name, |r| r.der_name) {
|
||||
Ok(index) => index,
|
||||
_ => return results,
|
||||
};
|
||||
|
||||
// binary search returned a matching index, but maybe not the smallest
|
||||
let mut min = index;
|
||||
while min > 0 && name.eq(BUILTINS[min - 1].der_name) {
|
||||
min -= 1;
|
||||
}
|
||||
|
||||
// ... and maybe not the largest.
|
||||
let mut max = index;
|
||||
while max < BUILTINS.len() - 1 && name.eq(BUILTINS[max + 1].der_name) {
|
||||
max += 1;
|
||||
}
|
||||
|
||||
for (index, builtin) in BUILTINS.iter().enumerate().take(max + 1).skip(min) {
|
||||
if match_cert(query, builtin) {
|
||||
results.push(ObjectHandle {
|
||||
class: ObjectClass::Certificate,
|
||||
index,
|
||||
});
|
||||
}
|
||||
if match_trust(query, builtin) {
|
||||
results.push(ObjectHandle {
|
||||
class: ObjectClass::Trust,
|
||||
index,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
fn match_root_list(query: &Query) -> bool {
|
||||
for &(typ, x) in query {
|
||||
match get_root_list_attribute(typ) {
|
||||
Some(y) if x.eq(y) => (),
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn match_cert(query: &Query, cert: &Root) -> bool {
|
||||
for &(typ, x) in query {
|
||||
match get_cert_attribute(typ, cert) {
|
||||
Some(y) if x.eq(y) => (),
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn match_trust(query: &Query, cert: &Root) -> bool {
|
||||
for &(typ, x) in query {
|
||||
match get_trust_attribute(typ, cert) {
|
||||
Some(y) if x.eq(y) => (),
|
||||
_ => return false,
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod internal_tests {
|
||||
use crate::certdata::BUILTINS;
|
||||
use crate::internal::*;
|
||||
use pkcs11_bindings::*;
|
||||
|
||||
// commented out to avoid vendoring x509_parser
|
||||
// fn is_valid_utctime(utctime: &[u8]) -> bool {
|
||||
// /* TODO: actual validation */
|
||||
// utctime.len() == 13
|
||||
// }
|
||||
// #[test]
|
||||
// fn test_certdata() {
|
||||
// for root in BUILTINS {
|
||||
// // the der_cert field is valid DER
|
||||
// let parsed_cert = X509Certificate::from_der(root.der_cert);
|
||||
// assert!(parsed_cert.is_ok());
|
||||
|
||||
// // the der_cert field has no trailing data
|
||||
// let (trailing, parsed_cert) = parsed_cert.unwrap();
|
||||
// assert!(trailing.is_empty());
|
||||
|
||||
// // the der_serial field matches the encoded serial
|
||||
// assert!(root.der_serial.len() > 2);
|
||||
// assert!(root.der_serial[0] == 0x02); // der integer
|
||||
// assert!(root.der_serial[1] <= 20); // no more than 20 bytes long
|
||||
// assert!(root.der_serial[1] as usize == root.der_serial.len() - 2);
|
||||
// assert!(parsed_cert.raw_serial().eq(&root.der_serial[2..]));
|
||||
|
||||
// // the der_name field matches the encoded subject
|
||||
// assert!(parsed_cert.subject.as_raw().eq(root.der_name));
|
||||
|
||||
// // the der_name field matches the encoded issuer
|
||||
// assert!(parsed_cert.issuer.as_raw().eq(root.der_name));
|
||||
|
||||
// // The server_distrust_after field is None or a valid UTC time
|
||||
// if let Some(utctime) = root.server_distrust_after {
|
||||
// assert!(is_valid_utctime(&utctime));
|
||||
// }
|
||||
|
||||
// // The email_distrust_after field is None or a valid UTC time
|
||||
// if let Some(utctime) = root.email_distrust_after {
|
||||
// assert!(is_valid_utctime(&utctime));
|
||||
// }
|
||||
|
||||
// assert!(
|
||||
// root.trust_server == CKT_NSS_MUST_VERIFY_TRUST_BYTES
|
||||
// || root.trust_server == CKT_NSS_TRUSTED_DELEGATOR_BYTES
|
||||
// || root.trust_server == CKT_NSS_NOT_TRUSTED_BYTES
|
||||
// );
|
||||
// assert!(
|
||||
// root.trust_email == CKT_NSS_MUST_VERIFY_TRUST_BYTES
|
||||
// || root.trust_email == CKT_NSS_TRUSTED_DELEGATOR_BYTES
|
||||
// || root.trust_email == CKT_NSS_NOT_TRUSTED_BYTES
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_builtins_sorted() {
|
||||
for i in 0..(BUILTINS.len() - 1) {
|
||||
assert!(BUILTINS[i].der_name.le(BUILTINS[i + 1].der_name));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_search() {
|
||||
// search for an element that will not be found
|
||||
let result = search(&[(CKA_TOKEN, &[CK_FALSE])]);
|
||||
assert_eq!(result.len(), 0);
|
||||
|
||||
// search for root list
|
||||
let result = search(&[(CKA_CLASS, CKO_NSS_BUILTIN_ROOT_LIST_BYTES)]);
|
||||
assert!(result.len() == 1);
|
||||
|
||||
// search by name
|
||||
let result = search(&[
|
||||
(CKA_CLASS, CKO_CERTIFICATE_BYTES),
|
||||
(CKA_SUBJECT, BUILTINS[0].der_name),
|
||||
]);
|
||||
assert!(result.len() >= 1);
|
||||
|
||||
// search by issuer and serial
|
||||
let result = search(&[
|
||||
(CKA_ISSUER, BUILTINS[0].der_name),
|
||||
(CKA_SERIAL_NUMBER, BUILTINS[0].der_serial),
|
||||
]);
|
||||
assert!(result.len() >= 1);
|
||||
}
|
||||
}
|
9
security/manager/ssl/builtins/src/lib.rs
Normal file
9
security/manager/ssl/builtins/src/lib.rs
Normal file
@ -0,0 +1,9 @@
|
||||
/* -*- Mode: rust; rust-indent-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
mod certdata;
|
||||
mod internal;
|
||||
mod pkcs11;
|
||||
mod version;
|
1227
security/manager/ssl/builtins/src/pkcs11.rs
Normal file
1227
security/manager/ssl/builtins/src/pkcs11.rs
Normal file
File diff suppressed because it is too large
Load Diff
6
security/manager/ssl/builtins/src/version.rs
Normal file
6
security/manager/ssl/builtins/src/version.rs
Normal file
@ -0,0 +1,6 @@
|
||||
/* -*- Mode: rust; rust-indent-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/version.rs"));
|
@ -13,6 +13,7 @@ if (CONFIG["OS_ARCH"] == "WINNT" and CONFIG["CPU_ARCH"] != "aarch64") or CONFIG[
|
||||
DIRS += ["osclientcerts"]
|
||||
|
||||
DIRS += ["ipcclientcerts"]
|
||||
DIRS += ["builtins"]
|
||||
|
||||
TEST_DIRS += ["tests"]
|
||||
|
||||
|
@ -86,6 +86,9 @@ gyp_vars["disable_tests"] = 1
|
||||
gyp_vars["disable_dbm"] = 1
|
||||
gyp_vars["disable_libpkix"] = 1
|
||||
gyp_vars["enable_sslkeylogfile"] = 1
|
||||
# Whether we're using system NSS or Rust nssckbi, we don't need
|
||||
# to build C nssckbi
|
||||
gyp_vars["disable_ckbi"] = 1
|
||||
# pkg-config won't reliably find zlib on our builders, so just force it.
|
||||
# System zlib is only used for modutil and signtool unless
|
||||
# SSL zlib is enabled, which we are disabling immediately below this.
|
||||
|
@ -890,6 +890,11 @@ auto-generated by running bindgen on the PKCS#11 specification headers. Other
|
||||
than the tests generated by bindgen, it consists of no runnable code.
|
||||
"""
|
||||
|
||||
[[audits.pkcs11-bindings]]
|
||||
who = "John M. Schanck <jmschanck@gmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
version = "0.1.1"
|
||||
|
||||
[[audits.precomputed-hash]]
|
||||
who = "Bobby Holley <bobbyholley@gmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"89762b452690c9480c9ffdbccf7959e76ec2c65664840dc5dd5840b2a64459de","LICENSE":"c0813b208cee13e9e06931186dc83b9577dbaa02e6a9dfee170c4873f11878d9","build.rs":"d6b1fadb210fe7e614c8976192c0a72eaeb74a09fb99688d7b540c89c2c57745","pkcs11.h":"fb113f0bc62e0d0894dd1c499b10659e6c47a8ec00d467a186770e07f9c9e293","pkcs11f.h":"11ee1d5026b1590a6c4a12be1023a2aec9ee185ba31bfb470084e4b6254779ee","pkcs11t.h":"2a152db4d461e9a315428a3d037ff1ae896baa04af9d9409d696b3cbd4478c6c","src/lib.rs":"74bbfdf6d931e82c21e3c4335717d90ed60a46a8ec65e602fb7ac34f40c5c6ae","wrapper.h":"1b86ee3838c94bc5a5c9513ef6961f9b6b3a5f6dde7c6fbfdc0cf58cb0fbd318"},"package":"054f65db435bb7cf99db2f38bbcf568dfa66c342201df54e700c772b178e2f20"}
|
||||
{"files":{"Cargo.toml":"3aa6a273775dc5e2045cab20190559e416371dbfe9fa89f50c2c44beb1c97d24","LICENSE":"c0813b208cee13e9e06931186dc83b9577dbaa02e6a9dfee170c4873f11878d9","build.rs":"803e766f05b2558a36873af2950e768f81f2aa954ce40d96ba7d83ac7c6dd953","pkcs11.h":"fb113f0bc62e0d0894dd1c499b10659e6c47a8ec00d467a186770e07f9c9e293","pkcs11f.h":"11ee1d5026b1590a6c4a12be1023a2aec9ee185ba31bfb470084e4b6254779ee","pkcs11t.h":"2a152db4d461e9a315428a3d037ff1ae896baa04af9d9409d696b3cbd4478c6c","src/lib.rs":"25f2ffe3aba98817b109b1bbfeccbde7a632aab353a032c6ccf7ea248b09af76","wrapper.h":"1b86ee3838c94bc5a5c9513ef6961f9b6b3a5f6dde7c6fbfdc0cf58cb0fbd318"},"package":"780bf71a814823f87d50b5bfbfd4ba5f2af46819a01f0ac31238f650693eb592"}
|
8
third_party/rust/pkcs11-bindings/Cargo.toml
vendored
8
third_party/rust/pkcs11-bindings/Cargo.toml
vendored
@ -12,12 +12,16 @@
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "pkcs11-bindings"
|
||||
version = "0.1.0"
|
||||
authors = ["Dana Keeler <dkeeler@mozilla.com>"]
|
||||
version = "0.1.1"
|
||||
authors = [
|
||||
"Dana Keeler <dkeeler@mozilla.com>",
|
||||
"John Schanck <jschanck@mozilla.com>",
|
||||
]
|
||||
build = "build.rs"
|
||||
description = "Rust bindings for the PKCS#11 specification"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/mozilla/pkcs11-bindings"
|
||||
resolver = "1"
|
||||
|
||||
[build-dependencies.bindgen]
|
||||
version = "0.59"
|
||||
|
5
third_party/rust/pkcs11-bindings/build.rs
vendored
5
third_party/rust/pkcs11-bindings/build.rs
vendored
@ -17,7 +17,7 @@ impl ParseCallbacks for PKCS11TypesParseCallbacks {
|
||||
}
|
||||
|
||||
fn int_macro(&self, name: &str, _value: i64) -> Option<IntKind> {
|
||||
if name == "CK_TRUE" {
|
||||
if name == "CK_TRUE" || name == "CK_FALSE" {
|
||||
Some(IntKind::U8)
|
||||
} else {
|
||||
Some(IntKind::ULong)
|
||||
@ -76,7 +76,10 @@ fn main() {
|
||||
.allowlist_type("CK_KEY_TYPE")
|
||||
.allowlist_type("CK_C_INITIALIZE_ARGS_PTR")
|
||||
.allowlist_var("CK_TRUE")
|
||||
.allowlist_var("CK_FALSE")
|
||||
.allowlist_var("CK_UNAVAILABLE_INFORMATION")
|
||||
.allowlist_var("CKA_.*")
|
||||
.allowlist_var("CKC_.*")
|
||||
.allowlist_var("CKF_.*")
|
||||
.allowlist_var("CKK_.*")
|
||||
.allowlist_var("CKM_.*")
|
||||
|
36
third_party/rust/pkcs11-bindings/src/lib.rs
vendored
36
third_party/rust/pkcs11-bindings/src/lib.rs
vendored
@ -3,3 +3,39 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
|
||||
|
||||
/// Constants from NSS [pkcs11n.h](https://hg.mozilla.org/projects/nss/file/tip/lib/util/pkcs11n.h)
|
||||
pub mod nss {
|
||||
use crate::{CKA_VENDOR_DEFINED, CKO_VENDOR_DEFINED, CK_ULONG};
|
||||
|
||||
pub const NSSCK_VENDOR_NSS: CK_ULONG = 0x4E534350;
|
||||
|
||||
pub const CKT_VENDOR_DEFINED: CK_ULONG = 0x80000000;
|
||||
pub const CKT_NSS: CK_ULONG = CKT_VENDOR_DEFINED | NSSCK_VENDOR_NSS;
|
||||
|
||||
pub const CKT_NSS_TRUSTED: CK_ULONG = CKT_NSS + 1;
|
||||
pub const CKT_NSS_TRUSTED_DELEGATOR: CK_ULONG = CKT_NSS + 2;
|
||||
pub const CKT_NSS_MUST_VERIFY_TRUST: CK_ULONG = CKT_NSS + 3;
|
||||
pub const CKT_NSS_NOT_TRUSTED: CK_ULONG = CKT_NSS + 10;
|
||||
pub const CKT_NSS_TRUST_UNKNOWN: CK_ULONG = CKT_NSS + 5;
|
||||
|
||||
pub const CKA_NSS: CK_ULONG = CKA_VENDOR_DEFINED | NSSCK_VENDOR_NSS;
|
||||
|
||||
pub const CKA_TRUST: CK_ULONG = CKA_NSS + 0x2000;
|
||||
pub const CKA_TRUST_SERVER_AUTH: CK_ULONG = CKA_TRUST + 8;
|
||||
pub const CKA_TRUST_CLIENT_AUTH: CK_ULONG = CKA_TRUST + 9;
|
||||
pub const CKA_TRUST_CODE_SIGNING: CK_ULONG = CKA_TRUST + 10;
|
||||
pub const CKA_TRUST_EMAIL_PROTECTION: CK_ULONG = CKA_TRUST + 11;
|
||||
pub const CKA_TRUST_STEP_UP_APPROVED: CK_ULONG = CKA_TRUST + 16;
|
||||
|
||||
pub const CKA_CERT_SHA1_HASH: CK_ULONG = CKA_TRUST + 100;
|
||||
pub const CKA_CERT_MD5_HASH: CK_ULONG = CKA_TRUST + 101;
|
||||
|
||||
pub const CKA_NSS_MOZILLA_CA_POLICY: CK_ULONG = CKA_NSS + 34;
|
||||
pub const CKA_NSS_SERVER_DISTRUST_AFTER: CK_ULONG = CKA_NSS + 35;
|
||||
pub const CKA_NSS_EMAIL_DISTRUST_AFTER: CK_ULONG = CKA_NSS + 36;
|
||||
|
||||
pub const CKO_NSS: CK_ULONG = CKO_VENDOR_DEFINED | NSSCK_VENDOR_NSS;
|
||||
pub const CKO_NSS_TRUST: CK_ULONG = CKO_NSS + 3;
|
||||
pub const CKO_NSS_BUILTIN_ROOT_LIST: CK_ULONG = CKO_NSS + 4;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user