82

My git client claims

error: Peer's Certificate issuer is not recognized.

That means it can not find the corresponding ssl server key in the global system keyring. I want to check this by looking at the list of all system wide available ssl keys on a gentoo linux system. How can I get this list?

Jonas Stein
  • 3,898
  • 4
  • 34
  • 55

8 Answers8

150

It's not SSL keys you want, it's certificate authorities, and more precisely their certificates.

You could try:

awk -v cmd='openssl x509 -noout -subject' '
    /BEGIN/{close(cmd)};{print | cmd}' < /etc/ssl/certs/ca-certificates.crt

To get the "subject" of every CA certificate in /etc/ssl/certs/ca-certificates.crt (this works because openssl exits after reading an individual cert block, but awk relaunches openssl on the next print | cmd call).

Beware that sometimes, you get that error when SSL servers forget to provide the intermediate certificates.

Use openssl s_client -showcerts -connect the-git-server:443 to get the list of certificates being sent.

Note that the pathname of the certificates bundle may differ depending on operating system. The directory holding the certs sub-directory is given by the command openssl version -d. The actual certificates file in that directory may additionally have a different name.

Kusalananda
  • 320,670
  • 36
  • 633
  • 936
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • 2
    // , This does not work on CEntOS 6, but I have added an answer for CEntOS 6 here: https://unix.stackexchange.com/a/363309/48498 – Nathan Basanese May 05 '17 at 21:25
  • 4
    The list from `trust list` from [p11-kit package](http://p11-glue.freedesktop.org/p11-kit.html) is essentially the same? – Pablo A Mar 27 '19 at 16:55
  • I just posted a [bash version of this](https://unix.stackexchange.com/a/614502/27653) – F. Hauri - Give Up GitHub Oct 14 '20 at 14:38
  • @F.Hauri, The command I gave should work in `bash` or any shell of the Bourne, rc, or fish families. If put on one line, it would work in any shell that I know, even csh, even the Unix V6 shell. – Stéphane Chazelas Oct 14 '20 at 16:34
  • I agree, your solution is correct and efficient, I've just posted an alternative, using bash's arrays and some pretty output formatting, showing some usefull bash features – F. Hauri - Give Up GitHub Oct 14 '20 at 17:10
  • @StéphaneChazelas, works great on Debian, thanks. Could you please provide a breakdown in your answer of what that first command line instruction to read the CA cert subject is actually doing? – Chris Halcrow Feb 01 '21 at 00:18
  • @JonasStein (Re: your edit suggestion) while it's true `openssl` exits upon seeing the `END CERTIFICATE`, it would still work even if it didn't as we `close(cmd)` which closes the pipe to `openssl` and waits for the corresponding process to exit upon the next `BEGIN` upon which `openssl` would see EOF and exit. Try with `cmd=wc` instead for instance. – Stéphane Chazelas Jun 29 '22 at 15:27
  • The `openssl s_client` tip to get the exact list of certs a server is sending is super useful (ran into an issue where a misconfigured server was only sending its leaf cert instead of the full chain. Browsers compensate for that, but most other SSL/TLS client libraries don't) – ncoghlan Jul 11 '22 at 06:18
  • That's one interesting way to use `awk`. – x-yuri Sep 01 '22 at 10:33
35

Not sure about Gentoo but most distros put their certificates soft-link in system-wide location at /etc/ssl/certs.

  • Key files go into /etc/ssl/private
  • System-provided actual files are located at /usr/share/ca-certificates
  • Custom certificates go into /usr/local/share/ca-certificates

Whenever you put a certificate in one of the above mentioned paths, run update-ca-certificates to update /etc/ssl/certs lists.

Sam Brightman
  • 362
  • 2
  • 10
SHW
  • 14,454
  • 14
  • 63
  • 101
6

I had a requirement to list all the certs on our server and notify if they are due to expire. We came up with this command:

locate .pem | grep "\.pem$" | xargs -I{} openssl x509 -issuer -enddate -noout -in {}
roaima
  • 107,089
  • 14
  • 139
  • 261
Dwight Emmons
  • 61
  • 1
  • 1
  • Note that openssl x509 format expects only a single cert in a pem file. Multiple certs if present need to follow some parsing given https://unix.stackexchange.com/questions/17744/how-do-i-extract-all-subjects-of-a-cacertfile-with-the-openssl-command-line – Akash Jul 27 '20 at 12:08
4

A quick way to list all currently trusted CA certificates by openssl (with Ubuntu default directories):

find /etc/ssl/certs -type l -iname "*.0" -exec cat "{}" \; | awk -v cmd='openssl x509 -noout -subject -enddate 2>/dev/null | tr "\n" " " ; echo' '/BEGIN/{cert=""};{cert=sprintf("%s\n%s",cert,$0)};/END/{print cert | cmd ;close(cmd)}' | sed -r 's:^subject=::' | sort -u
Mimmo
  • 41
  • 3
2

Another one it this one:

openssl crl2pkcs7 -nocrl -certfile /etc/ssl/certs/ca-certificates.crt | openssl pkcs7 -print_certs -noout | grep subject
1

Most of the times, when examining ca certificates, you will want (and should) grep with fingerprint. You can also pass the output to less for searching/matching manually.
In general verifying the certificate fingerprint rather than just its name/issuer name/date e.t.c is very important.

# By piping to less you can manually search by hitting '/'
cat /etc/ssl/certs/ca-certificates.crt | keytool -printcert 2>/dev/null | 
grep "^Certificate\[" -A11 | less

Output:

Certificate[1]:
Owner: C=ES, O=ACCV, OU=PKIACCV, CN=ACCVRAIZ1
Issuer: C=ES, O=ACCV, OU=PKIACCV, CN=ACCVRAIZ1
Serial number: 5ec3b7a6437fa4e0
Valid from: Thu May 05 12:37:37 EEST 2011 until: Tue Dec 31 11:37:37 EET 2030
Certificate fingerprints:
         SHA1: 93:05:7A:88:15:C6:4F:CE:88:2F:FA:91:16:52:28:78:BC:53:64:17
         SHA256: 9A:6E:C0:12:E1:A7:DA:9D:BE:34:19:4D:47:8A:D7:C0:DB:18:22:FB:07:1D:F1:29:81:49:6E:D1:04:38:41:13
Signature algorithm name: SHA1withRSA (weak)
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3

--
Certificate[2]:
Owner: OU=AC RAIZ FNMT-RCM, O=FNMT-RCM, C=ES
Issuer: OU=AC RAIZ FNMT-RCM, O=FNMT-RCM, C=ES
Serial number: 5d938d306736c8061d1ac754846907
Valid from: Wed Oct 29 17:59:56 EET 2008 until: Tue Jan 01 02:00:00 EET 2030
Certificate fingerprints:
         SHA1: EC:50:35:07:B2:15:C4:95:62:19:E2:A8:9A:5B:42:99:2C:4C:2C:20
         SHA256: EB:C5:57:0C:29:01:8C:4D:67:B1:AA:12:7B:AF:12:F7:03:B4:61:1E:BC:17:B7:DA:B5:57:38:94:17:9B:93:FA
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 4096-bit RSA key
Version: 3

--
....
....

And since the above command prints also a sequential number for each certificate (e.g. Certificate[3]) you can then pick the actual certificate with:

# Let's say you want to pick certificate number 3
awk -v n=3 '/BEGIN CERTIFICATE/ && ++k == n, /END CERTIFICATE/' /etc/ssl/certs/ca-certificates.crt

Output:

-----BEGIN CERTIFICATE-----
MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw
CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw
FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S
Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5
MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL
DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS
QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB
BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH
sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK
Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu
SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC
MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy
v+c=
-----END CERTIFICATE-----
Marinos An
  • 779
  • 7
  • 11
0

openssl and pure bash way

Even if Stéphane Chazelas's answer, work fine and is efficient, I would like to post this script who will give near same result, but don't use awk:

#!/bin/bash
exec {sslout}<> <(:)
cnt=1
while read -u $certs line; do
    [ "$line" ] && case $line in 
        *BEGIN*)
            exec {ssl}> >(openssl x509 -noout -subject >&${sslout})
            echo $line 1>&$ssl
        ;;
        *END*)
            echo $line 1>&$ssl
            exec {ssl}>&-
            read -u $sslout subject
            printf "%03d  %s\n" $((cnt++)) "${subject#subject=}"
        ;;
        *)
            echo $line 1>&$ssl
        ;;
    esac;
done {certs}< /etc/ssl/certs/ca-certificates.crt
exec {certs}>&- {sslout}>&-

One step further

Searching for certs in all dirs mentionned by SHW's answer, sorting by hashes and count

#!/bin/bash

exec {sslout}<> <(:)
cnt=0
hashed=()
while read -u $certs line; do
    [ "$line" ] && case $line in 
        *BEGIN*)
            exec {ssl}> >(openssl x509 -noout -hash -subject >&${sslout})
            echo $line 1>&$ssl
        ;;
        *END*)
            echo $line 1>&$ssl
            exec {ssl}>&-
            read -u $sslout hash
            read -u $sslout subject
            ((cnt++))
        hashed[16#$hash]+="${subject#subject=}"$'\t'
        ;;
        *)
            echo $line 1>&$ssl
        ;;
    esac
done {certs}< <(find /etc/ssl/certs /usr/{local/,}share/ca-certificates \
                    -type f -exec cat {} +)
exec {certs}>&- {sslout}>&-
echo "$cnt certs read, ${#hashed[@]} different hashes."
for i in ${!hashed[@]};do
    IFS=$'\t' read -a subj <<<"${hashed[i]}"
    printf "%8x  %s\n" $i "$subj"
    ((${#subj}>1)) && printf "          %s\n" "${subj[@]:1}"
done

may output something like:

    256 certs read, 128 different hashes.
 3179a64  C = NL, O = Staat der Nederlanden, CN = Staat der Nederlanden EV Root CA
          C = NL, O = Staat der Nederlanden, CN = Staat der Nederlanden EV Root CA
 62cdee6  OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign
          OU = GlobalSign Root CA - R3, O = GlobalSign, CN = GlobalSign
 64e0aa9  C = BM, O = QuoVadis Limited, CN = QuoVadis Root CA 2 G3
          C = BM, O = QuoVadis Limited, CN = QuoVadis Root CA 2 G3
...
-1

Find with crt or key files shall also work

find / -type f -name *.key
find / -type f -name *.crt