CryptodevATECCx08 Auth/en: различия между версиями
(Новая страница: «To do this, generate a key pair: <pre>openssl genrsa -out ca.key 2048</pre>») |
(Новая страница: «And certificate of our '''CA''':») |
||
Строка 34: | Строка 34: | ||
<pre>openssl genrsa -out ca.key 2048</pre> | <pre>openssl genrsa -out ca.key 2048</pre> | ||
And certificate of our '''CA''': | |||
<pre>openssl req -x509 -new -days 3650 -key ca.key -out ca.crt -subj "/CN=MY CA"</pre> | <pre>openssl req -x509 -new -days 3650 -key ca.key -out ca.crt -subj "/CN=MY CA"</pre> |
Версия 14:42, 18 июля 2019
Using the built-in chip ATECCx08 for authorization on external services.
Built-in chip for Wiren Board controllers ATECCx08 generates key pairs, storing the private keys and an asymmetric encryption operation using elliptic curves. After initial initialization private key is stored in the chip and does not leave it, thus eliminating its compromise.
Using this chip, you can organize the authorization of the controller and SSL connection protection on external services and be sure that the request is made using this particular instance of the chip.
This article will focus on three applications: nginx, openssl, mosquitto.
To access the crypto device needs a library libateccssl1.1, install it with the command:
apt install libateccssl1.1
Next you need to edit the /etc/ssl/openssl.cnf' file, adding the following lines:
openssl_conf = openssl_init [openssl_init] engines = engine_section [engine_section] ateccx08 = ateccx08_section [ateccx08_section] init = 1
Now let's start creating certificates. First, we will create our own Certification Authority (CA):
To do this, generate a key pair:
openssl genrsa -out ca.key 2048
And certificate of our 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 и устройства:
openssl x509 -text -noout -in device_AP6V5MDG.crt 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
Видим, что сертификат выписан Центром сертификации с именем "MY CA" на 1 год, начная с "Feb 4 14:50:14 2019 GMT" (для этого мы указывали -days 365 в команде подписи), устройству с именем wirenboard-AP6V5MDG, имеющим приватный ключ соответствующий публичному Subject Public Key Info. Сертификат подписан цифровой подписью.
Цифровая подпись гарантирует, что никакая часть сертификата не может быть незаметно изменена. В случае изменения проверка публичным ключом CA даст ошибку.
openssl x509 -text -noout -in ca.crt 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 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
Видим, что сертификат подписан сам своим-же приватным ключом (Issuer: CN = MY CA, Subject: CN = MY CA) и выписан на 10 лет: начная с "Feb 4 14:30:01 2019 GMT" (для этого мы указывали -days 3650 в команде подписи)
Таким образом цепочка доверия (проверки) выстраивается следующим образом:
Сертификат устройства подписан сертификатом CA и может быть им проверен:
openssl verify -CAfile ca.crt device_AP6V5MDG.crt device_AP6V5MDG.crt: OK
Ну а сам сертификат подписан "собой":
openssl verify -CAfile ca.crt ca.crt ca.crt: OK
Настройка nginx.
Допустим в интернете есть сервер, который должен обрабатывать запросы только от устройств обладающих сертификатами, выписанными нашим CA. Для включения такой проверки в конфигурационном файле nginx необходимо в секции http или server прописать следующие строчки:
ssl_client_certificate ca.crt; ssl_verify_client on;
Теперь nginx будет требовать от клиента сертификат, который должен проходить проверку с помощью ca.crt, иначе сервер вернет клиенту ошибку 400:
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>
Теперь сделаем так, чтобы HTTP запросы с контроллера WB проходили данную проверку. Для простоты будем использовать nginx и на клиентской стороне. Это даст возможность работать с защищенными серверами клиентам не умеющим делать SSL соединения.
Для начала создадим на неиспользуемом локальном порту http сервер, который будет делать всю https "магию" за нас:
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; } }
Добавим пользователя www-data в группу i2c для доступа к криптоустройству:
usermod -G www-data
Выполним команду service nginx restart для обновления конфигурации.
Теперь при обращении по http на локальный порт 8080 зашифрованные запросы с аутентификационной информацией будут отправлятся на сервер example.com.
curl localhost:8080/ <html> <body> EXAMPLE.COM </body> </html>
Настройка openvpn
Для начала установим пакет:
apt install openvpn
Cоздадим файл req.cnf - он нам потребуется для создания сертификата сервера.
[ v3_req ] basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment extendedKeyUsage = serverAuth, clientAuth
Серверу openvpn также требуется файл с параметрами DH, сделаем его.
openssl dhparam -out dh2048.pem 2048
Создание данного файла может потребовать несколько минут.
Далее сделаем приватный ключ нашего сервера и запрос на сертификат. Предполагаем, для примера, что сервер имеет имя example.com:
openssl genrsa -out example.key 2048 openssl req -new -key example.key -subj "/CN=example.com" -out example.csr
Подписываем запрос в нашем центре сертификации:
openssl x509 -req -in example.csr -CA ca.crt -CAkey ca.key -out example.crt -days 365 -CAcreateserial -extfile req.cnf -extensions v3_req
Теперь приступим к настройке openvpn сервера на машине example.com.
Копируем файлы ca.crt, example.crt, example.key и dh2048.pem и редактируем файл конфигурации openvpn сервера. По умолчанию конфигурационный файл лежит в файле /etc/openvpn/server.conf
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
Добавим пользователя openvpn в группу i2c для доступа к криптоустройству:
usermod -G www-data
после этого запускаем сервер командой service openvpn start.
Далее на контроллере создаем файл конфигурации клиента: client.ovpn:
------------------------------------------------------------------------- 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 -------------------------------------------------------------------------
Обратите внимание на строчку group i2c. Она необходима для работы с криптоустройством.
После этого запускаем клиента:
openvpn --config example.ovpn --ca ca.crt --cert device_AP6V5MDG.crt --key engine:ateccx08:ATECCx08:00:04:C0:00
Если все хорошо, то в системе должен появиться интерфейс tun0 с адресом из подсети 10.8.0.0/24:
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
Для проверки работоспособности запускаем ping:
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
Настройка mosquitto
UPD:
1) openssl.cnf
2) mosquitto=1.4.15-1+wb7-4
3) libateccssl1.1=0.2.1
4) ca-certificates-contactless
5) usermod -a -G i2c mosquitto
root@wirenboard-APIJVTIG:~# cat /etc/mosquitto/conf.d/bridge-hw.conf connection wb_devices_cloud.wirenboard-APIJVTIG address contactless.ru:8884 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 notifications true notification_topic /client/wirenboard-APIJVTIG/bridge_status topic /devices/# both 2 "" /client/wirenboard-APIJVTIG topic /config/# both 2 "" /client/wirenboard-APIJVTIG topic /rpc/# both 2 "" /client/wirenboard-APIJVTIG
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 prn() { cat $CERT_IN|grep "$1" -n|sed -n "$2p"|cut -d':' -f1 } fix() { B1=$(prn "BEGIN CERTIFICATE" 1) B2=$(prn "BEGIN CERTIFICATE" 2) E1=$(prn "END CERTIFICATE" 1) E2=$(prn "END CERTIFICATE" 2) if [[ "$E1" -le "$B1" || "$E2" -le "$B2" || "$E1" -ge "$B2" ]]; then echo "ERROR in device cert bundle." exit 1 fi cat $CERT_IN|sed -n "${B2},${E2}p" cat $CERT_IN|sed -n "${B1},${E1}p" } mkdir -p /etc/ssl/device if [ -f "$CERT_IN" ]; then echo "backup device bundle certificate..." cp "$CERT_IN" "$CERT_BKP" fi 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
Генерируем приватный ключ и запрос на сертификат:
openssl genrsa -out example.key 2048 openssl req -new -key example.key -subj "/CN=example.com" -out example.csr
Создаем сертификат сервера в CA.
openssl x509 -req -in example.csr -CA ca.crt -CAkey ca.key -out example.crt -days 365 -CAcreateserial -extfile req.cnf -extensions v3_req
Копируем файлы ca.crt, mosquitto.crt, mosquitto.key на сервер и редактируем файл конфигурации /etc/mosquitto/conf.d/server.conf
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
Запускаем серис:
service mosquitto start
Также, если требуется, можно сделать чтобы локальный mosquitto сервер на контроллере форвардил некоторые топики на удаленный сервер. Для этого создаем файл бриджа: /etc/mosquitto/bridge.conf
connection main topic test/# out address example.com:1883 bridge_cafile /etc/mosquitto/certs/ca.crt bridge_certfile /etc/mosquitto/certs/device_AP6V5MDG.crt bridge_keyfile engine:ateccx08:ATECCx08:00:04:C0:00
После перезапуска локального сервиса mosquitto топики /test/.. будут отправлятся на удаленный сервер example.com по защищенному ssl каналу.
Примеры клиентских команд mosquitto. Отправка сообщения "message" в топик "test" на сервере example.com
mosquitto_pub -h example.com --cert device_AP6V5MDG.crt --key 'engine:ateccx08:ATECCx08:00:04:C0:00' --cafile ca.crt -t "test" -m "message"
Получение сообщений из топика "test" на сервере example.com
mosquitto_sub -h example.com --cert device_AP6V5MDG.crt --key 'engine:ateccx08:ATECCx08:00:04:C0:00' -t "test" --cafile ca.crt