CryptodevATECCx08 Auth: различия между версиями

Материал из Wiren Board
(не показано 15 промежуточных версий 5 участников)
Строка 1: Строка 1:
<languages/>
<translate>
== Использование встроенного чипа ATECCx08 для авторизации на внешних сервисах. == <!--T:1-->


<!--T:2-->
== Использование встроенного чипа ATECCx08 для авторизации на внешних сервисах. ==
 
В контроллеры '''WirenBoard''' встроен чип '''ATECCx08''', назначением которого является генерация ключевых пар, хранение приватных ключей а также операции асимметричного шифрования с использованием эллиптических кривых.
В контроллеры '''WirenBoard''' встроен чип '''ATECCx08''', назначением которого является генерация ключевых пар, хранение приватных ключей а также операции асимметричного шифрования с использованием эллиптических кривых.
Приватный ключ после начальной инициализации хранится в микросхеме и не покидает ее, тем самым исключается его компрометация.
Приватный ключ после начальной инициализации хранится в микросхеме и не покидает ее, тем самым исключается его компрометация.


<!--T:3-->
Используя данную микросхему можно организовать авторизацию контроллера и защиту соединения по SSL на внешних сервисах и быть уверенным, что запрос выполнен с использованием именно этого экземпляра микросхемы.
Используя данную микросхему можно организовать авторизацию контроллера и защиту соединения по SSL на внешних сервисах и быть уверенным, что запрос выполнен с использованием именно этого экземпляра микросхемы.


<!--T:4-->
В данной статье пойдет речь о трех вариантах применения: '''nginx''', '''openssl''', '''mosquitto'''.
В данной статье пойдет речь о трех вариантах применения: '''nginx''', '''openssl''', '''mosquitto'''.


<!--T:5-->
Для доступа к криптоустройству нужна библиотека libateccssl1.1, установим ее командой:
Для доступа к криптоустройству нужна библиотека libateccssl1.1, установим ее командой:


<!--T:6-->
'''apt install libateccssl1.1'''
'''apt install libateccssl1.1'''


<!--T:7-->
Далее нужно отредактировать файл '''/etc/ssl/openssl.cnf''', добавив в нем следующие строчки:
Далее нужно отредактировать файл '''/etc/ssl/openssl.cnf''', добавив в нем следующие строчки:


<!--T:8-->
<pre>
<pre>
openssl_conf = openssl_init
openssl_conf = openssl_init


<!--T:9-->
[openssl_init]
[openssl_init]
engines        = engine_section
engines        = engine_section


<!--T:10-->
[engine_section]
[engine_section]
ateccx08 = ateccx08_section
ateccx08 = ateccx08_section


<!--T:11-->
[ateccx08_section]
[ateccx08_section]
init = 1
init = 1
</pre>
</pre>


<!--T:12-->
Теперь приступим к созданию сертификатов.
Теперь приступим к созданию сертификатов.
Для начала создадим свой центр сертификации (Certification Authority, '''CA'''):
Для начала создадим свой центр сертификации (Certification Authority, '''CA'''):


<!--T:13-->
Для этого сгенерируем ключевую пару:
Для этого сгенерируем ключевую пару:
<pre>openssl genrsa -out ca.key 2048</pre>


<!--T:14-->
'''openssl genrsa -out ca.key 2048'''
 
И сертификат нашего '''CA''':
И сертификат нашего '''CA''':


<!--T:15-->
'''openssl req -x509 -new -days 3650 -key ca.key -out ca.crt -subj "/CN=MY CA"'''
<pre>openssl req -x509 -new -days 3650 -key ca.key -out ca.crt -subj "/CN=MY CA"</pre>


<!--T:16-->
'''CA''' является основой безопасности в данной схеме, поэтому эти операции выполняем на машине доступ к которой
'''CA''' является основой безопасности в данной схеме, поэтому эти операции выполняем на машине доступ к которой
есть только у владельца '''CA'''.
есть только у владельца '''CA'''.


