Skip to content

Commit

Permalink
[wip] Proof of concept algorithm whitelisting implementation on macOS…
Browse files Browse the repository at this point in the history
… and Windows
  • Loading branch information
cyang1 committed Mar 23, 2020
1 parent 75e43da commit a82bfbe
Show file tree
Hide file tree
Showing 3 changed files with 791 additions and 3 deletions.
161 changes: 159 additions & 2 deletions src/imp/schannel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,163 @@ extern crate schannel;

use self::schannel::cert_context::{CertContext, HashAlgorithm};
use self::schannel::cert_store::{CertAdd, CertStore, Memory, PfxImportOptions};
use self::schannel::schannel_cred::{Direction, Protocol, SchannelCred};
use self::schannel::schannel_cred::{Algorithm, Direction, Protocol, SchannelCred};
use self::schannel::tls_stream;
use std::error;
use std::fmt;
use std::io;
use std::str;

use {TlsAcceptorBuilder, TlsConnectorBuilder};
use {
CipherSuiteSet,
TlsAcceptorBuilder,
TlsBulkEncryptionAlgorithm,
TlsConnectorBuilder,
TlsHashAlgorithm,
TlsKeyExchangeAlgorithm,
TlsSignatureAlgorithm
};

// The below four lists are mostly based on the default TLS cipher suites in
// https://docs.microsoft.com/en-us/windows/win32/secauthn/tls-cipher-suites-in-windows-10-v1903.
const DEFAULT_KEY_EXCHANGE_ALGS: &[Algorithm] = &[
Algorithm::DhEphem,
Algorithm::RsaKeyx,

// FIXME: This would be nice, but `schannel` doesn't have this value.
// Algorithm::EcdhEphem,

// Omitted insecure options
// Algorithm::Ecdh,

// TODO: These don't seem like they should be available in TLS cipher suites.
// Algorithm::AgreedkeyAny,
// Algorithm::DhSf,
// Algorithm::HughesMd5,
];

const DEFAULT_SIGNATURE_ALGS: &[Algorithm] = &[
Algorithm::DssSign,
Algorithm::Ecdsa,
Algorithm::RsaSign,

// Omitted insecure options
// Algorithm::NoSign,
];

const DEFAULT_ENCRYPTION_ALGS: &[Algorithm] = &[
Algorithm::Aes128,
Algorithm::Aes256,
Algorithm::TripleDes,

// Omitted insecure options
// Algorithm::Des,
// Algorithm::Rc2,
// Algorithm::Rc4,

// TODO: These don't seem like they should be available in TLS cipher suites.
// Algorithm::Aes192,
// Algorithm::CylinkMek,
// Algorithm::Desx,
// Algorithm::Rc5,
// Algorithm::TripleDes112,
];

const DEFAULT_HASH_ALGS: &[Algorithm] = &[
Algorithm::Sha1,
Algorithm::Sha256,
Algorithm::Sha384,
Algorithm::Sha512,

// Omitted insecure options
// Algorithm::Md5,

// TODO: These don't seem like they should be available in TLS cipher suites.
// Algorithm::HashReplaceOwf,
// Algorithm::Hmac,
// Algorithm::Mac,
// Algorithm::Md2,
// Algorithm::Md4,
];

impl From<TlsKeyExchangeAlgorithm> for Algorithm {
fn from(other: TlsKeyExchangeAlgorithm) -> Self {
match other {
TlsKeyExchangeAlgorithm::Dhe => Algorithm::DhEphem,
TlsKeyExchangeAlgorithm::Ecdhe => panic!("not currently implemented"),
TlsKeyExchangeAlgorithm::Rsa => Algorithm::RsaKeyx,
TlsKeyExchangeAlgorithm::__NonExhaustive => unreachable!(),
}
}
}

