česky | cymraeg | deutsch | english | español | français | nederlands | português --- 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 class3" 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.g1._fp.cacert.org and verify the SHA2-256 fingerprint given at _sha256.root.g1._fp.cacert.org. Fingerprints are always uppercase and without any delimiters.

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.g1._fp.cacert.org.
_url.root.g1._fp.cacert.org descriptive text "http://www.cacert.org/certs/root.crt"
$ host -t TXT _sha256.root.g1._fp.cacert.org.
_sha256.root.g1._fp.cacert.org descriptive text "FF2A65CFF1149C7430101E0F65A07EC19183A3B633EF4A6510890DAD18316B3A"
$ wget -O root.crt 'http://www.cacert.org/certs/root.crt'
$ openssl x509 -in root.crt -noout -fingerprint -sha256 | tr -d :
SHA256 Fingerprint=FF2A65CFF1149C7430101E0F65A07EC19183A3B633EF4A6510890DAD18316B3A

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.g1._fp.cacert.org.
Server:  my.dnssrv.eu
Address:  2001:470:6f:458:c56d:5931:992:4708
Non-authoritative answer:
_url.root.g1._fp.cacert.org     text =
        "http://www.cacert.org/certs/root.crt"
> _sha256.root.g1._fp.cacert.org.
Server:  my.dnssrv.eu
Address:  2001:470:6f:458:c56d:5931:992:4708
Non-authoritative answer:
_sha256.root.g1._fp.cacert.org  text =
        "FF2A65CFF1149C7430101E0F65A07EC19183A3B633EF4A6510890DAD18316B3A"
> _url.class3.g1._fp.cacert.org.
Server:  my.dnssrv.eu
Address:  2001:470:6f:458:c56d:5931:992:4708
Non-authoritative answer:
_url.class3.g1._fp.cacert.org   text =
        "http://www.cacert.org/certs/class3.crt"
> _sha256.class3.g1._fp.cacert.org.
Server:  my.dnssrv.eu
Address:  2001:470:6f:458:c56d:5931:992:4708
Non-authoritative answer:
_sha256.class3.g1._fp.cacert.org        text =
        "4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8"
> 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. /!\

   1 #!/bin/bash
   2 
   3 # Fetch list of available root certificates (names)
   4 TMP_RESPONSE=___root___$$.tmp
   5 dig +nocmd +comments +nostats +norrcomments +dnssec IN TXT _certs.g1._fp.cacert.org. > ${TMP_RESPONSE} || exit 1
   6 
   7 grep -q '^;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ' ${TMP_RESPONSE} || exit 2
   8 grep '^;; flags:' ${TMP_RESPONSE} | cut '-d;' -f3 | cut -d: -f2 | grep -q ad || exit 3
   9 grep '^; EDNS:' ${TMP_RESPONSE} | tr ";," "\n\n" | grep flags | cut -d: -f2 | grep -q do || exit 4
  10 grep -v '^;' ${TMP_RESPONSE} | grep -q RRSIG || exit 5
  11 
  12 ROOTS=$(grep -v '^;' "${TMP_RESPONSE}" | grep -v " RRSIG " | grep TXT | cut '-d"' -f2 | head -1)
  13 printf "Found roots: %s\n\n" "$ROOTS"
  14 
  15 rm -f -- "${TMP_RESPONSE}"
  16 
  17 for a in $ROOTS; do
  18         printf "Downloading %s ...\n" "$a"
  19 
  20         # Fetch the download URL of the current certificate in the list
  21         TMP_ROOT=___root___$$.tmp
  22         dig +nocmd +comments +nostats +norrcomments +dnssec IN TXT "_url.$a.g1._fp.cacert.org." > ${TMP_ROOT} || exit 11
  23         grep -q '^;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ' ${TMP_ROOT} || exit 12
  24         grep '^;; flags:' ${TMP_ROOT} | cut '-d;' -f3 | cut -d: -f2 | grep -q ad || exit 13
  25         grep '^; EDNS:' ${TMP_ROOT} | tr ";," "\n\n" | grep flags | cut -d: -f2 | grep -q do || exit 14
  26         grep -v '^;' ${TMP_ROOT} | grep -q RRSIG || exit 15
  27         CRT_URL=$(grep -v '^;' ${TMP_ROOT} | grep -v " RRSIG " | grep TXT | cut '-d"' -f2 | head -1)
  28 
  29         # Fetch the SHA2-256 fingerprint of the current certificate in the list
  30         TMP_ROOT_FP=___root___$$.tmp
  31         dig +nocmd +comments +nostats +norrcomments +dnssec IN TXT "_sha256.$a.g1._fp.cacert.org." > ${TMP_ROOT_FP} || exit 21
  32         grep -q '^;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: ' ${TMP_ROOT_FP} || exit 22
  33         grep '^;; flags:' ${TMP_ROOT_FP} | cut '-d;' -f3 | cut -d: -f2 | grep -q ad || exit 23
  34         grep '^; EDNS:' ${TMP_ROOT_FP} | tr ";," "\n\n" | grep flags | cut -d: -f2 | grep -q do || exit 24
  35         grep -v '^;' ${TMP_ROOT_FP} | grep -q RRSIG || exit 25
  36         CRT_FP=$(grep -v '^;' ${TMP_ROOT_FP} | grep -v " RRSIG " | grep TXT | cut '-d"' -f2 | head -1)
  37 
  38         # Download the current certificate in the list from the obtained URL
  39         wget --quiet -O "___CRT___$a.crt" "$CRT_URL" || exit 31
  40 
  41         # Calculate fingerprint of the downloaded certificate file
  42         DL_FP=$(openssl x509 -in "___CRT___$a.crt" -noout -fingerprint -sha256 | cut -d= -f2 | tr -d :)
  43 
  44         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"
  45 
  46         # Compare fingerprints of the downloaded certificate with the fetched value from DNS
  47         if [ ! "$CRT_FP" == "$DL_FP" ]; then
  48                 printf 'Verification Failed!'
  49                 exit 32
  50         fi
  51 
  52         rm -f -- "$TMP_ROOT" "$TMP_ROOT_FP"
  53 done

The above script should produce the following output:

_certs.g1._fp.cacert.org. 17355 IN      TXT     "root class3"

Found roots: root class3

Downloading root ...


_url.root.g1._fp.cacert.org. 17007 IN   TXT     "http://www.cacert.org/certs/root.crt"



_sha256.root.g1._fp.cacert.org. 17033 IN TXT    "FF2A65CFF1149C7430101E0F65A07EC19183A3B633EF4A6510890DAD18316B3A"

Found Certificate for Root "root":
- CRT URL:      http://www.cacert.org/certs/root.crt
- CRT FP:       FF2A65CFF1149C7430101E0F65A07EC19183A3B633EF4A6510890DAD18316B3A
- DL FP:        FF2A65CFF1149C7430101E0F65A07EC19183A3B633EF4A6510890DAD18316B3A

Downloading class3 ...


_url.class3.g1._fp.cacert.org. 43200 IN TXT     "http://www.cacert.org/certs/class3.crt"



_sha256.class3.g1._fp.cacert.org. 43200 IN TXT  "4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8"

Found Certificate for Root "class3":
- CRT URL:      http://www.cacert.org/certs/class3.crt
- CRT FP:       4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8
- DL FP:        4EDDE9E55CA453B388887CAA25D5C5C5BCCF2891D73B87495808293D5FAC83C8

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

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


HowToDocuments/FingerprintsViaDNSSEC (last edited 2016-04-10 11:51:45 by AlesKastner)