0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00

fix(ext/tls): ability to ignore IP-address certificate errors (#14610)

This commit is contained in:
Aleksei Kosyrev 2022-05-18 14:32:12 +03:00 committed by GitHub
parent 4d82610700
commit 037466e9cd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 95 additions and 32 deletions

4
Cargo.lock generated
View file

@ -3373,9 +3373,9 @@ dependencies = [
[[package]]
name = "rustls"
version = "0.20.4"
version = "0.20.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921"
checksum = "a024a432ae760ab3bff924ad91ce1cfa52cb57ed16e1ef32d0d249cfee1a6c13"
dependencies = [
"log",
"ring",

View file

@ -523,6 +523,12 @@ itest!(deno_land_unsafe_ssl {
output: "deno_land_unsafe_ssl.ts.out",
});
itest!(ip_address_unsafe_ssl {
args:
"run --quiet --reload --allow-net --unsafely-ignore-certificate-errors=1.1.1.1 ip_address_unsafe_ssl.ts",
output: "ip_address_unsafe_ssl.ts.out",
});
itest!(localhost_unsafe_ssl {
args:
"run --quiet --reload --allow-net --unsafely-ignore-certificate-errors=deno.land cafile_url_imports.ts",

View file

@ -0,0 +1,2 @@
const r = await fetch("https://1.1.1.1");
console.log(r.status);

View file

@ -0,0 +1,2 @@
DANGER: TLS certificate validation is disabled for: 1.1.1.1
200

View file

@ -36,18 +36,9 @@ Deno.test({ permissions: { net: false } }, async function connectTLSNoPerm() {
Deno.test(
{ permissions: { read: true, net: true } },
async function connectTLSInvalidHost() {
const listener = await Deno.listenTls({
hostname: "localhost",
port: 3567,
certFile: "cli/tests/testdata/tls/localhost.crt",
keyFile: "cli/tests/testdata/tls/localhost.key",
});
await assertRejects(async () => {
await Deno.connectTls({ hostname: "127.0.0.1", port: 3567 });
await Deno.connectTls({ hostname: "256.0.0.0", port: 3567 });
}, TypeError);
listener.close();
},
);

View file

@ -12,10 +12,12 @@ use deno_core::error::AnyError;
use deno_core::parking_lot::Mutex;
use deno_core::Extension;
use rustls::client::HandshakeSignatureValid;
use rustls::client::ServerCertVerified;
use rustls::client::ServerCertVerifier;
use rustls::client::StoresClientSessions;
use rustls::client::WebPkiVerifier;
use rustls::internal::msgs::handshake::DigitallySignedStruct;
use rustls::Certificate;
use rustls::ClientConfig;
use rustls::Error;
@ -38,6 +40,22 @@ pub fn init() -> Extension {
Extension::builder().build()
}
struct DefaultSignatureVerification;
impl ServerCertVerifier for DefaultSignatureVerification {
fn verify_server_cert(
&self,
_end_entity: &Certificate,
_intermediates: &[Certificate],
_server_name: &ServerName,
_scts: &mut dyn Iterator<Item = &[u8]>,
_ocsp_response: &[u8],
_now: SystemTime,
) -> Result<ServerCertVerified, Error> {
Err(Error::General("Should not be used".to_string()))
}
}
pub struct NoCertificateVerification(pub Vec<String>);
impl ServerCertVerifier for NoCertificateVerification {
@ -50,27 +68,60 @@ impl ServerCertVerifier for NoCertificateVerification {
ocsp_response: &[u8],
now: SystemTime,
) -> Result<ServerCertVerified, Error> {
if let ServerName::DnsName(dns_name) = server_name {
let dns_name = dns_name.as_ref().to_owned();
if self.0.is_empty() || self.0.contains(&dns_name) {
Ok(ServerCertVerified::assertion())
} else {
let root_store = create_default_root_cert_store();
let verifier = WebPkiVerifier::new(root_store, None);
verifier.verify_server_cert(
end_entity,
intermediates,
server_name,
scts,
ocsp_response,
now,
)
}
} else {
// NOTE(bartlomieju): `ServerName` is a non-exhaustive enum
// so we have this catch all error here.
Err(Error::General("Unknown `ServerName` variant".to_string()))
if self.0.is_empty() {
return Ok(ServerCertVerified::assertion());
}
let dns_name_or_ip_address = match server_name {
ServerName::DnsName(dns_name) => dns_name.as_ref().to_owned(),
ServerName::IpAddress(ip_address) => ip_address.to_string(),
_ => {
// NOTE(bartlomieju): `ServerName` is a non-exhaustive enum
// so we have this catch all errors here.
return Err(Error::General("Unknown `ServerName` variant".to_string()));
}
};
if self.0.contains(&dns_name_or_ip_address) {
Ok(ServerCertVerified::assertion())
} else {
let root_store = create_default_root_cert_store();
let verifier = WebPkiVerifier::new(root_store, None);
verifier.verify_server_cert(
end_entity,
intermediates,
server_name,
scts,
ocsp_response,
now,
)
}
}
fn verify_tls12_signature(
&self,
message: &[u8],
cert: &rustls::Certificate,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
if self.0.is_empty() {
return Ok(HandshakeSignatureValid::assertion());
}
filter_invalid_encoding_err(
DefaultSignatureVerification.verify_tls12_signature(message, cert, dss),
)
}
fn verify_tls13_signature(
&self,
message: &[u8],
cert: &rustls::Certificate,
dss: &DigitallySignedStruct,
) -> Result<HandshakeSignatureValid, Error> {
if self.0.is_empty() {
return Ok(HandshakeSignatureValid::assertion());
}
filter_invalid_encoding_err(
DefaultSignatureVerification.verify_tls13_signature(message, cert, dss),
)
}
}
@ -233,6 +284,17 @@ fn load_pkcs8_keys(mut bytes: &[u8]) -> Result<Vec<PrivateKey>, AnyError> {
Ok(keys.into_iter().map(PrivateKey).collect())
}
fn filter_invalid_encoding_err(
to_be_filtered: Result<HandshakeSignatureValid, Error>,
) -> Result<HandshakeSignatureValid, Error> {
match to_be_filtered {
Err(Error::InvalidCertificateEncoding) => {
Ok(HandshakeSignatureValid::assertion())
}
res => res,
}
}
pub fn load_private_keys(bytes: &[u8]) -> Result<Vec<PrivateKey>, AnyError> {
let mut keys = load_rsa_keys(bytes)?;