## 20190921 AK
----
[[HowToDocuments/FingerprintsViaDNSSEC/CZ|česky]] | [[HowToDocuments/FingerprintsViaDNSSEC/CY|cymraeg]] | [[HowToDocuments/FingerprintsViaDNSSEC/DE|deutsch]] | '''english''' | [[HowToDocuments/FingerprintsViaDNSSEC/ES|español]] | [[HowToDocuments/FingerprintsViaDNSSEC/FR|français]] | [[HowToDocuments/FingerprintsViaDNSSEC/NL|nederlands]] | [[HowToDocuments/FingerprintsViaDNSSEC/PT|português]] --- [[HowToDocuments|more step-by-step guides]]
----
== Verify fingerprints via DNSSEC ==

To verify if the fingerprints of the downloaded root certificates are correct you can use DNSSEC-protected TXT records under the cacert.org domain.

The information about  the fingerprints is stored in the DNS zone _fp.cacert.org - the  underscore indicates non-host information. For each generation of root  certificates a new sub-directory will be created. The current one is  "g1". To list all available certificates of a specific generation you  can query the label _certs for that sub-directory given a DNS query for  _certs.g1._fp.cacert.org yielding the two names "root_X0F class3_X0E" as the certificates. Each of those references in turn provides both an URL  ("_url") and a set of fingerprints (_md5, _sha1, _sha256) needed for the  verified download of that certificate. To download the current (g1)  root certificate you'd thus look for the download URL at _url.root_X0F.g1._fp.cacert.org and verify the SHA2-256 fingerprint given at  _sha256.root_X0F.g1._fp.cacert.org. Fingerprints are always uppercase and without any delimiters.

/!\ When using commands and scripts, always start with the heading record _certs.g1._fp.cacert.org, currently yielding "root_X0F class3_X0E". Where material uses "root class3" instead it is outdated and should be implementing the first query.

For short test on Linux the below code can do the check. For production use MAKE sure that the DNS responses are validated. This can be achieved by installation of a validating stub resolver [1, 2]. Please refer to your distributions advice on how to properly setup DNSSEC if necessary.

{{{

$ host -t TXT _url.root_X0F.g1._fp.cacert.org.
_url.root_X0F.g1._fp.cacert.org descriptive text "http://www.cacert.org/certs/root_X0F.crt"
$ host -t TXT _sha256.root_X0F.g1._fp.cacert.org.
_sha256.root_X0F.g1._fp.cacert.org descriptive text "07EDBD824A4988CFEF4215DA20D48C2B41D71529D7C900F570926F277CC230C5"
$ wget -O root_X0F.crt 'http://www.cacert.org/certs/root_X0F.crt'
$ openssl x509 -in root_X0F.crt -noout -fingerprint -sha256 | tr -d :
SHA256 Fingerprint=07EDBD824A4988CFEF4215DA20D48C2B41D71529D7C900F570926F277CC230C5

}}}

In Windows, the same information can be obtained using nslookup:
{{{

>nslookup
Default Server:  my.dnssrv.eu
Address:  2001:470:6f:458:c56d:5931:992:4708
> set type=TXT
> _url.root_X0F.g1._fp.cacert.org.
Server:  my.dnssrv.eu
Address:  2001:470:6f:458:c56d:5931:992:4708
Non-authoritative answer:
_url.root_X0F.g1._fp.cacert.org     text =
        "http://www.cacert.org/certs/root_X0F.crt"
> _sha256.root_X0F.g1._fp.cacert.org.
Server:  my.dnssrv.eu
Address:  2001:470:6f:458:c56d:5931:992:4708
Non-authoritative answer:
_sha256.root_X0F.g1._fp.cacert.org  text =
        "07EDBD824A4988CFEF4215DA20D48C2B41D71529D7C900F570926F277CC230C5"
> _url.class3_X0E.g1._fp.cacert.org.
Server:  my.dnssrv.eu
Address:  2001:470:6f:458:c56d:5931:992:4708
Non-authoritative answer:
_url.class3_X0E.g1._fp.cacert.org   text =
        "http://www.cacert.org/certs/class3_X0E.crt"
> _sha256.class3_X0E.g1._fp.cacert.org.
Server:  my.dnssrv.eu
Address:  2001:470:6f:458:c56d:5931:992:4708
Non-authoritative answer:
_sha256.class3_X0E.g1._fp.cacert.org        text =
        "F6873D70D67596C2ACBA34401E69738B52701DD6AB06B49749BC55150936D544"
> exit

}}}

A small script doing the validation (if the system resolver is properly configured) can be seen below. The exit status is 0 on success, or non-zero otherwise (error 3, 4 and 5 may indicate a system resolver dropping DNSSEC records).

/!\ The script does not work, at least on Ubuntu 15.10 platform. It ends with the result code of 3 on the line 8. /!\
 * The updated script with the original lines commented just before the changed ones: [[attachment:CAcert-roots-fingerprint-test.sh]]. These are changed lines, according to the original script listed below: 8, 10, 24, 26, 33, 35.
 * Reasons: 
  1. There is no flag "ad" in the "dig" output; it is replaced by "rd" in the script.
  1. There are no lines containing " RRSIG" in the "dig" output.

{{{#!highlight bash
#!/bin/bash

# Fetch list of available root certificates (names)
TMP_RESPONSE=___root___$$.tmp
dig +nocmd +comments +nostats +norrcomments +dnssec IN TXT _certs.g1._fp.cacert.org. > ${TMP_RESPONSE} || exit 1

grep -q '^;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ' ${TMP_RESPONSE} || exit 2
grep '^;; flags:' ${TMP_RESPONSE} | cut '-d;' -f3 | cut -d: -f2 | grep -q ad || exit 3
grep '^; EDNS:' ${TMP_RESPONSE} | tr ";," "\n\n" | grep flags | cut -d: -f2 | grep -q do || exit 4
grep -v '^;' ${TMP_RESPONSE} | grep -q RRSIG || exit 5

ROOTS=$(grep -v '^;' "${TMP_RESPONSE}" | grep -v " RRSIG " | grep TXT | cut '-d"' -f2 | head -1)
printf "Found roots: %s\n\n" "$ROOTS"

rm -f -- "${TMP_RESPONSE}"

for a in $ROOTS; do
	printf "Downloading %s ...\n" "$a"

	# Fetch the download URL of the current certificate in the list
	TMP_ROOT=___root___$$.tmp
	dig +nocmd +comments +nostats +norrcomments +dnssec IN TXT "_url.$a.g1._fp.cacert.org." > ${TMP_ROOT} || exit 11
	grep -q '^;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ' ${TMP_ROOT} || exit 12
	grep '^;; flags:' ${TMP_ROOT} | cut '-d;' -f3 | cut -d: -f2 | grep -q ad || exit 13
	grep '^; EDNS:' ${TMP_ROOT} | tr ";," "\n\n" | grep flags | cut -d: -f2 | grep -q do || exit 14
	grep -v '^;' ${TMP_ROOT} | grep -q RRSIG || exit 15
	CRT_URL=$(grep -v '^;' ${TMP_ROOT} | grep -v " RRSIG " | grep TXT | cut '-d"' -f2 | head -1)

	# Fetch the SHA2-256 fingerprint of the current certificate in the list
	TMP_ROOT_FP=___root___$$.tmp
	dig +nocmd +comments +nostats +norrcomments +dnssec IN TXT "_sha256.$a.g1._fp.cacert.org." > ${TMP_ROOT_FP} || exit 21
	grep -q '^;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ' ${TMP_ROOT_FP} || exit 22
	grep '^;; flags:' ${TMP_ROOT_FP} | cut '-d;' -f3 | cut -d: -f2 | grep -q ad || exit 23
	grep '^; EDNS:' ${TMP_ROOT_FP} | tr ";," "\n\n" | grep flags | cut -d: -f2 | grep -q do || exit 24
	grep -v '^;' ${TMP_ROOT_FP} | grep -q RRSIG || exit 25
	CRT_FP=$(grep -v '^;' ${TMP_ROOT_FP} | grep -v " RRSIG " | grep TXT | cut '-d"' -f2 | head -1)

	# Download the current certificate in the list from the obtained URL
	wget --quiet -O "___CRT___$a.crt" "$CRT_URL" || exit 31

	# Calculate fingerprint of the downloaded certificate file
	DL_FP=$(openssl x509 -in "___CRT___$a.crt" -noout -fingerprint -sha256 | cut -d= -f2 | tr -d :)

	printf "Found Certificate for Root \"%s\":\n- CRT URL:\t%s\n- CRT FP:\t%s\n- DL FP:\t%s\n\n" "$a" "$CRT_URL" "$CRT_FP" "$DL_FP"

	# Compare fingerprints of the downloaded certificate with the fetched value from DNS
	if [ ! "$CRT_FP" == "$DL_FP" ]; then
		printf 'Verification Failed!'
		exit 32
	fi

	rm -f -- "$TMP_ROOT" "$TMP_ROOT_FP"
done
}}}

The above script should produce the following output:

{{{
_certs.g1._fp.cacert.org. 21599	IN	TXT	"root_X0F class3_X0E"

Found roots: root_X0F class3_X0E

Downloading root_X0F ...


_url.root_X0F.g1._fp.cacert.org. 20558 IN TXT	"http://www.cacert.org/certs/root_X0F.crt"



_sha256.root_X0F.g1._fp.cacert.org. 20632 IN TXT "07EDBD824A4988CFEF4215DA20D48C2B41D71529D7C900F570926F277CC230C5"

Found Certificate for Root "root_X0F":
- CRT URL:	http://www.cacert.org/certs/root_X0F.crt
- CRT FP:	07EDBD824A4988CFEF4215DA20D48C2B41D71529D7C900F570926F277CC230C5
- DL FP:	07EDBD824A4988CFEF4215DA20D48C2B41D71529D7C900F570926F277CC230C5

Downloading class3_X0E ...


_url.class3_X0E.g1._fp.cacert.org. 20651 IN TXT	"http://www.cacert.org/certs/class3_X0E.crt"



_sha256.class3_X0E.g1._fp.cacert.org. 20680 IN TXT "F6873D70D67596C2ACBA34401E69738B52701DD6AB06B49749BC55150936D544"

Found Certificate for Root "class3_X0E":
- CRT URL:	http://www.cacert.org/certs/class3_X0E.crt
- CRT FP:	F6873D70D67596C2ACBA34401E69738B52701DD6AB06B49749BC55150936D544
- DL FP:	F6873D70D67596C2ACBA34401E69738B52701DD6AB06B49749BC55150936D544
}}}


[1] [http://askubuntu.com/questions/51367/how-do-i-configure-my-caching-nameserver-to-validate-dnssec]

[2] [https://wiki.debian.org/DNSSEC]

----
 . CategoryTutorials
 . CategoryStepByStep