impl From<TlsSignatureAlgorithm> for Algorithm {
fn from(other: TlsSignatureAlgorithm) -> Self {
match other {
TlsSignatureAlgorithm::Dss => Algorithm::DssSign,
TlsSignatureAlgorithm::Ecdsa => Algorithm::Ecdsa,
TlsSignatureAlgorithm::Rsa => Algorithm::RsaSign,
TlsSignatureAlgorithm::__NonExhaustive => unreachable!(),
}
}
}

impl From<TlsBulkEncryptionAlgorithm> for Algorithm {
fn from(other: TlsBulkEncryptionAlgorithm) -> Self {
match other {
TlsBulkEncryptionAlgorithm::Aes128 => Algorithm::Aes128,
TlsBulkEncryptionAlgorithm::Aes256 => Algorithm::Aes256,
TlsBulkEncryptionAlgorithm::Des => Algorithm::Des,
TlsBulkEncryptionAlgorithm::Rc2 => Algorithm::Rc2,
TlsBulkEncryptionAlgorithm::Rc4 => Algorithm::Rc4,
TlsBulkEncryptionAlgorithm::TripleDes => Algorithm::TripleDes,
TlsBulkEncryptionAlgorithm::__NonExhaustive => unreachable!(),
}
}
}

impl From<TlsHashAlgorithm> for Algorithm {
fn from(other: TlsHashAlgorithm) -> Self {
match other {
TlsHashAlgorithm::Md5 => Algorithm::Md5,
TlsHashAlgorithm::Sha1=> Algorithm::Sha1,
TlsHashAlgorithm::Sha256 => Algorithm::Sha256,
TlsHashAlgorithm::Sha384 => Algorithm::Sha384,
// TODO: Not supported by macOS Security Framework.
// TlsHashAlgorithm::Sha512 => Algorithm::Sha512,
TlsHashAlgorithm::__NonExhaustive => unreachable!(),
}
}
}

fn expand_algorithms(cipher_suites: CipherSuiteSet) -> Vec<Algorithm> {
let mut ret = vec![];
if cipher_suites.key_exchange.is_empty() {
ret.extend(DEFAULT_KEY_EXCHANGE_ALGS);
} else {
ret.extend(cipher_suites.key_exchange.iter().map(Algorithm::from));
}

if cipher_suites.signature.is_empty() {
ret.extend(DEFAULT_SIGNATURE_ALGS);
} else {
ret.extend(cipher_suites.signature.iter().map(Algorithm::from));
}

if cipher_suites.bulk_encryption.is_empty() {
ret.extend(DEFAULT_ENCRYPTION_ALGS);
} else {
ret.extend(cipher_suites.bulk_encryption.iter().map(Algorithm::from));
}

if cipher_suites.hash.is_empty() {
ret.extend(DEFAULT_HASH_ALGS);
} else {
ret.extend(cipher_suites.hash.iter().map(Algorithm::from));
}

ret
}

const SEC_E_NO_CREDENTIALS: u32 = 0x8009030E;

Expand Down Expand Up @@ -185,6 +334,7 @@ pub struct TlsConnector {
use_sni: bool,
accept_invalid_hostnames: bool,
accept_invalid_certs: bool,
supported_algorithms: Vec<Algorithm>,
}

impl TlsConnector {
Expand All @@ -203,6 +353,10 @@ impl TlsConnector {
use_sni: builder.use_sni,
accept_invalid_hostnames: builder.accept_invalid_hostnames,
accept_invalid_certs: builder.accept_invalid_certs,
supported_algorithms: match builder.cipher_suites {
Some(cipher_suites) => expand_algorithms(cipher_suites),
None => vec![],
},
})
}

Expand All @@ -225,6 +379,9 @@ impl TlsConnector {
if self.accept_invalid_certs {
builder.verify_callback(|_| Ok(()));
}
if !self.supported_algorithms.is_empty() {
builder.supported_algorithms(&self.supported_algorithms);
}
match builder.connect(cred, stream) {
Ok(s) => Ok(TlsStream(s)),
Err(e) => Err(e.into()),
Expand Down
Loading

0 comments on commit a82bfbe

Please sign in to comment.