use crate::error::WSError;
use crate::platform::{KeyHandle, SecureKeyProvider};
use crate::provisioning::{CertificateConfig, DeviceIdentity};
use crate::signature::PublicKey;
pub struct CertificateSigningRequest {
der: Vec<u8>,
device_id: DeviceIdentity,
public_key: PublicKey,
}
impl CertificateSigningRequest {
pub fn new(
provider: &dyn SecureKeyProvider,
key_handle: KeyHandle,
device_id: DeviceIdentity,
config: &CertificateConfig,
) -> Result<Self, WSError> {
device_id.validate()?;
let public_key = provider.get_public_key(key_handle)?;
let csr_info = Self::build_csr_info(&device_id, &public_key, config)?;
let signature = provider.sign(key_handle, &csr_info)?;
let der = Self::build_csr_der(&csr_info, &signature)?;
Ok(Self {
der,
device_id,
public_key,
})
}
fn build_csr_info(
device_id: &DeviceIdentity,
public_key: &PublicKey,
config: &CertificateConfig,
) -> Result<Vec<u8>, WSError> {
use der_encode::*;
let mut csr_info = Vec::new();
csr_info.extend_from_slice(&encode_integer(&[0]));
let subject = Self::build_subject(device_id, config)?;
csr_info.extend_from_slice(&subject);
let spki = Self::build_subject_public_key_info(public_key)?;
csr_info.extend_from_slice(&spki);
csr_info.extend_from_slice(&[0xA0, 0x00]);
Ok(encode_sequence(&csr_info))
}
fn build_subject(
device_id: &DeviceIdentity,
config: &CertificateConfig,
) -> Result<Vec<u8>, WSError> {
use der_encode::*;
let mut rdns = Vec::new();
let cn = device_id.to_common_name();
rdns.push(encode_attribute_type_and_value(OID_CN, &cn));
rdns.push(encode_attribute_type_and_value(
OID_O,
&config.organization,
));
if let Some(ou) = &config.organizational_unit {
rdns.push(encode_attribute_type_and_value(OID_OU, ou));
}
Ok(encode_sequence(&rdns.concat()))
}
fn build_subject_public_key_info(_public_key: &PublicKey) -> Result<Vec<u8>, WSError> {
Err(WSError::UnsupportedAlgorithm(
"CSR generation not yet fully implemented (placeholder)".to_string(),
))
}
fn build_csr_der(_csr_info: &[u8], _signature: &[u8]) -> Result<Vec<u8>, WSError> {
Err(WSError::UnsupportedAlgorithm(
"CSR DER building not yet fully implemented (placeholder)".to_string(),
))
}
pub fn to_der(&self) -> &[u8] {
&self.der
}
pub fn to_pem(&self) -> String {
use pem::Pem;
let pem = Pem::new("CERTIFICATE REQUEST", self.der.clone());
pem::encode(&pem)
}
pub fn device_id(&self) -> &DeviceIdentity {
&self.device_id
}
pub fn public_key(&self) -> &PublicKey {
&self.public_key
}
}
mod der_encode {
pub const OID_CN: &[u8] = &[0x55, 0x04, 0x03];
pub const OID_O: &[u8] = &[0x55, 0x04, 0x0A];
pub const OID_OU: &[u8] = &[0x55, 0x04, 0x0B];
pub fn encode_integer(value: &[u8]) -> Vec<u8> {
let mut result = vec![0x02]; result.push(value.len() as u8);
result.extend_from_slice(value);
result
}
pub fn encode_sequence(contents: &[u8]) -> Vec<u8> {
let mut result = vec![0x30]; encode_length(&mut result, contents.len());
result.extend_from_slice(contents);
result
}
pub fn encode_length(output: &mut Vec<u8>, length: usize) {
if length < 128 {
output.push(length as u8);
} else if length < 256 {
output.push(0x81);
output.push(length as u8);
} else {
output.push(0x82);
output.push((length >> 8) as u8);
output.push((length & 0xFF) as u8);
}
}
pub fn encode_attribute_type_and_value(oid: &[u8], value: &str) -> Vec<u8> {
let mut attr = Vec::new();
attr.push(0x06); attr.push(oid.len() as u8);
attr.extend_from_slice(oid);
attr.push(0x0C); attr.push(value.len() as u8);
attr.extend_from_slice(value.as_bytes());
encode_sequence(&attr)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::platform::software::SoftwareProvider;
#[test]
fn test_csr_creation_placeholder() {
let provider = SoftwareProvider::new();
let handle = provider.generate_key().unwrap();
let device = DeviceIdentity::new("device-123");
let config = CertificateConfig::new("device-123");
let result = CertificateSigningRequest::new(&provider, handle, device, &config);
assert!(result.is_err());
}
#[test]
fn test_der_encode_integer() {
use der_encode::encode_integer;
let encoded = encode_integer(&[0]);
assert_eq!(encoded, vec![0x02, 0x01, 0x00]);
}
#[test]
fn test_der_encode_sequence() {
use der_encode::encode_sequence;
let encoded = encode_sequence(&[0x02, 0x01, 0x00]);
assert_eq!(encoded, vec![0x30, 0x03, 0x02, 0x01, 0x00]);
}
#[test]
fn test_der_encode_length_short() {
use der_encode::encode_length;
let mut output = Vec::new();
encode_length(&mut output, 42);
assert_eq!(output, vec![42]);
}
#[test]
fn test_der_encode_length_medium() {
use der_encode::encode_length;
let mut output = Vec::new();
encode_length(&mut output, 200);
assert_eq!(output, vec![0x81, 200]);
}
#[test]
fn test_der_encode_length_long() {
use der_encode::encode_length;
let mut output = Vec::new();
encode_length(&mut output, 300);
assert_eq!(output, vec![0x82, 0x01, 0x2C]); }
}