em_app/
csr.rs

1/* Copyright (c) Fortanix, Inc.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7use crate::Error;
8use crate::Result;
9use crate::common_name_to_subject;
10use mbedtls::hash;
11use mbedtls::pk::{Pk, Type as PkType};
12pub use mbedtls::rng::Rdrand as FtxRng;
13use pkix;
14use pkix::bit_vec::BitVec;
15use pkix::pem::{der_to_pem, PEM_CERTIFICATE_REQUEST};
16use pkix::pkcs10::{CertificationRequest, CertificationRequestInfo};
17use pkix::types::{
18    Attribute, DerSequence, EcdsaX962, Extension, Name, ObjectIdentifier, RsaPkcs15, Sha256,
19};
20use pkix::DerWrite;
21
22#[derive(Clone, Copy, Debug)]
23pub enum SignatureAlgorithm {
24    EcdsaX962,
25    RsaPkcs15,
26}
27
28/// Operations needed on any input key pair. This is already implemented for mbedtls::Pk.
29pub trait ExternalKey {
30    fn get_public_key_der(&mut self) -> Result<Vec<u8>>;
31    fn sign_sha256(&mut self, input: &[u8]) -> Result<(Vec<u8>, SignatureAlgorithm)>;
32}
33
34pub trait CsrSigner {
35    fn get_public_key_der(&mut self) -> Result<Vec<u8>>;
36    fn sign_csr(&mut self, csr: &CertificationRequestInfo<DerSequence>) -> Result<String>;
37}
38
39impl<T> CsrSigner for T
40where
41    T: ExternalKey
42{
43    fn get_public_key_der(&mut self) -> Result<Vec<u8>> {
44        ExternalKey::get_public_key_der(self)
45    }
46
47    fn sign_csr(&mut self, csr: &CertificationRequestInfo<DerSequence>) -> Result<String>
48    {
49        let reqinfo = DerSequence::from(pkix::yasna::construct_der(|writer| {
50            csr.write(writer)
51        }));
52
53        let (sig, sigalg) = self.sign_sha256(reqinfo.as_ref())?;
54
55        let csr = match sigalg {
56            SignatureAlgorithm::EcdsaX962 => pkix::yasna::construct_der(|writer| {
57                CertificationRequest {
58                    reqinfo,
59                    sigalg: EcdsaX962(Sha256),
60                    sig: BitVec::from_bytes(&sig),
61                }.write(writer)
62            }),
63            SignatureAlgorithm::RsaPkcs15 => pkix::yasna::construct_der(|writer| {
64                CertificationRequest {
65                    reqinfo,
66                    sigalg: RsaPkcs15(Sha256),
67                    sig: BitVec::from_bytes(&sig),
68                }.write(writer)
69            })
70        };
71
72        Ok(der_to_pem(&csr, PEM_CERTIFICATE_REQUEST))
73    }
74}
75
76impl ExternalKey for Pk {
77    fn get_public_key_der(&mut self) -> Result<Vec<u8>> {
78        Ok(self.write_public_der_vec().map_err(|e| Error::ExternalKey(Box::new(e)))?)
79    }
80
81    fn sign_sha256(&mut self, input: &[u8]) -> Result<(Vec<u8>, SignatureAlgorithm)> {
82        let mut hash = [0u8; 32];
83        hash::Md::hash(hash::Type::Sha256, &input, &mut hash).map_err(|e| Error::ExternalKey(Box::new(e)))?;
84
85        let mut sig = vec![0u8; (self.len()+7)/8];
86        self.sign(hash::Type::Sha256, &hash, &mut sig, &mut FtxRng).map_err(|e| Error::ExternalKey(Box::new(e)))?;
87
88        let sigalg = match self.pk_type() {
89            PkType::Rsa | PkType::RsaAlt | PkType::RsassaPss => Ok(SignatureAlgorithm::RsaPkcs15),
90            PkType::Eckey | PkType::Ecdsa => Ok(SignatureAlgorithm::EcdsaX962),
91            _ => Err(Error::ExternalKeyString(format!("Invalid key type: {:?}", self.pk_type()))),
92        }?;
93
94        Ok((sig, sigalg))
95    }
96}
97
98pub fn get_csr(
99    signer: &mut dyn CsrSigner,
100    subject: &Name,
101    attributes: Vec<(ObjectIdentifier, Vec<Vec<u8>>)>,
102    extensions: &Option<Vec<(ObjectIdentifier, bool, Vec<u8>)>>,
103) -> Result<String> {
104
105    let pub_key_der = signer.get_public_key_der()?;
106
107    let mut attributes = attributes.iter().map(|&(ref oid,ref elems)| {
108        Attribute {
109            oid: oid.clone(),
110            value: elems.iter().map(|e| e[..].into()).collect(),
111        }
112    }).collect::<Vec<_>>();
113
114    let extension_bytes = extensions.as_ref().and_then(|ext| {
115        Some(pkix::yasna::construct_der(|w|w.write_sequence(|w|{
116            for &(ref oid, critical, ref value) in ext {
117                Extension {
118                    oid: oid.clone(),
119                    critical: critical,
120                    value: value[..].to_owned(),
121                }.write(w.next())
122            }
123        })))
124    });
125
126    if let Some(bytes) = &extension_bytes {
127        attributes.push(Attribute{
128            oid: pkix::oid::extensionRequest.clone(),
129            value: vec![bytes[..].into()],
130        });
131    }
132
133    let csr = CertificationRequestInfo {
134        subject: subject.to_owned(),
135        spki: DerSequence::from(&pub_key_der[..]),
136        attributes: attributes,
137    };
138
139    signer.sign_csr(&csr)
140}
141
142pub fn get_csr_common_name(
143    signer: &mut dyn CsrSigner,
144    common_name: &str,
145    attributes: Vec<(ObjectIdentifier, Vec<Vec<u8>>)>,
146    extensions: &Option<Vec<(ObjectIdentifier, bool, Vec<u8>)>>,
147) -> Result<String> {
148    let subject = common_name_to_subject(common_name);
149    get_csr(signer, &subject, attributes, extensions)
150}