Аспекты работы с Apache + mod_ssl

Оригинал

SSL workaround

В данном документе рассматриваются моменты установки и аспекты работы с Apache + mod_ssl, установка и обслуживание CA. Выдача и получение сертификатов. Авторизация пользователей web сервера при помощи сертификатов.

Данный документ представляет собой компиляцию с некоторыми комментариями следующих документов:

SSL и SSLeay.

Secure Sockets Layer protocol (SSL) - протокол уровня передачи данных, который может служить промежуточным слоем между протоколом сетевого уровня ( прим. TCP/IP ) и протоколом уровня приложения (те HTTP). SSL предлагает защищенный канал передачи данных между клиентом и сервером с использованием аутентификации, цифровых подписей и шифрования. Протокол разработан с поддержкой большого числа специальных алгоритмов , используемых для криптования, создания дайджестов и подписей. Он позволяет делать выбор алгоритмов с учетом требуемой надежности, соответствия принятому законодательству и пр. факторам, а так же расширение новыми алгоритмами. Выбор происходит во время начала протокольной сессии между клиентом и сервером.

Существует несколько версий SSL протокола:

Версия Источник Описание Поддержка
броузерами
SSL 2.0 Netscape Оригинальный протокол Netscape 3.0,Internet Explorer 3.0
SSL 3.0 Expired Internet Draft Revisions to prevent specific security attacks, add ciphers,and support certificate chains Netscape 3.0, Internet Explorer 3.0
TLS 2.0 IETF Draft Revision of SSL 3.0 Нет

Один из основных вариантов использования SSL - защита Web HTTP коммуникаций между клиентом и Web сервером. Этот вариант не пересекается и с использованием небезопасного HTTP. Защищенный вариант использует URLы, которые начинаются с https а не с http, и использует другой порт ( по умолчанию 443 ).

OpenSSL - свободная некоммерческая реализация SSL 2.0 и 3.0. Она включает реализацию открытых ключей ( public key ), которая может быть использована за пределами US. SSLeay предлагает достаточно несложный путь для освоения SSL и является темой данного документа.

Certificate Authority

Для использование ssl расширения Apache совершенно не нужно располагать Certificate Authority, достаточно получить, а точнее приобрести, необходимые ключи и сертификаты подписанные сторонним (CA). Некоторые компании, как Thawte и VeriSign имеют собственные CA и предоставляют следующий сервис:
Однако возможно создать собственную CA, для генерации и использования сертификатов внутри организации для идентификации серверов и пользователей. При установке CA, необходимо помнить, что CA не только выдает сертификаты, но и определяет сроки их действительности, обновляет их, управляет списком просроченных выданных сертификатов (Certificate Revocation Lists, or CRLs). Помните, что вам необходимо "познакомить" Ваш browser с сертификатом собственно CA, для того, чтобы browser мог работать с серверами, чьи сертификаты подписаны вышеупомянутым CA.

Первым шагом для создания Certificate Authority является создания сертификата для данного CA, подписанного самим же CA. Для этого используется команда "req" с ключом "-x509". Сертификат записывается в cacert.pem и личный ключ cakey.pem, которые располагаются (согласно указанным в sslay.cnf переменным certificate и private_key соответственно). commonName для самоподписанного сертификата не должно соответствовать имени домена для сервера ( поскольку Nescape использует имя домена для сертификации серверов). "req" потребует введение пароля для закрытого ключа ( private_key ). for Ex:(смотрите пути в ssleay.cnf).

SSLDIR в данном случае выставляется в значение равное dir, указанное в секции default_ca конфигурационного файла /usr/local/etc/ssleay.cnf
/usr/local/bin/ssleay req -new -x509 -keyout ${SSLDIR}/private/cakey.pem \ -out ${SSLDIR}/cacert.pem -config /usr/local/etc/ssleay.cnf Using configuration from /usr/local/etc/ssleay.cnf Generating a 512 bit private key writing new private key to '../private/cakey.pem' Enter PEM pass phrase: Verifying password - Enter PEM pass phrase: ----- You are about to be asked to enter information that will be incorperated 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. ----- Country Name (2 letter code) [US]: RU State or Province Name (full name) [MA]: Some State Locality Name (eg, city) [Cambridge]: some Locality Organization Name (eg, company) [The Open Group]: None Group Organizational Unit Name (eg, section) [Research Institute]: CT Common Name (eg, YOUR name) [example.opengroup.org]: NONE CA
CA сертификат и ключ должны оставаться в $SSLDIR/private и $SSLDIR, как указано в ssleay.conf в CA default section. Они будут использоваться для проверки сертификатов клиента подписанных созданным CA.

Cоздание ключа и сертификата для сервера

Сначала с использованием процедуры аналогичной вышеприведенной создаем для сервера запрос на сертификат:
ssleay req -new -keyout newkey.pem -out newreq.pem -days 360 Using configuration from /usr/local/etc/ssleay.cnf Generating a 1024 bit RSA private key .......................+++++ .+++++ writing new private key to 'newkey.pem' Enter PEM pass phrase: Verifying password - 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. ----- Country Name (2 letter code) [RU]: State or Province Name (full name) [Some State]: Locality Name (eg, city) [Some Locality]: Organization Name (eg, company) [Simple Org.]: Organizational Unit Name (eg, section) [Computing Dep.]: Common Name (eg, YOUR name) []:hostname.aaaa.ru Email Address []:some@some.aaaa.ru Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:
Используя "ca" команду подписываем полученный сертификат. Ключ -policy указывает секцию SSLeay конфигурации, которая определят, какие поля с distinguished name необходимы, а так же их порядок. В качестве входных подаются файл, содержащий запрос newreq.pem и ключ сервера newkey.pem. По запросу вводится пароль, открывающий private ключ CA.
Внимание!! Перед этим вы должны удостовериться в том, что в CA репозитарии, согласно ssleay.conf должны быть созданы $database файл, $new_certs_dir и $serial. Формат $serial - две цифры, если после создания CA никакие сертификаты больше не выдавались, то должен содержать в себе "01".
ssleay ca -policy policy_anything -out newcert.pem -config /usr/local/etc/ssleay.cnf -infiles newreq.pem Using configuration from /usr/local/etc/ssleay.cnf Enter PEM pass phrase: Check that the request matches the signature Signature ok The Subjects Distinguished Name is as follows countryName :PRINTABLE:'RU' stateOrProvinceName :PRINTABLE:'Some State' localityName :PRINTABLE:'Some Locality' organizationName :PRINTABLE:'Simple Org.' organizationalUnitName:PRINTABLE:'Computing Dep.' commonName :PRINTABLE:'aaaaa.abbn.cc' emailAddress :IA5STRING:'xz@abbn.cc' Certificate is to be certified until Mar 16 22:46:52 2000 GMT (365 days) Sign the certificate? [y/n]:y
После чего в текущем каталоге находиться сертификат сервера newcert.pem, он же находится в $new_certs_dir под именем index_number.pem , значение $serial увеличивается на 1, в $database заноситься запись про выданный сертификат. Для дальнейшего использования сохраним ключ сервера и его сертификат в private/serverkey.pem certs/servercert.pem соответственно. ( Какова роль расположения??). Многие документы рекомендуют создавать hash на сертификаты в том же каталоге, где сертификаты ищутся, возможно для быстроты доступа при проверке выданных сертификатов.
ln -s servercert.pem `x509 -noout -hash < servercert.pem`.0
И так, в нашем распоряжении есть ключ сервера (/usr/local/CA/private/serverkey.pem), его сертификат, подписанный неким CA ( в данной ситуации нашим CA)(/usr/local/certs/servercert.pem), и, собственно, сам CA - его ключ (/usr/local/CA/private/cakey.pem), его сертификат подписанный им самим(/usr/local/CA/cacert.pem).

Загрузка сертификата CA в browser

Для того, чтобы browser мог распознавать сертификаты, подписанные вашим CA, необходимо загрузить "самоподписанный" сертификат CA.
При загрузке помните, что после данной процедуры, ваш browser будет безоговорочно ??? принимать все сертификаты подписанные данным CA.
Сертификат CA загружается с использованием HTTP Content-Type application/x-x509-ca-cert. Это можно выполнить, если не привязываться к серверу, используя cgi скрипт. Netscape продукты могут принимать сертификаты, как в PEM, так и в DER формате. В силу неполной реализации работы с DER, SSLeay/OpenSSL в работе использует PEM формат. Но вы можете получить сертификат в DER формате используя команду
crl2pkcs7 -inform PEM -outform DER -certfile $CA_cert.pem -out $CA_cert.der -nocrl
Microsoft IE использует входной формат отличный от pem?????????
Miscrosoft IE5 понимает pem формат.
HTML форма для загрузки CA сертификата.
<HTML><HEAD><TITLE>Load CA Certificate</TITLE></HEAD><BODY> <H1>Load Certificate Authority Certificate</H1> <FORM ACTION="http://example.some.somwere/cgi-bin/loadCAcert.pl" METHOD=post> <TABLE> <TR> <TD>Netscape Browser (PEM Format):</TD> <TD><INPUT TYPE="RADIO" NAME="FORMAT" VALUE="PEM" CHECKED></TD></TR> <TR><TD>Microsoft Browser (DER Format):</TD> <TD><INPUT TYPE="RADIO" NAME="FORMAT" VALUE="DER"></TD></TR> </TABLE> <INPUT TYPE="SUBMIT" VALUE="Load Certificate"> </FORM> </BODY></HTML>
loadCAcert.pl скрипт.

Perl CGI скрипт загрузки CA сертификата
#!/usr/local/bin/perl -T require 5.003; use strict; use CGI; my $cert_dir = "/usr/local/CA/"; my $cert_file = "cacert.pem"; my $query = new CGI; my $kind = $query->param('FORMAT'); if($kind eq 'DER') { $cert_file = "cacert.der"; } my $cert_path = "$cert_dir/$cert_file"; open(CERT, "<$cert_path"); my $data = join '',<CERT>; close(CERT); print "Content-Type: application/x-x509-ca-cert\n"; print "Content-Length: ", length($data), "\n\n$data";
Проверено для Netscape Communicator 4.5 FreeBSD
Также возможно записать сертификат в файл с соответствующим суффиксом и объявить серверу в конфигурации соответствие данного суффикса с MIME типом application/x-x509-ca-cert. Для apache сервера это будет добавление строки AddType application/x-x509-ca-cert .pemв srm.conf если суффикс .pem.
Проверено для Netscape Communicator 4.5 FreeBSD

Apache + SSL

Теперь собственно обратимся к настройке SSL с Apache.

Укажем серверу его ключ: SSLCertificateKeyFile /usr/local/CA/private/serverkey.pem И его сертификат: SSLCertificateFile /usr/local/CA/certs/servercert.pem Далее укажем сертификат для CA и расположение сертификатов которые могут быть использованы для аутентификации. SSLCACertificatePath /usr/local/CA/certs/ SSLCACertificateFile /usr/local/CA/cacert.pem

Сертификаты должны быть в PEM кодировке, в внутри SSLCACertificatePath необходимо иметь для каждого сертификата линк на его hash.
Для того, что бы apache мог воспользоваться своим private key в случае, когда он зашифрован, вам необходимо передать перед стартом серверу секретную фразу, которой был зашифрован ключ. Эта процедура управляется директивой SSLPassPhraseDialog. Она может принимать значения builtin и exec:/path/to/program. В первом варианте при старте сервер запрашивает пароль для расшифровки своего ключа, во втором использует внешнюю программу, для получения пароля, пароль выдается ей на stdout.

Создание сертификатов для клиентов

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

Различные клиенты, такие как Nescape Navigator/Communicator и Microsoft Internet Explorer используют различный механизм для создания клиентских сертификатов.

Процедура создания сертификата представляет собой HTML формы, которые включают в себя вызов CGI скрипта, который вызывает процедуры SSLeay/OpenSSL для получения сертификата.
Последовательность действий такова:

  1. Пользователь запрашивает HTML страницу с формой.
  2. Пользователь вводит идентификационную информацию.
  3. Отправление формы вызывает следующие действия
    1. Browser создает пару ключей (public и private)
    2. Секретный ключ сохраняется в browser
    3. Открытый ключ с идентификационной информацией посылается на сервер.
    4. CGI сервер создает сертификат и пересылает его клиенту.
Вместо автоматической выдачи сертификата CA рекомендуется производить дополнительные проверки на предложенные данные.

HTML форма содержит поля ( с значениями по умолчанию ) для различных "distinguished name" атрибутов, которые используются в сертификате клиента, информация, позволяющая browser сгенерировать пару ключей, скрытые поля, которые зависят то типа browser, позволяющие передать эту информацию для CGI скрипта.

Netscape Navigator/Communicator

