FreeBSD: Самоподписные сертификаты

Давно хотел написать эту статью. Практически все действия и большое количество текста взято из этой статьи.

Начнем с небольшой теории.

В настоящее время протокол SSL практически незаметно для пользователя взаимодействует с остальными протоколами Интернет и обеспечивает передачу конфиденциальной информации по сетям общего пользования в зашифрованном виде. Программное обеспечение OpenSSL поддерживает протоколы SSL (Secure Sockets Layer) v2/v3 и TLS v1 (Transport Layer Security). Утилита командной строки openssl может использоваться для выполнения следующих задач:

  • Создание и управление ключами RSA и DSA
  • Создание сертификатов формата x509, запросов на подпись сертификатов, восстановление сертификатов
  • Шифровать данные с помощью симметрического или асимметрического алгоритма шифрования
  • Работать с S/MIME
  • Производить ssl/tls тестирование серверов и клиентов

SSL использует асимметричные алгоритмы шифрования, т.н. шифрование с открытым ключом. В таком алгоритме один ключ используется для расшифровки данных, зашифрованных другим ключом. Эти два ключа (private/public) – пара ключей – создаются одновременно, с помощью математической формулы. Это единственный простой способ найти два ключа, обладающих специальной ассиметрией (при которой один из ключей может расшифровать зашифрованное вторым): вычисление одного из ключей по второму – задача невероятно сложная. При применении шифрования с открытым ключом один ключ из пары делается свободно доступным, т.н. public key, а второй сохраняется в секрете, т.н. private key. Тот, кто хочет установить с создателем ключей безопасный контакт, может перед отправкой зашифровать свое сообщение, пользуясь открытым ключом (public key). Если адресат хранит закрытый ключ (private key) в секрете, то только он сможет расшифровать сообщение.

И наоборот, автор пары ключей может зашифровать свое сообщение закрытым ключом. Получатель может удостовериться, что сообщение действительно принадлежит автору ключей, попробовав расшифровать его с помощью открытого ключа. Если сообщение после расшифровки имеет какой то смысл, а отправитель действительно сохранил зарытый ключ в секрете, то сообщение действительно написано им. Успешная расшифровка также подтверждает, что сообщение не было изменено в процессе доставки (например, при прохождении через почтовый сервер), поскольку в противном случае не была бы получена правильная расшифровка. Так сообщение проверяется получателем.

Сертификат содержит публичный ключ, подписанный одним из корневых доверенных центров сертификации, данные об организации, выдавшей сертификат и в некоторых случаях зашифрованный закрытый ключ, а также отпечаток (хеш) публичного ключа. Сертификаты имеют время действия, по окончанию которого они автоматически считаются недействительными, иерархия сертификатов обычно строится на основании сети доверия (бывают довольно длинные цепочки сертификатов, ведущие к доверенному ключу из root CA).

————

Создание корневого (самоподписанного) сертификата.

Для начала надо поставить (если еще не поставили) openssl (на данный момент порт находится – /usr/ports/security/openssl).
Cоздаем папки (создал папки в ‘/usr/local/etc/’, но это не принципиально).

# cd /usr/local/etc
# mkdir -p CA/newcerts CA/private

Папка CA будет содержать сертификат нашего CA, базу данных сертификатов, которые мы подписали, а также ключи, запросы и сертификаты, которые мы сгенерируем. Она также будет нашей рабочей директорией, когда мы будем создавать или подписывать сертификаты.
CA/newcerts – будет содержать копию каждого сертификата, который мы подпишем.
CA/private – будет содержать наш CA private key.

Этот ключ (CA private key) очень важен. Не теряйте этот ключ, без него, вы не сможете подписать или обновить сертификаты. Не показывайте этот ключ никому, если его узнают, то злоумышленник сможет выдавать себя за вас.

Создаем БД для сертификатов (делаем это в нашей рабочей директории “CA”):

# echo '01' > serial
# touch index.txt

Создаем openssl.cnf и записываем в него:

#
# /usr/local/etc/CA/openssl.cnf
#

# Задаем рабочую директорию
dir      = .

# В данной секции описываются основные опции
[ req ]

# Длина ключа в битах
default_bits = 8192

# Алгоритм шифрования
default_md = md5

# Разрешенные символы
string_mask = nombstr

# Указываем, что DN (Distinguished Name) будет описана в секции req_distinguished_name
distinguished_name = req_distinguished_name

# В данной секции указываются данные, которые будут использоваться
# по умолчанию при генерации запроса на подписание сертификата
[ req_distinguished_name ]
0.organizationName       = Organization Name (company)
organizationalUnitName   = Organizational Unit Name (department, division)
emailAddress             = Email Address
emailAddress_max         = 40
localityName             = Locality Name (city, district)
stateOrProvinceName      = State or Province Name (full name)
countryName              = Country Name (2 letter code)
countryName_min          = 2
countryName_max          = 2
commonName               = Common Name (hostname, IP, or your name)
commonName_max           = 64

# Значения по умолчанию
0.organizationName_default    = Unix4Me
localityName_default          = Moscow
stateOrProvinceName_default   = Russia
countryName_default           = RU

[ v3_ca ]
basicConstraints         = CA:TRUE
subjectKeyIdentifier     = hash
authorityKeyIdentifier   = keyid:always,issuer:always

Создаем самоподписанный корневой сертификат (генерим с использованием пароля)

# openssl req -new -x509 -extensions v3_ca -keyout private/rootCA.key -out rootCA.crt -days 3650 -config ./openssl.cnf
Generating a 8192 bit RSA private key
....++
....++
writing new private key to 'private/rootCA.key'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Organization Name (company) [Unix4Me]:
Organizational Unit Name (department, division) []:UnitName
Email Address []:mymail@mymail.ru
Locality Name (city, district) [Moscow]:
State or Province Name (full name) [Russia]:
Country Name (2 letter code) [RU]:
Common Name (hostname, IP, or your name) []:MyName

Когда время действия корневого сертификата истекает, все подписанные им сертификаты становятся недействительными. Для исправления этой ситуации, необходимо создать и распространить новый корневой сертификат.

————

Создание запроса на подпись сертификата

Теперь на базе созданного корневого сертификата, мы можем создать любое количество сертификатов для ssl приложений. Эта процедура состоит из создания закрытого ключа и запроса на подпись сертификата, а далее в подписи его нашим корневым сертификатом.
Для создания не корневых сертификатов – внесем изменение в openssl.cnf (добавим в конец файла):

[ v3_req ]
basicConstraints       = CA:FALSE
subjectKeyIdentifier   = hash

и в секцию [ req ] после параметра distinguished_name добавим:

req_extensions    = v3_req

Создаем запрос на сертификат для веб сервера. Необходимо обратить внимание на поля:

  • Organizational Unit – необходимо указать, для чего предназначен сертификат
  • Email Address – указываем реальный почтовый адрес
  • Common Name – fqdn или ip адрес веб сервера
# openssl req -new -nodes -out web.unix4me.ru.csr -keyout web.unix4me.ru.key -config ./openssl.cnf
Generating a 8192 bit RSA private key
...........++
...........++
writing new private key to 'web.unix4me.ru.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Organization Name (company) [Unix4Me]:
Organizational Unit Name (department, division) []:Web Server unix4me.ru
Email Address []:mymail@mymail.ru
Locality Name (city, district) [Moscow]:
State or Province Name (full name) [Russia]:
Country Name (2 letter code) [RU]:
Common Name (hostname, IP, or your name) []:unix4me.ru

В результате выполнения этой команды мы получили два файла:

  • web.unix4me.ru.key – секретный закрытый ключ
  • web.unix4me.ru.csr – запрос на подпись сертификата

Эти файлы необходимо сохранить. Когда срок действия сертификата истечет, то запрос может быть использован снова для создания нового сертификата с новым сроком действия. Закрытый ключ необходим для SSL кодирования.
————

Подпись сертификата

Теперь добавим в конфигурационный файл (openssl.cnf) секцию [ ca ]. Эта секция определяет пути к различным частям, таким как база данных, CA сертификат и закрытый ключ. Она также содержит некоторые базовые настройки. Добавляем перед секцией [ req ]

[ ca ]
default_ca    = CA_default

[ CA_default ]
serial         = $dir/serial
database       = $dir/index.txt
new_certs_dir  = $dir/newcerts
certificate    = $dir/rootCA.crt
private_key    = $dir/private/rootCA.key
default_days   = 365
default_md     = md5
preserve       = no
email_in_dn    = no
nameopt        = default_ca
certopt        = default_ca
policy         = policy_match

[ policy_match ]
countryName              = match
stateOrProvinceName      = match
organizationName         = match
organizationalUnitName   = optional
commonName               = supplied
emailAddress             = optional

Чтобы подписать запрос сделанный на предыдущем шаге:

