📁
SKYSHELL MANAGER
PHP v8.2.30
Create
Create
Path:
root
/
home
/
qooetu
/
costes.qooetu.com
/
Name
Size
Perm
Actions
📁
.well-known
-
0755
🗑️
🏷️
🔒
📁
2e19d9
-
0755
🗑️
🏷️
🔒
📁
6b114
-
0755
🗑️
🏷️
🔒
📁
Modules
-
0755
🗑️
🏷️
🔒
📁
app
-
0755
🗑️
🏷️
🔒
📁
assets
-
0755
🗑️
🏷️
🔒
📁
bootstrap
-
0755
🗑️
🏷️
🔒
📁
cgi-bin
-
0755
🗑️
🏷️
🔒
📁
config
-
0755
🗑️
🏷️
🔒
📁
css
-
0755
🗑️
🏷️
🔒
📁
database
-
0755
🗑️
🏷️
🔒
📁
images
-
0755
🗑️
🏷️
🔒
📁
js
-
0755
🗑️
🏷️
🔒
📁
nbproject
-
0755
🗑️
🏷️
🔒
📁
public
-
0755
🗑️
🏷️
🔒
📁
resources
-
0755
🗑️
🏷️
🔒
📁
routes
-
0755
🗑️
🏷️
🔒
📁
storage
-
0755
🗑️
🏷️
🔒
📁
tests
-
0755
🗑️
🏷️
🔒
📁
uploads
-
0755
🗑️
🏷️
🔒
📁
vendor
-
0755
🗑️
🏷️
🔒
📁
wp-admin
-
0755
🗑️
🏷️
🔒
📁
wp-content
-
0755
🗑️
🏷️
🔒
📁
wp-includes
-
0755
🗑️
🏷️
🔒
📄
.htaccess
0.23 KB
0444
🗑️
🏷️
⬇️
✏️
🔒
📄
COOKIE.txt
0.2 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
X7ROOT.txt
0.27 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
defaults.php
1.29 KB
0444
🗑️
🏷️
⬇️
✏️
🔒
📄
engine.php
0 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
error_log
813.08 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
features.php
11.28 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
googlecfb82e09419fc0f6.html
0.05 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
index.php0
1.56 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
inputs.php
0.12 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
kurd.html
1.07 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
library.php
0 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
min.php
6.83 KB
0444
🗑️
🏷️
⬇️
✏️
🔒
📄
p.php
2.75 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
php.ini
0.04 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
product.php
1.78 KB
0444
🗑️
🏷️
⬇️
✏️
🔒
📄
qpmwztts.php
0.74 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
robots.txt
0.32 KB
0444
🗑️
🏷️
⬇️
✏️
🔒
📄
tovmbkwh.php
0.74 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
tyyffovi.php
0.74 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
📄
veoxv.html
1.23 KB
0644
🗑️
🏷️
⬇️
✏️
🔒
Edit: ssl.js
// Copyright 2024 WebPros International, LLC // All rights reserved. // copyright@cpanel.net http://cpanel.net // This code is subject to the cPanel license. Unauthorized copying is prohibited. // NOTE: This module requires Lapo Luchini's ASN.1 decoder library. // It does NOT wrap calls to that library in try/catch; be sure to // trap errors yourself if you use this module. // // IE <8 will require a JSON compatibility shim. // IE <10 also requires an atob() compatibility shim. /* eslint camelcase: 0 */ (function ssl_js(window) { "use strict"; var atob = window.atob; var ASN1 = window.ASN1; // ------------------------------------------------------------------------- // Constants // ------------------------------------------------------------------------- var ONE_DAY = 1000 * 60 * 60 * 24; var NEARLY_EXPIRED_WINDOW = 30 * ONE_DAY; var toLowerCase = Function.prototype.call.bind(String.prototype.toLowerCase); // TODO: Get these from the backend at build time // rather than hard-coding them here. var DEFAULT_KEY_SIZE = 2048; var ECDSA_CURVES = { "1.2.840.10045.3.1.7": "prime256v1", "1.3.132.0.34": "secp384r1", }; // Accommodates RSA and ECDSA keys. var KEY_TEXT_REGEXP = /^[^-]*(-+\s*BEGIN\s+(?:EC\s+|RSA\s+)?PRIVATE\s+KEY\s*-+[^-]*-+\s*END\s+(?:EC\s+|RSA\s+)?PRIVATE\s+KEY\s*-+)[^-]*$/; var CERTIFICATE_TEXT_REGEXP = /^[^-]*(-+\s*BEGIN\s+CERTIFICATE\s*-+[^-]*-+\s*END\s+CERTIFICATE\s*-+)[^-]*$/; var X509_EXTENSION_OID = { "netscape-cert-type": "2.16.840.1.113730.1", keyUsage: "2.5.29.15", subjectAltName: "2.5.29.17", basicConstraints: "2.5.29.19", }; var OID_NAME = { "1.2.840.113549.1.1.5": "sha1WithRSAEncryption", "1.2.840.113549.1.9.1": "emailAddress", "2.5.4.3": "commonName", "2.5.4.5": "serialNumber", "2.5.4.6": "countryName", "2.5.4.7": "localityName", "2.5.4.8": "stateOrProvinceName", "2.5.4.9": "streetAddress", "2.5.4.10": "organizationName", "2.5.4.11": "organizationalUnitName", // For APNS certificates... May no longer be needed "0.9.2342.19200300.100.1.1": "userId", }; Object.assign( OID_NAME, ECDSA_CURVES ); Object.keys(X509_EXTENSION_OID).forEach( function(name) { OID_NAME[X509_EXTENSION_OID[name]] = name; } ); var rsaEncryption_OID = "1.2.840.113549.1.1.1"; var id_ecPublicKey_OID = "1.2.840.10045.2.1"; // cf. RFC 2459, 4.1.2.5.1 // year, month, mday, hour, minute, second var TIME_REGEXP = /^([0-9]*)([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})Z$/; var X509V3_ORDER = ["version", "serial", null, "issuer", "dates", "subject", "key"]; // Unsure what the first element should be, but it seems always to be 0. var RSA_ORDER = [null, "modulus", "publicExponent", "privateExponent", "prime1", "prime2", "exponent1", "exponent2", "coefficient"]; var keyUsage_order = ["digitalSignature", "contentCommitment", "keyEncipherment", "dataEncipherment", "keyAgreement", "keyCertSign", "cRLSign", "encipherOnly", "decipherOnly"]; /** * Extract the raw content octets from an ASN1 object. * * @method _getContentOctets * @param {ASN1} asn1 The ASN1 object to parse. * @return {array} The octets, as number primitives. */ var _getContentOctets = function(asn1) { return asn1.stream.enc.slice(asn1.posContent(), asn1.posEnd()); }; /** * Extract the raw binary content from an ASN1 object. * * @method _getBinary * @param {ASN1} asn1 The ASN1 object to parse. * @return {string} The binary content, as a byte string. */ var _getBinary = function(asn1) { return String.fromCharCode.apply(String, _getContentOctets(asn1)); }; /** * Extract the raw binary content from an ASN1 object and return hex. * * @method _getHex * @param {ASN1} asn1 The ASN1 object to parse. * @return {string} The binary content, as lower-case hex. */ var _getHex = function(asn1) { var octets = _getContentOctets(asn1); var hex = []; for (var o = octets.length - 1; o >= 0; o--) { var octet = octets[o]; // Ensure that each octet uses two hex digits. hex[o] = (octet < 16 ? "0" : "") + octet.toString(16); } return hex.join("").toLowerCase().replace(/^00/, ""); }; /** * Parse a certificate or CSR subject into an array. * * @method _parseSubject * @param {ASN1} asn1 The ASN1 object to parse. * @return {array} The return list: [ [ key, value ], .. ] */ var _parseSubject = function(asn1) { var attrs = []; var sub = asn1.sub; for (var s = sub.length - 1; s >= 0; s--) { var sequence_sub = sub[s].sub[0].sub; var label = sequence_sub[0].content(); if (label in OID_NAME) { label = OID_NAME[label]; } attrs.unshift([label, sequence_sub[1].content()]); } return attrs; }; /** * Turn a [ [ key, value], .. ] array into a single object. * * @method _unrollKeyValueList * @param {array} theArray The array-of-arrays to unroll. * @return {object} The return object: { key: value, key2: value2, .. } */ var _unrollKeyValueList = function(theArray) { var attrs = {}; var len = theArray.length; for (var l = 0; l < len; l++) { attrs[theArray[l][0]] = theArray[l][1]; } return attrs; }; /** * Do an ASN1.decode() on an octet array, but strip leading 0 first. * This is useful for decoding ASN.1 structures that are embedded * within other ASN.1 structures. * * @method _asn1DecodeOctets * @param {array} theArray The array of octets to decode. * @return {ASN1} The parsed ASN1 object */ var _asn1DecodeOctets = function(octets) { if (octets[0] === 0) { octets.shift(); } return ASN1.decode(octets); }; /** * Extract the base64 from a text string and ASN1-decode it. * * @method _startParse * @param {string} text The text of whatever we are decoding * @return {ASN1} The decoded ASN1 object */ var _startParse = function(text) { var b64 = text.replace(/-[^\n]+-/g, "").replace(/\s+/g, ""); if (b64.length % 4) { throw new Error("Invalid base64: must be a multiple of 4 in length."); } // Node.js's Buffer object would be ideal here, but // browser atob works. var binary = atob(b64); var stream = []; for (var c = binary.length - 1; c >= 0; c--) { stream[c] = binary.charCodeAt(c); } var decode = ASN1.decode(stream); // Before we return the parse, ensure that its length matches what // the ASN.1 scaffolding says it should be. var second_byte = binary.charCodeAt(1); var should_be_length; if (second_byte > 0x80) { var size_octets_length = second_byte - 0x80; var size_octets = binary.substr(2, size_octets_length).split(""); should_be_length = 2 + size_octets_length + size_octets.reduce(function(a, b) { return a * 256 + b.charCodeAt(0); }, 0); } else { should_be_length = 2 + second_byte; } if (should_be_length !== binary.length) { throw new Error("ASN.1 data length mismatch: expected " + should_be_length + ", got " + binary.length); } return decode; }; /** * Figure how many bits a hex string takes up. * * @method _hexBinaryLength * @param {string} hex The hex string * @return {number} The number of bits in the hex string */ var _hexBinaryLength = function(hex) { hex = hex.replace(/^0+/, ""); return 4 * (hex.length - 1) + parseInt(hex.charAt(0), 16).toString(2).length; }; /** * Extract the RSA key components from an ASN1 object. * * @method _parseRSA * @param {ASN1} asn1 The ASN1 representation of the key. * @return {object} The key components. */ var _parseRSA = function(asn) { var parsed = {}; for (var i = RSA_ORDER.length - 1; i >= 0; i--) { var part = RSA_ORDER[i]; if (part) { parsed[part] = _getHex(asn.sub[i]); } } parsed.keyAlgorithm = "rsaEncryption"; // Convenience parsed.modulusLength = _hexBinaryLength(parsed.modulus); return parsed; }; function _parseECDSAPublic(asn) { // Normalize to compressed since we might receive a compressed or // uncompressed key, and it’s MUCH easier to derive the compressed // form from the uncompressed than vice-versa. (See CPAN’s Crypt::Perl // for an implementation of the “decompression” if you’re curious.) var hex = _compressECDSAPublic( _getHex(asn) ); // Sanity check. if ( !/^0[23]/.test(hex) ) { throw new Error("Unrecognized public point encoding: the leading non-null byte is “_”.".replace(/_/, hex.substr(0, 2))); } return hex; } function _compressECDSAPublic(pubHex) { // Might as well support hybrid keys (06/07), just in case. if ( /^0[467]/.test(pubHex) ) { var x = pubHex.substr(2); if (x.length % 4) { throw ( "Public hex (_) should be even … ?".replace(/_/, pubHex) ); } var leading_octet = ( parseInt(pubHex.substr(-1), 16) % 2 ) ? "03" : "02"; return leading_octet + x.substr( 0, x.length / 2 ); } return pubHex; // already compressed … ? } function _getCurveName(curveOID) { if ( OID_NAME[curveOID] ) { return OID_NAME[curveOID]; } throw new Error("Unknown ECDSA curve OID: “_”".replace(/_/, curveOID)); } function _packageECDSAParse(curveName, pubASN1) { return { keyAlgorithm: "id-ecPublicKey", ecdsaCurveName: curveName, ecdsaPublic: _parseECDSAPublic(pubASN1), }; } function _checkECDSAVersion(asn) { var version = asn.sub[0].content(); if ( version !== 1 ) { throw new Error("Unsupported ECDSA version: “_”".replace(/_/, version)); } } /** * Parse an RSA or ECDSA private key (algorithm-specific or PKCS8 format) * * @method parseKeyText * @param {string} text The key as a string * @return {object} A data structure representing the key's data. */ var _cachedKeyParses = {}; function parseKeyText(text) { if (!(text in _cachedKeyParses)) { if (!KEY_TEXT_REGEXP.test(text)) { throw new Error("The key text was not valid."); } var decoded = _startParse(text); var curveOID, curveName, pubPart; // RSA's special key file format, e.g., "openssl genrsa" if (/BEGIN RSA/.test(text)) { _cachedKeyParses[text] = _parseRSA(decoded); } else if (/BEGIN EC /.test(text)) { _checkECDSAVersion(decoded); curveOID = decoded.sub[2].sub[0].content(); curveName = _getCurveName(curveOID); pubPart = decoded.sub[3].sub[0]; _cachedKeyParses[text] = _packageECDSAParse( curveName, pubPart ); } else { // Generic PKCS8 key file format // e.g., "openssl genpkey" var format = decoded.sub[1].sub[0].content(); if (format === rsaEncryption_OID) { var subRSA = _asn1DecodeOctets(_getContentOctets(decoded.sub[2])); _cachedKeyParses[text] = _parseRSA(subRSA); } else if (format === id_ecPublicKey_OID) { // PKCS8 for ECDSA puts the curve name in the PKCS8 // part, not with the rest of the key. So we can’t just // parse the “meat” of the PKCS8 encoding as we could // above with _parseRSA(). curveOID = decoded.sub[1].sub[1].content(); curveName = _getCurveName(curveOID); var subECDSA = _asn1DecodeOctets(_getContentOctets(decoded.sub[2])); _checkECDSAVersion(subECDSA); pubPart = subECDSA.sub[2].sub[0]; return _packageECDSAParse( curveName, pubPart ); } else { _throwUnknownKeyOID(format); } } } return JSON.parse(JSON.stringify(_cachedKeyParses[text])); } function _throwUnknownKeyOID(format) { throw new Error("Unknown key algorithm OID: “_”".replace(/_/, format)); } /** * Parse an SSL certificate's time as described in RFC 2459, 4.1.2.5.1 * * @method parseTime * @param {string} text The string, either in UTCTime or GeneralizedTime. * @return {date} A JavaScript Date object. */ function parseTime(text) { var match = TIME_REGEXP.exec(text); if (!match) { return; } if (match[1].length === 2) { // cf. RFC 2459, 4.1.2.5.1 match[1] = ((match[1] <= 50) ? "20" : "19") + match[1]; } var date = new Date(Date.UTC( match[1], Number(match[2]) - 1, match[3], match[4], match[5], match[6] )); return date; } function _parseSubjectKey(keyASN1) { var algOID = keyASN1.sub[0].sub[0].content(); if ( algOID === rsaEncryption_OID ) { var modulusSubStructureOctets = _getContentOctets(keyASN1.sub[1]); var modulus = _getHex(_asn1DecodeOctets(modulusSubStructureOctets).sub[0]); return { keyAlgorithm: "rsaEncryption", modulus: modulus, modulusLength: _hexBinaryLength(modulus), // convenience }; } else if ( algOID === id_ecPublicKey_OID ) { var curveOID = keyASN1.sub[0].sub[1].content(); var curveName = _getCurveName(curveOID); var pubPart = keyASN1.sub[1]; return { keyAlgorithm: "id-ecPublicKey", ecdsaCurveName: curveName, ecdsaPublic: _compressECDSAPublic( _getHex(pubPart) ), }; } _throwUnknownKeyOID(algOID); } var ecdsaCurveNickname = { prime256v1: "P-256", secp384r1: "P-384", }; function _ecdsaCurveDisplayName(curveName) { return ecdsaCurveNickname[curveName] + "/" + curveName; } // Contents are as returned by parseCertificateText(). // // This class is more or less “designed” for its internal properties // to be accessed directly because parseCertificateText() historically // returned a plain object, and we want compatibility with that. // function CertificateParse(source) { Object.assign(this, source); } Object.assign( CertificateParse.prototype, { dispatchForKeyAlgorithm: function dispatchForKeyAlgorithm(onRsa, onEcdsa) { switch (this.keyAlgorithm) { case "rsaEncryption": return onRsa.bind(this)(); case "id-ecPublicKey": return onEcdsa.bind(this)(); } throw ("Bad key algorithm: " + this.keyAlgorithm); }, getKeyType: function getKeyType() { return this.dispatchForKeyAlgorithm( function() { return "rsa-" + this.modulusLength; }, function() { return "ecdsa-" + this.ecdsaCurveName; } ); }, getKeyTypeLabel: function getKeyLabel() { return this.dispatchForKeyAlgorithm( function() { return "RSA, " + LOCALE.maketext("[numf,_1]-bit", this.modulusLength); }, function() { return "ECDSA, " + _ecdsaCurveDisplayName(this.ecdsaCurveName); } ); }, } ); /** * Parse an x509 SSL certificate * * @method parseCertificateText * @param {string} text The SSL certificate as a string * @return {CertificateParse} A data structure representing the SSL certificate's data. */ var _cachedCertificateParses = {}; function parseCertificateText(text) { if (!(text in _cachedCertificateParses)) { if (!CERTIFICATE_TEXT_REGEXP.test(text)) { throw new Error("The certificate text was not valid."); } var decoded = _startParse(text).sub[0]; var order = X509V3_ORDER.slice(0); var version; try { version = _getContentOctets(decoded.sub[0].sub[0])[0]; } catch (e) { version = 0; order.shift(); } var parsed_extensions; var componentIndex = {}; for (var o = order.length; o >= 0; o--) { componentIndex[order[o]] = o; } var keyASN1 = decoded.sub[componentIndex.key]; var subjectKeyParse = _parseSubjectKey(keyASN1); var subjectList = _parseSubject(decoded.sub[componentIndex.subject]); var issuerList = _parseSubject(decoded.sub[componentIndex.issuer]); var extensions = (version > 0) ? decoded.sub[decoded.sub.length - 1] : undefined; extensions = extensions && extensions.sub[0]; if (extensions) { var extensions_count = extensions.sub.length; parsed_extensions = {}; EXTENSION: for (var e = 0; e < extensions_count; e++) { var curExt = extensions.sub[e]; var oid = curExt.sub && curExt.sub[0] && curExt.sub[0].content(); var name = oid && OID_NAME[oid]; // Ignore extensions that we don't know about. if (!name) { continue EXTENSION; } var payload_node = curExt.sub.slice(-1)[0]; var ext_value = _asn1DecodeOctets(_getContentOctets(payload_node)); switch (name) { case "subjectAltName": var san_values = []; // Some SAN values are objects. There seems to be no value // for us to parse these since CAs always seem to duplicate // the object SAN values as plain values. for (var s = 0; s < ext_value.sub.length; s++) { var value = ext_value.sub[s]; if (value.sub) { try { san_values.push({ oid: value.sub[0].content(), value: _getBinary(value.sub[1].sub[0]), }); } catch (err) { if (window.console && console.warn) { console.warn("Unparsable subjectAltName entry in certificate: "); console.warn(value, err); } } } else { san_values.push(_getBinary(ext_value.sub[s])); } } ext_value = san_values; break; // because we don't check for any other extensions case "basicConstraints": ext_value = { cA: ext_value.sub[0] && (_getBinary(ext_value.sub[0]) !== "0"), pathLenConstraint: ext_value.sub[1] && ext_value.sub[1].content(), }; break; case "keyUsage": var ones_zeros = ext_value.content().match(/[01]+$/)[0]; ext_value = {}; for (var b = 0; b < ones_zeros.length; b++) { if (ones_zeros.charAt(ones_zeros.length - 1 - b) === "1") { ext_value[keyUsage_order[b]] = true; } } break; // TODO: Is this needed? case "netscape-cert-type": continue EXTENSION; } var is_critical = false; if (curExt.sub.length > 2) { var critical_node = curExt.sub[1]; is_critical = (critical_node.tag === 1) && (critical_node.content() === "true"); } parsed_extensions[name] = { critical: is_critical, value: ext_value, }; } } var subject = _unrollKeyValueList(subjectList); var subjectAltName = parsed_extensions && parsed_extensions.subjectAltName && parsed_extensions.subjectAltName.value || []; // per RFC 2818, subject.commonName is deprecated; as a result, // some CAs are issuing single-domain certs with the domain in // both the subject commonName and subjectAltName. var domains; if (subject.commonName && subjectAltName.indexOf(subject.commonName) === -1) { domains = [subject.commonName].concat(subjectAltName); } else { domains = subjectAltName.slice(0); } domains = domains.filter( function(d) { return typeof d !== "object"; } ); // Add to this return object as needed. var the_parse = { // Certs store version as 0-indexed, but publicly they're 1-indexed. version: 1 + version, notBefore: _getBinary(decoded.sub[componentIndex.dates].sub[0]), notAfter: _getBinary(decoded.sub[componentIndex.dates].sub[1]), issuer: _unrollKeyValueList(issuerList), subject: subject, subjectList: subjectList, issuerList: issuerList, extensions: parsed_extensions, // Convenience domains: domains, isSelfSigned: (_getBinary(decoded.sub[componentIndex.subject]) === _getBinary(decoded.sub[componentIndex.issuer])), }; Object.assign( the_parse, subjectKeyParse ); the_parse = new CertificateParse(the_parse); _cachedCertificateParses[text] = the_parse; } var clone = JSON.parse(JSON.stringify(_cachedCertificateParses[text])); clone.notBefore = parseTime(clone.notBefore); clone.notAfter = parseTime(clone.notAfter); return new CertificateParse(clone); } /** * Returns an ordered list of certificate parses, with the leaf node first, * as is consistent with the TLS protocol. * * To facilitate reassembly of the CA bundle, each certificate parse has a "text" * property added. * * No caching here because the certificate parses are already cached. * * @method parseCABundleText * @param {string} text The CA bundle text. * @return {array} An ordered list of parsed certificates, each with a "text" property added. */ function parseCABundleText(text) { var certs = text.match(/(-+BEGIN[^\n]+-+\s+[a-zA-Z0-9\/+=\s]+\s+-+END[^\n]+-+)/g); if (!certs || !certs.length) { return; } var parses = certs.map(function(c) { var parsed = parseCertificateText(c); parsed.text = c; return parsed; }); var cab_chain = []; if (certs.length === 1) { cab_chain.push(parses[0]); } else { var subjectLookup = {}; var issuers = []; var chain = {}; var cur, subject, issuer; while (parses.length) { cur = parses.shift(); subject = JSON.stringify(cur.subjectList); issuer = JSON.stringify(cur.issuerList); subjectLookup[subject] = cur; issuers.push(issuer); if (subject !== issuer) { chain[subject] = cur; } } // Delete every cert from "chain" that was issued by something else // in the bundle. The remaining node will be the leaf node. while (issuers.length) { delete chain[issuers.shift()]; } var chainKeys = Object.keys(chain); if (chainKeys.length !== 1) { throw new Error("The certificates do not form a chain."); } var leafSubject = chainKeys[0]; cur = subjectLookup[leafSubject]; while (cur) { subject = JSON.stringify(cur.subjectList); issuer = JSON.stringify(cur.issuerList); cab_chain.push(cur); if (subject === issuer) { break; } cur = subjectLookup[issuer]; } } // The root cert in a CA bundle SHOULD have both flags, but just in // case there are "weird" situations out there, allow either/or. var root_exts_ok; try { root_exts_ok = cab_chain[0].extensions.keyUsage.value.keyCertSign; root_exts_ok = root_exts_ok || cab_chain[0].extensions.basicConstraints.value.cA; } catch (e) {} if (!_check_ca(cab_chain[0])) { throw new Error("Root node is not a CA cert."); } return cab_chain; } // cf. openssl/crypto/x509v3/v3_purp.c // NOTE: Ensure parity between this and Cpanel::SSL::Objects::Certificate. function _check_ca(cert) { var exts = cert.extensions; if (exts) { if (exts.basicConstraints) { return exts.basicConstraints.value.cA ? 1 : 0; } else if (exts.keyUsage) { return exts.keyUsage.value.keyCertSign ? 4 : 0; } } else if (cert.isSelfSigned && (cert.version === 1)) { return 3; } return 0; } /** * Determine if an x509 SSL certificate will support the given domain. * * @method validateCertificateForDomain * @param {string} text The SSL certificate as a string * @param {string} domain The domain to match against the given certificate. * @return {boolean} A boolean value indicating if the certificate supports the given domain. */ function validateCertificateForDomain(text, domain) { var parsed = parseCertificateText(text); return doesDomainMatchOneOf(domain, parsed.domains); } /** * Lower-case only the 7-bit ASCII portions of a string. * * @method _to_dns_lower_case * @param {string} domain The domain to lower-case per DNS. * @return {string} The ASCII-lower-cased string */ function _ascii_lower_case(domain) { return domain.replace( /([A-Z]+)/g, toLowerCase ); } /** * Determine if a domain or wildcard domain matches an item in a list of domains. * * @method doesDomainMatchOneOf * @param {string} domain The domain/wildcard to match against the given list of domains. * @param {array} domains The list against which to match the given domain. * @return {boolean} A boolean value indicating if the domain matches an item in the list of domains. */ function doesDomainMatchOneOf(domain, domains) { if (domains === null || domain === null) { return false; } // This only does ASCII because that’s the most common use case. // TODO: Implement case-folding to match how DNS does it. // (.toLowerCase() may be all we need...?) domain = _ascii_lower_case(domain); domains = domains.map(_ascii_lower_case); var domains_count = domains.length; for (var i = 0; i < domains_count; i++) { if (!domains[i]) { continue; } if (domains[i] === domain) { return true; } else { var domain_1 = domains[i]; var domain_2 = domain; var possible_wildcard; var domain_to_match; if (/^\*/.test(domain_1)) { possible_wildcard = domain_1; domain_to_match = domain_2; } else if (/^\*/.test(domain_2)) { possible_wildcard = domain_2; domain_to_match = domain_1; } else { continue; } possible_wildcard = possible_wildcard.replace(/^\*\./, ""); domain_to_match = domain_to_match.replace(/^[^\.]+\./, ""); if (possible_wildcard === domain_to_match) { return true; } } } return false; } // This duplicates logic from Cpanel::Crypt::ECDSA::Data. function ecdsaEquivalentRSAModulusLength(curveName) { switch (curveName) { case "prime256v1": return 2529; case "secp384r1": return 6692; default: throw ( "Bad curve name: " + curveName ); } } var ssl = { DEFAULT_KEY_SIZE: DEFAULT_KEY_SIZE, NEARLY_EXPIRED_WINDOW: NEARLY_EXPIRED_WINDOW, parseTime: parseTime, parseKeyText: parseKeyText, parseCertificateText: parseCertificateText, parseCABundleText: parseCABundleText, validateCertificateForDomain: validateCertificateForDomain, doesDomainMatchOneOf: doesDomainMatchOneOf, ecdsaEquivalentRSAModulusLength: ecdsaEquivalentRSAModulusLength, }; if (typeof window.CPANEL !== "undefined") { window.CPANEL.namespace("CPANEL.ssl"); window.YAHOO.lang.augmentObject(window.CPANEL.ssl, ssl); } return ssl; })(window);
Save