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 |