Подтвердить что ты не робот

Проверка подлинности SSL-сертификата NGinx, подписанная промежуточным CA (цепочкой)

Я пытаюсь включить аутентификацию сертификата клиента в nginx, где сертификаты были подписаны промежуточным центром сертификации. Я могу получить эту работу отлично при использовании сертификата, подписанного самозаверяющим корневым центром сертификации; однако это не работает, когда подпись CA является промежуточным CA.

Мой простой раздел сервера выглядит следующим образом:

server {
    listen       443;
    server_name  _;

    ssl                  on;
    ssl_certificate      cert.pem;
    ssl_certificate_key  cert.key;

    ssl_session_timeout  5m;

    ssl_protocols  SSLv2 SSLv3 TLSv1;
    ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
    ssl_prefer_server_ciphers   on;

    ssl_client_certificate ca.pem;
    ssl_verify_client on;
    ssl_verify_depth 1;

    location / {
        root   html;
        index  index.html index.htm;
    }
}

Для содержимого ca.pem я попытался использовать только промежуточный CA, а также конкатенацию промежуточного сертификата CA и корневого CA cert, то есть что-то вроде:

cp intermediate.crt ca.pem
cat root.crt >> ca.pem

Я также подтвердил, что сертификат действителен с точки зрения openssl при использовании той же самой цепочки CA:

openssl verify -CAfile /etc/nginx/ca.pem certs/client.crt 
certs/client.crt: OK

Я экспериментировал с установкой ssl_verify_depth явно на 1 (как указано выше), а затем даже на 0 (не уверен, что именно это число означает точно), но все равно получает ту же ошибку.

Ошибка, которую я получаю во всех вариантах промежуточного CA, это "400 Bad Request" и, более конкретно, "Ошибка сертификата SSL" (не уверен, что именно это означает).

Может, nginx просто не поддерживает цепочки сертификатов для промежуточных сертификатов? Любая помощь очень ценится!

4b9b3361

Ответ 1

Изменить: у меня также была эта "проблема", решение и объяснение находятся внизу текста.

Казалось, что nginx не поддерживает промежуточные сертификаты. Мои сертификаты сами создаются: (RootCA самонастраивается, IntrermediateCA1 подписывается RootCA и т.д.)

RootCA -> IntermediateCA1 -> Client1 
RootCA -> IntermediateCA2 -> Client2

Я хочу использовать в nginx "IntermediateCA1", чтобы разрешить доступ к сайту только владельцу сертификата "Client1".

Когда я помещаю в файл ssl_client_certificate с IntermediateCA1 и RootCA и устанавливаю "ssl_verify_depth 2" (или более), клиенты могут заходить на сайт с использованием сертификата Client1 и Client2 (должен только Client1). Тот же результат, когда я помещал в файл ssl_client_certificate с только RootCA - оба клиента могут войти в систему.

Когда я помещаю в файл ssl_client_certificate с только IntermediateCA1 и устанавливаю "ssl_verify_depth 1" (или "2" или более - неважно), невозможно войти в систему, я получаю ошибку 400. И в режиме отладки я вижу журналы:

verify:0, error:20, depth:1, subject:"/C=PL/CN=IntermediateCA1/[email protected]",issuer: "/C=PL/CN=RootCA/[email protected]"
verify:0, error:27, depth:1, subject:"/C=PL/CN=IntermediateCA1/[email protected]",issuer: "/C=PL/CN=RootCA/[email protected]"
verify:1, error:27, depth:0, subject:"/C=PL/CN=Client1/[email protected]",issuer: "/C=PL/CN=IntermediateCA1/[email protected]"
(..)
client SSL certificate verify error: (27:certificate not trusted) while reading client request headers, (..)

Я считаю, что это ошибка. Протестировано на Ubuntu, nginx 1.1.19 и 1.2.7-1 ~ dotdeb.1, openssl 1.0.1. Я вижу, что у nginx 1.3 есть несколько вариантов использования клиентских сертификатов, но я не вижу решения этой проблемы.

В настоящее время единственным способом разделить клиентов 1 и 2 является создание двух самонастраиваемых RootCAs, но это только обходное решение.

Изменить 1: Я сообщил об этом здесь: http://trac.nginx.org/nginx/ticket/301

Изменить 2 " * Хорошо, это не ошибка, это функция;) *

Я получаю ответ здесь: http://trac.nginx.org/nginx/ticket/301 Он работает, вы должны только проверить, что ваш ssl_client_i_dn (вместо эмитента вы можете использовать также тему сертификата или что вы хотите от http://wiki.nginx.org/HttpSslModule#Built-in_variables

Вот как работает проверка сертификата: сертификат должен быть проверен до доверенного корня. Если цепочка не может быть построена для надежного root (не промежуточное) - проверка не выполняется. Если вы доверяете root - все сертификаты, подписанные им, прямо или косвенно, будут успешно проверена.

Ограничение глубины проверки может быть использовано, если вы хотите ограничить клиентские сертификаты непосредственно выпущенными сертификатами только, но это больше о DoS-профилактике, и, очевидно, это не может быть используется для ограничения верификации только промежуточным1 (но не intermediate2).

Что вы хотите здесь, это некоторый уровень на основе авторизации на результат проверки - т.е. вы можете проверить, что клиент эмитент сертификата является промежуточным. Простейшим решением было бы отклонять запросы, если DN эмитента не соответствует одному разрешенному, например. что-то вроде этого (полностью непроверено):

[Редактировать меня, он работает правильно в моей конфигурации]

server {
    listen 443 ssl;

    ssl_certificate ...
    ssl_certificate_key ...

    ssl_client_certificate /path/to/ca.crt;
    ssl_verify_client on;
    ssl_verify_depth 2;

    if ($ssl_client_i_dn != "/C=PL/CN=IntermediateCA1/[email protected]") {
        return 403;
    }
}

Ответ 2

Вы пытались увеличить директиву ssl_verify_depth? Docs сказать:

(it) sets a verification depth in the client certificates chain.

Но ваша глубина проверки равна 1. Вы говорите:

Я экспериментировал с установкой ssl_verify_depth явно на 1 (как указано выше), а затем даже на 0 (не уверен, что именно это число означает точно), но все равно получает ту же ошибку.

Итак, попробуйте 2 или 3..

PS: Везде, где я нахожу эту проблему упомянутой, ее сказали объединить промежуточные сертификаты ЦС с сертификатом сервера. в один файл (как @vikas-nalwar предложил и вы это сделали) в порядке проверки (но я не уверен, имеет ли порядок порядок) и грубо говоря набор ssl_verify_depth количеству сертификатов в комплекте.

Ответ 3

Я считаю, что вы хотите включить проверку клиента на своей стороне сервера. Если это так, я не вижу, что у вас есть клиентский сертификат в цепочке. Попробуйте следующее в том же порядке. Используйте certchain.pem.

  cat client.crt > certchain.pem
  cat intermediate.crt >> certchain.pem
  cat root.crt >> certchain.pem

Ответ 4

поскольку я боролся с nginx и cloudflare,
эти строки сделали трюк для меня:

ssl_client_certificate    /etc/nginx/ssl/ca-bundle-client.crt;  
ssl_verify_client optional_no_ca;  
ssl_verify_depth 2;

вторая строка с optional_no_ca является важной частью

Ответ 5

Я должен сказать, что он работает отлично для меня с nginx/1.13.2, т.е.

  • У меня есть один корневой ЦС, который подписал два промежуточных ЦС
  • оба промежуточных элемента, каждый из которых подписан клиентом
  • Я соглашаюсь с сертификатами вроде cat client-intermediate1.crt ca-client.crt > ca.chained1.crt и cat client-intermediate2.crt ca-client.crt > ca.chained2.crt и cat ca.chained1.crt ca.chained2.crt > ca.multiple.intermediate.crt

  • если я только поставлю ca.chained1.crt как ssl_client_certificate, тогда только client1.crt может подключаться, аналогично для ca.chained2.crt/client2.crt

  • Когда я использую ca.multiple.intermediate.crt, тогда оба клиента могут подключиться

для отзыва промежуточного элемента просто удалите цепочку сертификатов из c.multiple.intermediate.crt

вот соответствующая конфигурация. он также имеет высокие настройки безопасности

# minimum settings for ssl client auth 
ssl_client_certificate /etc/ssl/ca.multiple.intermediate.crt;
ssl_verify_client on;
ssl_verify_depth 2;

# ssl high security settings (as of writing this post)
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_ecdh_curve secp384r1;
ssl_session_cache shared:SSL:10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload";
add_header X-Frame-Options DENY;
add_header X-Content-Type-Options nosniff;

если вы хотите разобрать сертификаты CN и передать их на бэкэнд, затем добавьте этот OUTSIDE в блок server {..

# parse out CN
map $ssl_client_s_dn $ssl_client_s_dn_cn {
    default "should_not_happen";
    ~CN=(?<CN>[^,]+) $CN;
}

и ВСТАВЛЯЙТЕ блок, который вы можете использовать, затем

# add headers for backend containing SSL DN/CN
add_header X-SSL-client-s-dn $ssl_client_s_dn;
add_header X-SSL-client-s-dn_cn $ssl_client_s_dn_cn;

Ответ 6

еще один простой способ - объединить сертификаты (включая сертификаты домена) в одном файле и использовать их на своих серверах и файл nginx conf

cat www.example.com.crt bundle.crt > www.example.com.chained.crt

Всегда помните, что сначала используйте сертификат сервера, а затем только сертификаты сервера сертификации

Вы можете узнать больше о http://nginx.org/en/docs/http/configuring_https_servers.html#chains