Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING(net): remove Deno.ConnectTlsOptions.{certChain,certFile,privateKey} and Deno.ListenTlsOptions.certChain,certFile,keyFile} #25525

Merged
merged 9 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cli/tsc/dts/lib.deno.ns.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5356,7 +5356,7 @@ declare namespace Deno {
export function serve(
options:
| ServeTcpOptions
| (ServeTcpOptions & TlsCertifiedKeyOptions),
| (ServeTcpOptions & TlsCertifiedKeyPem),
handler: ServeHandler<Deno.NetAddr>,
): HttpServer<Deno.NetAddr>;
/** Serves HTTP requests with the given option bag.
Expand Down Expand Up @@ -5413,7 +5413,7 @@ declare namespace Deno {
*/
export function serve(
options:
& (ServeTcpOptions | (ServeTcpOptions & TlsCertifiedKeyOptions))
& (ServeTcpOptions | (ServeTcpOptions & TlsCertifiedKeyPem))
& ServeInit<Deno.NetAddr>,
): HttpServer<Deno.NetAddr>;

Expand Down
2 changes: 1 addition & 1 deletion cli/tsc/dts/lib.deno.unstable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ declare namespace Deno {
* @experimental
*/
export function createHttpClient(
options: CreateHttpClientOptions & TlsCertifiedKeyOptions,
options: CreateHttpClientOptions & TlsCertifiedKeyPem,
): HttpClient;

/** **UNSTABLE**: New API, yet to be vetted.
Expand Down
109 changes: 11 additions & 98 deletions ext/net/02_tls.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
op_tls_handshake,
op_tls_key_null,
op_tls_key_static,
op_tls_key_static_from_file,
op_tls_start,
} from "ext:core/ops";
const {
Expand Down Expand Up @@ -50,45 +49,23 @@ async function connectTls({
alpnProtocols = undefined,
keyFormat = undefined,
cert = undefined,
certFile = undefined,
certChain = undefined,
key = undefined,
keyFile = undefined,
privateKey = undefined,
}) {
if (transport !== "tcp") {
throw new TypeError(`Unsupported transport: '${transport}'`);
}
let deprecatedCertFile = undefined;

// Deno.connectTls has an irregular option where you can just pass `certFile` and
// not `keyFile`. In this case it's used for `caCerts` rather than the client key.
if (certFile !== undefined && keyFile === undefined) {
internals.warnOnDeprecatedApi(
"Deno.ConnectTlsOptions.certFile",
new Error().stack,
"Pass the cert file's contents to the `Deno.ConnectTlsOptions.caCerts` option instead.",
);

deprecatedCertFile = certFile;
certFile = undefined;
}

const keyPair = loadTlsKeyPair("Deno.connectTls", {
keyFormat,
cert,
certFile,
certChain,
key,
keyFile,
privateKey,
});
// TODO(mmastrac): We only expose this feature via symbol for now. This should actually be a feature
// in Deno.connectTls, however.
const serverName = arguments[0][serverNameSymbol] ?? null;
const { 0: rid, 1: localAddr, 2: remoteAddr } = await op_net_connect_tls(
{ hostname, port },
{ certFile: deprecatedCertFile, caCerts, alpnProtocols, serverName },
{ caCerts, alpnProtocols, serverName },
keyPair,
);
localAddr.transport = "tcp";
Expand Down Expand Up @@ -137,10 +114,7 @@ function hasTlsKeyPairOptions(options) {
if (options[resolverSymbol] !== undefined) {
return true;
}
return (options.cert !== undefined || options.key !== undefined ||
options.certFile !== undefined ||
options.keyFile !== undefined || options.privateKey !== undefined ||
options.certChain !== undefined);
return (options.cert !== undefined || options.key !== undefined);
}

/**
Expand All @@ -150,19 +124,8 @@ function hasTlsKeyPairOptions(options) {
function loadTlsKeyPair(api, {
keyFormat,
cert,
certFile,
certChain,
key,
keyFile,
privateKey,
}) {
if (internals.future) {
certFile = undefined;
certChain = undefined;
keyFile = undefined;
privateKey = undefined;
}

// TODO(mmastrac): remove this temporary symbol when the API lands
if (arguments[1][resolverSymbol] !== undefined) {
return createTlsKeyResolver(arguments[1][resolverSymbol]);
Expand All @@ -173,68 +136,18 @@ function loadTlsKeyPair(api, {
throw new TypeError('If `keyFormat` is specified, it must be "pem"');
}

function exclusive(a1, a1v, a2, a2v) {
if (a1v !== undefined && a2v !== undefined) {
throw new TypeError(
`Cannot specify both \`${a1}\` and \`${a2}\` for \`${api}\`.`,
);
}
if (cert !== undefined && key === undefined) {
throw new TypeError(
`If \`cert\` is specified, \`key\` must be specified as well for \`${api}\`.`,
);
}

// Ensure that only one pair is valid
exclusive("certChain", certChain, "cert", cert);
exclusive("certChain", certChain, "certFile", certFile);
exclusive("key", key, "keyFile", keyFile);
exclusive("key", key, "privateKey", privateKey);

function both(a1, a1v, a2, a2v) {
if (a1v !== undefined && a2v === undefined) {
throw new TypeError(
`If \`${a1}\` is specified, \`${a2}\` must be specified as well for \`${api}\`.`,
);
}
if (a1v === undefined && a2v !== undefined) {
throw new TypeError(
`If \`${a2}\` is specified, \`${a1}\` must be specified as well for \`${api}\`.`,
);
}
if (cert === undefined && key !== undefined) {
throw new TypeError(
`If \`key\` is specified, \`cert\` must be specified as well for \`${api}\`.`,
);
}

// Pick one pair of cert/key, certFile/keyFile or certChain/privateKey
both("cert", cert, "key", key);
both("certFile", certFile, "keyFile", keyFile);
both("certChain", certChain, "privateKey", privateKey);

if (certFile !== undefined) {
internals.warnOnDeprecatedApi(
"Deno.TlsCertifiedKeyOptions.keyFile",
new Error().stack,
"Pass the key file's contents to the `Deno.TlsCertifiedKeyPem.key` option instead.",
);
internals.warnOnDeprecatedApi(
"Deno.TlsCertifiedKeyOptions.certFile",
new Error().stack,
"Pass the cert file's contents to the `Deno.TlsCertifiedKeyPem.cert` option instead.",
);
return op_tls_key_static_from_file(api, certFile, keyFile);
} else if (certChain !== undefined) {
if (api !== "Deno.connectTls") {
throw new TypeError(
`Invalid options 'certChain' and 'privateKey' for ${api}`,
);
}
internals.warnOnDeprecatedApi(
"Deno.TlsCertifiedKeyOptions.privateKey",
new Error().stack,
"Use the `Deno.TlsCertifiedKeyPem.key` option instead.",
);
internals.warnOnDeprecatedApi(
"Deno.TlsCertifiedKeyOptions.certChain",
new Error().stack,
"Use the `Deno.TlsCertifiedKeyPem.cert` option instead.",
);
return op_tls_key_static(certChain, privateKey);
} else if (cert !== undefined) {
if (cert !== undefined) {
return op_tls_key_static(cert, key);
} else {
return op_tls_key_null();
Expand Down
77 changes: 2 additions & 75 deletions ext/net/lib.deno_net.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,16 +232,6 @@ declare namespace Deno {
options: UnixListenOptions & { transport: "unix" },
): UnixListener;

/** Provides TLS certified keys, ie: a key that has been certified by a trusted certificate authority.
* A certified key generally consists of a private key and certificate part.
*
* @category Network
*/
export type TlsCertifiedKeyOptions =
| TlsCertifiedKeyPem
| TlsCertifiedKeyFromFile
| TlsCertifiedKeyConnectTls;

/**
* Provides certified key material from strings. The key material is provided in
* `PEM`-format (Privacy Enhanced Mail, https://www.rfc-editor.org/rfc/rfc1422) which can be identified by having
Expand All @@ -268,59 +258,6 @@ declare namespace Deno {
cert: string;
}

/**
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*
* @category Network
*/
export interface TlsCertifiedKeyFromFile {
/** Path to a file containing a PEM formatted CA certificate. Requires
* `--allow-read`.
*
* @tags allow-read
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
certFile: string;
/** Path to a file containing a private key file. Requires `--allow-read`.
*
* @tags allow-read
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
keyFile: string;
}

/**
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*
* @category Network
*/
export interface TlsCertifiedKeyConnectTls {
/**
* Certificate chain in `PEM` format.
*
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
certChain: string;
/**
* Private key in `PEM` format. RSA, EC, and PKCS8-format keys are supported.
*
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
privateKey: string;
}

/** @category Network */
export interface ListenTlsOptions extends TcpListenOptions {
transport?: "tcp";
Expand Down Expand Up @@ -349,7 +286,7 @@ declare namespace Deno {
* @category Network
*/
export function listenTls(
options: ListenTlsOptions & TlsCertifiedKeyOptions,
options: ListenTlsOptions & TlsCertifiedKeyPem,
): TlsListener;

/** @category Network */
Expand Down Expand Up @@ -430,16 +367,6 @@ declare namespace Deno {
*
* @default {"127.0.0.1"} */
hostname?: string;
/** Path to a file containing a PEM formatted list of root certificates that will
* be used in addition to the default root certificates to verify the peer's certificate. Requires
* `--allow-read`.
*
* @tags allow-read
* @deprecated This will be removed in Deno 2.0. See the
* {@link https://docs.deno.com/runtime/manual/advanced/migrate_deprecations | Deno 1.x to 2.x Migration Guide}
* for migration instructions.
*/
certFile?: string;
/** A list of root certificates that will be used in addition to the
* default root certificates to verify the peer's certificate.
*
Expand Down Expand Up @@ -493,7 +420,7 @@ declare namespace Deno {
* @category Network
*/
export function connectTls(
options: ConnectTlsOptions & TlsCertifiedKeyOptions,
options: ConnectTlsOptions & TlsCertifiedKeyPem,
): Promise<TlsConn>;

/** @category Network */
Expand Down
1 change: 0 additions & 1 deletion ext/net/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ deno_core::extension!(deno_net,

ops_tls::op_tls_key_null,
ops_tls::op_tls_key_static,
ops_tls::op_tls_key_static_from_file<P>,
ops_tls::op_tls_cert_resolver_create,
ops_tls::op_tls_cert_resolver_poll,
ops_tls::op_tls_cert_resolver_resolve,
Expand Down
43 changes: 0 additions & 43 deletions ext/net/ops_tls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ use deno_tls::new_resolver;
use deno_tls::rustls::pki_types::ServerName;
use deno_tls::rustls::ClientConnection;
use deno_tls::rustls::ServerConfig;
use deno_tls::webpki::types::CertificateDer;
use deno_tls::webpki::types::PrivateKeyDer;
use deno_tls::ServerConfigProvider;
use deno_tls::SocketUse;
use deno_tls::TlsKey;
Expand Down Expand Up @@ -213,32 +211,6 @@ pub fn op_tls_key_static(
Ok(TlsKeysHolder::from(TlsKeys::Static(TlsKey(cert, key))))
}

/// Legacy op -- will be removed in Deno 2.0.
#[op2]
#[cppgc]
pub fn op_tls_key_static_from_file<NP>(
state: &mut OpState,
#[string] api: String,
#[string] cert_file: String,
#[string] key_file: String,
) -> Result<TlsKeysHolder, AnyError>
where
NP: NetPermissions + 'static,
{
{
let permissions = state.borrow_mut::<NP>();
permissions.check_read(Path::new(&cert_file), &api)?;
permissions.check_read(Path::new(&key_file), &api)?;
}

let cert = load_certs_from_file(&cert_file)?;
let key = load_private_keys_from_file(&key_file)?
.into_iter()
.next()
.unwrap();
Ok(TlsKeysHolder::from(TlsKeys::Static(TlsKey(cert, key))))
}

#[op2]
pub fn op_tls_cert_resolver_create<'s>(
scope: &mut v8::HandleScope<'s>,
Expand Down Expand Up @@ -455,21 +427,6 @@ where
Ok((rid, IpAddr::from(local_addr), IpAddr::from(remote_addr)))
}

fn load_certs_from_file(
path: &str,
) -> Result<Vec<CertificateDer<'static>>, AnyError> {
let cert_file = File::open(path)?;
let reader = &mut BufReader::new(cert_file);
load_certs(reader)
}

fn load_private_keys_from_file(
path: &str,
) -> Result<Vec<PrivateKeyDer<'static>>, AnyError> {
let key_bytes = std::fs::read(path)?;
load_private_keys(&key_bytes)
}

#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ListenTlsArgs {
Expand Down
Loading