Skip to content

bug?: cannot extract client key from pem file if it encoded by SEC1 EC #1143

@YuJuncen

Description

@YuJuncen

Bug Report

Version

│   │   │   │   └── tonic v0.5.2
│   │   │   ├── tonic v0.5.2 (*)
│   │   │   └── tonic-build v0.5.2
│   │   ├── tonic v0.5.2 (*)

Platform

Linux 3.10.0-1160.36.2.el7.x86_64 #1 SMP Wed Jul 21 11:57:15 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

Crates

tonic, with feature tls enabled.

Description

I tried this code:

Generally, I have wrote a client looks like this:

Usage: tls-test [OPTIONS] --ca-path <CA_PATH> --cert-path <CERT_PATH> --key-path <KEY_PATH>

Options:
  -e, --endpoints <ENDPOINTS>  
      --ca-path <CA_PATH>      
      --cert-path <CERT_PATH>  
      --key-path <KEY_PATH>    
  -h, --help                   Print help information

Which fills the tls config like:

pub fn tonic_tls_config(&self) -> Option<ClientTlsConfig> {
        // This function loads the content from files at `{ca,cert,key}_path`.
        let (ca, cert, key) = self.cfg.load_certs().unwrap_or_default();
        if ca.is_empty() && cert.is_empty() && key.is_empty() {
            return None;
        }
        let mut cfg = ClientTlsConfig::new();
        if !ca.is_empty() {
            cfg = cfg.ca_certificate(Certificate::from_pem(ca));
        }
        if !cert.is_empty() && !key.is_empty() {
            cfg = cfg.identity(Identity::from_pem(cert, key));
        }
        Some(cfg)
    }

With a client key file generated by:

openssl ecparam -out "$TEST_DIR/certs/$cluster.key" -name prime256v1 -genkey

I expected to see this happen:
We should be able to connect to the server via the key, or return some error like DNSNameError which hints the key is invalid.

Instead, this happened:
It returns a error like:

tonic::transport::Error(Transport, PrivateKeyParseError)

Some notes:
By reading the code, I have noticed that we are going to extract key via applying pkcs8_private_keys and rsa_private_keys. It seems rustls-pemfile supports SEC1 EC keys however doesn't provide something like ec_private_keys (!).

Perhaps we can use read_once direcly, so we only need to iterate the key file once and can extract the EC keys:

    fn load_rustls_private_key(
        mut cursor: std::io::Cursor<&[u8]>,
    ) -> Result<PrivateKey, crate::Error> {
        while let Ok(Some(item)) = rustls_pemfile::read_one(&mut cursor) {
            match item {
                rustls_pemfile::Item::RSAKey(key)
                | rustls_pemfile::Item::PKCS8Key(key)
                | rustls_pemfile::Item::ECKey(key) => return Ok(PrivateKey(key)),
                _ => continue,
            }
        }

        // Otherwise we have a Private Key parsing problem
        Err(Box::new(TlsError::PrivateKeyParseError))
    }

-->

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions