Створіть самопідписаний сертифікат із кінцевою датою в минулому


24

Я хотів би створити самопідписані сертифікати на ходу з довільними датами початку та закінчення, включаючи кінцеві дати в минулому . Я вважаю за краще використовувати стандартні інструменти, наприклад, OpenSSL, але все, що робить цю роботу, було б чудово.

Питання про переповнення стека Як генерувати сертифікат openssl із закінченням терміну менше одного дня? задає подібне запитання, але я хочу, щоб моя довідка була самопідписаною.

Якщо вам цікаво, сертифікати потрібні для автоматизованого тестування.

Відповіді:


32

У вас є два способи створення сертифікатів у минулому. Або підробка часу (1) (2), або визначення часового інтервалу при підписанні сертифіката (3).

1) У - перших, про підробку час: щоб одна програма думаю , що це в іншу дату з системи, поглянути на libfaketimeіfaketime

Щоб встановити його в Debian:

sudo apt-get install faketime

Потім ви будете використовувати faketimeперед opensslкомандою.

Приклади використання:

$faketime 'last friday 5 pm' /bin/date
Fri Apr 14 17:00:00 WEST 2017
$faketime '2008-12-24 08:15:42' /bin/date
Wed Dec 24 08:15:42 WET 2008

Від man faketime:

Дана команда буде накладена на думку, що поточний системний час є тим, який вказаний у часовій позначці. Настінні годинники продовжуватимуть працювати з цієї дати та часу, якщо не вказано інше (див. Розширені параметри). Насправді, faketime - це проста оболонка для libfaketime, яка використовує механізм LD_PRELOAD для завантаження невеликої бібліотеки, яка перехоплює системні виклики таких функцій, як time (2) та fstat (2).

Так, наприклад, у вашому випадку ви можете дуже точно визначити дату 2008 року і створити потім сертифікат з терміном дії 2 роки до 2010 року.

faketime '2008-12-24 08:15:42' openssl ... 

В якості додаткової примітки, ця утиліта може використовуватися в декількох версіях Unix, включаючи MacOS, як обгортку для будь-якого виду програм (не виключно з командного рядка).

Як уточнення, час, завантажений цим методом (та їхні діти), лише змінив свій час, і підроблений час не впливає на поточний час решти системи.

2) Як заявляє @Wyzard, у вас також є datefudgeпакет, який дуже схожий на використання faketime.

Як відмінності, datefudgeце не впливає fstat(тобто не змінює створення файлу часу). У нього також є власна бібліотека, datefudge.so, яка завантажується за допомогою LD_PRELOAD.

Він також має місце, -s static timeде згадуваний час завжди повертається, незважаючи на те, скільки пройшло додаткових секунд.

$ datefudge --static "2007-04-01 10:23" sh -c "sleep 3; date -R"
Sun, 01 Apr 2007 10:23:00 +0100

3) Крім підробки часу, а ще простіше, ви також можете визначити початкову і кінцеву точку дії сертифіката при підписанні сертифіката в OpenSSL.

Помилкове уявлення про те, на яке ви посилаєтесь у своєму запитанні, полягає в тому, що термін дії сертифіката визначається не під час запиту (за запитом CSR), а підписується.

Використовуючи openssl caдля створення сертифіката, який підписує сам, додайте параметри -startdateта -enddate.

Формат дати в цих двох параметрах, згідно з джерелами openssl/crypto/x509/x509_vfy.copensl у , є ASN1_TIME aka ASN1UTCTime: формат повинен бути або YYMMDDHHMMSSZ, або YYYYMMDDHHMMSSZ.

Цитування openssl/crypto/x509/x509_vfy.c:

int X509_cmp_time(const ASN1_TIME *ctm, time_t *cmp_time)
{
    static const size_t utctime_length = sizeof("YYMMDDHHMMSSZ") - 1;
    static const size_t generalizedtime_length = sizeof("YYYYMMDDHHMMSSZ") - 1;
    ASN1_TIME *asn1_cmp_time = NULL;
    int i, day, sec, ret = 0;

    /*
     * Note that ASN.1 allows much more slack in the time format than RFC5280.
     * In RFC5280, the representation is fixed:
     * UTCTime: YYMMDDHHMMSSZ
     * GeneralizedTime: YYYYMMDDHHMMSSZ
     *
     * We do NOT currently enforce the following RFC 5280 requirement:
     * "CAs conforming to this profile MUST always encode certificate
     *  validity dates through the year 2049 as UTCTime; certificate validity
     *  dates in 2050 or later MUST be encoded as GeneralizedTime."
     */

І з журналу CHANGE (помилка 2038?) - Цей журнал змін є лише додатковою приміткою, оскільки стосується лише тих, хто безпосередньо використовує API.

Зміни між 1.1.0e та 1.1.1 [xx XXX xxxx]

*) Додайте типи ASN.1 INT32, UINT32, INT64, UINT64 та варіанти з префіксом Z. Вони призначені для заміни LONG та ZLONG та забезпечення безпечності розміру. Використання LONG та ZLONG не рекомендує та планує знецінення у OpenSSL 1.2.0.

