owacoder owacoder - 15 days ago 5
C++ Question

Boost.Asio SSL context not verifying certificate(s)

This is a continuation of my previous question, Boost.Asio SSL context load_verify_paths not loading certificate.

I have a CA file that is generated from the system CA store on Windows. Any invalid/expired certificates are not included in the generated file.

My Boost Asio code does not want to verify using this CA store. The file loads just fine, with

ssl::context::load_verify_file
returning without an error, but the verify callback keeps getting called with
preverified
set to
false
.

Here is an example run of openssl using the certificate file:

Loading 'screen' into random state - done
CONNECTED(00000178)
depth=3 /C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
verify return:1
depth=2 /C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA
Certification Authority
verify return:1
depth=1 /C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA
Domain Validation Secure Server CA
verify return:1
depth=0 /OU=Domain Control Validated/OU=PositiveSSL/CN=example.org
verify return:1
---
Certificate chain
0 s:/OU=Domain Control Validated/OU=PositiveSSL/CN=example.org
i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
1 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority
2 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority
i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
---
Server certificate
-----BEGIN CERTIFICATE-----
...snipped...
-----END CERTIFICATE-----
subject=/OU=Domain Control Validated/OU=PositiveSSL/CN=example.org
issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
---
Acceptable client certificate CA names
/OU=Domain Control Validated/OU=PositiveSSL/CN=example.org
/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority
/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
---
SSL handshake has read 5399 bytes and written 334 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : DHE-RSA-AES256-SHA
Session-ID: 8C04CCAE22F4B111AD13F10448ACDAD0C7F567F22C0D05829BDAE1DF9F29A005

Session-ID-ctx:
Master-Key: B99A5E1D0C3CF5421C41CDE88B6F21FD9816800409775C497859FAFCAE3A8942
1A670D72808C804A33A10BF9A26B22AB
Key-Arg : None
Start Time: 1477664766
Timeout : 300 (sec)
Verify return code: 0 (ok)


And another run of openssl without the certificate file:

Loading 'screen' into random state - done
CONNECTED(00000178)
depth=2 /C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
0 s:/OU=Domain Control Validated/OU=PositiveSSL/CN=example.org
i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
1 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority
2 s:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority
i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root
---
Server certificate
-----BEGIN CERTIFICATE-----
...snipped...
-----END CERTIFICATE-----
subject=/OU=Domain Control Validated/OU=PositiveSSL/CN=example.org
issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
---
Acceptable client certificate CA names
/OU=Domain Control Validated/OU=PositiveSSL/CN=example.org
/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Certification Authority
/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
---
SSL handshake has read 5399 bytes and written 334 bytes
---
New, TLSv1/SSLv3, Cipher is DHE-RSA-AES256-SHA
Server public key is 2048 bit
Compression: NONE
Expansion: NONE
SSL-Session:
Protocol : TLSv1
Cipher : DHE-RSA-AES256-SHA
Session-ID: 18036DF0E136729F9FE1BD8F51AA2FEF687D84D43918895B3F5847A2EB8C7109

Session-ID-ctx:
Master-Key: DA4BCC28FB9F4F5BCD9C9FBB51AA02B8A380F0580258A0F67E56BA2BFD627C54
AB700C343F0741A77AC037E54272EB1E
Key-Arg : None
Start Time: 1477665097
Timeout : 300 (sec)
Verify return code: 20 (unable to get local issuer certificate)


As you can see, the certificate file contains the appropriate root certificate, since openssl only connects when using the file.

My question is, why does openssl verify using this file, but Boost Asio does not? How do I correct the issue, so Boost Asio verifies using the generated CA store?

Answer

The problem was the creation of another boost::asio::ssl::context that was not loaded with system certificates, instead, it was using set_default_verify_paths, which works on Linux but not Windows. It worked on Linux because the system certificates are in the default verify path, but on Windows, it's an empty directory (I had not set up my OpenSSL install with any certificates).

For anyone else baffled by a similar problem, please, make sure you are actually using the boost::asio::ssl::context you are loading certificates into, so you don't waste as much time on it as I did.