У нас есть более 700 сертификатов, сгенерированных для использования OpenVPN с помощью Easy-RSA 2. Я не знаю, как это произошло (подозреваю, что кто-то удалил один раз index.txt
, serial
или и то, и другое), но более половины сгенерированных сертификатов имеют одинаковые серийные номера. Кроме того, оригинал index.txt
содержит только половину всех сертификатов (последнюю половину), не включая предыдущие.
Итак, новые сертификаты можно сделать, это нормально. Но когда я пытаюсь отозвать сертификат, которого нет в index.txt
, у меня возникает ошибка.
Я попробовал воссоздать index.txt
по скрипту:
for cert in *.crt
do
echo "-> $cert"
enddate=`openssl x509 -enddate -noout -in $cert | sed 's/notAfter=//' | awk '\
{ year=$4-2000;
months="JanFebMarAprMayJunJulAugSepOctNovDec" ;
month=1+index(months, $1)/3 ;
day=$2;
hour=substr($3,1,2) ;
minutes=substr($3,4,2);
seconds=substr($3,7,2);
printf "%02d%02d%02d%02d%02d%02dZ", year, month, day, hour, minutes, seconds}'`
serial=`openssl x509 -serial -noout -in $cert |sed 's/serial=//'`
subject=`openssl x509 -subject -noout -in $cert |sed 's/subject= //'`
echo -e "V\t$enddate\t\t$serial\tunknown\t$subject" >>index.txt
done
Он считывает сертификаты один за другим, получает их данные и заполняет новые index.txt
. Все вроде бы в порядке.
Но, согласно верхнему тексту, скрипт заполняет его сертификатами, которые имеют одинаковые серийные номера. Так что, с этим вновь созданным сертификатом index.txt
я не могу ничего сделать с сертификатами (создать, отозвать и т. д.)
Вопрос: есть ли возможность восстановить index.txt
базу, если у меня есть все сертификаты? Или, может быть, как-то изменить серийный номер сертификата (простое изменение заголовка *.crt
файла ничего не даст - серийный номер останется старым при запросе openssl
)
Если нет - мне нужно только отозвать сертификаты, которых нет в index.txt
, могу ли я сделать это без index.txt
базы?
решение1
У нас более 700 сертификатов... более половины сгенерированных сертификатов имеют одинаковый серийный номер... исходный index.txt содержит только половину всех сертификатов (последнюю половину), не считая предыдущих.
Я попытаюсь указать вам правильное направление, но, вероятно, не смогу довести это до конца, поскольку я не настроил тестовую установку и не воспроизвел проблему. Заранее приношу извинения.
Если вам нужен более подробный обзор выпуска сертификата в закрытой PKI, см.Как подписать запрос на подпись сертификата в вашем центре сертификации?В нем объясняется, как бы вы делали все вручную, если бы Easy-RSA не делал этого за вас.
Еще один важный документ —RFC 4158, Инфраструктура открытых ключей Internet X.509: Построение пути сертификации. Это__the__документ, который объясняет, что такое соответствия, и как можно использовать кортежи, такие как {Issuer Distinguished Name,Serial Number}
или {Subject Distinguished Name,Public Key Identifier}
для сравнения двух сертификатов на эквивалентность. OpenSSL использует этот документ для сопоставления. Также см. раздел 3.5.15,«Соответствие отличительного имени конечной точки (DN)»и раздел 3.5.12,«Совпадение идентификаторов ключей (KID)».
Серийные номера должны быть уникальными. Это проблема, которую нужно преодолеть.Отличительные имена субъектов (DN)— это другая история. Если у вас openssl.cnf
есть unique_subject=yes
, то они не могут быть продублированы. Если unique_subject=no
, то DN могут быть продублированы.
Я думаю, вам нужно сделать несколько вещей. Во-первых, используйте современную или обновленную версию утилит OpenSSL. Здесь «современная» означает одну из последних версий 1.0.2 или 1.1.0. В предыдущих версиях утилиты были тонкие проблемы с сопоставлением имен и серийных номеров.
Во-вторых, проверьте свой файл конфигурации (обычно, openssl.cnf
но вы можете использовать другой, возможно, скопированный файл с помощью -config filename
) и запишите соответствующие настройки, такие как serial.txt
и unique_subject=no
. Я считаю, что это соответствующие настройки [CA_Default]
из openssl.cnf
:
base_dir = .
certificate = $base_dir/cacert.pem # The CA certifcate
private_key = $base_dir/cakey.pem # The CA private key
new_certs_dir = $base_dir # Location for new certs after signing
database = $base_dir/index.txt # Database index file
serial = $base_dir/serial.txt # The current serial number
unique_subject = no # Allow reuse of subjects
В-третьих, сделайте резервную копию всего, особенно важных данных, таких как index.txt
и serial.txt
.
В-четвертых, создайте список сертификатов, которые вы хотите отозвать. В списке могут быть записи типа имен файлов - john-doe-vpn.pem
. Переместите их в отдельную папку, если хотите. Предпочтительно, чтобы каждый имел уникальный серийный номер, и все они ДОЛЖНЫ иметь одинаковое имя эмитента; функции openssl ca
и ocsp
не могут обрабатывать более одного эмитента одновременно, хотя для протокола OCSP это возможно.
Пятое, создайте новый, index.txt
содержащий строку для каждого серийного номера. Один из подходов — извлечь тему, серийный номер и срок действия из каждого файла сертификата, как в скрипте, который вы опубликовали, хотя вы можете свернуть большую часть работы оболочки в один openssl и один awk на сертификат:
for f in *files*; do
openssl x509 -noout -enddate -serial -subject -in $f \
| awk 'BEGIN{FS="=";OFS="\t"} /^serial/{num=$2} /^subject/{sub=$2}
/^notAfter/{split($2,a,/ /);mon=index(months,a[1])/3+1;day=a[2]...exp=sprintf(...)}
END{print "V",exp,"",num,sub}' >>index.txt
done
Если сложно (надежно) удалить дубликаты серийных номеров заранее, вы можете поместить все данные, а затем удалить дубликаты с помощью awk -F'\t' '!already[$4]++'
или sort -t$'\t' -k4,4 -u
или аналогичного метода.
Другой подход, доступный в версии 1.0.2 и выше, но задокументированный только в версии 1.1.0, заключается в использовании openssl ca [-config conffile] -valid certfile
для автоматического извлечения. Но -valid
это излишне загружает закрытый ключ CA каждый раз, поэтому, если ваш закрытый ключ зашифрован паролем, что является хорошей практикой, это будет означать, что вам придется вводить пароль снова и снова; для экономии времени временно замените настоящий ключ CA и сертификат на незашифрованный ключ и соответствующий, но в остальном поддельный (вероятно, самоподписанный) сертификат. -valid
не запишет дублирующую серийную запись, поэтому вам не нужно беспокоиться об их исключении или удалении.
Введите в serial
файл значение, котороепо меньшей меренаивысшее значение любого ранее выданного сертификата; если вы хотите перейти к следующему 10000
или 1000000
или чему-то еще, чтобы быть в безопасности и, возможно, также более ясным, это нормально. Вам может потребоваться установить unique_subject=no
в этой точке.
Шестое, отметьте каждый сертификат (серийный) в index
файле как отозванный. Вы можете пройтись по файлам сертификатов, используя openssl ca -revoke
on each, но проще просто использовать awk, например:
awk -F'\t' -vOFS='\t' '{$1="R"; $3="161101000000Z"}' <index.txt >temp && mv temp index.txt
# if you want, you can add a comma and a reason, see man ca or
# online at https://www.openssl.org/docs/manmaster/man1/ca.html
# under -crl_reason. But there isn't a code for 'CA stupid', and
# in practice the reason doesn't really matter to reliers except
# you should't use hold or remove (latter noted in the man)
В-седьмых, сгенерируйте CRL из этого index
и openssl ca -gencrl [-crldays n] [-out file]
/или настройте ответчик OCSP с его помощью, если (какой-либо из) старых сертификатов указывал расширение OCSP.
В-восьмых, как только вы распространите CRL и/или начнете работу (нового) ответчика OCSP,всесертификаты с затронутыми серийными номерами отзываются и приведут к сбою связи, если они используются (и должным образом проверены). Еслилюбойдублированных серийных номеров находятся в сертификатах, которые ваши системы все еще используют, их необходимо сначала заменить. Если у вас все еще есть файлы запросов (CSR) из систем, использующих затронутые сертификаты, вы можете просто повторно выпустить openssl ca [-config conffile] [-in reqfile | -infiles reqfile...]
и отправить новые сертификаты в соответствующие системы и попросить операторов этих систем установить их. В противном случае вам сначала нужно, чтобы оператор каждой системы отправил вам CSR, который может быть тем, который они ранее использовали (и сохранили), или новым, который они сгенерировали.
Наконец, восстановите все «хорошие» записи (серийные номера, которые вы не отозвали) из старого index
файла, объединив их с новыми записями для замены сертификатов, выданных в #8 выше. Если вы используете ответчик OCSP (см. выше), вы также должны сохранить отозванные записи; это не имеет значения, но, вероятно, проще. Делатьнетвосстановить старое значение, serial
если оно ниже самого высокого старого сертификатаилинаивысший новый заменяющий сертификат, вместо этого позвольте ему продолжать увеличиваться от нового значения.
Относительно for-loop
дат и печати:
hour=substr($3,1,2) ;
minutes=substr($3,4,2);
seconds=substr($3,7,2);
printf "%02d%02d%02d%02d%02d%02dZ", year, month, day, hour, minutes, seconds}'`
Даже не беспокойтесь о датах. Если они просрочены, их нельзя использовать, если ваш PKI функционирует нормально. Если вам от этого станет легче, то удалите закрытый ключ, связанный с сертификатом и открытым ключом.
Все, что вас волнует, это список сертификатов для отзыва, их серийный номер и отличительное имя. Здесь ваш список будет состоять из таких сертификатов, как (1) увольняющийся сотрудник, который имеет непросроченный сертификат и закрытый ключ (т. е. сотрудник уходит на пенсию или уволен); (2) сотрудник, который потерял устройство (т. е. закрытый ключ находится в свободном доступе); и т. д.
Другой вариант, который у вас есть... Сжечь существующий PKI до основания и начать заново. В этом случае шаг (1) — отозвать корневой CA и все промежуточные/подчиненные CA. Затем выбросить закрытый ключ. Шаг (2) — создать новый корневой CA, выпустить новые промежуточные/подчиненные CA и, наконец, выпустить новые сертификаты конечных субъектов. Для шага (2) вы даже можете станцевать танец подписи.
Хотите верьте, хотите нет, но OpenStack использует эту стратегию (или рассматривал возможность ее использования). Это своего рода «эфемерный PKI», который должен оставаться достаточно долго, чтобы удовлетворить ваши потребности; а затем быть отброшенным, когда что-то пойдет не так.
Ради смеха вы можете посмотреть Питера ГутманаИнженерная безопасность. Он безжалостен, когда дело касается PKI и публичных центров сертификации.