OpenVPN / openvpn

OpenVPN is an open source VPN daemon
http://openvpn.net
Other
10.25k stars 2.92k forks source link

Certificate fingerprint calculated for the `peer-fingerprint` option does not match output from `openssl x509 -fingerprint` #515

Closed vlk-charles closed 3 months ago

vlk-charles commented 3 months ago

Describe the bug Cannot obtain a working hash from a certificate for OpenVPN's peer-fingerprint option. The output from openssl x509 -fingerprint is not accepted. Instead the client reports a different value as the peer's certificate fingerprint. It is not known how it derived this value. The manual page simply says:

Specify a SHA256 fingerprint or list of SHA256 fingerprints to verify the peer certificate against. The peer certificate must match one of the fingerprint or certificate verification will fail.

To Reproduce

$ openssl x509 -noout -fingerprint -sha256 <peer.crt
SHA256 Fingerprint=9D:89:83:58:C6:58:06:87:45:FE:62:26:16:3E:D9:11:F9:14:48:6D:0C:8B:20:4B:87:99:75:8A:D4:AA:35:54
$ # or
$ openssl x509 -outform DER <peer.crt | sha256sum 
9d898358c658068745fe6226163ed911f914486d0c8b204b8799758ad4aa3554  -
$ openvpn --remote example.com --dev tun --client --auth-user-pass --tls-exit --peer-fingerprint 9d:89:83:58:c6:58:06:87:45:fe:62:26:16:3e:d9:11:f9:14:48:6d:0c:8b:20:4b:87:99:75:8a:d4:aa:35:54
2024-03-07 11:45:35 Note: --cipher is not set. OpenVPN versions before 2.5 defaulted to BF-CBC as fallback when cipher negotiation failed in this case. If you need this fallback please add '--data-ciphers-fallback BF-CBC' to your configuration and/or add BF-CBC to --data-ciphers.
2024-03-07 11:45:35 Using certificate fingerprint to verify peer (no CA option set). 
2024-03-07 11:45:35 OpenVPN 2.6.9 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO]
2024-03-07 11:45:35 library versions: OpenSSL 3.1.1 30 May 2023, LZO 2.10
2024-03-07 11:45:35 DCO version: N/A
Enter Auth Username: anything
Enter Auth Password: ********              
2024-03-07 11:45:41 WARNING: No server certificate verification method has been enabled.  See http://openvpn.net/howto.html#mitm for more info.
2024-03-07 11:45:41 TCP/UDP: Preserving recently used remote address: [AF_INET]example.com:1194
2024-03-07 11:45:41 UDPv4 link local: (not bound)
2024-03-07 11:45:41 UDPv4 link remote: [AF_INET]example.com:1194
2024-03-07 11:45:41 WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this
2024-03-07 11:45:41 TLS Error: --tls-verify/--peer-fingerprintcertificate hash verification failed. (got fingerprint: 9a:26:3e:4e:a3:9c:73:af:1d:7e:1f:d1:6a:b8:8f:61:29:26:ed:a7:42:d0:37:f9:4d:0c:9c:20:fc:34:3e:da
2024-03-07 11:45:41 OpenSSL: error:0A000086:SSL routines::certificate verify failed:
2024-03-07 11:45:41 TLS_ERROR: BIO read tls_read_plaintext error
2024-03-07 11:45:41 TLS Error: TLS object -> incoming plaintext read error
2024-03-07 11:45:41 TLS Error: TLS handshake failed
2024-03-07 11:45:41 SIGTERM[soft,tls-error] received, process exiting

Note the line:

2024-03-07 11:45:41 TLS Error: --tls-verify/--peer-fingerprintcertificate hash verification failed. (got fingerprint: 9a:26:3e:4e:a3:9c:73:af:1d:7e:1f:d1:6a:b8:8f:61:29:26:ed:a7:42:d0:37:f9:4d:0c:9c:20:fc:34:3e:da

Where did this value come from? Also the formatting is a little wrong. A space and a closing parenthesis are missing.

Expected behavior Either peer-fingerprint should use the "standard" (i.e. the hash of the DER content) or the calculation method should be documented.

Version information:

Additional context I did make sure peer.crt is actually the certificate presented by the server. It can also be seen in the tls_digest_sha256_1 variable if I use a tls-verify script:

$ openvpn --remote example.com --dev tun --client --auth-user-pass --tls-exit --peer-fingerprint 9d:89:83:58:c6:58:06:87:45:fe:62:26:16:3e:d9:11:f9:14:48:6d:0c:8b:20:4b:87:99:75:8a:d4:aa:35:54 --tls-verify tls-verify.sh --script-security 2
2024-03-07 12:02:38 Note: --cipher is not set. OpenVPN versions before 2.5 defaulted to BF-CBC as fallback when cipher negotiation failed in this case. If you need this fallback please add '--data-ciphers-fallback BF-CBC' to your configuration and/or add BF-CBC to --data-ciphers.
2024-03-07 12:02:38 Using certificate fingerprint to verify peer (no CA option set). 
2024-03-07 12:02:38 OpenVPN 2.6.9 x86_64-redhat-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] [DCO]
2024-03-07 12:02:38 library versions: OpenSSL 3.1.1 30 May 2023, LZO 2.10
2024-03-07 12:02:38 DCO version: N/A
Enter Auth Username: kvlktest
Enter Auth Password: *********               
2024-03-07 12:02:42 NOTE: the current --script-security setting may allow this configuration to call user-defined scripts
2024-03-07 12:02:42 TCP/UDP: Preserving recently used remote address: [AF_INET]example.com:1194
2024-03-07 12:02:42 UDPv4 link local: (not bound)
2024-03-07 12:02:42 UDPv4 link remote: [AF_INET]example.com:1194
2024-03-07 12:02:42 WARNING: this configuration may cache passwords in memory -- use the auth-nocache option to prevent this
tls_digest_sha256_1=9d:89:83:58:c6:58:06:87:45:fe:62:26:16:3e:d9:11:f9:14:48:6d:0c:8b:20:4b:87:99:75:8a:d4:aa:35:54
tls_digest_1=45:2c:95:b7:13:a7:29:0b:4e:34:2a:73:0d:82:8d:b4:fb:d8:f2:2b
tls_digest_sha256_1=9d:89:83:58:c6:58:06:87:45:fe:62:26:16:3e:d9:11:f9:14:48:6d:0c:8b:20:4b:87:99:75:8a:d4:aa:35:54
tls_digest_1=45:2c:95:b7:13:a7:29:0b:4e:34:2a:73:0d:82:8d:b4:fb:d8:f2:2b
2024-03-07 12:02:42 TLS Error: --tls-verify/--peer-fingerprintcertificate hash verification failed. (got fingerprint: 9a:26:3e:4e:a3:9c:73:af:1d:7e:1f:d1:6a:b8:8f:61:29:26:ed:a7:42:d0:37:f9:4d:0c:9c:20:fc:34:3e:da
2024-03-07 12:02:42 OpenSSL: error:0A000086:SSL routines::certificate verify failed:
2024-03-07 12:02:42 TLS_ERROR: BIO read tls_read_plaintext error
2024-03-07 12:02:42 TLS Error: TLS object -> incoming plaintext read error
2024-03-07 12:02:42 TLS Error: TLS handshake failed
2024-03-07 12:02:42 SIGTERM[soft,tls-error] received, process exiting

tls-verify.sh is trivial:

#! /bin/sh

env | grep digest
selvanair commented 3 months ago

Double check that "peer.crt" you expect is really what the server is using.

Your test using tls-verify.sh is not conclusive in this case. The script gets called multiple times with each leaf of the chain only after successfully verifying the certificate. As server cert verification fails, tls-cerify.sh will not get called for it. The call you are seeing is probably with a higher depth certificate presented by the server. You can confirm that by also printing out the arguments passed to the script -- the first arg is depth and second arg the subject (DN) of the certificate. See whether depth = 0, and CN in the subject matches that of the server.

Alternatively, as a test, trust the logs for a moment, use the fingerprint that it reports as the one to expect. This will allow the handshake to complete and you can extract all certificates presented by the server using --tls-export-cert and check.

vlk-charles commented 3 months ago

You are totally right. I thought I had checked this multiple times. This is a simple deployment where peer.crt is a self-signed certificate generated by the server. It didn't occur to me that it uses that (CA) certificate to sign another generated certificate and then both get sent as a chain during the handshake. What also threw me off was that both of these certificates have the same issuer DN, subject DN and validity period.

I apologize for the unwanted noise and thank you for the pointer. Not a bug and works as intended.

TinCanTech commented 3 months ago

@vlk-charles Please, could you clarify which certificate fingerprint was sent ?

vlk-charles commented 3 months ago

@TinCanTech No fingerprint was "sent" over the network. At first I was telling the client to verify against 9d:89:83:58:c6:58:06:87:45:fe:62:26:16:3e:d9:11:f9:14:48:6d:0c:8b:20:4b:87:99:75:8a:d4:aa:35:54 as written in the original report as I thought that was the only certificate being used. After @selvanair's helpful comment, I tried using the fingerprint mentioned in

2024-03-07 11:45:41 TLS Error: --tls-verify/--peer-fingerprintcertificate hash verification failed. (got fingerprint: 9a:26:3e:4e:a3:9c:73:af:1d:7e:1f:d1:6a:b8:8f:61:29:26:ed:a7:42:d0:37:f9:4d:0c:9c:20:fc:34:3e:da

The verification worked and I used --tls-export-cert in combination with a --tls-verify script to see that there are actually two different (albeit similar) certificates. One for each of the above mentioned fingerprints.