<!--T:17-->
Далее на конроллере WB создаем запрос на сертификат устройства:
Далее на конроллере WB создаем запрос на сертификат устройства:


openssl req -new -engine ateccx08 -keyform engine -key ATECCx08:00:04:C0:00 -subj "/CN=wirenboard-AP6V5MDG" -out device_AP6V5MDG.csr


<!--T:18-->
Для Wiren Board 7:
<pre>openssl req -new -engine ateccx08 -keyform engine -key ATECCx08:00:02:C0:00 -subj "/CN=wirenboard-AP6V5MDG" -out device_AP6V5MDG.csr</pre>
Для Wiren Board 6:
<pre>openssl req -new -engine ateccx08 -keyform engine -key ATECCx08:00:04:C0:00 -subj "/CN=wirenboard-AP6V5MDG" -out device_AP6V5MDG.csr</pre>
<!--T:19-->
В этой команде мы указываем, что запрос подписывается приватным ключом, находящимся в криптоустройстве ateccx08 ключом
В этой команде мы указываем, что запрос подписывается приватным ключом, находящимся в криптоустройстве ateccx08 ключом
с идентификатором '''ATECCx08:00:02:C0:00''' и публичным именем wirenboard-AP6V5MDG. Запрос помещаем в файл device_AP6V5MDG.csr.
с идентификатором ATECCx08:00:04:C0:00 и публичным именем wirenboard-AP6V5MDG. Запрос помещаем в файл device_AP6V5MDG.csr.


<!--T:20-->
Имя можно выбрать любое уникальное, удобно для этой цели спользовать идентификатор устройства, который по умолчанию прописывается
Имя можно выбрать любое уникальное, удобно для этой цели спользовать идентификатор устройства, который по умолчанию прописывается
в файле /etc/hostname:
в файле /etc/hostname:


<!--T:21-->
<pre>
cat /etc/hostname
cat /etc/hostname
wirenboard-AP6V5MDG
wirenboard-AP6V5MDG
</pre>


<!--T:22-->
Далее этот запрос подписываем в нашем центре сертификации:
Далее этот запрос подписываем в нашем центре сертификации:
openssl x509 -req -in device_AP6V5MDG.csr -CA ca.crt -CAkey ca.key -out device_AP6V5MDG.crt -days 365 -CAcreateserial
openssl x509 -req -in device_AP6V5MDG.csr -CA ca.crt -CAkey ca.key -out device_AP6V5MDG.crt -days 365 -CAcreateserial


<!--T:23-->
В этой команде мы уазываем файл запроса, и файлы CA необходимые для подписи. В итоге получаем сертификат устройства device_AP6V5MDG.crt.
В этой команде мы уазываем файл запроса, и файлы CA необходимые для подписи. В итоге получаем сертификат устройства device_AP6V5MDG.crt.
Файл '''device_AP6V5MDG.crt''' копируем на контроллер WB, он будет необходим для авторизацци.
Файл device_AP6V5MDG.crt копируем на контроллер WB, он будет необходим для авторизацци.


