use crate::crypto::PKC_CANON_PUBLIC_KEY_LEN;
use crate::error::{Error, ErrorCode};
use der::asn1::{AnyRef, BitStringRef, GeneralizedTime, ObjectIdentifier, OctetStringRef, UtcTime};
use der::{Choice, Sequence, Tag};
pub mod cert;
pub mod csr;
const OID_ECDSA_WITH_SHA256: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.4.3.2");
const OID_EC_PUBLIC_KEY: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.2.1");
const OID_PRIME256V1: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.10045.3.1.7");
const OID_SUBJECT_KEY_ID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.5.29.14");
const OID_AUTHORITY_KEY_ID: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.5.29.35");
const OID_BASIC_CONSTRAINTS: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.5.29.19");
const OID_KEY_USAGE: ObjectIdentifier = ObjectIdentifier::new_unwrap("2.5.29.15");
const P256_PUBLIC_KEY_LEN: usize = PKC_CANON_PUBLIC_KEY_LEN;
#[derive(Sequence)]
pub struct AlgorithmIdentifier<'a> {
pub algorithm: ObjectIdentifier,
pub parameters: Option<AnyRef<'a>>,
}
struct SubjectPublicKeyInfo<'a> {
algorithm: AlgorithmIdentifier<'a>,
subject_public_key: BitStringRef<'a>,
}
impl<'a> der::FixedTag for SubjectPublicKeyInfo<'a> {
const TAG: Tag = Tag::Sequence;
}
#[derive(Sequence)]
struct AttributeTypeAndValue<'a> {
oid: ObjectIdentifier,
value: AnyRef<'a>,
}
#[derive(Sequence)]
struct BasicConstraints {
#[asn1(default = "default_false")]
ca: bool,
path_len_constraint: Option<u8>,
}
fn default_false() -> bool {
false
}
pub mod key_usage_der {
pub const DIGITAL_SIGNATURE: u16 = 0x8000;
pub const NON_REPUDIATION: u16 = 0x4000;
pub const KEY_ENCIPHERMENT: u16 = 0x2000;
pub const DATA_ENCIPHERMENT: u16 = 0x1000;
pub const KEY_AGREEMENT: u16 = 0x0800;
pub const KEY_CERT_SIGN: u16 = 0x0400;
pub const CRL_SIGN: u16 = 0x0200;
pub const ENCIPHER_ONLY: u16 = 0x0100;
pub const DECIPHER_ONLY: u16 = 0x0080;
}
pub mod key_usage_tlv {
pub const DIGITAL_SIGNATURE: u16 = 0x0001;
pub const NON_REPUDIATION: u16 = 0x0002;
pub const KEY_ENCIPHERMENT: u16 = 0x0004;
pub const DATA_ENCIPHERMENT: u16 = 0x0008;
pub const KEY_AGREEMENT: u16 = 0x0010;
pub const KEY_CERT_SIGN: u16 = 0x0020;
pub const CRL_SIGN: u16 = 0x0040;
pub const ENCIPHER_ONLY: u16 = 0x0080;
pub const DECIPHER_ONLY: u16 = 0x0100;
}
struct KeyUsage {
bits: u16,
}
impl KeyUsage {
fn digital_signature(&self) -> bool {
self.bits & key_usage_der::DIGITAL_SIGNATURE != 0
}
fn key_cert_sign(&self) -> bool {
self.bits & key_usage_der::KEY_CERT_SIGN != 0
}
fn crl_sign(&self) -> bool {
self.bits & key_usage_der::CRL_SIGN != 0
}
fn has_only_bits(&self, mask: u16) -> bool {
self.bits == mask
}
}
impl<'a> From<BitStringRef<'a>> for KeyUsage {
fn from(bs: BitStringRef<'a>) -> Self {
let bytes = bs.raw_bytes();
let unused = bs.unused_bits();
if bytes.len() > 2 {
return Self { bits: 0 };
}
let mut buf = [0u8; 2];
let len = bytes.len();
buf[..len].copy_from_slice(&bytes[..len]);
let mut bits = u16::from_be_bytes(buf);
if unused > 0 && len > 0 {
let shift = if len == 1 { 8 } else { 0 };
let mask = !((1u16 << unused) - 1) << shift;
bits &= mask;
}
Self { bits }
}
}
#[derive(Sequence)]
struct AuthorityKeyIdentifier<'a> {
#[asn1(context_specific = "0", tag_mode = "IMPLICIT")]
key_identifier: OctetStringRef<'a>,
}
#[derive(Choice)]
enum Time {
#[asn1(type = "UTCTime")]
Utc(UtcTime),
#[asn1(type = "GeneralizedTime")]
General(GeneralizedTime),
}
#[derive(Sequence)]
struct Validity {
not_before: Time,
not_after: Time,
}
fn hex_digit(b: u8) -> Result<u8, Error> {
match b {
b'0'..=b'9' => Ok(b - b'0'),
b'A'..=b'F' => Ok(b - b'A' + 10),
b'a'..=b'f' => Ok(b - b'a' + 10),
_ => Err(ErrorCode::InvalidData.into()),
}
}
fn parse_hex_u16(s: &[u8]) -> Result<u16, Error> {
if s.len() != 4 {
return Err(ErrorCode::InvalidData.into());
}
let mut val: u16 = 0;
for &b in s {
val = val << 4 | hex_digit(b)? as u16;
}
Ok(val)
}
fn time_to_unix_secs(time: &Time) -> Result<u64, Error> {
let dt = match time {
Time::Utc(utc) => utc.to_date_time(),
Time::General(gt) => gt.to_date_time(),
};
if dt == der::DateTime::INFINITY {
return Ok(u64::MAX);
}
Ok(dt.unix_duration().as_secs())
}