Я пытаюсь настроить stunnel
чтобы предоставить оболочку TLS для службы HTTP, которая изначально не поддерживает TLS. У меня это хорошо работает без использования клиентских сертификатов TLS.
При добавлении конфигурации сертификата клиента:
CAfile = /path/to/trusted.crt
verify = 4
Кажется, я не могу подключиться, используя openssl s_client
. (Обратите внимание, что я немного обманываю - использую сертификат моего TLS-сервера в качестве сертификата клиента, но в сертификате указано, что у него есть расширение для X509v3 Extended Key Usage: TLS Web Client Authentication, TLS Web Server Authentication
, поэтому я считаю, что это должно сработать.)
$ openssl s_client -state -connect [my-host-name]:[port] -cert [my-host-name].crt -key [my-host-name].key-nopass
CONNECTED(00000003)
SSL_connect:before/connect initialization
SSL_connect:SSLv2/v3 write client hello A
SSL_connect:SSLv3 read server hello A
depth=2 C = IL, O = StartCom Ltd., OU = Secure Digital Certificate Signing, CN = StartCom Certification Authority
verify return:1
depth=1 C = IL, O = StartCom Ltd., OU = StartCom Certification Authority, CN = StartCom Class 1 DV Server CA
verify return:1
depth=0 CN = [my-hostname]
verify return:1
SSL_connect:SSLv3 read server certificate A
SSL_connect:SSLv3 read server key exchange A
SSL_connect:SSLv3 read server certificate request A
SSL_connect:SSLv3 read server done A
SSL_connect:SSLv3 write client certificate A
SSL_connect:SSLv3 write client key exchange A
SSL_connect:SSLv3 write certificate verify A
SSL_connect:SSLv3 write change cipher spec A
SSL_connect:SSLv3 write finished A
SSL_connect:SSLv3 flush data
SSL3 alert read:fatal:unknown CA
SSL_connect:failed in SSLv3 read server session ticket A
140391435724640:error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca:s3_pkt.c:1293:SSL alert number 48
140391435724640:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake failure:s23_lib.c:184:
---
Certificate chain
0 s:/CN=[my-host-name]
i:/C=IL/O=StartCom Ltd./OU=StartCom Certification Authority/CN=StartCom Class 1 DV Server CA
1 s:/C=IL/O=StartCom Ltd./OU=StartCom Certification Authority/CN=StartCom Class 1 DV Server CA
i:/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority
2 s:/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority
i:/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Certification Authority
---
Server certificate
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
subject=/CN=[my-host-name]
issuer=/C=IL/O=StartCom Ltd./OU=StartCom Certification Authority/CN=StartCom Class 1 DV Server CA
---
Acceptable client certificate CA names
/C=[the actual client cert I'd like to use]
/CN=[my-host-name] (for testing)
Server Temp Key: ECDH, prime256v1, 256 bits
---
SSL handshake has read 5620 bytes and written 1937 bytes
---
New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-SHA
Server public key is 3072 bit
Secure Renegotiation IS supported
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : ECDHE-RSA-AES256-SHA
Session-ID:
Session-ID-ctx:
Master-Key: [...]
Key-Arg : None
Krb5 Principal: None
PSK identity: None
PSK identity hint: None
Start Time: 1465393332
Timeout : 300 (sec)
Verify return code: 0 (ok)
---
(На этом этапе соединение закрыто.)
Если я установлю verify = 0
в конфигурации stunnel соединение успешно, и я могу сделать запрос. Если я установлю verify = 1
в stunnel
конфигурации соединение разрывается, если я предоставляю сертификат клиента, но принимается, если я его не предоставляю.
Таким образом, похоже, что что-то не так с самим сертификатом (для тестирования это тот же сертификат, который используется для сервера TLS, поэтому я не думаю, что с ним что-то не так) или с моей конфигурацией того, как проверить сертификат.
Я хочу проверять только те сертификаты, которые действительно присутствуют в моем trusted.crts
файл. Эти строки отладки наводят меня на мысль, что я правильно указал сертификаты (это вывод от клиента):
Acceptable client certificate CA names
/C=[the actual client cert I'd like to use]
/CN=[my-host-name] (for testing)
Поскольку мой сертификат для тестирования присутствует в этом списке, я полагаю, что он должен быть приемлемым.
Я не уверен, что мне не хватает.
В /var/log/secure
, stunnel
регистрирует это:
Jun 8 13:58:59 ip-10-0-0-176 stunnel: LOG5[17497:139964729063168]: Service [mysvc] accepted connection from 52.203.5.20:57224
Jun 8 13:58:59 ip-10-0-0-176 stunnel: LOG4[17497:139964729063168]: CERT: Verification error: unable to get local issuer certificate
Jun 8 13:58:59 ip-10-0-0-176 stunnel: LOG4[17497:139964729063168]: Certificate check failed: depth=0, /CN=[my-host-name]
Jun 8 13:58:59 ip-10-0-0-176 stunnel: LOG3[17497:139964729063168]: SSL_accept: 140890B2: error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned
Jun 8 13:58:59 ip-10-0-0-176 stunnel: LOG5[17497:139964729063168]: Connection reset: 0 byte(s) sent to SSL, 0 byte(s) sent to socket
Это выглядит как stunnel
пытается проверить сертификат по ЦС, вместо того, чтобы напрямую доверять сертификату, который находится в моем trusted.crts
файл.
Какие-либо предложения?
ОБНОВИТЬ
Если я уйду verify = 4
в stunnel
файл конфигурации, но поместите родительский сертификат клиентского сертификата (тот, что от StartCom) в trusted.crts
файл, я могу подключиться, используя свой тестовый сертификат. Если я перейду на использование verify = 3
с тестовым сертификатом и его подписывающей стороной в trusted.crts
файл, я снова не могу подключиться.
Есть ли способ дать stunnel
точные сертификаты, которые я готов принять от клиентов? В документации предлагается использовать verify = 3
или verify = 4
это способ сделать это, но я не могу заставить его работать так, как я думаю, я должен быть в состоянии.
Этот ответ не проверен, поскольку я только начинаю использовать stunnel, но из документации я думаю:
а) вам следует отказаться от verify
вариант, так как он либо неполный, либо не такой ясный, как verifyChain
и verifyPeer
варианты и он устарел:
verify = LEVEL
verify the peer certificate
This option is obsolete and should be replaced with the verifyChain
and verifyPeer options.
б) verifyChain
следует проверить цепочку сертификатов, используя указанное в CAfile
или в файле внутри CApath
. Для цепочки с промежуточными сертификатами все промежуточные сертификаты должны быть действительны для корня CA, который должен содержаться в коллекциях CA (файл или путь).
в) verifyPeer
проверяет, должен ли сам сертификат содержаться в CAfile
или CApath
.
Обратите внимание, что на самом деле, без ссылки на расширения, корневой сертификат CA - это просто самозаверяющий сертификат с установленным флагом CA значением yes. Конечно, такие сертификаты CA не входят в набор доверенных CA, обычно распространяемых с браузерами или в операционной системе. В Linux путь CApath, в котором openssl хранит доверенные центры сертификации (/etc/ssl/certs
) следует проверить на соответствие стандартному набору доверенных сертификатов. Конечно, вы также можете добавить туда свой собственный CA.
Условия /C
и /CN
являются частью субъекта сертификатов, где /C
это страна и /CN
это общее имя. См. Вывод
openssl x509 -noout -subject </etc/ssl/certs/Deutsche_Telekom_Root_CA_2.pem
subject=C = DE, O = Deutsche Telekom AG, OU = T-TeleSec Trust Center, CN = Deutsche Telekom Root CA 2
Например. Опять же: эти корневые сертификаты полезны только в том случае, если вы используете verifyChain=yes
. Если вариант verifyPeer=yes
проверяется сам сертификат, если вы установите для обоих значение «Да», будут проверены как корневой, так и одноранговый сертификаты, возможно, со всеми промежуточными (не отмеченными).
Из stunnel (8):
cert = CERT_FILE
certificate chain file name
The parameter specifies the file containing certificates used by
stunnel to authenticate itself against the remote client or server.
The file should contain the whole certificate chain starting from
the actual server/client certificate, and ending with the self-
signed root CA certificate. The file must be either in PEM or P12
format.
Я предполагаю, что сертификаты корневого ЦС на самом деле не обязательно должны содержаться в цепочке. В большинстве конфигураций этого нет, но знать всю цепочку следует рассматривать как хорошее достоинство, так почему бы не добавить ее в файл!
Теперь мы можем проверить, действителен ли сертификат, но мы все еще не знаем, как проверить, действительно ли сертификат принадлежит одноранговому узлу. Одноранговый узел мог украсть действующий сертификат и пытается использовать его сейчас.
В stunnel теперь есть:
checkEmail
, чтобы проверить DN
(отличительное имя или имя каталога) в теме или в расширении альтернативного имени субъекта (rfc822Name (см. RFC280)) (X509v3).
checkHost
проверьте DNS-имя сертификата. Это может быть сложно или непригодно для проверки сертификатов клиента.
checkIP
, IP-адрес сертификата проверяется.
В руководстве говорится "Certificates are accepted if no subject checks where specified"
. На самом деле я этого не понимаю, потому что считаю checkIP
, checkHost
и checkEmail
поля являются "subject checks"
и трудно указать checkEmail
предмет проверки, а "no subject checks are specified"
.
Я полагаю, они имеют в виду «никакой другой предметной проверки». Конечно, если предметная проверка не указана, сертификат должен быть действительным.
Обратите внимание, что хост и IP-адрес из сертификата проверяются, и нет ни слова о том, сравнивается ли он с именем хоста или IP-адресом однорангового узла при подключении, как это делается при связи с серверами HTTPS, где CN должен соответствовать Имя хоста или DNS-имя в альтернативных вариантах или IP-адрес в альтернативных вариантах.
Все эти побочные случаи не тестировались, и они могли пропустить часть документации.
Также предметные проверки излишни, если вы используете verifyPeer
так как verifyPeer
содержит полный одноранговый сертификат с темой и альтернативами и так далее.
Я не вижу, чтобы поля использования сертификата где-то проверялись. Если да, то этот пункт отсутствует в документации!
Я выложу обновление, когда проверю все боковые корпуса.