1 // Copyright Joyent, Inc. and other Node contributors.
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
22 var net = require('net');
23 var url = require('url');
24 var util = require('util');
26 // Allow {CLIENT_RENEG_LIMIT} client-initiated session renegotiations
27 // every {CLIENT_RENEG_WINDOW} seconds. An error event is emitted if more
28 // renegotations are seen. The settings are applied to all remote client
30 exports.CLIENT_RENEG_LIMIT = 3;
31 exports.CLIENT_RENEG_WINDOW = 600;
33 exports.SLAB_BUFFER_SIZE = 10 * 1024 * 1024;
35 exports.DEFAULT_CIPHERS =
37 'ECDHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA256:AES128-GCM-SHA256:' +
39 'RC4:HIGH:!MD5:!aNULL';
41 exports.DEFAULT_ECDH_CURVE = 'prime256v1';
43 exports.getCiphers = function() {
44 var names = process.binding('crypto').getSSLCiphers();
45 // Drop all-caps names in favor of their lowercase aliases,
47 names.forEach(function(name) {
48 if (/^[0-9A-Z\-]+$/.test(name)) name = name.toLowerCase();
51 return Object.getOwnPropertyNames(ctx).sort();
54 // Convert protocols array into valid OpenSSL protocols list
55 // ("\x06spdy/2\x08http/1.1\x08http/1.0")
56 exports.convertNPNProtocols = function convertNPNProtocols(NPNProtocols, out) {
57 // If NPNProtocols is Array - translate it into buffer
58 if (util.isArray(NPNProtocols)) {
59 var buff = new Buffer(NPNProtocols.reduce(function(p, c) {
60 return p + 1 + Buffer.byteLength(c);
63 NPNProtocols.reduce(function(offset, c) {
64 var clen = Buffer.byteLength(c);
66 buff.write(c, offset + 1);
68 return offset + 1 + clen;
74 // If it's already a Buffer - store it
75 if (util.isBuffer(NPNProtocols)) {
76 out.NPNProtocols = NPNProtocols;
80 exports.checkServerIdentity = function checkServerIdentity(host, cert) {
81 // Create regexp to much hostnames
82 function regexpify(host, wildcards) {
83 // Add trailing dot (make hostnames uniform)
84 if (!/\.$/.test(host)) host += '.';
86 // The same applies to hostname with more than one wildcard,
87 // if hostname has wildcard when wildcards are not allowed,
88 // or if there are less than two dots after wildcard (i.e. *.com or *d.com)
92 // "The client SHOULD NOT attempt to match a presented identifier in
93 // which the wildcard character comprises a label other than the
94 // left-most label (e.g., do not match bar.*.example.net)."
96 if (!wildcards && /\*/.test(host) || /[\.\*].*\*/.test(host) ||
97 /\*/.test(host) && !/\*.*\..+\..+/.test(host)) {
101 // Replace wildcard chars with regexp's wildcard and
102 // escape all characters that have special meaning in regexps
103 // (i.e. '.', '[', '{', '*', and others)
104 var re = host.replace(
105 /\*([a-z0-9\\-_\.])|[\.,\-\\\^\$+?*\[\]\(\):!\|{}]/g,
107 if (sub) return '[a-z0-9\\-_]*' + (sub === '-' ? '\\-' : sub);
111 return new RegExp('^' + re + '$', 'i');
119 reason = 'Unknown reason';
121 // There're several names to perform check against:
122 // CN and altnames in certificate extension
123 // (DNS names, IP addresses, and URIs)
125 // Walk through altnames and generate lists of those names
126 if (cert.subjectaltname) {
127 cert.subjectaltname.split(/, /g).forEach(function(altname) {
128 var option = altname.match(/^(DNS|IP Address|URI):(.*)$/);
131 if (option[1] === 'DNS') {
132 dnsNames.push(option[2]);
133 } else if (option[1] === 'IP Address') {
135 } else if (option[1] === 'URI') {
136 var uri = url.parse(option[2]);
137 if (uri) uriNames.push(uri.hostname);
142 // If hostname is an IP address, it should be present in the list of IP
144 if (net.isIP(host)) {
145 valid = ips.some(function(ip) {
149 reason = util.format('IP: %s is not in the cert\'s list: %s',
154 // Transform hostname to canonical form
155 if (!/\.$/.test(host)) host += '.';
157 // Otherwise check all DNS/URI records from certificate
158 // (with allowed wildcards)
159 dnsNames = dnsNames.map(function(name) {
160 return regexpify(name, true);
163 // Wildcards ain't allowed in URI names
164 uriNames = uriNames.map(function(name) {
165 return regexpify(name, false);
168 dnsNames = dnsNames.concat(uriNames);
170 if (dnsNames.length > 0) matchCN = false;
172 // Match against Common Name (CN) only if no supported identifiers are
175 // "As noted, a client MUST NOT seek a match for a reference identifier
176 // of CN-ID if the presented identifiers include a DNS-ID, SRV-ID,
177 // URI-ID, or any application-specific identifier types supported by the
181 var commonNames = cert.subject.CN;
182 if (util.isArray(commonNames)) {
183 for (var i = 0, k = commonNames.length; i < k; ++i) {
184 dnsNames.push(regexpify(commonNames[i], true));
187 dnsNames.push(regexpify(commonNames, true));
191 valid = dnsNames.some(function(re) {
192 return re.test(host);
196 if (cert.subjectaltname) {
197 reason = util.format('Host: %s is not in the cert\'s altnames: %s',
199 cert.subjectaltname);
201 reason = util.format('Host: %s is not cert\'s CN: %s',
210 util.format('Hostname/IP doesn\'t match certificate\'s altnames: %j',
220 // C=US\nST=CA\nL=SF\nO=Joyent\nOU=Node.js\nCN=ca1\nemailAddress=ry@clouds.org
221 exports.parseCertString = function parseCertString(s) {
223 var parts = s.split('\n');
224 for (var i = 0, len = parts.length; i < len; i++) {
225 var sepIndex = parts[i].indexOf('=');
227 var key = parts[i].slice(0, sepIndex);
228 var value = parts[i].slice(sepIndex + 1);
230 if (!util.isArray(out[key])) {
231 out[key] = [out[key]];
233 out[key].push(value);
243 exports.createSecureContext = require('_tls_common').createSecureContext;
244 exports.SecureContext = require('_tls_common').SecureContext;
245 exports.TLSSocket = require('_tls_wrap').TLSSocket;
246 exports.Server = require('_tls_wrap').Server;
247 exports.createServer = require('_tls_wrap').createServer;
248 exports.connect = require('_tls_wrap').connect;
251 exports.__defineGetter__('createSecurePair', util.deprecate(function() {
252 return require('_tls_legacy').createSecurePair;
253 }, 'createSecurePair() is deprecated, use TLSSocket instead'));