blob: 28351b26741cc88c7fc92fd4e17a2ee4d8106076 [file] [log] [blame]
// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
part of dart.io;
/**
* The object containing the certificates to trust when making
* a secure client connection, and the certificate chain and
* private key to serve from a secure server.
*
* The [SecureSocket] and [SecureServer] classes take a SecurityContext
* as an argument to their connect and bind methods.
*
* Certificates and keys can be added to a SecurityContext from PEM files
* on the disk. A PEM file contains one or more base-64 encoded DER-serialized
* ASN1 objects, surrounded with delimiter strings like
* "-----BEGIN CERTIFICATE -----" and "-----END CERTIFICATE-----".
* Distinguished encoding rules (DER) is a canonical binary serialization
* of ASN1 objects into an octet string.
*
* [usePrivateKey], [setTrustedCertificates], [useCertificateChain], and
* [setClientAuthorities] are deprecated. They have been renamed
* [usePrivateKeySync], [setTrustedCertificatesSync], [useCertificateChainSync],
* and [setClientAuthoritiesSync] to reflect the fact that they do blocking
* IO. Async-friendly versions have been added in [usePrivateKeyBytes],
* [setTrustedCertificatesBytes], [useCertificateChainBytes], and
* [setClientAuthoritiesBytes].
*/
abstract class SecurityContext {
external factory SecurityContext();
/**
* Secure networking classes with an optional `context` parameter
* use the [defaultContext] object if the parameter is omitted.
* This object can also be accessed, and modified, directly.
* Each isolate has a different [defaultContext] object.
* The [defaultContext] object uses a list of well-known trusted
* certificate authorities as its trusted roots. This list is
* taken from Mozilla, who maintains it as part of Firefox.
*/
external static SecurityContext get defaultContext;
/**
* Sets the private key for a server certificate or client certificate.
*
* A secure connection using this SecurityContext will use this key with
* the server or client certificate to sign and decrypt messages.
* [keyFile] is a PEM file containing an encrypted
* private key, encrypted with [password]. An unencrypted file can be
* used, but this is not usual.
*/
void usePrivateKeySync(String keyFile, {String password});
/**
* [usePrivateKey] is deprecated. Use [usePrivateKeySync] or
* [usePrivateKeyBytes].
*/
@deprecated
void usePrivateKey(String keyFile, {String password});
/**
* Sets the private key for a server certificate or client certificate.
*
* A secure connection using this SecurityContext will use this key with
* the server or client certificate to sign and decrypt messages.
* [keyBytes] is the contents of a PEM file containing an encrypted
* private key, encrypted with [password]. An unencrypted file can be
* used, but this is not usual.
*/
void usePrivateKeyBytes(List<int> keyBytes, {String password});
/**
* Sets the set of trusted X509 certificates used by [SecureSocket]
* client connections, when connecting to a secure server.
*
* [file] is the path to a PEM file containing X509 certificates, usually
* root certificates from certificate authorities.
*/
void setTrustedCertificatesSync(String file);
/**
* [setTrustedCertificates] is deprecated. Use [setTrustedCertificatesSync]
* or [setTrustedCertificatesBytes].
*/
@deprecated
void setTrustedCertificates(String file);
/**
* Sets the set of trusted X509 certificates used by [SecureSocket]
* client connections, when connecting to a secure server.
*
* [file] is the contents of a PEM file containing X509 certificates, usually
* root certificates from certificate authorities.
*/
void setTrustedCertificatesBytes(List<int> certBytes);
/**
* Sets the chain of X509 certificates served by [SecureServer]
* when making secure connections, including the server certificate.
*
* [file] is a PEM file containing X509 certificates, starting with
* the root authority and intermediate authorities forming the signed
* chain to the server certificate, and ending with the server certificate.
* The private key for the server certificate is set by [usePrivateKey].
*/
void useCertificateChainSync(String file);
/**
* [useCertificateChain] is deprecated. Use [useCertificateChainSync]
* or [useCertificateChainBytes].
*/
@deprecated
void useCertificateChain({String file, String directory});
/**
* Sets the chain of X509 certificates served by [SecureServer]
* when making secure connections, including the server certificate.
*
* [chainBytes] is the contents of a PEM file containing X509 certificates,
* starting with the root authority and intermediate authorities forming the
* signed chain to the server certificate, and ending with the server
* certificate. The private key for the server certificate is set by
* [usePrivateKey].
*/
void useCertificateChainBytes(List<int> chainBytes);
/**
* Sets the list of authority names that a [SecureServer] will advertise
* as accepted, when requesting a client certificate from a connecting
* client. [file] is a PEM file containing the accepted signing authority
* certificates - the authority names are extracted from the certificates.
*/
void setClientAuthoritiesSync(String file);
/**
* [setClientAuthorities] is deprecated. Use [setClientAuthoritiesSync]
* or [setClientAuthoritiesBytes].
*/
@deprecated
void setClientAuthorities(String file);
/**
* Sets the list of authority names that a [SecureServer] will advertise
* as accepted, when requesting a client certificate from a connecting
* client. [authCertBytes] is the contents of a PEM file containing the
* accepted signing authority certificates - the authority names are extracted
* from the certificates.
*/
void setClientAuthoritiesBytes(List<int> authCertBytes);
/**
* Sets the list of application-level protocols supported by a client
* connection or server connection. The ALPN (application level protocol
* negotiation) extension to TLS allows a client to send a list of
* protocols in the TLS client hello message, and the server to pick
* one and send the selected one back in its server hello message.
*
* Separate lists of protocols can be sent for client connections and
* for server connections, using the same SecurityContext. The [isServer]
* boolean argument specifies whether to set the list for server connections
* or client connections.
*/
void setAlpnProtocols(List<String> protocols, bool isServer);
/// Encodes a set of supported protocols for ALPN/NPN usage.
///
/// The `protocols` list is expected to contain protocols in descending order
/// of preference.
///
/// See RFC 7301 (https://tools.ietf.org/html/rfc7301) for the encoding of
/// `List<String> protocols`:
/// opaque ProtocolName<1..2^8-1>;
///
/// struct {
/// ProtocolName protocol_name_list<2..2^16-1>
/// } ProtocolNameList;
///
/// The encoding of the opaque `ProtocolName<lower..upper>` vector is
/// described in RFC 2246: 4.3 Vectors.
///
/// Note: Even though this encoding scheme would allow a total
/// `ProtocolNameList` length of 65535, this limit cannot be reached. Testing
/// showed that more than ~ 2^14 bytes will fail to negotiate a protocol.
/// We will be conservative and support only messages up to (1<<13)-1 bytes.
static Uint8List _protocolsToLengthEncoding(List<String> protocols) {
if (protocols == null || protocols.length == 0) {
return new Uint8List(0);
}
int protocolsLength = protocols.length;
// Calculate the number of bytes we will need if it is ASCII.
int expectedLength = protocolsLength;
for (int i = 0; i < protocolsLength; i++) {
int length = protocols[i].length;
if (length > 0 && length <= 255) {
expectedLength += length;
} else {
throw new ArgumentError(
'Length of protocol must be between 1 and 255 (was: $length).');
}
}
if (expectedLength >= (1 << 13)) {
throw new ArgumentError(
'The maximum message length supported is 2^13-1.');
}
// Try encoding the `List<String> protocols` array using fast ASCII path.
var bytes = new Uint8List(expectedLength);
int bytesOffset = 0;
for (int i = 0; i < protocolsLength; i++) {
String proto = protocols[i];
// Add length byte.
bytes[bytesOffset++] = proto.length;
int bits = 0;
// Add protocol bytes.
for (int j = 0; j < proto.length; j++) {
var char = proto.codeUnitAt(j);
bits |= char;
bytes[bytesOffset++] = char & 0xff;
}
// Go slow case if we have encountered anything non-ascii.
if (bits > 0x7f) {
return _protocolsToLengthEncodingNonAsciiBailout(protocols);
}
}
return bytes;
}
static Uint8List _protocolsToLengthEncodingNonAsciiBailout(
List<String> protocols) {
void addProtocol(List<int> outBytes, String protocol) {
var protocolBytes = UTF8.encode(protocol);
var len = protocolBytes.length;
if (len > 255) {
throw new ArgumentError(
'Length of protocol must be between 1 and 255 (was: $len)');
}
// Add length byte.
outBytes.add(len);
// Add protocol bytes.
outBytes.addAll(protocolBytes);
}
List<int> bytes = [];
for (var i = 0; i < protocols.length; i++) {
addProtocol(bytes, protocols[i]);
}
if (bytes.length >= (1 << 13)) {
throw new ArgumentError(
'The maximum message length supported is 2^13-1.');
}
return new Uint8List.fromList(bytes);
}
}