В Netscape Navigator форма содержит дополнительный тэг <KEYGEN> Этот тэг создает пару ключей и определяет, что открытый ключ должен быть возвращен как значение формы, когда форма будет исполнена. <KEYGEN> тэг вызывает диалог browser, позволяющий выбрать степень защищенности в зависимости от версии Netscape Navigator/Communicator. Информация формы используется CGI скриптом для создания запроса на сертификацию и этот запрос используется для создания сертификата клиента.
Netscape возвращает "Signed Public Key And Challenge" (SPKAC) открытый ключ, если обнаруживает <KEYGEN> элемент формы. Нижеприведенная форма возвращает его в скрытом SPKAC поле. CGI скрипт затем считывает данные из этого поля и передает SPKAC значение в SSLeay/OpenSSL используя -spkac ключ при вызове ca. (Смотри ns-ca.doc в doc каталоге в поставке SSLeay/OpenSSL).

Форма для запроса Netscape клиентом сертификата
<HTML><HEAD><TITLE>Create Client Certificate</TITLE></HEAD><BODY> <CENTER><H1>Create Client Certificate</H1></CENTER> <FORM NAME="GenerateForm" ACTION="http://example.osf.org/cgi-bin/ns_key.pl"> <TABLE> <TR><TD>Common Name:</TD><TD> <INPUT TYPE="TEXT" NAME="commonName" VALUE="Client Certificate" SIZE=64> </TD></TR> <TR><TD>email:</TD><TD> <INPUT TYPE="TEXT" NAME="emailAddress" VALUE="f.hirsch@opengroup.org" SIZE=40> </TD></TR> <TR><TD>Organization:</TD><TD> <INPUT TYPE="TEXT" NAME="organizationName" VALUE="The Open Group"> </TD></TR> <TR><TD>Organizational Unit:</TD><TD> <INPUT TYPE="TEXT" NAME="organizationalUnitName" VALUE="Research Institute"> </TD></TR> <TR><TD>Locality (City):</TD><TD> <INPUT TYPE="TEXT" NAME="localityName" VALUE="Cambridge"> </TD></TR> <TR><TD>State:</TD><TD> <INPUT TYPE="TEXT" NAME="stateOrProvinceName" VALUE="MA"> </TD></TR> <TR><TD>Country:</TD><TD> <INPUT TYPE="TEXT" NAME="countryName" VALUE="US" SIZE="2"> </TD></TR> </TABLE> <!-- ' keygen is Netscape specific and will be ignored in ' internet explorer --> <KEYGEN NAME="SPKAC" CHALLENGE="challengePassword"> <INPUT TYPE="SUBMIT" NAME="SUBMIT"> </FORM> <P><HR></BODY></HTML>

Perl скрипт для обработки запроса сертификата для Netscape клиента
#!/usr/local/bin/perl require 5.003; use strict; use CGI; use File::CounterFile; # module to maintain certificate request counter my $doc_dir = $ENV{'DOCUMENT_ROOT'}; # apache specific location for storage unless($doc_dir) { print "<HTML><HEAD><TITLE>Failure</TITLE></HEAD>"; print "<BODY>DOCUMENT_ROOT not defined</BODY></HTML>"; exit(0); } my $base_dir = $doc_dir; $base_dir =~ s/\/htdocs//; my $SSLDIR = '/usr/local/ssl'; # define where SSLeay files are located my $CA = "$SSLDIR/bin/ca"; my $CONFIG = "/usr/local/etc/ssleay.cnf"; my $CAPASS = "caKEY"; my $query = new CGI; # get a handle on the form data my $key = $query->param('SPKAC'); # this will fail if not Netscape browser unless($key) { fail("No Key provided $key. Netscape required"); } my $counter = new File::CounterFile("$base_dir/.counter", 1); unless($counter) { fail("Could not create counter: $!"); } my $count = $counter->inc(); my $certs_dir = "$base_dir/certs"; my $req_file = "$certs_dir/cert$count.req"; # certificate request filename my $result_file = "$certs_dir/cert$count.result"; # certificate filename # Explicitly list form fields we must have for certificate creation to work. my @req_names = ('commonName', 'emailAddress', 'organizationName', 'organizationalUnitName', 'localityName', 'stateOrProvinceName', 'countryName', 'SPKAC'); # build the request file open(REQ, ">$req_file") or fail("Could not create request $req_file: $!"); my $name; foreach $name (@req_names) { my $value = $query->param("$name"); $value =~ tr/\n//d; print REQ "$name = $value\n"; } close(REQ); # make sure we actually created a request file unless(-f $req_file) { fail("request missing: $req_file"); } unless(-e $CA) { fail("command missing"); } # ensure that ca command will run # command for processing certificate request, without password my $cmd = "$CA -config $CONFIG -spkac $req_file -out $result_file -days 360"; my $rc = system("$cmd -key $CAPASS 2>errs"); if($rc != 0) { fail("$cmd<P>rc = $rc", "errs"); } open(CERT, "<$result_file") or fail("Could not open $result_file<P>$!"); # send the client certificate to the browser print "Content-Type: application/x-x509-user-cert\n"; my $result = join '', <CERT>; close CERT; my $len = length($result); print "Content-Length: $len\n\n"; print $result; exit(0); sub fail { my($msg, $errs) = @_; print $query->header; print $query->start_html(-title => "Certificate Request Failure"); print "<H2>Certificate request failed</H2>$msg<P>"; if($errs) { if(open(ERR, "<errs")) { while(<ERR>) { print "$_<BR>"; } close ERR; } } print $query->dump(); print $query->end_html(); exit(0); }

