CryptodevATECCx08 Auth
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