Support PKCS8 private keys

Also follow upstream changes in ring/base64
This commit is contained in:
Joseph Birr-Pixton 2017-05-04 20:51:50 +01:00
parent 1a1904ee4b
commit dac2274e80
8 changed files with 73 additions and 40 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "rustls"
version = "0.5.8"
version = "0.6.0"
authors = ["Joseph Birr-Pixton <jpixton@gmail.com>"]
license = "Apache-2.0/ISC/MIT"
readme = "README.md"
@ -10,24 +10,24 @@ repository = "https://github.com/ctz/rustls"
categories = ["network-programming", "cryptography"]
[dependencies]
untrusted = "0.3.1"
time = "0.1.35"
base64 = "~0.2.0"
untrusted = "0.5"
time = "0.1.37"
base64 = "0.5"
log = { version = "0.3.6", optional = true }
ring = { version = "0.7", features = ["rsa_signing"] }
webpki = "0.10"
ring = { version = "0.8", features = ["rsa_signing"] }
webpki = "0.11"
[features]
default = ["logging"]
logging = ["log"]
[dev-dependencies]
log = "0.3.6"
env_logger = "0.3.3"
mio = "0.5.1"
docopt = "0.6"
log = "0.3.7"
env_logger = "0.4.2"
mio = "0.5"
docopt = "0.7"
rustc-serialize = "0.3"
webpki-roots = "0.7"
webpki-roots = "0.9"
regex = "0.2"
[[example]]

View File