<!--T:24-->
Давайте посмотрим, что содержится в файлах сертификатов CA и устройства:
Давайте посмотрим, что содержится в файлах сертификатов CA и устройства:
<!--T:25-->
<pre>
openssl x509 -text -noout -in device_AP6V5MDG.crt
<!--T:26-->
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            bf:85:29:be:19:67:f5:3e
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = MY CA
        Validity
            Not Before: Feb  4 14:50:14 2019 GMT
            Not After : Feb  4 14:50:14 2020 GMT
        Subject: CN = wirenboard-AP6V5MDG
        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:66:80:f6:83:ea:4f:88:a5:05:df:8f:2c:62:f3:
                    ad:71:55:87:7f:ae:12:ae:b1:74:4b:68:68:fd:f7:
                    e0:8a:f4:44:87:45:ab:c1:07:3f:54:2a:a9:ea:c6:
                    71:1d:41:63:67:1b:75:f4:00:42:8d:fd:f6:d5:b6:
                    52:38:e8:5a:a9
                ASN1 OID: prime256v1
                NIST CURVE: P-256
    Signature Algorithm: sha256WithRSAEncryption
        be:d1:f8:04:fb:34:a9:84:ff:25:b6:04:04:c0:f1:1d:4a:a4:
        04:b8:54:6c:a8:46:61:5f:6c:e7:ab:16:8f:ae:45:46:02:99:
        c6:d3:90:42:91:20:c7:89:d5:cf:4e:23:3a:33:64:ab:1b:c9:
        78:18:82:f4:39:8b:97:ae:6c:ee:a4:13:0c:5a:54:6b:69:c8:
        1e:fa:24:3d:48:2c:ea:0e:5c:0d:c3:43:c2:49:ea:b2:f8:5e:
        d7:0b:b5:4e:67:87:53:84:76:23:aa:10:77:5d:f1:21:9e:b0:
        4b:16:99:7c:d4:d3:d6:e7:00:9c:bf:53:a1:4b:f4:2c:fc:0b:
        64:10:fb:77:fc:3d:b2:71:cf:be:0b:b1:a2:62:ed:8c:92:e4:
        78:73:dc:69:c4:61:10:22:66:11:11:8b:d4:3c:b6:4f:7f:2c:
        24:07:61:47:15:2a:56:7e:71:69:59:15:8b:53:c8:e2:b5:ed:
        34:a0:78:70:d4:f6:cf:0f:6d:df:45:00:3b:0a:39:a2:fb:e7:
        89:f3:d9:88:7f:6b:bd:fa:ca:5e:44:94:74:70:5e:86:0b:93:
        ca:16:71:42:67:eb:77:bd:15:e3:90:2f:68:fd:bc:61:25:a3:
        a6:e7:8b:b1:42:bc:c2:36:d4:17:67:b3:77:fb:bd:06:e9:35:
        3b:8e:08:48
</pre>
<!--T:27-->
Видим, что сертификат выписан Центром сертификации с именем "MY CA" на 1 год, начная с "Feb  4 14:50:14 2019 GMT" (для этого мы указывали -days 365 в команде подписи),
устройству с именем '''wirenboard-AP6V5MDG''', имеющим приватный ключ соответствующий публичному Subject Public Key Info.
Сертификат подписан цифровой подписью.
<!--T:28-->
Цифровая подпись гарантирует, что никакая часть сертификата не может быть незаметно изменена. В случае изменения проверка публичным
ключом '''CA''' даст ошибку.
<!--T:29-->
<pre>
openssl x509 -text -noout -in ca.crt
<!--T:30-->
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            d9:e0:91:e7:d0:27:02:db
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: CN = MY CA
        Validity
            Not Before: Feb  4 14:30:01 2019 GMT
            Not After : Feb  1 14:30:01 2029 GMT
        Subject: CN = MY CA
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:c8:5e:02:b8:55:e5:42:97:f7:c6:53:61:d3:df:
                    66:bf:05:dd:7a:0c:61:a4:68:36:23:3f:3b:c7:83:
                    ec:47:9b:5a:ed:78:8a:5b:f1:5f:88:3d:36:f2:3e:
                    7b:84:9e:1b:e5:87:bf:3b:00:33:36:1c:0b:3a:16:
                    2f:8d:be:0e:a4:9e:25:73:4d:93:8a:47:74:29:65:
                    0e:4e:ea:44:fd:c4:c0:bf:fa:bc:11:d5:93:43:e2:
                    65:18:bb:f7:e5:fc:16:8c:f9:11:97:76:2c:bb:cb:
                    c0:94:7e:78:12:20:c9:8a:68:29:c1:e8:af:7e:d7:
                    63:6e:a3:57:79:c9:b3:a8:8c:a3:2d:3e:15:1a:25:
                    ea:f1:50:fc:ea:93:8f:14:5f:34:61:07:a9:dc:24:
                    b8:11:de:9c:17:13:03:19:0d:0c:a3:e8:10:31:50:
                    82:5b:cb:0e:26:d5:b1:fe:df:c3:f6:f9:e4:0f:b1:
                    24:40:f2:8d:95:d5:ea:34:b3:27:a1:87:76:9d:f2:
                    65:74:d5:40:47:dd:a1:32:46:c3:37:ec:a5:b3:09:
                    30:73:99:d1:9c:bb:a8:05:61:2a:56:89:32:5e:c0:
                    5d:1d:b6:a6:b6:74:17:be:74:69:9c:b0:e3:bc:b4:
                    f9:96:6d:aa:60:ae:70:d1:ee:07:e5:2c:5d:0a:af:
                    ce:b3
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                53:4B:6D:7A:1A:1F:F8:BE:3F:59:64:70:2B:31:2F:7A:7F:2A:6B:14
            X509v3 Authority Key Identifier:
                keyid:53:4B:6D:7A:1A:1F:F8:BE:3F:59:64:70:2B:31:2F:7A:7F:2A:6B:14
            <!--T:31-->