# openssl ca -out web.unix4me.ru.crt -config ./openssl.cnf -infiles web.unix4me.ru.csr
Using configuration from ./openssl.cnf
Enter pass phrase for ./private/rootCA.key:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
organizationName      :PRINTABLE:'Unix4Me'
organizationalUnitName:PRINTABLE:'Web Server unix4me.ru'
localityName          :PRINTABLE:'Moscow'
stateOrProvinceName   :PRINTABLE:'Russia'
countryName           :PRINTABLE:'RU'
commonName            :PRINTABLE:'unix4me.ru'
Certificate is to be certified until Apr 15 14:47:22 2022 GMT (3650 days)
Sign the certificate? [y/n]:y

1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated

В итоге обновили нашу бд и получаем два файла

  • web.unix4me.ru.crt – непосредственно сам сертификат
  • newcerts/<серийный номер>.pem – копия сертификата

Если вы будете пользоваться услугами сторонних центров сертификации, таких как VeriSign, VISA, Thawte, Baltimore и т.д. То Вы должны будете отослать запрос на подпись сертификата (web.unix4me.ru.csr) в один из центров сертификации. По истечении некоторого времени, как правило, 1-3 недели вам пришлют готовый и подписанный сертификат (web.unix4me.ru.crt). Который уже можно будет использовать непосредственно в ПО. Естественно это услуга платная.

————

Полезные команды.

Чтобы посмотреть информацию о назначении сертификата

# openssl x509 -in rootCA.crt -noout -purpose
Certificate purposes:
SSL client : Yes
SSL client CA : Yes
SSL server : Yes
SSL server CA : Yes
Netscape SSL server : Yes
Netscape SSL server CA : Yes
S/MIME signing : Yes
S/MIME signing CA : Yes
S/MIME encryption : Yes
S/MIME encryption CA : Yes
CRL signing : Yes
CRL signing CA : Yes
Any Purpose : Yes
Any Purpose CA : Yes
OCSP helper : Yes
OCSP helper CA : Yes

Чтобы посмотреть информацию о периоде действия сертификата

openssl x509 -in rootCA.crt -noout -dates
notBefore=Apr 17 13:40:54 2012 GMT
notAfter=Apr 15 13:40:54 2022 GMT

Чтобы посмотреть информацию о сертификате

# openssl x509 -in rootCA.crt -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            00:00:00:00:00:00:00:00
        Signature Algorithm: md5WithRSAEncryption
        Issuer: O=UnitName, OU=HS/emailAddress=mymail@mymail.ru, L=Moscow, ST=Russia, C=RU, CN=MyName
        Validity
            Not Before: Apr 17 13:40:54 2012 GMT
            Not After : Apr 15 13:40:54 2022 GMT
        Subject: O=Unitname, OU=HS/emailAddress=mymail@mymail.ru, L=Moscow, ST=Russia, C=RU, CN=MyName
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (8192 bit)
                Modulus (8192 bit):
      ............

Чтобы получить rootca с определенного сайта

# openssl s_client -connect www.domain.com:443 | tee www.domain.com-rootca.txt
# openssl x509 -inform PEM -in www.domain.com-rootca.txt -text -out www.domain.com-rootca.crt

Чтобы убрать пароль с закрытого ключа (private key) выполните следующую команду (например, это может понадобится при создании сертификата для postfix, т.к. в документации написано – «The private key must not be encrypted, meaning: the key must be accessible without password»)

# openssl rsa -in server.key -out nopass.key

Чтобы защитить секретный ключ паролем выполните следующую команду

# openssl rsa -des3 -in nopass.key -out pass.key

Если вы после этого посмотрите сам ключ в любом текстовом редакторе, то в самом начале ключа должны будут быть подобные строки

# head -3 pass.key
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,E4786E5109C67B86

Преобразование сертификата из DER формата в PEM

# openssl x509 -inform DER -in web.unix4me.ru.crt -outform PEM -out web.unix4me.ru.pem

Преобразование сертификата из PEM формата в DER

# openssl x509 -inform PEM -in web.unix4me.ru.pem -outform DER -out web.unix4me.ru.crt

Преобразование сертификата из формата PKS#10 (формат, используемый по умолчанию в openssl) в PKCS#12 (формат, используемый по умолчанию Microsoft)

# openssl pkcs12 -export -inkey web.unix4me.ru.key -in web.unix4me.ru.crt -out web.unix4me.ru.p12 -name "Ivanov Ivan. Client certificate."
Enter Export Password: *******
Verifying - Enter Export Password: *******

Преобразование сертификата из формата PKS#12 в PEM

# openssl pkcs12 -in web.unix4me.ru.p12 -out web.unix4me.ru.pem
Enter Import Password: *******
MAC verified OK
Enter PEM pass phrase: *******
Verifying - Enter PEM pass phrase:  *******

————

Как уже писал вначале – статья была написано по статье выложенной здесь.