@ -396,7 +396,7 @@ Options:
\
--key KEYFILE Read private key from KEYFILE. This should be a RSA
\
private key, in PEM format.
private key or PKCS8-encoded private key, in PEM format.
--auth CERTFILE Enable client authentication, and accept \
certificates
signed by those roots provided in CERTFILE.
@ -470,11 +470,29 @@ fn load_certs(filename: &str) -> Vec<rustls::Certificate> {
}
fn load_private_key(filename: &str) -> rustls::PrivateKey {
let keyfile = fs::File::open(filename).expect("cannot open private key file");
let mut reader = BufReader::new(keyfile);
let keys = rustls::internal::pemfile::rsa_private_keys(&mut reader).unwrap();
assert!(keys.len() == 1);
keys[0].clone()
let rsa_keys = {
let keyfile = fs::File::open(filename)
.expect("cannot open private key file");
let mut reader = BufReader::new(keyfile);
rustls::internal::pemfile::rsa_private_keys(&mut reader)
.expect("file contains invalid rsa private key")
};
let pkcs8_keys = {
let keyfile = fs::File::open(filename)
.expect("cannot open private key file");
let mut reader = BufReader::new(keyfile);
rustls::internal::pemfile::pkcs8_private_keys(&mut reader)
.expect("file contains invalid pkcs8 private key (encrypted keys not supported)")
};
// prefer to load pkcs8 keys
if !pkcs8_keys.is_empty() {
pkcs8_keys[0].clone()
} else {
assert!(!rsa_keys.is_empty());
rsa_keys[0].clone()
}
}
fn make_config(args: &Args) -> Arc<rustls::ServerConfig> {

View File

@ -218,7 +218,7 @@ mod key;
pub mod internal {
/// Functions for parsing PEM files containing certificates/keys.
pub mod pemfile {
pub use pemfile::{certs, rsa_private_keys};
pub use pemfile::{certs, rsa_private_keys, pkcs8_private_keys};
}
/// Low-level TLS message parsing and encoding functions.

View File

@ -32,7 +32,10 @@ fn extract<A>(rd: &mut io::BufRead,
if line.starts_with(end_mark) {
take_base64 = false;
let der = try!(base64::decode_ws(&b64buf).map_err(|_| ()));
let der = try! {
base64::decode_config(&b64buf, base64::MIME)
.map_err(|_| ())
};
ders.push(f(der));
b64buf = String::new();
continue;
@ -62,3 +65,12 @@ pub fn rsa_private_keys(rd: &mut io::BufRead) -> Result<Vec<key::PrivateKey>, ()
"-----END RSA PRIVATE KEY-----",
&|v| key::PrivateKey(v))
}
/// Extract all PKCS8-encoded private keys from rd, and return a vec of
/// `key::PrivateKey`s containing the der-format contents.
pub fn pkcs8_private_keys(rd: &mut io::BufRead) -> Result<Vec<key::PrivateKey>, ()> {
extract(rd,
"-----BEGIN PRIVATE KEY-----",
"-----END PRIVATE KEY-----",
&|v| key::PrivateKey(v))
}

View File

@ -3,7 +3,7 @@ use ring::hmac;
use std::io::Write;
fn concat_sign(key: &hmac::SigningKey, a: &[u8], b: &[u8]) -> digest::Digest {
fn concat_sign(key: &hmac::SigningKey, a: &[u8], b: &[u8]) -> hmac::Signature {
let mut ctx = hmac::SigningContext::with_key(key);
ctx.update(a);
ctx.update(b);

View File

@ -3,12 +3,12 @@
/// for our own use. These functions never fail,
/// they panic on error.
use ring;
use ring::rand::{SystemRandom, SecureRandom};
use msgs::codec;
/// Fill the whole slice with random material.
pub fn fill_random(bytes: &mut [u8]) {
ring::rand::SystemRandom::new()
SystemRandom::new()
.fill(bytes)
.unwrap();
}

View File

@ -232,7 +232,8 @@ struct AlwaysResolvesChain {
impl AlwaysResolvesChain {
fn new_rsa(chain: Vec<key::Certificate>, priv_key: &key::PrivateKey) -> AlwaysResolvesChain {
let key = sign::RSASigner::new(priv_key).expect("Invalid RSA private key");
let key = sign::RSASigner::new(priv_key)
.expect("Invalid RSA private key");
AlwaysResolvesChain {
chain: chain,
key: Arc::new(Box::new(key)),

View File

@ -3,6 +3,7 @@ use util;
use untrusted;
use ring;
use ring::signature;
use ring::signature::RSAKeyPair;
use std::sync::Arc;
use key;
@ -22,27 +23,28 @@ pub type CertChainAndSigner = (Vec<key::Certificate>, Arc<Box<Signer>>);
/// A Signer for RSA-PKCS1 or RSA-PSS
pub struct RSASigner {
key: Arc<signature::RSAKeyPair>,
schemes: Vec<SignatureScheme>,
key: Arc<RSAKeyPair>,
schemes: &'static [SignatureScheme],
}
fn all_schemes() -> Vec<SignatureScheme> {
vec![SignatureScheme::RSA_PSS_SHA512,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::RSA_PKCS1_SHA256]
}
static ALL_SCHEMES: &'static [SignatureScheme] = &[
SignatureScheme::RSA_PSS_SHA512,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::RSA_PKCS1_SHA256,
];
impl RSASigner {
pub fn new(der: &key::PrivateKey) -> Result<RSASigner, ()> {
let key = signature::RSAKeyPair::from_der(untrusted::Input::from(&der.0));
key.map(|s| {
RSASigner {
key: Arc::new(s),
schemes: all_schemes(),
}
RSAKeyPair::from_der(untrusted::Input::from(&der.0))
.or_else(|_| RSAKeyPair::from_pkcs8(untrusted::Input::from(&der.0)))
.map(|s| {
RSASigner {
key: Arc::new(s),
schemes: ALL_SCHEMES,
}
})
.map_err(|_| ())
}
@ -50,7 +52,7 @@ impl RSASigner {
impl Signer for RSASigner {
fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<SignatureScheme> {
util::first_in_both(&self.schemes, offered)
util::first_in_both(self.schemes, offered)
}
fn sign(&self, scheme: SignatureScheme, message: &[u8]) -> Result<Vec<u8>, ()> {