X509v3 Basic Constraints: critical
                CA:TRUE
    Signature Algorithm: sha256WithRSAEncryption
        30:c2:f3:e0:96:51:7d:13:be:06:1d:40:06:70:b8:36:e9:46:
        81:64:0c:f0:e7:69:6f:31:2c:e1:86:df:f8:ad:b2:84:6e:90:
        4a:38:48:7d:ae:92:a5:71:40:c8:8e:0f:7e:67:e5:66:e7:70:
        4d:52:92:fa:a6:54:45:3b:a6:b9:b3:f4:35:ad:1c:6e:6e:15:
        06:81:ef:13:54:80:89:2e:7d:75:06:22:59:89:44:a9:ad:25:
        30:6c:02:e1:3b:2e:e2:bc:46:90:d1:a5:00:eb:87:57:60:a4:
        cf:e0:03:4a:b5:32:c4:dc:c7:e3:34:d4:c8:af:e3:ce:20:8c:
        c4:7f:f0:b8:72:d7:65:3b:38:be:2b:b1:d0:4e:9e:e2:52:32:
        41:fe:22:d2:7c:13:60:fe:4a:13:4b:c5:09:f0:00:89:32:22:
        47:4d:2c:a1:21:8e:b2:7d:0f:1a:10:f5:94:ee:fb:18:d3:15:
        f1:9e:70:89:73:c4:41:71:0e:92:22:9c:18:ef:0b:b1:7c:42:
        41:e7:9f:e7:82:d5:db:f3:60:d3:2f:2a:86:e4:0c:c0:4c:0c:
        17:12:ec:e4:37:96:dc:2d:01:00:22:ac:b5:33:6b:97:41:d7:
        37:e5:75:fa:c9:6b:00:2a:d8:87:0f:9e:f3:aa:c5:23:4e:60:
        02:a9:5b:eb
