use yasna::{construct_der, DERWriterSet};
use crate::pkcs10::Attribute;
pub(crate) trait WcceAttribute {
const ATTRIBUTE_OID: &'static [u64];
fn values(&self, writer: &mut DERWriterSet);
}
impl<T> Attribute for T
where
T: WcceAttribute,
{
fn oid(&self) -> &'static [u64] {
Self::ATTRIBUTE_OID
}
fn values(&self) -> Vec<u8> {
construct_der(|writer| {
writer.write_set(|writer| {
self.values(writer);
});
})
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RenewalCertificate<'a> {
pub certificate: &'a [u8],
}
impl WcceAttribute for RenewalCertificate<'_> {
const ATTRIBUTE_OID: &'static [u64] = &[1, 3, 6, 1, 4, 1, 311, 13, 1];
fn values(&self, writer: &mut DERWriterSet) {
writer.next().write_der(self.certificate);
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum ValidityPeriod {
Seconds,
Minutes,
Hours,
Days,
Weeks,
Months,
Years,
}
impl ValidityPeriod {
const fn value(self) -> &'static str {
match self {
Self::Seconds => "Seconds",
Self::Minutes => "Minutes",
Self::Hours => "Hours",
Self::Days => "Days",
Self::Weeks => "Weeks",
Self::Months => "Months",
Self::Years => "Years",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EnrollmentNameValuePair<'a> {
CertType,
CertificateUsage { oids: &'a str },
ValidityPeriod(ValidityPeriod),
ValidityPeriodUnits { count: &'a str },
ExpirationDate { date: &'a str },
Cdc { cdc_fqdn: &'a str },
Rmd { rmd_fqdn: &'a str },
CertificateTemplate { cn: &'a str },
San { collection: &'a str },
Challenge { challenge: &'a str },
RequesterName { domain_account: &'a str },
CertFile { unc_path: &'a str },
RequestId { id: &'a str },
Other { name: &'static str, value: &'a str },
}
impl<'a> EnrollmentNameValuePair<'a> {
pub(crate) const ATTRIBUTE_OID_STR: &'static str = "1.3.6.1.4.1.311.13.2.1";
#[must_use]
pub const fn name(&self) -> &'static str {
match self {
Self::CertType => "CertType",
Self::CertificateUsage { oids: _ } => "CertificateUsage",
Self::ValidityPeriod(_) => "ValidityPeriod",
Self::ValidityPeriodUnits { count: _ } => "ValidityPeriodUnits",
Self::ExpirationDate { date: _ } => "ExpirationDate",
Self::Cdc { cdc_fqdn: _ } => "cdc",
Self::Rmd { rmd_fqdn: _ } => "rmd",
Self::CertificateTemplate { cn: _ } => "CertificateTemplate",
Self::San { collection: _ } => "SAN",
Self::Challenge { challenge: _ } => "challenge",
Self::RequesterName { domain_account: _ } => "requestername",
Self::CertFile { unc_path: _ } => "CertFile",
Self::RequestId { id: _ } => "RequestId",
Self::Other { name, value: _ } => name,
}
}
#[must_use]
pub const fn value(&self) -> &'a str {
match self {
Self::CertType => "server",
Self::CertificateUsage { oids } => oids,
Self::ValidityPeriod(period) => period.value(),
Self::ValidityPeriodUnits { count } => count,
Self::ExpirationDate { date } => date,
Self::Cdc { cdc_fqdn } => cdc_fqdn,
Self::Rmd { rmd_fqdn } => rmd_fqdn,
Self::CertificateTemplate { cn } => cn,
Self::San { collection } => collection,
Self::Challenge { challenge } => challenge,
Self::RequesterName { domain_account } => domain_account,
Self::CertFile { unc_path } => unc_path,
Self::RequestId { id } => id,
Self::Other { name: _, value } => value,
}
}
}
impl WcceAttribute for EnrollmentNameValuePair<'_> {
const ATTRIBUTE_OID: &'static [u64] = &[1, 3, 6, 1, 4, 1, 311, 13, 2, 1];
fn values(&self, writer: &mut DERWriterSet) {
writer.next().write_sequence(|writer| {
writer.next().write_bmp_string(self.name());
writer.next().write_bmp_string(self.value());
});
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RequestClientInfo<'a> {
pub machine: &'a str,
pub user: &'a str,
pub exe: &'a str,
pub version: u32,
}
impl WcceAttribute for RequestClientInfo<'_> {
const ATTRIBUTE_OID: &'static [u64] = &[1, 3, 6, 1, 4, 1, 311, 21, 20];
fn values(&self, writer: &mut DERWriterSet) {
writer.next().write_sequence(|writer| {
writer.next().write_u32(self.version);
writer.next().write_utf8_string(self.machine);
writer.next().write_utf8_string(self.user);
writer.next().write_utf8_string(self.exe);
});
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_renewal_certificate_der() {
#[rustfmt::skip]
let expected: &[u8] = &[
0x31, 0x03,
0x30, 0x01, 0x00,
];
let actual = <RenewalCertificate as Attribute>::values(&RenewalCertificate {
certificate: &[0x30, 0x01, 0x00],
});
assert_eq!(expected, actual);
#[rustfmt::skip]
let expected: &[u8] = &[
0x31, 0x0a,
0x30, 0x08, 0x02, 0x01, 0x01, 0x04, 0x03, 0x66, 0x6f, 0x6f,
];
let actual = <RenewalCertificate as Attribute>::values(&RenewalCertificate {
certificate: &[0x30, 0x08, 0x02, 0x01, 0x01, 0x04, 0x03, 0x66, 0x6f, 0x6f],
});
assert_eq!(expected, actual);
}
#[test]
fn test_request_client_info_der() {
#[rustfmt::skip]
let expected: &[u8] = &[
0x31, 0x19,
0x30, 0x17,
0x02, 0x01, 0x00,
0x0c, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
0x0c, 0x04, 0x75, 0x73, 0x65, 0x72,
0x0c, 0x03, 0x65, 0x78, 0x65,
];
let actual = <RequestClientInfo as Attribute>::values(&RequestClientInfo {
machine: "machine",
user: "user",
exe: "exe",
version: 0,
});
assert_eq!(expected, actual);
#[rustfmt::skip]
let expected: &[u8] = &[
0x31, 0x1d,
0x30, 0x1b,
0x02, 0x05, 0x00, 0xff, 0xff, 0xff, 0xff,
0x0c, 0x07, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65,
0x0c, 0x04, 0x75, 0x73, 0x65, 0x72,
0x0c, 0x03, 0x65, 0x78, 0x65,
];
let actual = <RequestClientInfo as Attribute>::values(&RequestClientInfo {
machine: "machine",
user: "user",
exe: "exe",
version: u32::MAX,
});
assert_eq!(expected, actual);
}
#[test]
fn test_enrollment_name_value_pair_der() {
#[rustfmt::skip]
let expected: &[u8] = &[
0x31, 0x22,
0x30, 0x20,
0x1e, 0x10, 0x00, 0x43, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x54, 0x00, 0x79,
0x00, 0x70, 0x00, 0x65,
0x1e, 0x0c, 0x00, 0x73, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72,
];
let actual =
<EnrollmentNameValuePair as Attribute>::values(&EnrollmentNameValuePair::CertType);
assert_eq!(expected, actual);
#[rustfmt::skip]
let expected: &[u8] = &[
0x31, 0x3e,
0x30, 0x3c,
0x1e, 0x26, 0x00, 0x43, 0x00, 0x65, 0x00, 0x72, 0x00, 0x74, 0x00, 0x69, 0x00, 0x66,
0x00, 0x69, 0x00, 0x63, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00, 0x54, 0x00, 0x65,
0x00, 0x6d, 0x00, 0x70, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65,
0x1e, 0x12, 0x00, 0x57, 0x00, 0x65, 0x00, 0x62, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72,
0x00, 0x76, 0x00, 0x65, 0x00, 0x72,
];
let actual = <EnrollmentNameValuePair as Attribute>::values(
&EnrollmentNameValuePair::CertificateTemplate { cn: "WebServer" },
);
assert_eq!(expected, actual);
#[rustfmt::skip]
let expected: &[u8] = &[
0x31, 0x2a,
0x30, 0x28,
0x1e, 0x1c, 0x00, 0x56, 0x00, 0x61, 0x00, 0x6c, 0x00, 0x69, 0x00, 0x64, 0x00, 0x69,
0x00, 0x74, 0x00, 0x79, 0x00, 0x50, 0x00, 0x65, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6f,
0x00, 0x64,
0x1e, 0x08, 0x00, 0x44, 0x00, 0x61, 0x00, 0x79, 0x00, 0x73,
];
let actual = <EnrollmentNameValuePair as Attribute>::values(
&EnrollmentNameValuePair::ValidityPeriod(ValidityPeriod::Days),
);
assert_eq!(expected, actual);
}
}