tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

backend.rs (8325B)


      1 /* -*- Mode: rust; rust-indent-offset: 4 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 use pkcs11_bindings::*;
      7 use rsclientcerts::cryptoki::*;
      8 use rsclientcerts::manager::{ClientCertsBackend, CryptokiObject, Sign};
      9 use rsclientcerts_util::error::Error;
     10 use rsclientcerts_util::*;
     11 
     12 use base64::prelude::*;
     13 use libcrux_p256::{ecdsa_sign_p256_without_hash, validate_private_key};
     14 use num_bigint::BigUint;
     15 use rand::{thread_rng, RngCore};
     16 
     17 #[derive(Clone)]
     18 struct RSAKey {
     19    modulus: BigUint,
     20    private_exponent: BigUint,
     21 }
     22 
     23 #[derive(Clone)]
     24 struct ECKey {
     25    private_key: Vec<u8>,
     26 }
     27 
     28 #[derive(Clone)]
     29 enum PrivateKey {
     30    RSA(RSAKey),
     31    EC(ECKey),
     32 }
     33 
     34 #[derive(Clone)]
     35 pub struct Key {
     36    cryptoki_key: CryptokiKey,
     37    private_key: PrivateKey,
     38 }
     39 
     40 impl Key {
     41    fn new(private_key_info: Vec<u8>, cert: Vec<u8>) -> Result<Key, Error> {
     42        let private_key_info = read_private_key_info(&private_key_info).unwrap();
     43        let (cryptoki_key, private_key) = match private_key_info {
     44            PrivateKeyInfo::RSA(rsa_private_key) => (
     45                CryptokiKey::new(Some(rsa_private_key.modulus.clone()), None, &cert).unwrap(),
     46                PrivateKey::RSA(RSAKey {
     47                    modulus: BigUint::from_bytes_be(rsa_private_key.modulus.as_ref()),
     48                    private_exponent: BigUint::from_bytes_be(
     49                        rsa_private_key.private_exponent.as_ref(),
     50                    ),
     51                }),
     52            ),
     53            PrivateKeyInfo::EC(ec_private_key) => (
     54                CryptokiKey::new(None, Some(ENCODED_OID_BYTES_SECP256R1.to_vec()), &cert).unwrap(),
     55                PrivateKey::EC(ECKey {
     56                    private_key: ec_private_key.private_key,
     57                }),
     58            ),
     59        };
     60        Ok(Key {
     61            cryptoki_key,
     62            private_key,
     63        })
     64    }
     65 }
     66 
     67 impl CryptokiObject for Key {
     68    fn matches(&self, attrs: &[(CK_ATTRIBUTE_TYPE, Vec<u8>)]) -> bool {
     69        self.cryptoki_key.matches(attrs)
     70    }
     71 
     72    fn get_attribute(&self, attribute: CK_ATTRIBUTE_TYPE) -> Option<&[u8]> {
     73        self.cryptoki_key.get_attribute(attribute)
     74    }
     75 }
     76 
     77 // Implements EMSA-PKCS1-v1_5-ENCODE as per RFC 8017 section 9.2, except that the message `M` has
     78 // already been hashed and encoded into a `DigestInfo` with the appropriate digest algorithm.
     79 fn emsa_pkcs1v1_5_encode(digest_info: &[u8], em_len: usize) -> Vec<u8> {
     80    assert!(em_len >= digest_info.len() + 11);
     81    let mut ps = vec![0xff; em_len - digest_info.len() - 3];
     82    let mut em = vec![0x00, 0x01];
     83    em.append(&mut ps);
     84    em.push(0x00);
     85    em.extend_from_slice(digest_info);
     86    em
     87 }
     88 
     89 impl Sign for Key {
     90    fn get_signature_length(
     91        &mut self,
     92        _data: &[u8],
     93        _params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
     94    ) -> Result<usize, Error> {
     95        match &self.private_key {
     96            PrivateKey::RSA(rsa_private_key) => Ok(((rsa_private_key.modulus.bits() + 7) / 8)
     97                .try_into()
     98                .unwrap()),
     99            PrivateKey::EC(_) => Ok(64), // currently, only secp256r1 is supported
    100        }
    101    }
    102 
    103    fn sign(
    104        &mut self,
    105        data: &[u8],
    106        params: &Option<CK_RSA_PKCS_PSS_PARAMS>,
    107    ) -> Result<Vec<u8>, Error> {
    108        match &self.private_key {
    109            PrivateKey::RSA(rsa_private_key) => {
    110                let encoded = if let Some(params) = params.as_ref() {
    111                    let em_bits = rsa_private_key.modulus.bits() - 1;
    112                    emsa_pss_encode(data, em_bits.try_into().unwrap(), params).unwrap()
    113                } else {
    114                    let em_len = ((rsa_private_key.modulus.bits() + 7) / 8)
    115                        .try_into()
    116                        .unwrap();
    117                    emsa_pkcs1v1_5_encode(data, em_len)
    118                };
    119                let message = BigUint::from_bytes_be(&encoded);
    120                // NB: Do not use this implementation where maintaining the secrecy of the private key is
    121                // important. In particular, the underlying exponentiation implementation may not be
    122                // constant-time and could leak information. This is intended to only be used in tests.
    123                // Additionally, the "private" key in use is already not at all a secret.
    124                let signature =
    125                    message.modpow(&rsa_private_key.private_exponent, &rsa_private_key.modulus);
    126                Ok(signature.to_bytes_be())
    127            }
    128            PrivateKey::EC(ec_private_key) => {
    129                Ok(ecdsa(data, ec_private_key.private_key.as_slice()))
    130            }
    131        }
    132    }
    133 }
    134 
    135 fn ecdsa(hash: &[u8], private_key: &[u8]) -> Vec<u8> {
    136    assert_eq!(hash.len(), 32);
    137    assert_eq!(private_key.len(), 32);
    138    assert!(validate_private_key(private_key));
    139    let mut signature = vec![0; 64];
    140    let nonce = loop {
    141        let mut nonce = [0u8; 32];
    142        thread_rng().fill_bytes(&mut nonce);
    143        if validate_private_key(&nonce) {
    144            break nonce;
    145        }
    146    };
    147    assert!(ecdsa_sign_p256_without_hash(
    148        signature.as_mut_slice(),
    149        hash.len().try_into().unwrap(),
    150        hash,
    151        private_key,
    152        nonce.as_slice(),
    153    ));
    154    signature
    155 }
    156 
    157 pub struct Backend {
    158    slot_description: &'static [u8; 64],
    159    token_label: &'static [u8; 32],
    160    slot_flags: CK_FLAGS,
    161    token_flags: CK_FLAGS,
    162    logged_in: bool,
    163    certs: Vec<CryptokiCert>,
    164    keys: Vec<Key>,
    165 }
    166 
    167 const TOKEN_MODEL_BYTES: &[u8; 16] = b"Test Model      ";
    168 const TOKEN_SERIAL_NUMBER_BYTES: &[u8; 16] = b"0000000000000000";
    169 
    170 impl Backend {
    171    pub fn new(
    172        slot_description: &'static [u8; 64],
    173        token_label: &'static [u8; 32],
    174        slot_flags: CK_FLAGS,
    175        token_flags: CK_FLAGS,
    176        certs_pem: Vec<&'static str>,
    177        keys_pem: Vec<&'static str>,
    178    ) -> Backend {
    179        let certs_der = certs_pem
    180            .into_iter()
    181            .map(pem_to_base64)
    182            .map(|base64| BASE64_STANDARD.decode(base64).unwrap());
    183        let keys_der = keys_pem
    184            .into_iter()
    185            .map(pem_to_base64)
    186            .map(|base64| BASE64_STANDARD.decode(base64).unwrap());
    187        let mut certs = Vec::new();
    188        let mut keys = Vec::new();
    189        for (cert_der, key_der) in std::iter::zip(certs_der, keys_der) {
    190            let cert = CryptokiCert::new(cert_der.to_vec(), b"test certificate".to_vec()).unwrap();
    191            certs.push(cert);
    192            let key = Key::new(key_der.to_vec(), cert_der.to_vec()).unwrap();
    193            keys.push(key);
    194        }
    195        Backend {
    196            slot_description,
    197            token_label,
    198            slot_flags,
    199            token_flags,
    200            logged_in: false,
    201            certs,
    202            keys,
    203        }
    204    }
    205 }
    206 
    207 fn pem_to_base64(pem: &str) -> String {
    208    let lines = pem.split('\n');
    209    let line_count = lines.clone().count();
    210    // Strip off "-----BEGIN CERTIFICATE-----" / "-----END CERTIFICATE-----"
    211    lines
    212        .skip(1)
    213        .take(line_count - 3)
    214        .collect::<Vec<&str>>()
    215        .join("")
    216 }
    217 
    218 impl ClientCertsBackend for Backend {
    219    type Key = Key;
    220 
    221    fn find_objects(&mut self) -> Result<(Vec<CryptokiCert>, Vec<Key>), Error> {
    222        Ok((self.certs.clone(), self.keys.clone()))
    223    }
    224 
    225    fn get_slot_info(&self) -> CK_SLOT_INFO {
    226        CK_SLOT_INFO {
    227            slotDescription: *self.slot_description,
    228            manufacturerID: *crate::MANUFACTURER_ID_BYTES,
    229            flags: self.slot_flags,
    230            ..Default::default()
    231        }
    232    }
    233 
    234    fn get_token_info(&self) -> CK_TOKEN_INFO {
    235        CK_TOKEN_INFO {
    236            label: *self.token_label,
    237            manufacturerID: *crate::MANUFACTURER_ID_BYTES,
    238            model: *TOKEN_MODEL_BYTES,
    239            serialNumber: *TOKEN_SERIAL_NUMBER_BYTES,
    240            flags: self.token_flags,
    241            ..Default::default()
    242        }
    243    }
    244 
    245    fn get_mechanism_list(&self) -> Vec<CK_MECHANISM_TYPE> {
    246        vec![CKM_ECDSA, CKM_RSA_PKCS, CKM_RSA_PKCS_PSS]
    247    }
    248 
    249    fn login(&mut self) {
    250        self.logged_in = true;
    251    }
    252 
    253    fn logout(&mut self) {
    254        self.logged_in = false;
    255    }
    256 
    257    fn is_logged_in(&self) -> bool {
    258        self.logged_in
    259    }
    260 }