Description
Du fait de gérer moi-même la zone DNS pour mon propre ndd, dans le but “d’implémenter” DNSSEC.
Je commence maintenant à m’intéresser aux enregistrements DANE. Pour l’instant, je ne génère qu’un enregistrement pour le port 443/tcp - service web. Mais il est possible d’en générer pour d’autres services, tel que 25/tcp qui correspond à smtp, d’autres protocoles que tcp, etc…
Créer un enregistrement TLSA n’est pas compliqué !
Pour le propos, un enregistrement TLSA est ainsi construit :
_numeroDePort._protocol.domain. IN TLSA usage selecteur correspondance certificatAssocie
Veuillez consulter la documentation de l’Afnic, ci-dessous, pour bien comprendre le propos.
Génération TLSA en shell
Pour générer un enregistrement TLSA en shell, c’est assez simple en somme :
openssl x509 -noout -pubkey -in /etc/ssl/acme/nomDeDomaine.cert.pem | openssl rsa -pubin -outform der 2>/dev/null | sha512 | tr "a-z" "A-Z"
Dans un premier temps :
- on choisit l’algo, soit sha256, soit sha512
- on choisit de n’utiliser tout le certificat ou juste la clé publique de celui-ci
algo="sha512"
domain="stephane-huc.net"
cert="/etc/ssl/acme/${domain}.cert.pem" # chemin vers le fichier cert SSL généré par LetsEncrypt, avec le client natif OpenBSD - acme secure !
tls_port=443
tls_proto="tcp"
tlsa_usage=3 # Usage Field; possible: 0 => 3
tlsa_selector=0 # Selector Field; 0: use cert; 1: use public key
tlsa_method=0 # Matching Type Field
case "${algo}" in
"sha256") tlsa_method=1 ;;
"sha512") tlsa_method=2 ;;
esac
#tlsa_cert_associated="$(openssl x509 -in "${cert}" -outform der | openssl $algo | cut -d ' ' -f2)"
tlsa_cert_associated="$(openssl x509 -noout -pubkey -in "${cert}" | openssl rsa -pubin -outform der 2>/dev/null | ${algo} | tr "a-z" "A-Z" )"
tlsa_record="_${tls_port}._${tls_proto}.${domain}. IN TLSA ${tlsa_usage} ${tlsa_selector} ${tlsa_method} ${tlsa_cert_associated}"
# ajout de l'enregistrement vers votre zone dns ; dans ce cas, l'enregistrement de cette dernière est dû au fait de l'outil ldnscript de @"22decembre" !
echo "${tlsa_record}" >> /etc/ns/${domain}
Version multi-domaines
Voici le même code shell, pour gérer plusieurs domaines, pour exemple :
#!/bin/sh
algo=sha256
#cert="/etc/ssl/acme/${domain}.cert.pem"
domains="yeuxdelibad.net 3hg.fr ouaf.xyz"
tls_proto="tcp"
tls_ports="443"
tlsa_usage=3 # Usage Field; possible: 0 => 3
tlsa_selector=1 # Selector Field; 0: use cert; 1: use public key
tlsa_method=0 # Matching Type Field
case "${algo}" in
"sha256") tlsa_method=1 ;;
"sha512") tlsa_method=2 ;;
esac
for domain in ${domains}; do
cert="etc/ssl/acme/${domain}.cert.pem"
tlsa_cert_associated="$(openssl x509 -noout -pubkey -in "${cert}" | openssl rsa -pubin -outform der 2>/dev/null | ${algo} | tr "a-z" "A-Z" )"
for port in ${tls_ports}; do
tlsa_record="_${port}._${tls_proto}.${domain}. IN TLSA ${tlsa_usage} ${tlsa_selector} ${tlsa_method} ${tlsa_cert_associated}"
echo "${tlsa_record}" >> "/etc/ns/${domain}"
done
echo "You should update your ${domain} zone in 48h" | mail -s "${domain} TLSA update" root
sleep 1
# reload zone and nsd ; à décommenter, si vous utiliser nsd ;)
#/var/ldns/ldnscript signing "${domain}"
done
Merci Xavier ;)
Générer TLSA en PHP
Générer un enregistrement TLSA en PHP n’est guère plus compliqué, à partir du moment où on a les bonnes infos !
On veille à récupérer le certificat au format PEM, à l’injecter dans un formulaire HTML et à traiter les informations reçues par celui-ci. Je ne décris pas le code HTML.
<?php
function extractPublicKey($cert) {
$certificate = openssl_x509_read($cert);
$pub_key = openssl_get_publickey($certificate);
$pub_key = openssl_pkey_get_details($pub_key);
if (!isset($pub_key['key'])) {
// @codeCoverageIgnoreStart
throw new \InvalidArgumentException('Provided certificate is invalid.');
// @codeCoverageIgnoreEnd
}
return $pub_key['key'];
}
function pem2der($pem) {
return base64_decode(str_replace(["\n", "\r"], '', $pem));
}
function stripDatas($pem) {
$datas = [
'-----BEGIN PUBLIC KEY-----',
'-----END PUBLIC KEY-----',
'-----BEGIN CERTIFICATE-----',
'-----END CERTIFICATE-----'
];
$data = str_replace($datas, '', $pem);
return trim($data);
}
# $datas = certificat au format PEM
$pkey = extractPublicKey($datas);
$pem = pem2der(stripDatas($pkey));
switch($tlsa_match) {
case 0: $data = $pem; break;
case 1: $data = hash('sha256', $pem, true); break;
case 2: $data = hash('sha512', $pem, true); break;
}
$tlsa_cert_associated = bin2hex($data);
# les variables $port, $protocol, $domain ainsi que les $tlsa_* sont des variables créées dans le contexte du formulaire HTML, et nommées très simplement selon leur contexte.
$tlsa_gen = "_".$port."._".$protocol.".".$domain.". IN TLSA ".$tlsa_usage." ".$tlsa_selector." ".$tlsa_match." ".$tlsa_cert_associated;
# pour finir, un echo là où vous le désirez dans votre code HTML de restitution...
echo $tlsa_gen
?>
Les fonctions dans le code ne sont pas de moi - je partage ni + ni -
Vérification de l’enregistrement TLSA
Il existe des modules à Firefox :
On peut le faire par l’usage de générateur TLSA en ligne - puis comparer les infos restituées avec celles que vous avez générées - malheureusement rien d’automati(que|sé) :
- celui de Simon Huque
- celui de SSL-Tools
- et forcément le mien - le seul en français !?
Documentation
L’afnic a écrit des articles intéressants à-propos de :
Stéphane Bortzmeyer aussi parle de la RFC 6698 et explique beaucoup de choses intéressantes !
Un autre article expliquant de manière claire, simple DANE-TLSA.
Voilà !