CGI скрипт создает файл, содержащий значения для "distinguished name", переданных формой и специальный SPKAC значение для "Signed Public Key And Challenge (SPKAC)" созданное Navigator/Communicator.

SSLeay/OpenSSL ca команда вызывается, используя данный файл в качестве аргумента.(Смотри ns-ca.doc в документации к SSLeay/OpenSSL)

$SSLDIR/bin/ca -spkac $req_file -out $result_file -days 360 -key $CAPASS \ 2>errs
$req_file является именем уникального файла в каталоге сертификатов certs, который содержит запрос на сертификацию, полученный из CGI данных. $result_file является уникальным именем файла в каталоге сертификатов certs, и будет содержать собственно сертификат. $CAPASS Perl переменная содержит CA ключ.
Если ca команда завершилась успешно, то сертификат возвращается через CGI как application/x-x509-user-cert HTTP. Content-Type. Navigator распознает этот тип и производит оставшиеся запросы данных от пользователя для установки сертификата в browser.

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

Краткая терминология

ASN.1:
Abstract Syntax Notation One, as defined in X.208.
BER:
Basic Encoding Rules, as defined in X.209.
Certificate:
A type that binds an entity's distinguished name to a public key with a digital signature. This type is defined in X.509. This type also contains the distinguished name of the certificate issuer (the signer), an issuer- specific serial number, the issuer's signature algorithm identifier, and a validity period.
CertificateSerialNumber:
A type that uniquely identifies a certificate (and thereby an entity and a public key) among those signed by a particular certificate issuer. This type is defined in X.509.
CertificateRevocationList:
A type that contains information about certificates whose validity an issuer has prematurely revoked. The information consists of an issuer name, the time of issue, the next scheduled time of issue, and a list of certificate serial numbers and their associated revocation times. The CRL is signed by the issuer. The type intended by this standard is the one defined RFC 1422.
DER:
Distinguished Encoding Rules for ASN.1, as defined in X.509, Section 8.7.
DES:
Data Encryption Standard, as defined in FIPS PUB 46-1.
desCBC:
The object identifier for DES in cipher-block chaining (CBC) mode, as defined in [NIST91].
ExtendedCertificate:
A type that consists of an X.509 public- key certificate and a set of attributes, collectively signed by the issuer of the X.509 public-key certificate. This type is defined in PKCS #6.
MD2:
RSA Data Security, Inc.'s MD2 message-digest algorithm, as defined in RFC 1319.
md2:
The object identifier for MD2, as defined in RFC 1319.
MD5:
RSA Data Security, Inc.'s MD5 message-digest algorithm, as defined in RFC 1321.
md5:
The object identifier for MD5, as defined in RFC 1321.
Name:
A type that uniquely identifies or "distinguishes" objects in an X.500 directory. This type is defined in X.501. In an X.509 certificate, the type identifies the certificate issuer and the entity whose public key is certified.
PEM:
Internet Privacy-Enhanced Mail, as defined in RFCs 1421-1424.
RSA:
The RSA public-key cryptosystem, as defined in [RSA78].
rsaEncryption:
The object identifier for RSA encryption, as defined in PKCS #1.

To Do

  1. Протестировать созданный CA с MSIE.
  2. Lynx+OpenSSL ???
  3. Протестировать доступ с использованием сертификатов
  4. Как принудительно делать exire на сертификаты
  5. Что такое serial и зачем он нужен
  6. x509 extensions & netscape extensions
  7. Как работать с policy.