OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 part of dart.io; |
| 6 |
| 7 /** |
| 8 * The object containing the certificates to trust when making |
| 9 * a secure client connection, and the certificate chain and |
| 10 * private key to serve from a secure server. |
| 11 * |
| 12 * The [SecureSocket] and [SecureServer] classes take a SecurityContext |
| 13 * as an argument to their connect and bind methods. |
| 14 * |
| 15 * Certificates and keys can be added to a SecurityContext from either PEM |
| 16 * or PKCS12 containers. |
| 17 * |
| 18 * iOS note: Some methods to add, remove, and inspect certificates are not yet |
| 19 * implemented. However, the platform's built-in trusted certificates can |
| 20 * be used, by way of [SecurityContext.defaultContext]. |
| 21 */ |
| 22 abstract class SecurityContext { |
| 23 external factory SecurityContext(); |
| 24 |
| 25 /** |
| 26 * Secure networking classes with an optional `context` parameter |
| 27 * use the [defaultContext] object if the parameter is omitted. |
| 28 * This object can also be accessed, and modified, directly. |
| 29 * Each isolate has a different [defaultContext] object. |
| 30 * The [defaultContext] object uses a list of well-known trusted |
| 31 * certificate authorities as its trusted roots. On Linux and Windows, this |
| 32 * list is taken from Mozilla, who maintains it as part of Firefox. On, |
| 33 * MacOS, iOS, and Android, this list comes from the trusted certificates |
| 34 * stores built in to the platforms. |
| 35 */ |
| 36 external static SecurityContext get defaultContext; |
| 37 |
| 38 /** |
| 39 * Sets the private key for a server certificate or client certificate. |
| 40 * |
| 41 * A secure connection using this SecurityContext will use this key with |
| 42 * the server or client certificate to sign and decrypt messages. |
| 43 * [file] is the path to a PEM or PKCS12 file containing an encrypted |
| 44 * private key, encrypted with [password]. Assuming it is well-formatted, all |
| 45 * other contents of [file] are ignored. An unencrypted file can be used, |
| 46 * but this is not usual. |
| 47 * |
| 48 * NB: This function calls [ReadFileAsBytesSync], and will block on file IO. |
| 49 * Prefer using [usePrivateKeyBytes]. |
| 50 * |
| 51 * iOS note: Only PKCS12 data is supported. It should contain both the private |
| 52 * key and the certificate chain. On iOS one call to [usePrivateKey] with this |
| 53 * data is used instead of two calls to [useCertificateChain] and |
| 54 * [usePrivateKey]. |
| 55 */ |
| 56 void usePrivateKey(String file, {String password}); |
| 57 |
| 58 /** |
| 59 * Sets the private key for a server certificate or client certificate. |
| 60 * |
| 61 * Like [usePrivateKey], but takes the contents of the file as a list |
| 62 * of bytes. |
| 63 */ |
| 64 void usePrivateKeyBytes(List<int> keyBytes, {String password}); |
| 65 |
| 66 /** |
| 67 * Sets the set of trusted X509 certificates used by [SecureSocket] |
| 68 * client connections, when connecting to a secure server. |
| 69 * |
| 70 * [file] is the path to a PEM or PKCS12 file containing X509 certificates, |
| 71 * usually root certificates from certificate authorities. For PKCS12 files, |
| 72 * [password] is the password for the file. For PEM files, [password] is |
| 73 * ignored. Assuming it is well-formatted, all other contents of [file] are |
| 74 * ignored. |
| 75 * |
| 76 * NB: This function calls [ReadFileAsBytesSync], and will block on file IO. |
| 77 * Prefer using [setTrustedCertificatesBytes]. |
| 78 * |
| 79 * iOS note: On iOS, this call takes only the bytes for a single DER |
| 80 * encoded X509 certificate. It may be called multiple times to add |
| 81 * multiple trusted certificates to the context. A DER encoded certificate |
| 82 * can be obtained from a PEM encoded certificate by using the openssl tool: |
| 83 * |
| 84 * $ openssl x509 -outform der -in cert.pem -out cert.der |
| 85 */ |
| 86 void setTrustedCertificates(String file, {String password}); |
| 87 |
| 88 /** |
| 89 * Sets the set of trusted X509 certificates used by [SecureSocket] |
| 90 * client connections, when connecting to a secure server. |
| 91 * |
| 92 * Like [setTrustedCertificates] but takes the contents of the file. |
| 93 */ |
| 94 void setTrustedCertificatesBytes(List<int> certBytes, {String password}); |
| 95 |
| 96 /** |
| 97 * Sets the chain of X509 certificates served by [SecureServer] |
| 98 * when making secure connections, including the server certificate. |
| 99 * |
| 100 * [file] is a PEM or PKCS12 file containing X509 certificates, starting with |
| 101 * the root authority and intermediate authorities forming the signed |
| 102 * chain to the server certificate, and ending with the server certificate. |
| 103 * The private key for the server certificate is set by [usePrivateKey]. For |
| 104 * PKCS12 files, [password] is the password for the file. For PEM files, |
| 105 * [password] is ignored. Assuming it is well-formatted, all |
| 106 * other contents of [file] are ignored. |
| 107 * |
| 108 * NB: This function calls [ReadFileAsBytesSync], and will block on file IO. |
| 109 * Prefer using [useCertificateChainBytes]. |
| 110 * |
| 111 * iOS note: As noted above, [usePrivateKey] does the job of both |
| 112 * that call and this one. On iOS, this call is a no-op. |
| 113 */ |
| 114 void useCertificateChain(String file, {String password}); |
| 115 |
| 116 /** |
| 117 * Sets the chain of X509 certificates served by [SecureServer] |
| 118 * when making secure connections, including the server certificate. |
| 119 * |
| 120 * Like [useCertificateChain] but takes the contents of the file. |
| 121 */ |
| 122 void useCertificateChainBytes(List<int> chainBytes, {String password}); |
| 123 |
| 124 /** |
| 125 * Sets the list of authority names that a [SecureServer] will advertise |
| 126 * as accepted when requesting a client certificate from a connecting |
| 127 * client. |
| 128 * |
| 129 * [file] is a PEM or PKCS12 file containing the accepted signing |
| 130 * authority certificates - the authority names are extracted from the |
| 131 * certificates. For PKCS12 files, [password] is the password for the file. |
| 132 * For PEM files, [password] is ignored. Assuming it is well-formatted, all |
| 133 * other contents of [file] are ignored. |
| 134 * |
| 135 * NB: This function calls [ReadFileAsBytesSync], and will block on file IO. |
| 136 * Prefer using [setClientAuthoritiesBytes]. |
| 137 * |
| 138 * iOS note: This call is not supported. |
| 139 */ |
| 140 void setClientAuthorities(String file, {String password}); |
| 141 |
| 142 /** |
| 143 * Sets the list of authority names that a [SecureServer] will advertise |
| 144 * as accepted, when requesting a client certificate from a connecting |
| 145 * client. |
| 146 * |
| 147 * Like [setClientAuthority] but takes the contents of the file. |
| 148 */ |
| 149 void setClientAuthoritiesBytes(List<int> authCertBytes, {String password}); |
| 150 |
| 151 /** |
| 152 * Whether the platform supports ALPN. |
| 153 */ |
| 154 external static bool get alpnSupported; |
| 155 |
| 156 /** |
| 157 * Sets the list of application-level protocols supported by a client |
| 158 * connection or server connection. The ALPN (application level protocol |
| 159 * negotiation) extension to TLS allows a client to send a list of |
| 160 * protocols in the TLS client hello message, and the server to pick |
| 161 * one and send the selected one back in its server hello message. |
| 162 * |
| 163 * Separate lists of protocols can be sent for client connections and |
| 164 * for server connections, using the same SecurityContext. The [isServer] |
| 165 * boolean argument specifies whether to set the list for server connections |
| 166 * or client connections. |
| 167 */ |
| 168 void setAlpnProtocols(List<String> protocols, bool isServer); |
| 169 |
| 170 /// Encodes a set of supported protocols for ALPN/NPN usage. |
| 171 /// |
| 172 /// The `protocols` list is expected to contain protocols in descending order |
| 173 /// of preference. |
| 174 /// |
| 175 /// See RFC 7301 (https://tools.ietf.org/html/rfc7301) for the encoding of |
| 176 /// `List<String> protocols`: |
| 177 /// opaque ProtocolName<1..2^8-1>; |
| 178 /// |
| 179 /// struct { |
| 180 /// ProtocolName protocol_name_list<2..2^16-1> |
| 181 /// } ProtocolNameList; |
| 182 /// |
| 183 /// The encoding of the opaque `ProtocolName<lower..upper>` vector is |
| 184 /// described in RFC 2246: 4.3 Vectors. |
| 185 /// |
| 186 /// Note: Even though this encoding scheme would allow a total |
| 187 /// `ProtocolNameList` length of 65535, this limit cannot be reached. Testing |
| 188 /// showed that more than ~ 2^14 bytes will fail to negotiate a protocol. |
| 189 /// We will be conservative and support only messages up to (1<<13)-1 bytes. |
| 190 static Uint8List _protocolsToLengthEncoding(List<String> protocols) { |
| 191 if (protocols == null || protocols.length == 0) { |
| 192 return new Uint8List(0); |
| 193 } |
| 194 int protocolsLength = protocols.length; |
| 195 |
| 196 // Calculate the number of bytes we will need if it is ASCII. |
| 197 int expectedLength = protocolsLength; |
| 198 for (int i = 0; i < protocolsLength; i++) { |
| 199 int length = protocols[i].length; |
| 200 if (length > 0 && length <= 255) { |
| 201 expectedLength += length; |
| 202 } else { |
| 203 throw new ArgumentError( |
| 204 'Length of protocol must be between 1 and 255 (was: $length).'); |
| 205 } |
| 206 } |
| 207 |
| 208 if (expectedLength >= (1 << 13)) { |
| 209 throw new ArgumentError( |
| 210 'The maximum message length supported is 2^13-1.'); |
| 211 } |
| 212 |
| 213 // Try encoding the `List<String> protocols` array using fast ASCII path. |
| 214 var bytes = new Uint8List(expectedLength); |
| 215 int bytesOffset = 0; |
| 216 for (int i = 0; i < protocolsLength; i++) { |
| 217 String proto = protocols[i]; |
| 218 |
| 219 // Add length byte. |
| 220 bytes[bytesOffset++] = proto.length; |
| 221 int bits = 0; |
| 222 |
| 223 // Add protocol bytes. |
| 224 for (int j = 0; j < proto.length; j++) { |
| 225 var char = proto.codeUnitAt(j); |
| 226 bits |= char; |
| 227 bytes[bytesOffset++] = char & 0xff; |
| 228 } |
| 229 |
| 230 // Go slow case if we have encountered anything non-ascii. |
| 231 if (bits > 0x7f) { |
| 232 return _protocolsToLengthEncodingNonAsciiBailout(protocols); |
| 233 } |
| 234 } |
| 235 return bytes; |
| 236 } |
| 237 |
| 238 static Uint8List _protocolsToLengthEncodingNonAsciiBailout( |
| 239 List<String> protocols) { |
| 240 void addProtocol(List<int> outBytes, String protocol) { |
| 241 var protocolBytes = UTF8.encode(protocol); |
| 242 var len = protocolBytes.length; |
| 243 |
| 244 if (len > 255) { |
| 245 throw new ArgumentError( |
| 246 'Length of protocol must be between 1 and 255 (was: $len)'); |
| 247 } |
| 248 // Add length byte. |
| 249 outBytes.add(len); |
| 250 |
| 251 // Add protocol bytes. |
| 252 outBytes.addAll(protocolBytes); |
| 253 } |
| 254 |
| 255 List<int> bytes = []; |
| 256 for (var i = 0; i < protocols.length; i++) { |
| 257 addProtocol(bytes, protocols[i]); |
| 258 } |
| 259 |
| 260 if (bytes.length >= (1 << 13)) { |
| 261 throw new ArgumentError( |
| 262 'The maximum message length supported is 2^13-1.'); |
| 263 } |
| 264 |
| 265 return new Uint8List.fromList(bytes); |
| 266 } |
| 267 } |
OLD | NEW |