Programming, electronics, lifestyle
Коротко зачем это все? Протокол TLS решает две проблемы, первая – то что клиент и сервер уверены что они никто из них не подменен, второе – все передаваемые данные - зашифрованы. При использовании MQTT данные могут быть перехвачены и подменены. А главное могут быть перехвачены учетные данные брокера сообщений (RabbitMQ) и в случае широких прав, злоумышленник может получить доступ к данным других клиентов брокера.
Для тех кто мало знаком с терминами SSL и TLS - это одно и тоже, в прошлом был только SSL, затем его переименовали в TLS. На практике люди до сих называют TLS как SSL и наоборот.
Также можно включить не только шифрование и проверку подписи через TLS, но и аутентификацию пользователя Authentication using Client TLS (x.509) Certificate Data (я это не использую, далее речь пойдет только о шифровании). Другими словами пользователю не нужно будет вводить логин и пароль, а достаточно просто использовать сертификат. Для этого требуется прописать пару настроек в основном конфигурационном файле брокера, а также в соответствии с именами пользователей задать соответствующие поля (Subject Alternative Name
/ Common Name
) в сертификате клиента, подробнее в README модуля SSL аутентификации.
В целом большая часть информации касаемо критериев к сертификатам содержится в официальной документации RabbitMQ. Однако там нет практических примеров.
Вкратце:
От сертификата сервера требуется совпадение CN (Common Name)
(имя сертификата) с именем хоста сервера, иначе при TSL соединении будет ошибка, что сертификат выписан не на тот хост. Также можно в сертификате сервера определить алиасы (SAN (Subject Alternative Name)) или дополнительные доменные имена и тогда будет проверять не только имя сертификата, но еще и этот список алиасов. Подробнее здесь Enabling Peer Verification.
Теперь пройдемся по X509v3 Extensions - это что-то вроде определенных функций (из перечня) для которых может использоваться сертификат.
Требованием X509v3 Key Usage
к сертификату CA - собственно иметь разрешение на выписку других сертификатов, а также я добавил возможность создавать Certificate Revocation List (CRL). В конфигурационном файле это выглядит вот так:
[ root_ca_extensions ]
basicConstraints = CA:true
keyUsage = keyCertSign, cRLSign
Требованием X509v3 Key Usage
к сертификату сервера это право пользоваться им для цифровой подписи, а также для участия в шифровании симметричного ключа (Difference between key encipherment and data encipherment?). Хотя вот тут Extensions and Their Effect on Accepted Cipher Suites (Cipher Suite Filtering) немного другая логика, поправьте если я не прав:
[ ${SR_NAME}_ca_extensions ]
basicConstraints = CA:false
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = 1.3.6.1.5.5.7.3.1
Требованием Extensions к сертификату клиента это только право пользоваться им для цифровой подписи:
[ ${CL_NAME}_ca_extensions ]
basicConstraints = CA:false
keyUsage = digitalSignature
extendedKeyUsage = 1.3.6.1.5.5.7.3.2
Для удобства работы и сокращения кода я определю ряд переменных для использования в качестве путей к файлам:
CA_NAME=urpylka.com
CL_NAME=mqttclient_1
SR_NAME=mqtt.urpylka.com
ORG=mqtt
DIR_CA=./ca
DIR_EX=./export
D_PRI=${DIR_CA}/private
D_CRT=${DIR_CA}/certs
D_CRL=${DIR_CA}/crls
D_CSR=${DIR_CA}/csrs
rm -r ${DIR_CA} 2> /dev/null
rm -r ${DIR_EX} 2> /dev/null
mkdir ${DIR_CA} ${DIR_EX} ${D_PRI} ${D_CRT} ${D_CRL} ${D_CSR}
chmod 0750 ${D_PRI}
echo 01 > ${DIR_CA}/serial
touch ${DIR_CA}/index.txt
CA_CFG=${DIR_CA}/openssl.cnf
CA_KEY=${D_PRI}/ca_key.pem
CA_CRT=${DIR_CA}/ca_crt.pem
SR_KEY=${DIR_EX}/${SR_NAME}_key.pem
SR_CSR=${D_CSR}/${SR_NAME}_csr.pem
SR_CRT=${DIR_EX}/${SR_NAME}_crt.pem
CL_KEY=${DIR_EX}/${CL_NAME}_key.pem
CL_CSR=${D_CSR}/${CL_NAME}_csr.pem
CL_CRT=${DIR_EX}/${CL_NAME}_crt.pem
Далее определим конфигурационный файл.
[ req ]
отвечает как раз за генерацию CA сертификата.[ ca ]
– используется для CSR запроса.[ ${CA_NAME} ]
отвечает за создание файловой структуры CA.${SR_NAME}_ca_extensions
и ${CL_NAME}_ca_extensions
отвечают за выбор расширений для сертификата сервера и клиента соответственно.cat << EOF > $CA_CFG
[ ca ]
default_ca = ${CA_NAME}
[ ${CA_NAME} ]
dir = ${DIR_CA}
certificate = \$dir/ca_crt.pem
private_key = \$dir/private/ca_key.pem
database = \$dir/index.txt
serial = \$dir/serial
new_certs_dir = \$dir/certs
default_days = 30
default_md = sha256
default_crl_days = 7
# Set to 'no' to allow creation of several certs with same subject.
unique_subject = yes
policy = ca_policy
x509_extensions = certificate_extensions
# A few difference way of specifying how similar the request should look
# For type CA, the listed attributes must be the same, and the optional
# and supplied fields are just that :-)
[ ca_policy ]
commonName = supplied
stateOrProvinceName = optional
countryName = optional
emailAddress = optional
organizationName = optional
organizationalUnitName = optional
domainComponent = optional
[ certificate_extensions ]
basicConstraints = CA:false
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer
[ req ]
# default_bits = 2048
default_keyfile = ${D_PRI}/ca_key.pem
# default_md = sha512
default_md = sha256
# encrypt_key = no
# accept information from '-subj' arg 'openssl req'
# if prompt = no -> will use 'root_ca_distinguished_name'
prompt = yes
distinguished_name = root_ca_distinguished_name
x509_extensions = root_ca_extensions
[ root_ca_distinguished_name ]
commonName = ${CA_NAME}
[ root_ca_extensions ]
basicConstraints = CA:true
keyUsage = keyCertSign, cRLSign
[ ${SR_NAME}_ca_extensions ]
basicConstraints = CA:false
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = 1.3.6.1.5.5.7.3.1
[ ${CL_NAME}_ca_extensions ]
basicConstraints = CA:false
keyUsage = digitalSignature
extendedKeyUsage = 1.3.6.1.5.5.7.3.2
EOF
Без использования digitalSignature
на стороне сервера, многие MQTT клиенты откажутся работать выдав ошибку вида:
Error: write EPROTO 140372507405416:error:10000090:SSL routines:OPENSSL_internal:ECC_CERT_NOT_FOR_SIGNING:../../third_party/boringssl/src/ssl/ssl_cert.cc:596:
Подробнее про возможные параметры openssl.cnf.
# генерация пары ключей алгоритмом ec длиной 521 bits для CA
openssl ecparam -genkey -name secp521r1 -noout -outform PEM -out $CA_KEY
Пару ключей для сервера и клиента я создам с помощью более простого алгоритма. Тут нужно исходить из того, с каими алгоритмами может работать реализации TLS на стороне сервера и клиента.
# генерация пары ключей алгоритмом rsa
# openssl genrsa -out $CA_KEY 2048
openssl genrsa -out $SR_KEY 4096
openssl genrsa -out $CL_KEY 4096
# или с помощью алгоритма основанного на эллептических кривых
openssl ecparam -genkey -name secp521r1 -noout -outform PEM -out $SR_KEY
openssl ecparam -genkey -name secp384r1 -noout -outform PEM -out $CL_KEY
Разные параметры ключей How to generate RSA and EC keys with OpenSSL.
# генерация сертификата, параметры вы должны ввести в процессе создания
openssl req -new -key $CA_KEY -out $CA_CRT -x509 -days 100
# генерацию ключа (rsa:2048, без пароля) и сертификата в один файл
openssl req -x509 -config $CA_CFG -days 3650 -outform PEM -out $CA_KEY -subj /CN=$CA_NAME/ -newkey rsa:2048 -nodes
# генерация сертификата на основе конфига, файла ключей и аргумента '-subj'
openssl req -x509 -config $CA_CFG -days 3650 -outform PEM -out $CA_CRT -subj /CN=$CA_NAME/ -new -key $CA_KEY
-noout
– this option prevents output of the encoded version of the request.-inform DER|PEM
- This specifies the input format. The DER option uses an ASN1 DER encoded form compatible with the PKCS#10. The PEM form is the default format: it consists of the DER format base64 encoded with additional header and footer lines.-outform DER|PEM
- This specifies the output format, the options have the same meaning as the -inform option.-nodes
– if this option is specified then if a private key is created it will not be encrypted.-days n
– when the -x509 option is being used this specifies the number of days to certify the certificate for. The default is 30 days.Полное описание параметров openssl.org.
openssl x509 -in $CA_CRT -text -noout
# Создание CSR (Certificate Signing Request)
openssl req -new -key $SR_KEY -outform PEM -subj /CN=$SR_NAME/O=$ORG/ -out $SR_CSR
openssl req -new -key $CL_KEY -outform PEM -subj /CN=$CL_NAME/O=$ORG/ -out $CL_CSR
# Генерация сертификата по CSR запросу
openssl ca -config $CA_CFG -in $SR_CSR -keyform PEM -notext -out $SR_CRT -batch -extensions ${SR_NAME}_ca_extensions -days 1000
openssl ca -config $CA_CFG -in $CL_CSR -keyform PEM -notext -out $CL_CRT -batch -extensions ${CL_NAME}_ca_extensions
-days
– you can skip it (by default 30).-notext
– don’t output the text form of a certificate to the output file.-batch
– this sets the batch mode. In this mode no questions will be asked and all certificates will be certified automatically.Подробнее о openssl ca.
openssl x509 -in $SR_CRT -text -noout
openssl x509 -in $CL_CRT -text -noout
openssl s_server -accept 8883 -CAfile ${CA_CRT} -cert ${SR_CRT} -key ${SR_KEY}
openssl s_client -connect localhost:8883 -CAfile ${CA_CRT} -cert ${CL_CRT} -key ${CL_KEY}
Для конвертации сертификата:
openssl x509 -inform pem -in ca_crt.pem -outform der -out ca_crt.der
openssl x509 -inform pem -in s_crt.pem -outform der -out s_crt.der
openssl x509 -inform pem -in c_crt.pem -outform der -out c_crt.der
Для конвертации ключа:
openssl rsa -inform pem -in s_key.pem -outform der -out s_key.der
openssl rsa -inform pem -in c_key.pem -outform der -out c_key.der
Источник: HOWTO convert PEM certificates and keys to DER format for emSSL.
На эту темы я аккумулировал информацию и, пока, у меня не удалось завести это. Как будет какой-то прогресс – напишу в отдельной статье.