cert: verify alg
This commit is contained in:
parent
45216e8af6
commit
65220dbb46
|
@ -71,6 +71,11 @@ version = "0.4.19"
|
|||
default-features = false
|
||||
features = []
|
||||
|
||||
[dependencies.intrusive-collections]
|
||||
version = "0.9.0"
|
||||
default-features = false
|
||||
features = []
|
||||
|
||||
[dependencies.simple_logger]
|
||||
version = "1.11.0"
|
||||
optional = true
|
||||
|
|
|
@ -24,7 +24,10 @@ use p256::ecdsa::signature::{Verifier, DigestVerifier};
|
|||
use alloc::vec::Vec;
|
||||
use heapless::{ Vec as HeaplessVec, consts::* };
|
||||
|
||||
use byteorder::{ByteOrder, NetworkEndian};
|
||||
|
||||
use core::convert::TryFrom;
|
||||
use core::convert::TryInto;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Certificate<'a> {
|
||||
|
@ -64,6 +67,15 @@ pub struct Validity {
|
|||
pub not_after: DateTime<FixedOffset>,
|
||||
}
|
||||
|
||||
impl Validity {
|
||||
pub fn is_valid(&self, current_time: &DateTime<FixedOffset>) -> Result<(), TlsError> {
|
||||
match (current_time >= &self.not_before) && (current_time <= &self.not_after) {
|
||||
true => Ok(()),
|
||||
false => Err(TlsError::TimeValidityError),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Time<'a> {
|
||||
UTCTime(&'a [u8]),
|
||||
|
@ -156,7 +168,9 @@ pub enum ExtensionValue<'a> {
|
|||
Unrecognized,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
// Embedded value might be empty (&[])
|
||||
// This means a reject-all/accept-none condition
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
|
||||
pub enum GeneralName<'a> {
|
||||
OtherName {
|
||||
type_id: &'a [u8],
|
||||
|
@ -175,6 +189,131 @@ pub enum GeneralName<'a> {
|
|||
RegisteredID(&'a [u8]),
|
||||
}
|
||||
|
||||
// Set operation for General Name (X is a subset of Y, where X, Y are the same variant)
|
||||
// Will not handle `OtherName`, `X400Address`, `EDIPartyName`, `RegisteredID`,
|
||||
// as these restrictions of these variants are not suggested
|
||||
impl<'a> GeneralName<'a> {
|
||||
|
||||
pub fn is_subset_of(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
// Special case: empty set
|
||||
// Empty set is a subset of everything
|
||||
(Self::URI(self_uri), Self::URI(other_uri)) => {
|
||||
if self_uri.len() == 0 || other_uri.len() == 0 {
|
||||
self_uri.len() == 0
|
||||
} else {
|
||||
self_uri.ends_with(other_uri)
|
||||
}
|
||||
},
|
||||
(Self::RFC822Name(self_mail), Self::RFC822Name(other_mail)) => {
|
||||
if self_mail.len() == 0 || other_mail.len() == 0 {
|
||||
self_mail.len() == 0
|
||||
} else {
|
||||
self_mail.ends_with(other_mail)
|
||||
}
|
||||
},
|
||||
(Self::DNSName(self_dns), Self::DNSName(other_dns)) => {
|
||||
if self_dns.len() == 0 || other_dns.len() == 0 {
|
||||
self_dns.len() == 0
|
||||
} else {
|
||||
self_dns.ends_with(other_dns)
|
||||
}
|
||||
},
|
||||
(Self::IPAddress(self_ip), Self::IPAddress(other_ip)) => {
|
||||
match (self_ip.len(), other_ip.len()) {
|
||||
// `self` is a NULL network block
|
||||
// It is always a subset of any network block
|
||||
(0, _) => true,
|
||||
|
||||
// IPv4 Addresses
|
||||
(8, 8) => {
|
||||
let mut self_ip_prefix_len = 0;
|
||||
for index in 4..8 {
|
||||
self_ip_prefix_len += self_ip[index].count_ones();
|
||||
}
|
||||
let self_ipv4_cidr = smoltcp::wire::IpCidr::new(
|
||||
smoltcp::wire::IpAddress::v4(
|
||||
self_ip[0], self_ip[1], self_ip[2], self_ip[3]
|
||||
),
|
||||
self_ip_prefix_len.try_into().unwrap()
|
||||
);
|
||||
|
||||
let mut other_ip_prefix_len = 0;
|
||||
for index in 4..8 {
|
||||
other_ip_prefix_len += other_ip[index].count_ones();
|
||||
}
|
||||
let other_ipv4_cidr = smoltcp::wire::IpCidr::new(
|
||||
smoltcp::wire::IpAddress::v4(
|
||||
other_ip[0], other_ip[1], other_ip[2], other_ip[3]
|
||||
),
|
||||
other_ip_prefix_len.try_into().unwrap()
|
||||
);
|
||||
|
||||
other_ipv4_cidr.contains_subnet(&self_ipv4_cidr)
|
||||
},
|
||||
|
||||
// Ipv6 Addresses
|
||||
(32, 32) => {
|
||||
let mut self_ip_prefix_len = 0;
|
||||
for index in 16..32 {
|
||||
self_ip_prefix_len += self_ip[index].count_ones();
|
||||
}
|
||||
let self_ipv4_cidr = smoltcp::wire::IpCidr::new(
|
||||
smoltcp::wire::IpAddress::v6(
|
||||
NetworkEndian::read_u16(&self_ip[0..2]),
|
||||
NetworkEndian::read_u16(&self_ip[2..4]),
|
||||
NetworkEndian::read_u16(&self_ip[4..6]),
|
||||
NetworkEndian::read_u16(&self_ip[6..8]),
|
||||
NetworkEndian::read_u16(&self_ip[8..10]),
|
||||
NetworkEndian::read_u16(&self_ip[10..12]),
|
||||
NetworkEndian::read_u16(&self_ip[12..14]),
|
||||
NetworkEndian::read_u16(&self_ip[14..16]),
|
||||
),
|
||||
self_ip_prefix_len.try_into().unwrap()
|
||||
);
|
||||
|
||||
let mut other_ip_prefix_len = 0;
|
||||
for index in 16..32 {
|
||||
other_ip_prefix_len += other_ip[index].count_ones();
|
||||
}
|
||||
let other_ipv4_cidr = smoltcp::wire::IpCidr::new(
|
||||
smoltcp::wire::IpAddress::v6(
|
||||
NetworkEndian::read_u16(&other_ip[0..2]),
|
||||
NetworkEndian::read_u16(&other_ip[2..4]),
|
||||
NetworkEndian::read_u16(&other_ip[4..6]),
|
||||
NetworkEndian::read_u16(&other_ip[6..8]),
|
||||
NetworkEndian::read_u16(&other_ip[8..10]),
|
||||
NetworkEndian::read_u16(&other_ip[10..12]),
|
||||
NetworkEndian::read_u16(&other_ip[12..14]),
|
||||
NetworkEndian::read_u16(&other_ip[14..16]),
|
||||
),
|
||||
other_ip_prefix_len.try_into().unwrap()
|
||||
);
|
||||
|
||||
other_ipv4_cidr.contains_subnet(&self_ipv4_cidr)
|
||||
},
|
||||
|
||||
(_, _) => false // Heterogeneity, in terms of IP address type
|
||||
// Self IP address is not NULL
|
||||
}
|
||||
},
|
||||
_ => false // Heterogeneity, in terms of GeneralName variant
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_same_variant(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::URI(..), Self::URI(..))
|
||||
| (Self::RFC822Name(..), Self::RFC822Name(..))
|
||||
| (Self::DNSName(..), Self::DNSName(..))
|
||||
| (Self::IPAddress(..), Self::IPAddress(..)) => {
|
||||
true
|
||||
},
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PolicyInformation<'a> {
|
||||
pub id: &'a [u8],
|
||||
|
@ -192,7 +331,20 @@ pub struct Name<'a> {
|
|||
pub relative_distinguished_name: Vec<AttributeTypeAndValue<'a>>
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
impl<'a> PartialEq for Name<'a> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
for self_name in self.relative_distinguished_name.iter() {
|
||||
if other.relative_distinguished_name.iter().find(
|
||||
|&att_type_val| att_type_val == self_name
|
||||
).is_none() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct AttributeTypeAndValue<'a> {
|
||||
pub attribute_type: &'a [u8], // OID
|
||||
pub attribute_value: &'a str,
|
||||
|
@ -438,3 +590,606 @@ impl<'a> Certificate<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ValidPolicyNode<'a> {
|
||||
valid_policy: &'a [u8],
|
||||
qualifier_set: &'a [u8],
|
||||
expected_policy_set: Vec<&'a [u8]>,
|
||||
}
|
||||
|
||||
// Method to verify a prospective certificate chain
|
||||
// Section 6.1, RFC 5280
|
||||
pub fn verify_certificate_chain(
|
||||
certificates: Vec<Certificate>,
|
||||
current_time: DateTime<FixedOffset>,
|
||||
// `user_initial_policy_set`, it is any_policy
|
||||
trusted_issuer_name: Name,
|
||||
// trusted_signature_algorithm: crate::tls_packet::SignatureScheme,
|
||||
trusted_public_key: CertificatePublicKey,
|
||||
initial_policy_mapping_inhibit: bool,
|
||||
initial_explicit_policy: bool,
|
||||
initial_any_policy_inhibit: bool,
|
||||
initial_permitted_subtrees: Vec<GeneralName>,
|
||||
initial_excluded_subtrees: Vec<GeneralName>
|
||||
) -> Result<(), TlsError> {
|
||||
// Note that if the `user_initial_policy_set` variable is set to anyPolicy,
|
||||
// Requirement: The existance of `valid_policy_tree`
|
||||
// `valid_policy_tree` is not NULL iff leaves exist at depth k when k certificates are processed
|
||||
// This leave us with a mapping of operation in the processing steps:
|
||||
// Adding nodes below leaves -> Swap the leaves with a new set of nodes as leaves
|
||||
// Pruning a branch due to the lack of new leaf -> no-op (old leaves are deallocated)
|
||||
let mut valid_policy_tree: Vec<ValidPolicyNode> = Vec::new();
|
||||
let mut initial_policy = ValidPolicyNode {
|
||||
valid_policy: crate::oid::ANY_POLICY,
|
||||
qualifier_set: &[],
|
||||
expected_policy_set: Vec::new(),
|
||||
};
|
||||
initial_policy.expected_policy_set.push(crate::oid::ANY_POLICY);
|
||||
valid_policy_tree.push(initial_policy);
|
||||
|
||||
let mut permitted_subtrees = initial_permitted_subtrees;
|
||||
let mut excluded_subtrees = initial_excluded_subtrees;
|
||||
let mut explicit_policy = if initial_explicit_policy {
|
||||
0
|
||||
} else {
|
||||
certificates.len() + 1
|
||||
};
|
||||
let mut inhibit_any_policy = if initial_any_policy_inhibit {
|
||||
0
|
||||
} else {
|
||||
certificates.len() + 1
|
||||
};
|
||||
let mut policy_mapping = if initial_policy_mapping_inhibit {
|
||||
0
|
||||
} else {
|
||||
certificates.len() + 1
|
||||
};
|
||||
let mut working_public_key = trusted_public_key;
|
||||
// working_public_key_parameters, except it is compeltely unnecessary
|
||||
let mut working_issuer_name = trusted_issuer_name;
|
||||
let mut max_path_length = certificates.len();
|
||||
|
||||
for cert_index in 0..certificates.len() {
|
||||
let current_certificate = &certificates[cert_index];
|
||||
current_certificate
|
||||
.validate_signature_with_trusted(&working_public_key)
|
||||
.map_err(|_| TlsError::SignatureValidationError)?;
|
||||
current_certificate.tbs_certificate.validity
|
||||
.is_valid(¤t_time)?;
|
||||
// Certificate Revocation List is not implemented
|
||||
// This is a certificate-in-certificate scenario
|
||||
if current_certificate.tbs_certificate.issuer != working_issuer_name {
|
||||
return Err(TlsError::CertificateIssuerMismatch);
|
||||
}
|
||||
|
||||
if current_certificate.tbs_certificate.issuer != current_certificate.tbs_certificate.subject
|
||||
&& (cert_index + 1) != certificates.len() {
|
||||
|
||||
if permitted_subtrees.len() != 0 {
|
||||
// Find the SAN extension
|
||||
for extension in current_certificate.tbs_certificate
|
||||
.extensions.extensions.iter() {
|
||||
if let ExtensionValue::SubjectAlternativeName {
|
||||
general_names
|
||||
} = &extension.extension_value {
|
||||
// For each alt. names in SAN, it is within one of the
|
||||
// permitted_subtrees for that name type
|
||||
// TODO: Do more than find exact match
|
||||
for general_name in general_names.iter() {
|
||||
permitted_subtrees.iter().find(
|
||||
|&permitted_name| permitted_name == general_name
|
||||
).ok_or(
|
||||
TlsError::CertificateSubjectNotPermitted
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if excluded_subtrees.len() != 0 {
|
||||
// Find the SAN extension
|
||||
for extension in current_certificate.tbs_certificate
|
||||
.extensions.extensions.iter() {
|
||||
if let ExtensionValue::SubjectAlternativeName {
|
||||
general_names
|
||||
} = &extension.extension_value {
|
||||
// For each alt. names in SAN, it is NOT within one of the
|
||||
// excluded_subtrees for that name type
|
||||
// TODO: Do more than find exact match
|
||||
for general_name in general_names.iter() {
|
||||
excluded_subtrees.iter().find(
|
||||
|&excluded_name| excluded_name == general_name
|
||||
).map_or(
|
||||
Ok(()),
|
||||
|_| Err(TlsError::CertificateSubjectExcluded)
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Certificate policy, find a new set of leaves if exist
|
||||
let mut new_valid_policy_leaves: Vec<ValidPolicyNode> = Vec::new();
|
||||
let mut policy_info = None;
|
||||
for extension in current_certificate.tbs_certificate.extensions.extensions.iter() {
|
||||
if let ExtensionValue::CertificatePolicies { info } = &extension.extension_value {
|
||||
policy_info.replace(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if policy_info.is_some() {
|
||||
let mut possible_any_policy = None;
|
||||
// For each policy P that is not anyPolicy
|
||||
for policy in policy_info.unwrap().iter() {
|
||||
if policy.id == crate::oid::ANY_POLICY {
|
||||
possible_any_policy.replace(policy);
|
||||
continue;
|
||||
}
|
||||
|
||||
let mut policy_not_matched = true;
|
||||
let mut any_policy_found = false;
|
||||
|
||||
// For each node S at depth i-1, if S expects P,
|
||||
// create a child with (P-OID, P-Q, {P-OID})
|
||||
for policy_parent in valid_policy_tree.iter() {
|
||||
if policy_parent.expected_policy_set
|
||||
.iter()
|
||||
.find(|&&expected_policy| expected_policy == policy.id)
|
||||
.is_some() {
|
||||
let mut new_node = ValidPolicyNode {
|
||||
valid_policy: policy.id,
|
||||
qualifier_set: policy.qualifier,
|
||||
expected_policy_set: Vec::new()
|
||||
};
|
||||
new_node.expected_policy_set.push(policy.id);
|
||||
new_valid_policy_leaves.push(new_node);
|
||||
policy_not_matched = false;
|
||||
}
|
||||
|
||||
if policy_parent.valid_policy == crate::oid::ANY_POLICY {
|
||||
any_policy_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If a match is not found for this policy,
|
||||
// while an `anyPolicy' parent exists,
|
||||
// Add policy P with (P-OID, P-Q, {P-OID})
|
||||
// There is no need to add more than once
|
||||
// Only `horizontal` leaf search will be performed,
|
||||
// will only duplicate branch
|
||||
if !policy_not_matched && any_policy_found {
|
||||
let mut new_node = ValidPolicyNode {
|
||||
valid_policy: policy.id,
|
||||
qualifier_set: policy.qualifier,
|
||||
expected_policy_set: Vec::new()
|
||||
};
|
||||
new_node.expected_policy_set.push(policy.id);
|
||||
new_valid_policy_leaves.push(new_node);
|
||||
}
|
||||
}
|
||||
|
||||
// If cert has anyPolicy, and either (inhibit_anyPolicy > 0 OR i < n)
|
||||
// AND certificate is self-issued, then forward all yet-to-be-copied
|
||||
// policies in depth i-1 to leaves with qualifier as AP-Q
|
||||
if possible_any_policy.is_some()
|
||||
&& inhibit_any_policy > 0
|
||||
&& cert_index + 1 < certificates.len()
|
||||
{
|
||||
for policy_parent in valid_policy_tree.iter() {
|
||||
for expected_policy in policy_parent.expected_policy_set.iter() {
|
||||
// If any expected policy cannot be found among the new leaves
|
||||
// it needs to be added into the valid policies
|
||||
if new_valid_policy_leaves.iter().find(
|
||||
|&leaf_policy| &leaf_policy.valid_policy == expected_policy
|
||||
).is_none() {
|
||||
let mut new_node = ValidPolicyNode {
|
||||
valid_policy: expected_policy,
|
||||
qualifier_set: possible_any_policy.unwrap().qualifier,
|
||||
expected_policy_set: Vec::new()
|
||||
};
|
||||
new_node.expected_policy_set.push(expected_policy);
|
||||
new_valid_policy_leaves.push(new_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Otherwise, do nothing.
|
||||
// Empty vector can represent NULL.
|
||||
|
||||
// Replace old `valid_policy_tree` with new leaves
|
||||
// This automatically does the following things:
|
||||
// (d) prune childless branches, and
|
||||
// (e) set the entire tree to NULL, if there are no cert policies.
|
||||
valid_policy_tree = new_valid_policy_leaves;
|
||||
|
||||
// (f) Verify that either:
|
||||
// -`explicit_policy` is greater than 0, OR
|
||||
// -`valid_policy_tree` is not NULL
|
||||
if explicit_policy == 0 && valid_policy_tree.len() == 0 {
|
||||
return Err(TlsError::CertificatePolicyError);
|
||||
}
|
||||
|
||||
// Prepare for the next certificate (towards end cert)
|
||||
// Policy mapping is not handled
|
||||
if cert_index + 1 == certificates.len() {
|
||||
return wrap_up_verification(
|
||||
current_certificate,
|
||||
explicit_policy,
|
||||
&valid_policy_tree
|
||||
);
|
||||
}
|
||||
|
||||
// (c, d, e, f) Re-assign `working_issuer_name` and `working_public_key`
|
||||
// working_public_key already includes the algorithm of the key
|
||||
working_issuer_name = current_certificate.tbs_certificate.subject.clone();
|
||||
working_public_key = current_certificate.get_cert_public_key()
|
||||
.map_err(|_| TlsError::SignatureValidationError)?;
|
||||
// Only default pre-set signature algorithms are used.
|
||||
// Parameter will never be relavent
|
||||
|
||||
// Counter updates, (l) verification for non-self-issued certs
|
||||
// (h) If certificate is not self-issued, decrement all counters if non-zero
|
||||
if current_certificate.tbs_certificate.issuer != current_certificate.tbs_certificate.subject {
|
||||
explicit_policy -= 1;
|
||||
policy_mapping -= 1;
|
||||
inhibit_any_policy -= 1;
|
||||
|
||||
if max_path_length == 0 {
|
||||
return Err(TlsError::CertificateVersionError);
|
||||
} else {
|
||||
max_path_length -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the certificate is v3
|
||||
if current_certificate.tbs_certificate.version != Version::v3 {
|
||||
return Err(TlsError::CertificateVersionError);
|
||||
}
|
||||
|
||||
// (g) Permitted/Excluded subtrees operations
|
||||
for extension in current_certificate.tbs_certificate.extensions.extensions.iter() {
|
||||
if let ExtensionValue::NameConstraints {
|
||||
permitted_subtrees: certificate_permitted_subtrees,
|
||||
excluded_subtrees: certificate_excluded_subtrees
|
||||
} = &extension.extension_value {
|
||||
if certificate_permitted_subtrees.len() != 0 {
|
||||
get_subtree_intersection(
|
||||
&mut permitted_subtrees,
|
||||
certificate_permitted_subtrees
|
||||
);
|
||||
}
|
||||
if certificate_excluded_subtrees.len() != 0 {
|
||||
get_subtree_union(
|
||||
&mut excluded_subtrees,
|
||||
certificate_excluded_subtrees
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// (i) If policyConstraint extension is found, modify
|
||||
// - explicit_policy, and/or
|
||||
// - policy_mapping
|
||||
if let ExtensionValue::PolicyConstraints {
|
||||
require_explicit_policy,
|
||||
inhibit_policy_mapping,
|
||||
} = &extension.extension_value {
|
||||
if require_explicit_policy.is_some() {
|
||||
if usize::from(require_explicit_policy.unwrap()) < explicit_policy {
|
||||
explicit_policy = require_explicit_policy.unwrap().into();
|
||||
}
|
||||
}
|
||||
if inhibit_policy_mapping.is_some() {
|
||||
if usize::from(inhibit_policy_mapping.unwrap()) < policy_mapping {
|
||||
policy_mapping = inhibit_policy_mapping.unwrap().into();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (j) Reduce inhibit_anyPolicy to that stated in the certificate
|
||||
if let ExtensionValue::InhibitAnyPolicy {
|
||||
skip_certs
|
||||
} = &extension.extension_value {
|
||||
if usize::from(*skip_certs) < inhibit_any_policy {
|
||||
inhibit_any_policy = (*skip_certs).into();
|
||||
}
|
||||
}
|
||||
|
||||
// (m) Verify that there is a BasicConstraint extension,
|
||||
// with cA set to true
|
||||
if let ExtensionValue::BasicConstraints {
|
||||
is_ca,
|
||||
path_len_constraint
|
||||
} = &extension.extension_value {
|
||||
if !is_ca {
|
||||
return Err(TlsError::CertificateVersionError);
|
||||
}
|
||||
if path_len_constraint.is_some() {
|
||||
if path_len_constraint.unwrap() < max_path_length as u8 {
|
||||
max_path_length = path_len_constraint.unwrap().into();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (n) If key usage extension is found, keyCertSignbit must be set
|
||||
if let ExtensionValue::KeyUsage {
|
||||
usage
|
||||
} = &extension.extension_value {
|
||||
if usage & 0x0020 == 0 {
|
||||
return Err(TlsError::CertificateVersionError);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wrap_up_verification(
|
||||
end_cert: &Certificate,
|
||||
mut explicit_policy: usize,
|
||||
valid_policy_tree: &Vec<ValidPolicyNode>
|
||||
) -> Result<(), TlsError> {
|
||||
|
||||
// (a) Decrement explicit_policy
|
||||
if explicit_policy != 0 {
|
||||
explicit_policy -= 1;
|
||||
}
|
||||
|
||||
for extension in end_cert.tbs_certificate.extensions.extensions.iter() {
|
||||
// (b) If there is policy constraint extension, and
|
||||
// require_explicit_policy is 0, set explicit_policy_state to be 0
|
||||
if let ExtensionValue::PolicyConstraints {
|
||||
require_explicit_policy,
|
||||
inhibit_policy_mapping
|
||||
} = &extension.extension_value {
|
||||
if require_explicit_policy.is_some() {
|
||||
if require_explicit_policy.unwrap() == 0 {
|
||||
explicit_policy = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// (c) Instantiate cert key again, but only for returning to other procedure
|
||||
// Getting it directly from certificate when needs to
|
||||
|
||||
// (d, e, f) Will not work with customized algorithm
|
||||
// Only TLS signature algorithm will be supported
|
||||
|
||||
// (e) `initial_policy_set` is hardwired to any-policy
|
||||
// The intersection is the entire valid_policy_tree (case II, section 6.1.4)
|
||||
if explicit_policy > 0 || valid_policy_tree.len() != 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(TlsError::CertificatePolicyError)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Mutate state_subtree to get the intersection
|
||||
fn get_subtree_intersection<'a>(
|
||||
state_subtree: &mut Vec<GeneralName<'a>>,
|
||||
cert_subtree: &Vec<GeneralName<'a>>
|
||||
) {
|
||||
// 1. Determine the variants that need to be preserved (i.e. body-count)
|
||||
let mut has_self_uri_tree = false;
|
||||
let mut has_other_uri_tree = false;
|
||||
let mut has_self_rfc_822_name_tree = false;
|
||||
let mut has_other_rfc_822_name_tree = false;
|
||||
let mut has_self_dns_name_tree = false;
|
||||
let mut has_other_dns_name_tree = false;
|
||||
let mut has_self_ip_address_tree = false;
|
||||
let mut has_other_ip_address_tree = false;
|
||||
|
||||
for general_name in state_subtree.iter() {
|
||||
match general_name {
|
||||
GeneralName::URI(..) => has_self_uri_tree = true,
|
||||
GeneralName::RFC822Name(..) => has_self_rfc_822_name_tree = true,
|
||||
GeneralName::DNSName(..) => has_self_dns_name_tree = true,
|
||||
GeneralName::IPAddress(..) => has_self_ip_address_tree = true,
|
||||
// Other general_name variants should not appear in this subtree
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
for general_name in cert_subtree.iter() {
|
||||
match general_name {
|
||||
GeneralName::URI(..) => has_other_uri_tree = true,
|
||||
GeneralName::RFC822Name(..) => has_other_rfc_822_name_tree = true,
|
||||
GeneralName::DNSName(..) => has_other_dns_name_tree = true,
|
||||
GeneralName::IPAddress(..) => has_other_ip_address_tree = true,
|
||||
// Other general_name variants should not appear in this subtree
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Preserve subtrees that fit into the variants
|
||||
let mut preserved_subtrees: Vec<GeneralName> = Vec::new();
|
||||
|
||||
for general_name in state_subtree.iter() {
|
||||
match general_name {
|
||||
GeneralName::URI(..) => {
|
||||
if !has_other_uri_tree {
|
||||
preserved_subtrees.push(*general_name);
|
||||
}
|
||||
},
|
||||
GeneralName::RFC822Name(..) => {
|
||||
if !has_other_rfc_822_name_tree {
|
||||
preserved_subtrees.push(*general_name);
|
||||
}
|
||||
}
|
||||
GeneralName::DNSName(..) => {
|
||||
if !has_other_dns_name_tree {
|
||||
preserved_subtrees.push(*general_name);
|
||||
}
|
||||
}
|
||||
GeneralName::IPAddress(..) => {
|
||||
if !has_other_ip_address_tree {
|
||||
preserved_subtrees.push(*general_name);
|
||||
}
|
||||
}
|
||||
// Other general_name variants should not appear in this subtree
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
for general_name in cert_subtree.iter() {
|
||||
match general_name {
|
||||
GeneralName::URI(..) => {
|
||||
if !has_self_uri_tree {
|
||||
preserved_subtrees.push(*general_name);
|
||||
}
|
||||
},
|
||||
GeneralName::RFC822Name(..) => {
|
||||
if !has_self_rfc_822_name_tree {
|
||||
preserved_subtrees.push(*general_name);
|
||||
}
|
||||
}
|
||||
GeneralName::DNSName(..) => {
|
||||
if !has_self_dns_name_tree {
|
||||
preserved_subtrees.push(*general_name);
|
||||
}
|
||||
}
|
||||
GeneralName::IPAddress(..) => {
|
||||
if !has_self_ip_address_tree {
|
||||
preserved_subtrees.push(*general_name);
|
||||
}
|
||||
}
|
||||
// Other general_name variants should not appear in this subtree
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Perform intersection operation among 2 sets indirectly
|
||||
//
|
||||
// First, if the certificate does not specify any URI restrictions,
|
||||
// leave the stored URI be.
|
||||
//
|
||||
// Assume all elements smong self_xxxx_tree and other_xxxx_tree are homogeneous.
|
||||
//
|
||||
// For each element in self_xxxx_tree, find intersection with other_xxxx_tree
|
||||
// Take union operation at the result of each operations at the end
|
||||
// i.e. (S1 U S2 U ... U Sk) n O = (S1 n O) U (S2 n O) U ... U (Sk n O)
|
||||
// as stated in distributive law
|
||||
//
|
||||
// The with the same argument, but reversing the self_tree and other_tree,
|
||||
// For each element in other_xxx_tree, find intersection with that elemenet from self
|
||||
// Take union operation of the result of each operations at the end
|
||||
// i.e. Sx n (O1 U O2 U ... Oj) = (Sx n O1) U (Sx n O2) U ... U (Sx n Oj)
|
||||
// as stated in distributive law
|
||||
//
|
||||
// To further simplify, recognize that the brackets of (Sx n O) in the first statement
|
||||
// encapsulates a series of union operators, while the bracks perform union operations
|
||||
// among themselves as well.
|
||||
// Therefore, the order of operations does not matter, stated in the associative law.
|
||||
// i.e. S n O = U_(x, y) {Sx n Oy}
|
||||
//
|
||||
// Now consider all the variants, the processed subtree shall be a union of all variants
|
||||
// where the variants are computed as a union of homogeneous intersections.
|
||||
// By Identity law, if all heterogeneous intersections returns NULL,
|
||||
// union of homogeneous intersections are equivalent to that of heterogeneous intersections.
|
||||
//
|
||||
// However, an empty set is not what always the correct solution. Here are exceptions:
|
||||
//
|
||||
// 1. If other_tree does not contain a variant that exists in self_tree,
|
||||
// that variant in self_tree shall be left untouched.
|
||||
//
|
||||
// 2. Reverse of (1), self_tree does not have definitions on some variant,
|
||||
// while other_tree has.
|
||||
// Consider this method is for permitted_subtree operation, no definition means no restriction
|
||||
// other_tree would like to impose tighter restriction, so every items of such variant
|
||||
// from `other_tree` should be preserved.
|
||||
//
|
||||
// Both can be fixed by saving all `guaranteed` permitted subtrees before this process
|
||||
for self_name in state_subtree.iter() {
|
||||
for other_name in cert_subtree.iter() {
|
||||
|
||||
// Make use of subset method, note that all general names are hierarchical
|
||||
if self_name.is_subset_of(other_name) {
|
||||
preserved_subtrees.push(*self_name)
|
||||
} else if other_name.is_subset_of(self_name) {
|
||||
preserved_subtrees.push(*other_name)
|
||||
}
|
||||
|
||||
// If neither are subset of the other, the intersection shall be none
|
||||
// Should both names be homogeneous, it should imply an all-blocking name
|
||||
match (self_name, other_name) {
|
||||
(GeneralName::URI(self_uri), GeneralName::URI(other_uri)) => {
|
||||
preserved_subtrees.push(
|
||||
GeneralName::URI(&[])
|
||||
)
|
||||
},
|
||||
(GeneralName::RFC822Name(self_mail), GeneralName::RFC822Name(other_mail)) => {
|
||||
preserved_subtrees.push(
|
||||
GeneralName::RFC822Name(&[])
|
||||
)
|
||||
},
|
||||
(GeneralName::DNSName(self_dns), GeneralName::DNSName(other_dns)) => {
|
||||
preserved_subtrees.push(
|
||||
GeneralName::DNSName(&[])
|
||||
)
|
||||
},
|
||||
(GeneralName::IPAddress(self_ip), GeneralName::IPAddress(other_ip)) => {
|
||||
preserved_subtrees.push(
|
||||
GeneralName::IPAddress(&[])
|
||||
)
|
||||
},
|
||||
|
||||
// Heterogeneous general name variants
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Perform union operation
|
||||
// Again recall that general names are hierarchical
|
||||
// If two general names are not disjoint, one must be other's subset
|
||||
// Therefore, pruning subsets is sufficient to determine the union.
|
||||
// Put the result into state_subtree, as this shall be the output
|
||||
//
|
||||
// Note: Technically union operation can be a simple no-op
|
||||
// But this is performed for the sake of memory space
|
||||
|
||||
state_subtree.clear();
|
||||
prune_subset(state_subtree, &mut preserved_subtrees);
|
||||
}
|
||||
|
||||
|
||||
fn prune_subset<'a>(subtree_out: &mut Vec<GeneralName<'a>>, subtree_in: &mut Vec<GeneralName<'a>>) {
|
||||
'outer: for i in 0..subtree_in.len() {
|
||||
for j in 0..subtree_in.len() {
|
||||
// A few cases to consider:
|
||||
// If subtree_i is a strict_subset of subtree_j,
|
||||
// then obviously i needs to be ejected
|
||||
// However, if Si and Sj are equivalent, then only 1 needs to be ejected
|
||||
// the following implementation will eject the one with lower index
|
||||
if i != j {
|
||||
if subtree_in[i] == subtree_in[j] {
|
||||
if i < j {
|
||||
continue 'outer;
|
||||
}
|
||||
} else if subtree_in[i].is_subset_of(&subtree_in[j]) {
|
||||
continue 'outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
subtree_out.push(subtree_in[i])
|
||||
}
|
||||
}
|
||||
|
||||
// Union operation among 2 subtrees sets, output through state_subtree
|
||||
pub fn get_subtree_union<'a>(
|
||||
state_subtree: &mut Vec<GeneralName<'a>>,
|
||||
other_subtree: &Vec<GeneralName<'a>>
|
||||
) {
|
||||
// Join the 2 lists together, and then prune all subsets
|
||||
let mut merged_subtrees: Vec<GeneralName> = Vec::new();
|
||||
merged_subtrees.extend_from_slice(state_subtree);
|
||||
merged_subtrees.extend_from_slice(other_subtree);
|
||||
state_subtree.clear();
|
||||
|
||||
prune_subset(state_subtree, &mut merged_subtrees);
|
||||
}
|
||||
|
|
|
@ -22,4 +22,10 @@ pub enum Error {
|
|||
DecryptionError,
|
||||
CapacityError,
|
||||
SignatureValidationError,
|
||||
TimeValidityError,
|
||||
CertificateIssuerMismatch,
|
||||
CertificateSubjectNotPermitted,
|
||||
CertificateSubjectExcluded,
|
||||
CertificatePolicyError,
|
||||
CertificateVersionError,
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ const CA_SIGNED_CERT: [u8; 0x0356] =
|
|||
"308203523082023a02146048517ee55aabd1e8f2bd7db1d91e679708e644300d06092a864886f70d01010b05003067310b30090603550406130255533113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c74643120301e06035504030c176578616d706c65732e63612e756c666865696d2e6e6574301e170d3230313130363034323035305a170d3230313230363034323035305a3064310b30090603550406130255533113301106035504080c0a536f6d652d53746174653121301f060355040a0c18496e7465726e6574205769646769747320507479204c7464311d301b06035504030c146578616d706c65732e756c666865696d2e6e657430820122300d06092a864886f70d01010105000382010f003082010a0282010100b2940671bfe7ace7416ba9d34018c229588e9d4eed8bd6623e44ab1239e8f1f0de9050b2f485a98e63f5b483330fb0b5abaeb33d11889033b0b684bf34696d28206bb361782c4b106a8d47874cbbdf971b5ab887bca508bccf250a1a811cee078464638e441941347d4c8885ac9b59d9fc9636276912b04d9e3ab29bd8ad319572ae54f0b6145c4d675a78607dcc4793a4d432f1c2a41ea29dd4f7262b6fe472dfaea51aca992b4624e73fa9901fa364fc5b721052ef3187e659d58d2706770d365380a7ebab6caac5b23271c01531fdf95368ee48af5383035f249be7c18f50ce9e52877558efe4b2e29f61328396e2a3b5e71309ad13d93d6ba3d5c3eb2b650203010001300d06092a864886f70d01010b0500038201010063c9ab0f5d2e164513e8e74b656ae4f48dd004c3ead9f1026b7741cbf02bb0efcf19e0fbf8a788dae059a2393167f016bafc0e3efd5c5b4c43079b6506eb67f17f44f9591503c7d1fdb77bf631894817393ea82610ad5106d23ec6bf1a6d96d749f05c0136cd71256617a51fe862529aee4a37d5f456dc7da8b220ff10ede4e87bc63e4589b3f81133a7f82ab900419e8a2d802d59e99cfbbd268702efd17616168b45b5211da0e644c29dcb92dbbf32b43586bbab05deb0261771605c52836363bd28ff9853d44436349f5ba11f2640bc9c42688e0d5eb6cac9f3f5e5f98652fa4f4ba52604371ec45f09d678e31d463285a4b3734f587f35a339920544f476"
|
||||
);
|
||||
|
||||
const SELF_SIGNED_WITH_SAN: [u8; 0x046C] =
|
||||
const SELF_SIGNED_WITH_SAN: [u8; 0x048A] =
|
||||
hex_literal::hex!(
|
||||
"3082046830820350a00302010202145525dc68e0e749158bf5bee8fe12c71675127510300d06092a864886f70d01010b05003073310b3009060355040613025553310b300906035504080c0256413114301206035504070c0b416e6f746865724369747931123010060355040a0c094d79436f6d70616e7931133011060355040b0c0a4d794469766973696f6e3118301606035504030c0f7777772e636f6d70616e792e636f6d301e170d3230313130393035353034385a170d3231313130393035353034385a3073310b3009060355040613025553310b300906035504080c0256413114301206035504070c0b416e6f746865724369747931123010060355040a0c094d79436f6d70616e7931133011060355040b0c0a4d794469766973696f6e3118301606035504030c0f7777772e636f6d70616e792e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100a03fec3ee07c6dce516520ab9166b7b5d95c13196328cb443e8419d748889ebc99a22b8032240a816b585e2affaea7383e4b655aacc06ee67814693fc440f6a27939e793a85280334a4662da460802123d191dccfe029997cc7f94f7ff9aef7a2d662f01fb9cd153e14c6b21ab28b209f09082d635b705bca4553efaeaddc21d7fc73366130a54270175c608cff2f2336fbf13896ebfc44016259032c81f2499f19ce14da840f25b0339fae72926b231ec6f14b7ff66716be0d3471f6485b6657270834fc4058e93625d4df95eb3a95c2eec48c3f060cdd740e373fc240e3c76d5c3c3f11cb53dab471d8af6b46e0294b3c7a75c82edcbab24af0448237310b90203010001a381f33081f0300b0603551d0f04040302043030130603551d25040c300a06082b0601050507030130760603551d11046f306d820f7777772e636f6d70616e792e6e6574820b636f6d70616e792e636f6d820b636f6d70616e792e6e6574810b626f6240636f6d70616e79810d616c69636540636f6d70616e79a01e06032a0304a0170c15736f6d65206f74686572206964656e7469666965728704c0a801c830430603551d1e043c303aa01c300e820c2e6578616d706c652e636f6d300a8708c0a80001ffffff00a11a300a8708c0aa0001ffffff00300c820a2e6c6f63616c686f7374300f0603551d2404083006800103810105300d06092a864886f70d01010b0500038201010079721d5b3b0f17edc425ac5f6faa5d085760eba5ebd0bc2a5010a0893e46c68656fecc0b66c7216fb093a07aaad88819011b9daa0407aef06778c7c04dbc2f5dd20d3156cccd3a36298b26d8d548d2ae4564b55f1e00fe49d6a7c53f05eecd0b63d7716d51a59c71141f9b223cbf79c57d46a7a240d2bc851f38c7da45c9ec7ad99381605247e46309541ea89fe9e175f8fd4c296b7ea667dafb8d4310e577c79be50a1d3b48c4d012a01aaf605816f37f5a00f1cb86dee776b31f8a444a79f48313502b23d001d1f3a641f9ec05960180cfa0440b8002afc3b49c3c1779adfd7f9ecef38fb14c2b3902323314990928f764c70a579e02453fec03bc78f98914"
|
||||
"308204863082036ea003020102021447e58ecab88d894c58ec746381e6d039c04e3a93300d06092a864886f70d01010b05003073310b3009060355040613025553310b300906035504080c0256413114301206035504070c0b416e6f746865724369747931123010060355040a0c094d79436f6d70616e7931133011060355040b0c0a4d794469766973696f6e3118301606035504030c0f7777772e636f6d70616e792e636f6d301e170d3230313131303032313132385a170d3231313131303032313132385a3073310b3009060355040613025553310b300906035504080c0256413114301206035504070c0b416e6f746865724369747931123010060355040a0c094d79436f6d70616e7931133011060355040b0c0a4d794469766973696f6e3118301606035504030c0f7777772e636f6d70616e792e636f6d30820122300d06092a864886f70d01010105000382010f003082010a0282010100bacdd00cf364e116a6b7cd23df3ccc31f6d6d2e6e82da833d50f7bd850b1e482acd1e9ecc9e0ea2c36925576fff44bdefbbb73f38c8d7db67ac7210801e5580329504ebc6982e5c95a758a36a1d0ff891478ab2f7392c1c6b4657d08645ff97ef23b0870de511d3532599eb250eac82bae22d6de23f2a5a48733d3a045fe0c5f942b5f79dbb08117bf1a814f00489e4118f30f8e37e66c61c5c4398cdc9f77ec39de78bf0b4c677cb9e485b868ce03c32c41f78849b82949df8231290172618234de85ec02990206fec3ed74b6b18e9d0acd6b4bed1c4f52749574f7cd9b8ad0db14be78a99eb8a894adecdbd0922ab953e3e447346022a4485ffd121efdfe1d0203010001a38201103082010c300b0603551d0f04040302043030130603551d25040c300a06082b0601050507030130760603551d11046f306d820f7777772e636f6d70616e792e6e6574820b636f6d70616e792e636f6d820b636f6d70616e792e6e6574810b626f6240636f6d70616e79810d616c69636540636f6d70616e79a01e06032a0304a0170c15736f6d65206f74686572206964656e7469666965728704c0a801c830430603551d1e043c303aa01c300e820c2e6578616d706c652e636f6d300a8708c0a80001ffffff00a11a300a8708c0aa0001ffffff00300c820a2e6c6f63616c686f7374300f0603551d2404083006800103810105301a0603551d200413301130060604551d2000300706052b05071314300d06092a864886f70d01010b050003820101008e6891f7bf506cb9bbc2d8f679d2d510b0b3121ee4662cbe90ddd1b1fa4f8a5b9cca49877fc64b9c08a2dbbb4563e3e92be62ce79088b2a1b382724f1b479efaba1749696461893335f56e9ad7b89359997af85a20425250be0559b2daf1179b61b65284f39da4386377a035038af179b93508925c227d4f205538c1dedfc768a98cd243196a9476ac79bb91c16e827ff84376520e89b09a236037be4f21b0262b151d156638ccfafac7cf383c5f20213cdd29d0f95329a4a2783328986fa2e70b501289c263e0bdc42cb439412b8be2601b6f1fe8c3e15f11230760d36ff008ccb42d8b10c5c92db35ae2a6a8dfcf461233cefbc30fc2d709608452744f1ce7"
|
||||
);
|
||||
|
|
|
@ -82,4 +82,7 @@ pub const ID_KP_CLIENT_AUTH: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3,
|
|||
pub const ID_KP_CODE_SIGNING: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 3]; // 1.3.6.1.5.5.7.3.3
|
||||
pub const ID_KP_EMAIL_PROTECTION: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 4]; // 1.3.6.1.5.5.7.3.4
|
||||
pub const ID_KP_TIME_STAMPING: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 8]; // 1.3.6.1.5.5.7.3.8
|
||||
pub const ID_KP_OCSP_SIGNING: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 9];
|
||||
pub const ID_KP_OCSP_SIGNING: &'static [u8] = &[43, 6, 1, 5, 5, 7, 3, 9];
|
||||
|
||||
// anyPolicy OID
|
||||
pub const ANY_POLICY: &'static [u8] = &[85, 29, 32, 0];
|
||||
|
|
|
@ -1419,12 +1419,7 @@ pub fn parse_asn1_der_policy_information(bytes: &[u8]) -> IResult<&[u8], Asn1Der
|
|||
return Err(nom::Err::Failure((&[], ErrorKind::Verify)));
|
||||
}
|
||||
|
||||
let (_, (oid, (_, _, qualifier))) = complete(
|
||||
tuple((
|
||||
parse_asn1_der_oid,
|
||||
parse_asn1_der_object
|
||||
))
|
||||
)(value)?;
|
||||
let (qualifier, oid) = parse_asn1_der_oid(value)?;
|
||||
|
||||
Ok((
|
||||
rest,
|
||||
|
|
|
@ -595,7 +595,7 @@ pub(crate) struct Cookie {
|
|||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy, IntoPrimitive, TryFromPrimitive)]
|
||||
#[repr(u16)]
|
||||
pub(crate) enum SignatureScheme {
|
||||
pub enum SignatureScheme {
|
||||
/* RSASSA-PKCS1-v1_5 algorithms */
|
||||
rsa_pkcs1_sha256 = 0x0401,
|
||||
rsa_pkcs1_sha384 = 0x0501,
|
||||
|
|
Loading…
Reference in New Issue