我需要检查本地计算机的SSl证书到期日期并将其与当前日期进行比较,并通知用户他/她的证书将在X天内到期。我需要用JavaScript做这一切。
答案 0 :(得分:1)
您的证书应如下所示:
-----BEGIN CERTIFICATE-----
MIIGoDCCBIigAwIBAgIJAICRY3cWdgK1MA0GCSqGSIb3DQEBCwUAMIGeMQswCQYD
VQQGEwJCRzERMA8GA1UECAwIQnVsZ2FyaWExDjAMBgNVBAcMBVNvZmlhMQ8wDQYD
..
ud5Nja8+xycA/Jk7bSvB1jJjpc3oL0G9j0HOcxqQKd4e1IQXuss5V7FnQxSOVCq4
GVK0r3LkAxtl/EGmQC1DRlHAUWg=
-----END CERTIFICATE-----
您需要从证书数据中删除-----BEGIN CERTIFICATE-----
标头和-----END CERTIFICATE-----
尾部,其余为Base64编码的字节数组。
您需要将其解码为字节数组(在本示例中,该数组表示为数字数组,其中每个数字表示一个字节-介于0和255之间的数字)。
该字节数组是DER中定义的ASN.1编码的RFC-5280结构。
下面的示例将在-----BEGIN CERTIFICATE-----
和-----END CERTIFICATE-----
尾迹被剥离之后解析证书的内容。
用法:
var pem =
"MIIGijCCBXKgAwIBAgIQEpI/gkvDS6idH2m2Zwn7ZzANBgkqhkiG9w0BAQsFADCB\n"
...
+"VQ+o34uWo7z19I8eXWSXN6P+Uj1OvHn8zNM1G/ddjQXBwMvzwwJEdVBhdK1uQw==\n";
var bytes = fromBase64(pem);
var validity = getValidity(bytes);
var notBefore = validity.notBefore;
var notAfter = validity.notAfter;
var now = new Date();
if ( notBefore.getTime() < now.getTime()
&& now.getTime() < notAfter.getTime())
{
// Certificate is withing its validity days
} else {
// Certificate is either not yet valid or has already expired.
}
解析:
var TYPE_INTEGER = 0x02;
var TYPE_SEQUENCE = 0x10;
var TYPE_UTC_TIME = 0x17;
var TYPE_GENERALIZED_TIME = 0x18;
function subArray(original, start, end) {
var subArr = [];
var index = 0;
for (var i = start; i < end; i++) {
subArr[index++] = original[i];
}
return subArr;
}
function getDigit(d) {
switch (d) {
default:
case 0x30: case '0': return 0;
case 0x31: case '1': return 1;
case 0x32: case '2': return 2;
case 0x33: case '3': return 3;
case 0x34: case '4': return 4;
case 0x35: case '5': return 5;
case 0x36: case '6': return 6;
case 0x37: case '7': return 7;
case 0x38: case '8': return 8;
case 0x39: case '9': return 9;
}
}
function enterTag(bytes, start, requiredTypes, name) {
if (start + 1 > bytes.length) {
throw new Error("Too short certificate input");
}
var typeByte = bytes[start ] & 0x0FF;
var lenByte = bytes[start +1] & 0x0FF;
var type = typeByte & 0x1F;
var len = lenByte;
var index = start + 2;
if (requiredTypes.length > 0 && requiredTypes.indexOf(type) == -1) {
throw new Error("Invalid type");
}
var lengthOfLength = 0;
if (len > 0x07F) {
lengthOfLength = len & 0x7F;
len = 0;
for (var i =0; i < lengthOfLength && index < bytes.length; i++) {
len = (len << 8 ) | (bytes[index] & 0x00FF);
index++;
}
}
if (index >= bytes.length) {
throw new Error("Too short certificate input");
}
return {index: index, type: type, length: len}
}
function processTag(bytes, start, requiredTypes, name) {
var result = enterTag(bytes, start, requiredTypes, name);
var index = result.index + result.length;
if (index >= bytes.length) {
throw new Error("Too short certificate input");
}
var valueStart = result.index;
var valueEnd = result.index + result.length;
var value = subArray(bytes, valueStart, valueEnd);
return { index: index, type: result.type, value: value};
}
function readDate(bytes, start, name) {
var date = new Date();
var result = processTag(bytes, start,
[TYPE_UTC_TIME, TYPE_GENERALIZED_TIME], name);
var index, year;
if (result.type == 0x17) { // UTCTime
if (result.value.length < 12) {
throw new Error("Invalid type");
}
var yearHigh = getDigit(result.value[0]);
var yearLow = getDigit(result.value[1]);
var year2Digits = (yearHigh * 10 ) + (yearLow)
if (year2Digits >= 50) {
year = 1900 + year2Digits;
} else {
year = 2000 + year2Digits;
}
index = 2;
} else if (result.type = 0x18) { // GeneralizedTime
if (result.value.length < 14) {
throw new Error("Invalid type");
}
var year1 = getDigit(result.value[0]);
var year2 = getDigit(result.value[1]);
var year3 = getDigit(result.value[2]);
var year4 = getDigit(result.value[3]);
year = (year1 * 1000) + (year2 * 100) + (year3*10) + year4;
index = 4;
}
var monthHigh = getDigit(result.value[index++]);
var monthLow = getDigit(result.value[index++]);
var dayHigh = getDigit(result.value[index++]);
var dayhLow = getDigit(result.value[index++]);
var hourHigh = getDigit(result.value[index++]);
var hourLow = getDigit(result.value[index++]);
var minuteHigh = getDigit(result.value[index++]);
var minuteLow = getDigit(result.value[index++]);
var secondHigh = getDigit(result.value[index++]);
var secondLow = getDigit(result.value[index]);
var month = (monthHigh * 10) + monthLow;
var day = (dayHigh * 10) + dayhLow;
var hour = (hourHigh * 10) + hourLow;
var minute = (minuteHigh * 10) + minuteLow;
var second = (secondHigh * 10) + secondLow;
if (month < 1 || month > 12) {
throw new Error("Invalid month");
}
if (day < 1 || day > 31) {
throw new Error("Invalid day");
}
if (hour < 0 || hour > 24) {
throw new Error("Invalid hour");
}
if (minute < 0 || minute > 59) {
throw new Error("Invalid minute");
}
if (second < 0 || second > 59) {
throw new Error("Invalid second ");
}
date.setUTCFullYear(year);
date.setUTCMonth(month-1);
date.setUTCDate(day);
date.setUTCHours(hour);
date.setUTCMinutes(minute);
date.setUTCSeconds(second);
return {
index: result.index,
type: result.type,
length: result.length,
value: result.value,
date: date
};
}
function getValidity(bytes) {
if (bytes == null || bytes.length <= 0) {
return null;
}
var index = 0;
index = enterTag(bytes, index, [TYPE_SEQUENCE], "Certificate").index;
index = enterTag(bytes, index, [TYPE_SEQUENCE], "TBSCertificate").index;
var result = processTag(bytes, index, [0x00, 0x02],
"Version or SerialNumber");
if (result.type == 0) {
index = result.index;
result = processTag(bytes, index, [TYPE_INTEGER], "SerialNumber")
}
index = result.index;
result = processTag(bytes, index, [TYPE_SEQUENCE],
"Signature AlgorithmIdentifier");
index = result.index;
result = processTag(bytes, index, [], "Issuer Name");
index = result.index;
index = enterTag(bytes, index, [TYPE_SEQUENCE], "Validity").index;
result = readDate(bytes, index, "Not Before");
var notBefore = result.date;
index = result.index;
result = readDate(bytes, index, "Not After");
var notAfter = result.date;
return {notBefore: notBefore, notAfter: notAfter};
}
function getNextBase64Chr(str, index, equalSignReceived, alpha) {
var chr = null;
var code = 0;
var padding = equalSignReceived;
while (index < str.length) {
chr = str.charAt(index);
if (chr == " " || chr == "\r" || chr == "\n" || chr == "\t") {
index++;
continue;
}
if (chr == "=") {
padding = true;
} else {
if (equalSignReceived) {
throw new Error("Invalid Base64 Endcoding.");
}
code = alpha.indexOf(chr);
if (code == -1) {
throw new Error("Invalid Base64 Encoding .");
}
}
break;
}
return { character: chr, code: code, padding: padding, nextIndex: ++index};
}
function fromBase64(str) {
var alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var value = [];
var index = 0;
var destIndex = 0;
var padding = false;
while (true) {
var first = getNextBase64Chr(str, index, padding, alpha);
var second = getNextBase64Chr(str, first .nextIndex, first .padding, alpha);
var third = getNextBase64Chr(str, second.nextIndex, second.padding, alpha);
var fourth = getNextBase64Chr(str, third .nextIndex, third .padding, alpha);
index = fourth.nextIndex;
padding = fourth.padding;
// ffffffss sssstttt ttffffff
var base64_first = first.code == null ? 0 : first.code;
var base64_second = second.code == null ? 0 : second.code;
var base64_third = third.code == null ? 0 : third.code;
var base64_fourth = fourth.code == null ? 0 : fourth.code;
var a = (( base64_first << 2 ) & 0xFC ) | ((base64_second >> 4) & 0x03);
var b = (( base64_second << 4 ) & 0xF0 ) | ((base64_third >> 2) & 0x0F);
var c = (( base64_third << 6 ) & 0xC0 ) | ((base64_fourth >> 0) & 0x3F);
value [destIndex++] = a;
if (!third.padding) {
value [destIndex++] = b;
} else {
break;
}
if (!fourth.padding) {
value [destIndex++] = c;
} else {
break;
}
if (index >= str.length) {
break;
}
}
return value;
}
已用资源:
A Layman's Guide to a Subset of ASN.1, BER, and DER
答案 1 :(得分:0)
目前唯一可用的选项是forge - https://github.com/digitalbazaar/forge/blob/master/README.md或客户端的某种自定义扩展程序。
客户端除了DOM元素之外什么都不知道,因此无法检查SSL层。
的更多信息答案 2 :(得分:0)
这不可能来自客户端,但您可以使用node / shell组合执行此类操作。
假设您可以访问运行证书的服务器,您可以在主机上执行以下操作:
var execSync = require('child_process').execSync
var cmd = "echo | openssl s_client -connect 127.0.0.1:443 2>/dev/null | openssl x509 -noout -dates"
var stdout = execSync(cmd).toString()
// "notBefore=Feb 16 15:33:00 2017 GMT\nnotAfter=May 17 15:33:00 2017 GMT"
从那里你可以解析stdout
报告的日期并将它们写入公共资源或json文件,以便它们可以从客户端读取,并从那里进行日期比较。