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

Материал из Wiren Board
(Новая страница: «For example, suppose you have a server on the Internet that must process requests only from devices that have certificates, issued by our CA. To enable this check…»)
(Новая страница: «Nginx will now require a certificate from the client that must be validated by a ca.crt, otherwise the server returns an error 400 to the client:»)
Строка 207: Строка 207:
</pre>
</pre>


Теперь nginx будет требовать от клиента сертификат, который должен проходить проверку с помощью ca.crt, иначе сервер
Nginx will now require a certificate from the client that must be validated by a ca.crt, otherwise the server
вернет клиенту ошибку 400:
returns an error 400 to the client:


<pre>
<pre>

Версия 15:48, 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 is the basis of security in this scheme, so these operations are performed on the machine that is accessed only the owner of the CA.

Next, create a request for a device certificate on the Wiren Board controller:

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

In this command, we specify that the request is signed with a private key that is in the ateccx08 crypto device with ID ateccx08:00:04:C0:00 and public name wirenboard-AP6V5MDG. The request is placed in the file device_AP6V5MDG.csr.

You can choose any unique name, it is convenient for this purpose to use the device ID, which is prescribed by default in /etc/hostname:

cat /etc/hostname
wirenboard-AP6V5MDG

Next, we sign this request in our certification authority: openssl x509 -req -in device_AP6V5MDG.csr -CA ca.crt -CAkey ca.key-out device_AP6V5MDG.crt -days 365 -CAcreateserial

In this command, we specify the request file and the CA files required for signing. The result is a device certificate device_AP6V5MDG.crt. File device_AP6V5MDG.crt copy to the Wiren Board controller, it will be necessary for authorization.

Let's see what is there in the CA and device certificate files:

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

We see that the certificate is issued by a Certification Authority named "MY CA" for 1 year, starting with "Feb 4 14:50:14 2019 GMT" (for this we specified -days 365 in the signature team), a device named wirenboard-AP6V5MDG that has a private key corresponding to the Subject Public Key Info. The certificate is digitally signed.

A digital signature ensures that no part of the certificate can be tampered. In case of a change, a public inspection with the key CA will show an error.

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

We see that the certificate is signed by its own private key (Issuer: CN = MY CA, Subject: CN = MY CA) and discharged for 10 years: starting with "Feb 4 14:30:01 2019 GMT" (for this we indicated -days 3650 in the signature team)

Thus, the chain of trust (verification) is built as follows:

The device certificate is signed by a CA certificate and can be verified by it:

openssl verify -CAfile ca.crt device_AP6V5MDG.crt 
device_AP6V5MDG.crt: OK

Well, the certificate is signed "by itself"

openssl verify -CAfile ca.crt ca.crt
ca.crt: OK


Nginx configuration

For example, suppose you have a server on the Internet that must process requests only from devices that have certificates, issued by our CA. To enable this check in the nginx configuration file, you need to write the following lines in the http or server section:

  ssl_client_certificate  ca.crt;
  ssl_verify_client       on;

Nginx will now require a certificate from the client that must be validated by a ca.crt, otherwise the server returns an error 400 to the client:

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