Корректная обработка временных параметров — критически важный аспект при работе с криптографическими структурами. Библиотека Jsrsasign предоставляет инструменты для анализа сроков действия X.509 сертификатов, а также проверки временных атрибутов цифровых подписей.
В каждом X.509 сертификате присутствуют два ключевых поля:
Эти значения определяют допустимый интервал использования сертификата.
Пример структуры:
Validity:
Not Before: Jan 1 00:00:00 2024 GMT
Not After : Dec 31 23:59:59 2026 GMT
Для работы с сертификатами используется класс X509:
const x509 = new KJUR.crypto.X509();
x509.readCertPEM(pemCert);
Получение дат:
const notBefore = x509.getNotBefore();
const notAfter = x509.getNotAfter();
Формат возвращаемого значения — строка в ASN.1 формате времени, например:
240101000000Z
Для удобной работы требуется преобразование в стандартный JavaScript Date:
function parseASN1Time(asn1Time) {
const year = parseInt(asn1Time.substr(0, 2), 10) + 2000;
const month = parseInt(asn1Time.substr(2, 2), 10) - 1;
const day = parseInt(asn1Time.substr(4, 2), 10);
const hour = parseInt(asn1Time.substr(6, 2), 10);
const min = parseInt(asn1Time.substr(8, 2), 10);
const sec = parseInt(asn1Time.substr(10, 2), 10);
return new Date(Date.UTC(year, month, day, hour, min, sec));
}
Проверка, действителен ли сертификат на текущий момент:
const now = new Date();
const validFrom = parseASN1Time(x509.getNotBefore());
const validTo = parseASN1Time(x509.getNotAfter());
const isValidNow = now >= validFrom && now <= validTo;
В ряде сценариев требуется проверить валидность на конкретный момент времени (например, для архивных подписей):
function isValidAt(date, cert) {
const x509 = new KJUR.crypto.X509();
x509.readCertPEM(cert);
const from = parseASN1Time(x509.getNotBefore());
const to = parseASN1Time(x509.getNotAfter());
return date >= from && date <= to;
}
ASN.1 время хранится в формате UTC. Ошибки возникают при:
Корректная практика:
new Date(Date.UTC(...))
Если сертификат имеет срок действия после 2049 года, используется формат GeneralizedTime:
YYYYMMDDHHMMSSZ
Пример:
20501231235959Z
Адаптация парсинга:
function parseTime(asn1Time) {
if (asn1Time.length === 13) {
return parseASN1Time(asn1Time);
} else if (asn1Time.length === 15) {
const year = parseInt(asn1Time.substr(0, 4), 10);
const month = parseInt(asn1Time.substr(4, 2), 10) - 1;
const day = parseInt(asn1Time.substr(6, 2), 10);
const hour = parseInt(asn1Time.substr(8, 2), 10);
const min = parseInt(asn1Time.substr(10, 2), 10);
const sec = parseInt(asn1Time.substr(12, 2), 10);
return new Date(Date.UTC(year, month, day, hour, min, sec));
}
}
При проверке цепочки необходимо учитывать:
Пример логики:
function validateChain(chain) {
const now = new Date();
return chain.every(certPEM => {
const x509 = new KJUR.crypto.X509();
x509.readCertPEM(certPEM);
const from = parseTime(x509.getNotBefore());
const to = parseTime(x509.getNotAfter());
return now >= from && now <= to;
});
}
Цифровая подпись может содержать атрибут времени — SigningTime.
Извлечение:
const si = new KJUR.asn1.cms.SignerInfo();
si.fromHex(hexSignerInfo);
const signingTime = si.getSigningTime();
После извлечения необходимо проверить:
function isSignatureTimeValid(signTime, certPEM) {
const x509 = new KJUR.crypto.X509();
x509.readCertPEM(certPEM);
const from = parseTime(x509.getNotBefore());
const to = parseTime(x509.getNotAfter());
return signTime >= from && signTime <= to;
}
1. Игнорирование временных зон Результат — ложные отрицания валидности.
2. Использование локального времени Следует всегда использовать UTC.
3. Неправильная интерпретация UTCTime Годы до 1950 и после 2049 требуют особой обработки.
4. Проверка только текущего времени Недостаточно для архивных документов.
Определение, истек ли сертификат:
function isExpired(certPEM) {
const x509 = new KJUR.crypto.X509();
x509.readCertPEM(certPEM);
const now = new Date();
const to = parseTime(x509.getNotAfter());
return now > to;
}
function isNotYetValid(certPEM) {
const x509 = new KJUR.crypto.X509();
x509.readCertPEM(certPEM);
const now = new Date();
const from = parseTime(x509.getNotBefore());
return now < from;
}
function getCertStatus(certPEM) {
const x509 = new KJUR.crypto.X509();
x509.readCertPEM(certPEM);
const now = new Date();
const from = parseTime(x509.getNotBefore());
const to = parseTime(x509.getNotAfter());
if (now < from) return "NOT_YET_VALID";
if (now > to) return "EXPIRED";
return "VALID";
}
1. TLS-клиенты Проверка перед установкой соединения
2. Подписи документов Анализ момента подписания
3. Архивные системы Проверка валидности на дату создания
4. PKI-инфраструктура Контроль жизненного цикла сертификатов
Библиотека не выполняет автоматическую проверку валидности времени — разработчик обязан реализовать эту логику самостоятельно, используя:
getNotBefore()getNotAfter()Это обеспечивает гибкость, но требует строгого контроля корректности реализации.
Полноценная проверка срока действия включает:
Такая последовательность обеспечивает корректную и безопасную работу с цифровыми сертификатами и подписями.