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:
parent
4d82610700
commit
037466e9cd
6 changed files with 95 additions and 32 deletions
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
2
cli/tests/testdata/ip_address_unsafe_ssl.ts
vendored
Normal file
2
cli/tests/testdata/ip_address_unsafe_ssl.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
const r = await fetch("https://1.1.1.1");
|
||||
console.log(r.status);
|
2
cli/tests/testdata/ip_address_unsafe_ssl.ts.out
vendored
Normal file
2
cli/tests/testdata/ip_address_unsafe_ssl.ts.out
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
DANGER: TLS certificate validation is disabled for: 1.1.1.1
|
||||
200
|
|
@ -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();
|
||||
},
|
||||
);
|
||||
|
||||
|
|
102
ext/tls/lib.rs
102
ext/tls/lib.rs
|
@ -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)?;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue