Защита беспроводных сетей, WPA: теория и практика (часть шестая)


 

В предпоследней статье речь шла о настройке WPA в доменных сетях Windows. Последняя статья этой серии будет посвящена работе со списком отзывов сертификатов.

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

 

Нижеследующие компоненты будут необходимы для работы:

  • беспроводной клиент — в данном случае использовался ноутбук Toshiba Satellite M40-101 со встроенной беспроводной картой Intel PRO/Wireless 2200BG с установленной операционной системой Windows XP pro + SP2
  • точка доступа с поддержкой WPA — ей являлась Gigabyte GN BR404W
  • RADIUS-сервер — был использован FreeRadius сервер версии 1.1.1, работающий под операционной системой Gentoo Linux.
  • OpenSSL (был использован пакет openssl-0.9.7j)

Использование персональных цифровых сертификатов для аутентификации пользователей — замечательная идея. Один раз создали, выдали пользователю, и он использует его вместо логина и пароля (а точнее, это делает операционная система, "прозрачно" для пользователя). Не нужно помнить пароли и так далее.

Но что делать, если вдруг человек, на персональном ноутбуке которого установлен сертификат, увольняется из компании? Ведь он будет иметь возможность подключаться к беспроводной сети, по крайней мере, до тех пор, пока не истечет срок действия сертификата… а ведь это серьезная дыра в безопасности нашей сети…

Для блокировки таких пользователей (а точнее, их сертификатов) применяется процедура "отзыва сертификата". А точнее, нужный сертификат помечается, как отозванный, после чего создается список всех отозванных сертификатов (под названием CRL — Certificate Revocation List). Этот список распространяется (подключается) ко всем серверам, которые производят аутентификацию пользователей с использованием сертификатов. В нашем случае этим сервером является Radius.

Давайте разберем эту процедуру подробнее.

1. Создание нового пользовательского сертификата.

Для начала создадим новый пользовательский сертификат для пользователя test_user9:


=====================================================


$ ./sign_cert.sh  client_cert test_user9

create certificate key: test_user9.key

Generating RSA private key, 2048 bit long modulus
…+++
…………………………………………+++
e is 65537 (0x10001)
Enter pass phrase for test_user9.key:
Verifying — Enter pass phrase for test_user9.key:

#
# вводим пасс-фразу, которой будет закрыт ключ сертификата пользователя
# create certificate request: test_user9.csr Enter pass phrase for test_user9.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, vega 111 # ./sign_cert.sh client_cert test_user9 ----- 1. Country Name (2 letter code) [RU]: 2. State or Province Name (full name) [Euro]: 3. Locality Name (eg, city) [Moscow]: 4. Organization Name (eg, company) [TempOrg]: 5. Organizational Unit Name (eg, section) [network IT]: 6. Common Name (eg, CA name) [test_user9]: 7. Email Address (eg, name@FQDN) [email@tmp_org.ru]: # # тут вводим данные для заполнения необходимых полей сертификата # (если скрипт sign_cert.sh был настроен, то в данном диалоге # достаточно будет просто жать клавишу Enter) # sign certificate by CA: test_user9.crt (sign ca is: tmp_org-ca) CA signing: test_user9.csr -> test_user9.crt: Using configuration from ca.config Enter pass phrase for ./../tmp_org-ca.key: # # здесь надо ввести парольную фразу, которой был закрыт # приватный ключ корневого сертификата нашего CA # DEBUG[load_index]: unique_subject = "no" Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows countryName :PRINTABLE:'RU' stateOrProvinceName :PRINTABLE:'Euro' localityName :PRINTABLE:'Moscow' organizationName :PRINTABLE:'TempOrg' organizationalUnitName:PRINTABLE:'network IT' commonName :T61STRING:'test_user9' emailAddress :IA5STRING:'email@tmp_org.ru' Certificate is to be certified until Aug 30 15:18:21 2008 GMT (730 days) Write out database with 1 new entries Data Base Updated convertign test_user9 certificate to pkcs12 format Enter pass phrase for test_user9.key: # # последний раз вводим пассфразу для клиентского сертификата
# Enter Export Password: Verifying — Enter Export Password: # # вводим пароль, который понадобится при импортировании # пользовательского сертификата в Windows-е # CA verifying: test_user9.crt <-> CA cert test_user9.crt: OK =====================================================

Сертификат готов. Переносим его (и корневой сертификат) на клиентскую машину, устанавливаем их, согласно описанному тут и тут алгоритму.

2. Настройка профиля беспроводной сети и точки доступа

Настраиваем профиль беспроводной сети (если это еще не было сделано).

Не забываем настроить точку доступа на работу с WPA совместно с Radius-сервером.

Теперь переходим к самому интересному — настройке Radius-сервера на работу совместно со списком отзыва сертификатов. 

3. Настройка Radius для работы со списком отзыва сертификатов.

3.1 Создание CRL-списка.

Запускаем скрипт (подробнее о нем рассказывалось в третьей части) с параметром "regen_crl" — для создания списка отозванных сертификатов:


./sign_cert.sh  regen_crl

regen crl

Using configuration from ca.config
Enter pass phrase for ./../tmp_org-ca.key:

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

В результате отработки, скрипт создаст нам файл "tmp_org-ca.crl", который и содержит список всех отозванных ранее сертификатов (а точнее, файл содержит лишь серийные номера оных). Если сертификаты еще не отзывались, список будет пуст. Если часть сертификатов уже отзывалась, содержимое файла будет, например, таким (так выглядит список отзыва, если щелкнуть мышкой по этому файлу в Windows):

Особенно интересны тут два поля:

  • действителен с — с какого момента список отзыва будет действителен
  • действителен по — после этого числа список отзыва будет недействителен и его необходимо будет обновить (если этого не сделать, то тот же Radius, с включенной проверкой на отозванные сертификаты, заругается на то, что crl-файл не найден и всем клиентам будет отказано в аутентификации)

Дату "действительности" сертификата можно задать в переменной CRL_DAYS, внутри sign_cert.sh скрипта.

На закладке "список отзыва" можно посмотреть серийные номера сертификатов и дату их отзыва.

В нашем случае три сертификата, из ранее созданных, уже были отозваны (с серийными номерами 03, 06, 0а), поэтому они и фигурируют в списке CRL.

В юникс просмотреть созданный список отзыва можно так:

#=====================================================
# openssl ca -gencrl -out tmp_org-ca.crl
#=====================================================

Основная проблема при генерации CRL-списка — пароль корневого сертификата всегда приходится вводить вручную (или прописать жестко в скрипте). То есть либо ручной ввод, либо пароль лежит в открытом виде. Первое — неудобно, второе — небезопасно.

Теперь необходимо подключить CRL к нашему Radius-серверу. Так как в конфигурационном файле Radius отсутствует переменная, хранящая путь именно к CRL-файлу, необходимо добавить содержимое этого файла к корневому сертификату нашего центра CA. Делаем это. 

3.2 Создание файла CRL для Radius.

#=====================================================
# cp -f tmp_org-ca.crl /etc/raddb/ssl/
#
# копируем CRL-файл в директорию, где располагаются все 
# сертификаты нашего Radius-сервера
#
# cd /etc/raddb/ssl
# 
# переходим в эту директорию
#
# cat tmp_org-ca.crt > tmp_org-ca.crt_with_crl
#
# копируем содержимое корневого сертификата в файл  tmp_org-ca.crt_with_crl
# (файл при этом создается заново)
#
# cat tmp_org-ca.crl >> tmp_org-ca.crt_with_crl
#
# добавляем к содержимому файла tmp_org-ca.crt_with_crl содержимое CRL-файла
#
#=====================================================

В результате этих действий у нас получился файл tmp_org-ca.crt_with_crl, который содержит корневой сертификат нашего центра CA и список отзыва сертификатов.  

3.3 Настройка Radius на работу с CRL-списками

Теперь обновим конфигурационный файл для Radius. Открываем

/etc/raddb/eap.conf

и в секции tls{ } раздела eap{ } прописываем

#----------------------------------------------------
#
#  Trusted Root CA list
#CA_file = /etc/raddb/ssl/tmp_org/tmp_org-ca.crt
#
# старое значение переменной CA_file закомментировано
#
CA_file = /etc/raddb/ssl/tmp_org-ca.crt_with_crl
#
# обновили путь к CA-файлу
#
#
#  Check the Certificate Revocation List
#  1) Copy CA certificates and CRLs to same directory.
#  2) Execute 'c_rehash '.
#    'c_rehash' is OpenSSL's command.
#  3) Add 'CA_path='
#      to radiusd.conf's tls section.
#  4) uncomment the line below.
#  5) Restart radiusd

check_crl = yes

# 
# добавили (или раскомментировали) переменную check_crl
# установили ее в "yes"
#
#----------------------------------------------------

После перезапуска Radius-а (radiusd -X) сервер готов проверять CRL-списки.

4. Проверка возможности подключения пользователя с валидным сертификатом.

Сначала попробуем подключиться с использованием валидного (неотозванного) сертификата (test_user9):

 


#=====================================================
rad_recv: Access-Request packet from host 192.168.1.254:2048, id=0, length=182
        Message-Authenticator = 0xf4710cf8c7bfa44269baf29799913c4e
        Service-Type = Framed-User
        User-Name = "test_user9"
        Framed-MTU = 1488
        Called-Station-Id = "00-20-ED-07-7F-0B:GIGABYTE"
        Calling-Station-Id = "00-0E-35-EE-67-0F"
        NAS-Port-Type = Wireless-802.11
        Connect-Info = "CONNECT 54Mbps 802.11g"
        EAP-Message = 0x0200000f01746573745f7573657239
        NAS-IP-Address = 192.168.1.254
        NAS-Port = 1
        NAS-Port-Id = "STA port # 1"
		
<.......>
		
rlm_eap_tls: Received EAP-TLS ACK message
  rlm_eap_tls: ack handshake is finished
  eaptls_verify returned 3
  eaptls_process returned 3
  rlm_eap: Freeing handler
  modcall[authenticate]: module "eap" returns ok for request 13
modcall: leaving group authenticate (returns ok) for request 13
Login OK: [test_user9/] 
(from client test_ap port 1 cli 00-0E-35-EE-67-0F)
Sending Access-Accept of id 6 to 192.168.1.254 port 2048
        Framed-IP-Address = 255.255.255.254
        Framed-MTU = 576
        Service-Type = Framed-User
        MS-MPPE-Recv-Key = 0xefdb50b0db0cc990710<.......>
        MS-MPPE-Send-Key = 0x43f35a2b6a83afc716e<.......>
        EAP-Message = 0x03060004
        Message-Authenticator = 0x00000000000000000000000000000000
        User-Name = "test_user9"
Finished request 13
		
		

#=====================================================

Как видно, подключение к беспроводной сети с использованием сертификата test_user9 прошло успешно.

Теперь попробуем отозвать этот сертификат.

5. Отзыв сертификата.

Отзываем сертификат test_user9:

#=====================================================
./sign_cert.sh  revoke_cert test_user9

revoke certificate test_user9.crt

Using configuration from ca.config
Enter pass phrase for ./../tmp_org-ca.key:
#
# необходимо ввести пассфразу на корневой сертификат нашего CA
#
DEBUG[load_index]: unique_subject = "no"
Revoking Certificate 0B.
Data Base Updated
#
# сертификат был отозван и помечен в базе
#
regen crl
#
# теперь генерируем CRL-список заново
#
Using configuration from ca.config
Enter pass phrase for ./../tmp_org-ca.key:
#
# еще раз вводим пассфразу для корневого CA.
#
#=====================================================

Посмотрим на полученный новый CRL-файл:

Как видно, у него, по сравнению со старым, немного изменилось время, с которого он действителен (с текущего момента — то есть момента создания).

А в списке отзыва появился еще один элемент, с индексом 0b. Это и есть отозванный нами сертификат test_user9:

Посмотрим серийный номер нашего отозванного сертификата:

Все верно, test_user9 имеет серийный номер 0b.

Так как crl-файл был сгенерирован заново, нужно обновить файл, содержащий crl-список и корневой сертификат для Radius-а. То есть действуем аналогично уже написанному.

Не забываем после этого рестартовать Radius.

6. Кратко о формате хранения данных по сертификатам

А база данных по сертификатам у OpenSSL выглядит очень просто — это текстовый файл (в нашем случае — ca.db.index), который содержит следующее:

#----------------------------------------------------
V       071209120518Z           01      unknown /C=RU/
ST=Euro/L=Moscow/O=TempOrg/OU=network IT/
CN=radius.tmp_org.ru/emailAddress=email@tmp_org.ru
V       071209123124Z           02      unknown /C=RU<.......>
R       071209123227Z   051213115133Z   03      unknown /C=RU<.......>
V       071209143947Z           04      unknown /C=RU<.......>
V       071213113137Z           05      unknown /C=RU<.......>
R       071213115005Z   051213120125Z   06      unknown <.......>
V       071216103544Z           07      unknown /C=RU<.......>
V       080829140940Z           08      unknown /C=RU<.......>
V       080829141011Z           09      unknown /C=RU<.......>
R       080830151400Z   060831151547Z   0A      unknown /C=RU<.......>
R       080830151821Z   060831165555Z   0B      unknown /C=RU
/ST=Euro/L=Moscow/O=TempOrg/OU=network IT
/CN=test_user9/emailAddress=email@tmp_org.ru
#----------------------------------------------------

В этом файле построчно перечислены все сертификаты с их индексами. В данном случае нас интересует первая буква — R или V. Если "R" — значит, сертификат помечен, как отозванный. Если "V" — значит сертификат валиден. На основе этой информации OpenSSL и создает CRL-список.

7. Попытка подключения с использованием отозванного сертификата.

Попробуем вновь подключиться к беспроводной сети, используя все тот же сертификат test_user9. Но на этот раз сертификат фигурирует в CRL списке.


#=====================================================

<.......>

rad_recv: Access-Request packet from host 192.168.1.254:2051, id=5, length=248
        Message-Authenticator = 0xd2825733a3dbe4e316263d0c2e21b2a3
        Service-Type = Framed-User
        User-Name = "test_user9"
        Framed-MTU = 1488
        State = 0xfd12e050711787dd6917fe4de35abef9
        Called-Station-Id = "00-20-ED-07-7F-0B:GIGABYTE"
        Calling-Station-Id = "00-0E-35-EE-67-0F"
        NAS-Port-Type = Wireless-802.11
        Connect-Info = "CONNECT 54Mbps 802.11g"
        EAP-Message = 0x0205003f0d0030a8fbf<.......>
        NAS-IP-Address = 192.168.1.254
        NAS-Port = 1
        NAS-Port-Id = "STA port # 1"
  Processing the authorize section of radiusd.conf
modcall: entering group authorize for request 5
  modcall[authorize]: module "preprocess" returns ok for request 5
  modcall[authorize]: module "chap" returns noop for request 5
  modcall[authorize]: module "mschap" returns noop for request 5
    rlm_realm: No '@' in User-Name = "test_user9", looking up realm NULL
    rlm_realm: No such realm "NULL"
  modcall[authorize]: module "suffix" returns noop for request 5
  rlm_eap: EAP packet type response id 5 length 63
  rlm_eap: No EAP Start, assuming it's an on-going EAP conversation
  modcall[authorize]: module "eap" returns updated for request 5
    users: Matched entry DEFAULT at line 152
    users: Matched entry DEFAULT at line 171
  modcall[authorize]: module "files" returns ok for request 5
modcall: leaving group authorize (returns updated) for request 5
  rad_check_password:  Found Auth-Type EAP
auth: type "EAP"
  Processing the authenticate section of radiusd.conf
modcall: entering group authenticate for request 5
  rlm_eap: Request found, released from the list

#
# переходим к проверке клиентского сертификата
#

  rlm_eap: EAP/tls
  rlm_eap: processing type tls
  rlm_eap_tls: Authenticate
  rlm_eap_tls: processing TLS
  eaptls_verify returned 7
  rlm_eap_tls: Done initial handshake
  rlm_eap_tls: <<< TLS 1.0 Handshake [length 03c5], Certificate
--> verify error:num=23:certificate revoked
  rlm_eap_tls: >>> TLS 1.0 Alert [length 0002], fatal certificate_revoked
TLS Alert write:fatal:certificate revoked

#
# ошибка — клиентский сертификат содержится в списке отозванных
#

    TLS_accept:error in SSLv3 read client certificate B
27670:error:140890B2:SSL routines:SSL3_GET_CLIENT_CERTIFICATE:no certificate returned:s3_srvr.c:2015
:
rlm_eap_tls: SSL_read failed in a system call (-1), TLS session fails.
In SSL Handshake Phase
In SSL Accept mode
  eaptls_process returned 13
  modcall[authenticate]: module "eap" returns handled for request 5
modcall: leaving group authenticate (returns handled) for request 5
Sending Access-Challenge of id 5 to 192.168.1.254 port 2051
        Framed-IP-Address = 255.255.255.254
        Framed-MTU = 576
        Service-Type = Framed-User
        EAP-Message = 0x010600110d80000000071503010002022c
        Message-Authenticator = 0x00000000000000000000000000000000
        State = 0x49a47117763404fa043e38b3ffc9d750
Finished request 5
Going to the next request
Waking up in 5 seconds…
rad_recv: Access-Request packet from host 192.168.1.254:2051, id=6, length=191
        Message-Authenticator = 0x19bca273353b9936cbd0a07ae47df289
        Service-Type = Framed-User
        User-Name = "test_user9"
        Framed-MTU = 1488
        State = 0x49a47117763404fa043e38b3ffc9d750
        Called-Station-Id = "00-20-ED-07-7F-0B:GIGABYTE"
        Calling-Station-Id = "00-0E-35-EE-67-0F"
        NAS-Port-Type = Wireless-802.11
        Connect-Info = "CONNECT 54Mbps 802.11g"
        EAP-Message = 0x020600060d00
        NAS-IP-Address = 192.168.1.254
        NAS-Port = 1
        NAS-Port-Id = "STA port # 1"
  Processing the authorize section of radiusd.conf
modcall: entering group authorize for request 6
  modcall[authorize]: module "preprocess" returns ok for request 6
  modcall[authorize]: module "chap" returns noop for request 6
  modcall[authorize]: module "mschap" returns noop for request 6
    rlm_realm: No '@' in User-Name = "test_user9", looking up realm NULL
:
  modcall[authorize]: module "suffix" returns noop for request 6
  modcall[authorize]: module "suffix" returns noop for request 6
  rlm_eap: EAP packet type response id 6 length 6
  rlm_eap: No EAP Start, assuming it's an on-going EAP conversation
  modcall[authorize]: module "eap" returns updated for request 6
    users: Matched entry DEFAULT at line 152
    users: Matched entry DEFAULT at line 171
  modcall[authorize]: module "files" returns ok for request 6
modcall: leaving group authorize (returns updated) for request 6
  rad_check_password:  Found Auth-Type EAP
auth: type "EAP"
  Processing the authenticate section of radiusd.conf
modcall: entering group authenticate for request 6
  rlm_eap: Request found, released from the list
  rlm_eap: EAP/tls
  rlm_eap: processing type tls
  rlm_eap_tls: Authenticate
  rlm_eap_tls: processing TLS
rlm_eap_tls: Received EAP-TLS ACK message
  rlm_eap_tls: ack alert
  eaptls_verify returned 4
  eaptls_process returned 4
 rlm_eap: Handler failed in EAP/tls
  rlm_eap: Failed in EAP select
  modcall[authenticate]: module "eap" returns invalid for request 6
modcall: leaving group authenticate (returns invalid) for request 6
auth: Failed to validate the user.
Login incorrect: [test_user9/] (from client test_ap port 1 cli 00-0E-35-
EE-67-0F)

#
# в доступе клиенту отказано
#

Delaying request 6 for 1 seconds
Finished request 6

#=====================================================

Таким образом, если Radius видит, что клиентский сертификат отозван, то клиенту отказывают в доступе — именно то, что нам надо. Главное — не забывать вовремя перегенерировать CRL-списки и не ждать их устаревания. 

На этом, полагаю, цикл статей о настройке WPA шифрования с использованием Radius сервера под Linux можно завершить. Разумеется, если появится дополнительная информация, не отраженная в этом материале, свет увидит и седьмая, а возможно и последующие статьи… а пока — поставим в материале точку. 

Навигация

 




Дополнительно

iXBT BRAND 2016

«iXBT Brand 2016» — Выбор читателей в номинации «Процессоры (CPU)»:
Подробнее с условиями участия в розыгрыше можно ознакомиться здесь. Текущие результаты опроса доступны тут.

Нашли ошибку на сайте? Выделите текст и нажмите Shift+Enter

Код для блога бета

Выделите HTML-код в поле, скопируйте его в буфер и вставьте в свой блог.