Отже, створення сертифіката з 1 січня 2008 року по 1 січня 2010 року можна зробити так:

openssl ca -config /path/to/myca.conf -in req.csr -out ourdomain.pem \
-startdate 200801010000Z -enddate 201001010000Z

або

openssl ca -config /path/to/myca.conf -in req.csr -out ourdomain.pem \
-startdate 0801010000Z -enddate 1001010000Z

-startdateі -enddateвідображаються у opensslджерелах та журналі ЗМІНИ; Як зауважив @guntbert, хоча вони не відображаються на головній man opensslсторінці, вони також відображаються у man ca:

-startdate date
       this allows the start date to be explicitly set. The format of the date is
       YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure).

   -enddate date
       this allows the expiry date to be explicitly set. The format of the date is
       YYMMDDHHMMSSZ (the same as an ASN1 UTCTime structure).

Цитування openssl/CHANGE:

Зміни між 0.9.3a та 0.9.4 [09 серпня 1999]

*) Виправити -startdate та -enddate (якого не було) аргументи програми 'ca'.

PS Що стосується обраної відповіді на запитання, на яке ви посилаєтесь у StackExchange: як правило, погана ідея змінити системний час, особливо у виробничих системах; і з методами у цій відповіді не потрібно кореневих привілеїв під час їх використання.


1
+1. Я знав, що хтось прийде разом із чимось кращим, ніж те, що я написав :)
Селада

2
Існує також подібна програма під назвою datefudge.
Уайдард

@Wyzard Спасибі, я дійсно знайшов це в Debian; Цікаво, що в посібнику зазначено, що, хоча він також змінює системні виклики на такі функції, як time (2), він не впливає на fstat (2).
Rui F Ribeiro

1
І вони, faketimeі datefudgeпрекрасно працюють над моєю системою джессі Debian.
rlandster

1
OTOH: +5 для того, щоб дізнатися, де встановити ці дати!
guntbert

8

Я майже здивований, виявивши, що очевидна річ працює: тоді opensslяк аргумент бере кількість днів, протягом яких сертифікат повинен бути дійсним, просто введіть від'ємне число!

openssl req -x509 -newkey rsa:4096 \
    -keyout key.pem -out cert.pem -days -365

Зверніть увагу , що це на самому справі призводить до чого - то дуже дивне: свідоцтво якого експірації відмітка часу передує його запуск через дії тимчасової мітки. Я не рекомендую використовувати це для автоматизованого тестування, оскільки це дивно. Ви, мабуть, хочете, щоб також було встановлено зворотну дату часової мітки початку дії.


Ну, якщо чесно, я не знав, що ти можеш використовувати негативні дні.
Rui F Ribeiro

Ви не можете вказати дату початку?
FreeSoftwareServers

@FreeSoftwareServers У CSR ви не можете; дивіться останню частину моєї відповіді.
Rui F Ribeiro

Більш цікаво, але, звичайно, кодовий барф знайшов такий сертифікат? btw, я розширив свою відповідь
Rui F Ribeiro

3

Або ви можете використовувати щось подібне до цієї короткої програми пітона ... (застосовуються застереження)

Він створює ключ (test.key) та сертифікат (test.crt) з початком часу початку 10 років (-10 * 365 * 24 * 60 * 60 секунд - 10 років) та терміном придатності 5 років у минулому (-5 * 365 * 24 * 60 * 60).

Зверніть увагу, що це мінімальна демонстраційна програма, тому вона не турбується встановлювати будь-які розширення (наприклад, basicConstraints) і використовує фіксований серійний.

#!/usr/bin/env python

from OpenSSL import crypto

key = crypto.PKey()
key.generate_key(crypto.TYPE_RSA, 2048)
cert = crypto.X509()
cert.get_subject().CN = "Test"
cert.set_serial_number(666)
cert.gmtime_adj_notBefore(-10*365*24*60*60)
cert.gmtime_adj_notAfter(-5*365*24*60*60)
cert.set_issuer(cert.get_subject())
cert.set_pubkey(key)
cert.sign(key, 'sha384')

open("test.crt", "wb").write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
open("test.key", "wb").write(crypto.dump_privatekey(crypto.FILETYPE_PEM, key))

у коді, здається, відсутні відсутні основні стандартні поля X.509.
Rui F Ribeiro

2
Це дуже корисно. Це дає мені легший програмний контроль над створенням сертифікату.
rlandster
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.