</pre>
<!--T:32-->
Видим, что сертификат подписан сам своим-же приватным ключом (Issuer: CN = MY CA, Subject: CN = MY CA)
и выписан на 10 лет: начная с "Feb  4 14:30:01 2019 GMT" (для этого мы указывали -days 3650 в команде подписи)
<!--T:33-->
Таким образом цепочка доверия (проверки) выстраивается следующим образом:
<!--T:34-->
Сертификат устройства подписан сертификатом CA и может быть им проверен:
<pre>
openssl verify -CAfile ca.crt device_AP6V5MDG.crt
device_AP6V5MDG.crt: OK
</pre>
<!--T:35-->
Ну а сам сертификат подписан "собой":
<pre>
openssl verify -CAfile ca.crt ca.crt
ca.crt: OK
</pre>
'''
== Проверка сертификатов на сервере с помощью nginx . == <!--T:36-->
<!--T:37-->
Допустим в интернете есть сервер, который должен обрабатывать запросы только от устройств обладающих сертификатами,
выписанными нашим CA.
Для включения такой проверки в конфигурационном файле nginx необходимо в секции http или server прописать следующие строчки:
<!--T:38-->
<pre>
  ssl_client_certificate  ca.crt;
  ssl_verify_client      on;
</pre>
<!--T:39-->
Теперь nginx будет требовать от клиента сертификат, который должен проходить проверку с помощью ca.crt, иначе сервер
вернет клиенту ошибку 400:
<!--T:40-->
<pre>
curl https://example.com
<html>
<head><title>400 No required SSL certificate was sent</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<center>No required SSL certificate was sent</center>
<hr><center>nginx/1.14.0 (Ubuntu)</center>
</body>
</html>
</pre>
Nginx в такой конфигурации удобно использовать на сервере перед реальным сервисом, которые не поддерживают проверку клиентских сертификатов. Для этого нужно настроить proxy_pass на сам сервис и, например, добавить в заголовки серийный номер контроллера через переменную <code>$ssl_client_s_dn</code> или весь клиентский сертификат целиком.
== Добавление поддержки клиентских сертификатов к произвольным сервисам на контроллере ==
Часто программы на контролелере не поддерживают TLS совсем, либо не поддерживают указание клиентских сертификатов, либо не поддерживают работу с openssl engine.
Можно отправить обращения от таких программ к серверу сквозь локальный прокси, который будет оборачивать трафик в TLS с использованием аппаратных ключей.
Вместе с рецептом из предыдущего пункта, это позволяет реализовать аутентификацию по аппаратному ключу практически для любого клиент-серверного ПО.
<!--T:41-->
Теперь сделаем так, чтобы HTTP запросы с контроллера WB проходили данную проверку.
Для простоты будем использовать nginx и на клиентской стороне. Это даст возможность работать
с защищенными серверами клиентам не умеющим делать SSL соединения.
<!--T:42-->
Для начала создадим на неиспользуемом локальном порту http сервер, который будет делать
всю https "магию" за нас:
<!--T:43-->
<pre>
server {
    listen 8080;
    location / {
        proxy_pass                https://example.com;
        proxy_ssl_name            example.com;
        proxy_ssl_server_name      on;
        proxy_ssl_certificate      device_AP6V5MDG.crt;
        proxy_ssl_certificate_key  engine:ateccx08:ATECCx08:00:04:C0:00;
    } 
}
</pre>
<!--T:44-->
Добавим пользователя www-data в группу i2c для доступа к криптоустройству:
<pre>
usermod -G www-data
</pre>
<!--T:45-->
Выполним команду '''service nginx restart''' для обновления конфигурации.
<!--T:46-->
Теперь при обращении по http на локальный порт 8080 зашифрованные запросы с аутентификационной
информацией будут отправлятся на сервер example.com.
<!--T:47-->
<pre>
curl localhost:8080/
<html>
<body>
EXAMPLE.COM
</body>
</html>
</pre>
== Настройка openvpn == <!--T:48-->
<!--T:49-->
Для начала установим пакет:
<!--T:50-->
<pre>
apt install openvpn
</pre>
<!--T:51-->
Cоздадим файл req.cnf - он нам потребуется для создания сертификата сервера.
<pre>
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
</pre>
<!--T:52-->
Серверу openvpn также требуется файл с параметрами DH, сделаем его.
<pre>
openssl dhparam -out dh2048.pem 2048
</pre>
<!--T:53-->
Создание данного файла может потребовать несколько минут.
<!--T:54-->
Далее сделаем приватный ключ нашего сервера и запрос на сертификат. Предполагаем, для примера, что
сервер имеет имя example.com:
<!--T:55-->
<pre>
openssl genrsa -out example.key 2048
<!--T:56-->
openssl req -new -key example.key -subj "/CN=example.com" -out example.csr
</pre>
<!--T:57-->
Подписываем запрос в нашем центре сертификации:
<!--T:58-->
<pre>
openssl x509 -req -in example.csr -CA ca.crt -CAkey ca.key -out example.crt -days 365 -CAcreateserial -extfile req.cnf -extensions v3_req
</pre>
<!--T:59-->
Теперь приступим к настройке openvpn сервера на машине example.com.
<!--T:60-->
Копируем файлы '''ca.crt''', '''example.crt''', '''example.key''' и '''dh2048.pem''' и редактируем файл конфигурации openvpn сервера.
По умолчанию конфигурационный файл лежит в файле /etc/openvpn/server.conf
<!--T:61-->
<pre>
port 1194
proto tcp
dev tun
ca          /etc/openvpn/server/ca.crt
cert        /etc/openvpn/server/example.crt
key        /etc/openvpn/server/example.key
dh          /etc/openvpn/server/dh2048.pem
topology subnet
server 10.8.0.0 255.255.255.0
keepalive 10 60
key-direction 0
cipher AES-128-CBC
auth SHA256
comp-lzo
user nobody
group nogroup
persist-key
persist-tun
status /var/run/openvpn/openvpn-status.log
management 127.0.0.1 7500
log-append  /var/log/openvpn.log
</pre>
<!--T:62-->
Добавим пользователя openvpn в группу i2c для доступа к криптоустройству:
<!--T:63-->
<pre>
usermod -G www-data
</pre>
<!--T:64-->
после этого запускаем сервер командой
service openvpn start.
<!--T:65-->
Далее на контроллере создаем файл конфигурации клиента:
client.ovpn:
<pre>
-------------------------------------------------------------------------
client
dev tun
proto tcp
remote example.com 1194
resolv-retry infinite
nobind
user openvpn
'''group i2c'''
persist-key
persist-tun
cipher AES-128-CBC
auth SHA256
key-direction 1
keepalive 1 10
remote-cert-tls server
comp-lzo
-------------------------------------------------------------------------
</pre>
Обратите внимание на строчку group i2c. Она необходима для работы с криптоустройством.
<!--T:66-->
После этого запускаем клиента:
<!--T:67-->
<pre>
openvpn --config example.ovpn --ca ca.crt --cert device_AP6V5MDG.crt --key engine:ateccx08:ATECCx08:00:04:C0:00
</pre>
<!--T:68-->
Если все хорошо, то в системе должен появиться интерфейс tun0 с адресом из подсети 10.8.0.0/24:
<!--T:69-->
<pre>
tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST>  mtu 1500
        inet 10.8.0.2  netmask 255.255.255.0  destination 10.8.0.2
        inet6 fe80::53b0:83f3:b1f5:b817  prefixlen 64  scopeid 0x20<link>
        unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  txqueuelen 100  (UNSPEC)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 6  bytes 288 (288.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
</pre>
<!--T:70-->
Для проверки работоспособности запускаем ping:
<!--T:71-->
<pre>
ping 10.8.0.1
PING 10.8.0.1 (10.8.0.1) 56(84) bytes of data.
64 bytes from 10.8.0.1: icmp_seq=1 ttl=64 time=2.23 ms
64 bytes from 10.8.0.1: icmp_seq=2 ttl=64 time=2.83 ms
</pre>
== Настройка mosquitto == <!--T:72-->
<!--T:73-->
UPD:
<!--T:74-->
1) openssl.cnf
<!--T:75-->
2)  mosquitto=1.4.15-1+wb7-4
<!--T:76-->
3) libateccssl1.1=0.2.1
<!--T:77-->
4) ca-certificates-contactless
<!--T:78-->
5) usermod -a -G i2c mosquitto
<!--T:79-->
<pre>
root@wirenboard-APIJVTIG:~# cat /etc/mosquitto/conf.d/bridge-hw.conf
connection wb_devices_cloud.wirenboard-APIJVTIG
address contactless.ru:8884
<!--T:80-->
bridge_cafile  /etc/ssl/certs/WirenBoard_Root_CA.pem
bridge_certfile /etc/ssl/device/device_bundle.crt.pem
bridge_keyfile  engine:ateccx08:ATECCx08:00:04:C0:00
bridge_capath /etc/ssl/certs/
bridge_insecure true
<!--T:81-->
notifications true
notification_topic /client/wirenboard-APIJVTIG/bridge_status
<!--T:82-->
topic /devices/#  both 2 "" /client/wirenboard-APIJVTIG
topic /config/#  both 2 "" /client/wirenboard-APIJVTIG
topic /rpc/#  both 2 "" /client/wirenboard-APIJVTIG
</pre>
<!--T:83-->
<pre>
root@wirenboard-APIJVTIG:~# cat fix.sh
#!/bin/bash -x
CERT_IN=/etc/ssl/certs/device_bundle.crt.pem
CERT_OUT=/etc/ssl/device/device_bundle.crt.pem
CERT_BKP=/etc/ssl/device/_device_bundle.crt.pem
<!--T:84-->
prn() {
    cat $CERT_IN|grep "$1" -n|sed -n "$2p"|cut -d':' -f1
}
<!--T:85-->
fix() {
    B1=$(prn "BEGIN CERTIFICATE" 1)
    B2=$(prn "BEGIN CERTIFICATE" 2)
    E1=$(prn "END CERTIFICATE" 1)
    E2=$(prn "END CERTIFICATE" 2)
    <!--T:86-->
if [[ "$E1" -le "$B1" || "$E2" -le "$B2" || "$E1" -ge "$B2" ]]; then
        echo "ERROR in device cert bundle."
        exit 1
    fi
    <!--T:87-->
cat $CERT_IN|sed -n "${B2},${E2}p"
    cat $CERT_IN|sed -n "${B1},${E1}p"
}
<!--T:88-->
mkdir -p /etc/ssl/device
<!--T:89-->
if [ -f "$CERT_IN" ]; then
    echo "backup device bundle certificate..."
    cp "$CERT_IN" "$CERT_BKP"
fi
<!--T:90-->
if [ ! -f "$CERT_OUT" ]; then
    if [ ! -f "$CERT_IN" ]; then
        echo "ERROR: no such file: $CERT_IN"
        exit 1
    fi
    fix > "$CERT_OUT"
    echo "Device bundle certificate fix done."
    rm -f "${CERT_IN}"
else
    echo "Device cert $CERT_OUT already fixed."
fi
</pre>
<!--T:91-->
Генерируем приватный ключ и запрос на сертификат:
<!--T:92-->
<pre>
openssl genrsa -out example.key 2048
openssl req -new -key example.key -subj "/CN=example.com" -out example.csr
</pre>
<!--T:93-->
Создаем сертификат сервера в CA.
<pre>
openssl x509 -req -in example.csr -CA ca.crt -CAkey ca.key -out example.crt -days 365 -CAcreateserial -extfile req.cnf -extensions v3_req
</pre>
<!--T:94-->
Копируем файлы '''ca.crt''', '''mosquitto.crt''', '''mosquitto.key''' на сервер и редактируем файл конфигурации '''/etc/mosquitto/conf.d/server.conf'''
<!--T:95-->
<pre>
cafile                      /etc/mosquitto/ssl/ca.crt
certfile                    /etc/mosquitto/ssl/mosquitto.crt
keyfile                    /etc/mosquitto/ssl/mosquitto.key
require_certificate        true
use_identity_as_username    true
</pre>
<!--T:96-->
Запускаем серис:
<pre>
service mosquitto start
</pre>
<!--T:97-->
Также, если требуется, можно сделать чтобы локальный mosquitto сервер на контроллере
форвардил некоторые топики на удаленный сервер. Для этого создаем файл бриджа: '''/etc/mosquitto/bridge.conf'''
<!--T:98-->
<pre>
connection main
topic test/# out
address example.com:1883
<!--T:99-->
bridge_cafile      /etc/mosquitto/certs/ca.crt
bridge_certfile    /etc/mosquitto/certs/device_AP6V5MDG.crt
bridge_keyfile      engine:ateccx08:ATECCx08:00:04:C0:00
</pre>
<!--T:100-->
После перезапуска локального сервиса mosquitto топики /test/.. будут отправлятся на удаленный сервер example.com
по защищенному ssl каналу.
<!--T:101-->
Примеры клиентских команд mosquitto.
Отправка сообщения "message" в топик "test" на сервере example.com
<!--T:102-->
<pre>
mosquitto_pub -h example.com --cert device_AP6V5MDG.crt --key 'engine:ateccx08:ATECCx08:00:04:C0:00' --cafile ca.crt -t "test" -m "message"
</pre>
<!--T:103-->
Получение сообщений из топика "test" на сервере example.com
<!--T:104-->
<pre>
mosquitto_sub -h example.com --cert device_AP6V5MDG.crt --key 'engine:ateccx08:ATECCx08:00:04:C0:00' -t "test" --cafile ca.crt
</pre>
== Полезные ссылки ==
[https://habr.com/ru/companies/oleg-bunin/articles/476304/ Аутентификация устройств на Linux по аппаратному ключу в системах верхнего уровня]
</translate>

Версия 17:48, 5 февраля 2019

Использование встроенного чипа ATECCx08 для авторизации на внешних сервисах.

В контроллеры WirenBoard встроен чип ATECCx08, назначением которого является генерация ключевых пар, хранение приватных ключей а также операции асимметричного шифрования с использованием эллиптических кривых. Приватный ключ после начальной инициализации хранится в микросхеме и не покидает ее, тем самым исключается его компрометация.

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

В данной статье пойдет речь о трех вариантах применения: nginx, openssl, mosquitto.

Для доступа к криптоустройству нужна библиотека libateccssl1.1, установим ее командой:

apt install libateccssl1.1

Далее нужно отредактировать файл /etc/ssl/openssl.cnf, добавив в нем следующие строчки:

openssl_conf = openssl_init

[openssl_init]
engines         = engine_section

[engine_section]
ateccx08 = ateccx08_section

[ateccx08_section]
init = 1

Теперь приступим к созданию сертификатов. Для начала создадим свой центр сертификации (Certification Authority, CA):

Для этого сгенерируем ключевую пару:

openssl genrsa -out ca.key 2048

И сертификат нашего CA:

openssl req -x509 -new -days 3650 -key ca.key -out ca.crt -subj "/CN=MY CA"

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

Далее на конроллере WB создаем запрос на сертификат устройства:

openssl req -new -engine ateccx08 -keyform engine -key ATECCx08:00:04:C0:00 -subj "/CN=wirenboard-AP6V5MDG" -out device_AP6V5MDG.csr

В этой команде мы указываем, что запрос подписывается приватным ключом, находящимся в криптоустройстве ateccx08 ключом с идентификатором ATECCx08:00:04:C0:00 и публичным именем wirenboard-AP6V5MDG. Запрос помещаем в файл device_AP6V5MDG.csr.

Имя можно выбрать любое уникальное, удобно для этой цели спользовать идентификатор устройства, который по умолчанию прописывается в файле /etc/hostname:

cat /etc/hostname wirenboard-AP6V5MDG

Далее этот запрос подписываем в нашем центре сертификации: openssl x509 -req -in device_AP6V5MDG.csr -CA ca.crt -CAkey ca.key -out device_AP6V5MDG.crt -days 365 -CAcreateserial

В этой команде мы уазываем файл запроса, и файлы CA необходимые для подписи. В итоге получаем сертификат устройства device_AP6V5MDG.crt. Файл device_AP6V5MDG.crt копируем на контроллер WB, он будет необходим для авторизацци.

Давайте посмотрим, что содержится в файлах сертификатов CA и устройства: