CryptodevATECCx08 Auth

Материал из Wiren Board
Это утверждённая версия страницы. Она же — наиболее свежая версия.
Другие языки:

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>

Now let's make http requests from WB controller pass this check. For simplicity, we will use nginx on the client side. This will give the opportunity to work with secure servers for clients who can't make SSL connections.

First, we will create a server on the unused local http port, which will do the following all https "magic" for us:

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;
    }   
}

Add the www-data user to the i2c group to access the crypto device:

usermod -G www-data

Run the command service nginx restart to update the configuration.

Now, when you access http on the local port 8080, encrypted requests with authentication information will be sent to the server example.com

curl localhost:8080/
<html>
<body>
EXAMPLE.COM
</body>
</html>

Openvpn configuration

First, install the package:

apt install openvpn

Create file named req.cnf - we need it to make a server certificate.

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth

The openvpn server also needs a file with DH parameters, let's make it.

openssl dhparam -out dh2048.pem 2048

It may take a few minutes to create this file.

Next, make a private key of our server and request a certificate. We assume, for example, that server has name example.com:

 
openssl genrsa -out example.key 2048

openssl req -new -key example.key -subj "/CN=example.com" -out example.csr

Sign the request in our certification authority:

openssl x509 -req -in example.csr -CA ca.crt -CAkey ca.key -out example.crt -days 365 -CAcreateserial -extfile req.cnf -extensions v3_req

Now let's start setting up openvpn server on the machine example.com

Copy the file ca.crt, example.crt, example.key and dh2048.pem and edit the openvpn server configuration file. By default, the configuration file is in /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

Add the openvpn user to the i2c group to access the crypto device:

usermod -G www-data

after that, start the server with the command service openvpn start.

Next, create a client configuration file on the controller: 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
-------------------------------------------------------------------------

Note the line group i2c. It is necessary to work with the crypto device.

Then run the client:

openvpn --config example.ovpn --ca ca.crt --cert device_AP6V5MDG.crt --key engine:ateccx08:ATECCx08:00:04:C0:00

If all is well, then the system should appear tun0 interface with the address from the subnet 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

To check the performance run 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 settings

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


Generate a private key and certificate request:

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

Copy the file ca.crt, mosquitto.crt, mosquitto.key to the server and edit the configuration file /etc/mosquito/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

Start service:

service mosquitto start

Also, if required, you can make the local mosquitto server on the controller forwarder some topics on a remote server. To do this, create a bridge file: /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

After restarting the local service mosquito topics /test/.. will be sent to the remote server example.com secure ssl channel.

Examples of client mosquitto commands. Sending a message to the "test" topic on the example.com server

mosquitto_pub -h example.com --cert device_AP6V5MDG.crt --key 'engine:ateccx08:ATECCx08:00:04:C0:00' --cafile ca.crt -t "test" -m "message" 

Getting messages from the "test" topic on the example.com server

mosquitto_sub -h example.com --cert device_AP6V5MDG.crt --key 'engine:ateccx08:ATECCx08:00:04:C0:00' -t "test" --cafile ca.crt