I would want my C/C++ client to authenticate the server via SSL.
I first downloaded the certificate file from the server with
openssl s_client -showcerts -connect www.openssl.org:443 </dev/null 2>/dev/null | openssl x509 -outform PEM > mycertfile.pem
Then in my application I do the following API invocations (pseudo code):
// Register the error strings for libcrypto & libssl
SSL_load_error_strings();
// Register the available ciphers and digests
SSL_library_init();
// New context saying we are a client, and using SSL 2 or 3
ctx = SSL_CTX_new(SSLv23_client_method());
// load the certificate
if(!SSL_CTX_load_verify_locations(ctx, "mycertfile.pem", 0))
...
// Create an SSL struct for the connection
ssl = SSL_new(ctx);
// Connect the SSL struct to our pre-existing TCP/IP socket connection
if (!SSL_set_fd(ssl, sd))
...
// Initiate SSL handshake
if(SSL_connect(ssl) != 1)
...
// form this point onwards the SSL connection is established and works
// perfectly, I would be able to send and receive encrypted data
// **Crucial point now**
// Get certificate (it works)
X509 *cert = SSL_get_peer_certificate(ssl);
if(cert) {
// the below API returns code 19
const long cert_res = SSL_get_verify_result(ssl);
if(cert_res == X509_V_OK) {
printf("Certificate verified!\n");
}
X509_free(cert);
}
Above code works fine if I don't mind checking the certificate and I'm just interested in an encrypted connection.
Problem with it is that when I try to verify the authenticity of the server, I do get the certificate from SSL_get_peer_certificate but then the verification of results doesn't work even if I've just downloaded the certificate 5 minutes before.
What am I doing wrong?
All this is on Ubuntu 12.04.03 x86-64 with gcc and openssl.
Thanks,
Ema
You should only call SSL_CTX_load_verify_locations() if you have a more complete set of CA certificates than what OpenSSL already provides, or if you are connecting to a server that has used a non-standard CA to sign its cert, and for which you have the CA certificate to verify the server cert. Otherwise, you should call SSL_CTX_set_default_verify_paths() instead.
// load the certificate^H^H^H^H^H^H^H^H^H^H^H^H CA trust-store
if(!SSL_CTX_set_default_verify_paths(ctx))
...
On a side note, your program had another error. You passed the wrong pointer to SSL_get_verify_result(). Instead of passing in a SSL_CTX *, you should pass in the SSL *. The compiler should have warned you about this error.
const long cert_res = SSL_get_verify_result(ssl);
The certificate you just downloaded should have been signed by a certificate authority (CA). You need to load the certificate of the CA (or the root CA) and not the certificate itself. Since you loaded the server's certificate directly into the SSL_CTX_load_verify_locations, the verification routine SSL_get_verify_result returned with a failure code. Most likely the verification code must have been 19 (X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN).
That said, OpenSSL comes with a built-in set of CAs (and root CAs) that you can use in your client application. The path to these certificates, on a Linux distribution, is typically /etc/ssl/certs. So, you can try changing your SSL_CTX_load_verify_locations as below:
if (!SSL_CTX_load_verify_locations(ctx, NULL, "/etc/ssl/certs"))
...
Of course, this assumes that /etc/ssl/certs exists and has the relevant certificates (one of which signed the server certificate). If you are authenticating a well known host, you will most likely find the CA in /etc/ssl/certs.
Related
I am not getting any SCTs when using OpenSSL. After setting up the SSL connection, I'm calling
SSL_enable_ct(ssl, SSL_CT_VALIDATION_PERMISSIVE);
const STACK_OF(SCT) *sct_stack = sk_SCT_new_null();
sct_stack = SSL_get0_peer_scts(ssl);
printf("%i SCTs obtained.\n", sk_SCT_num(sct_stack));
And it always prints out that I obtained 0 SCTs, regardless of the domain that I connect to. The thing is, the connection is being setup correctly, because I can grab the X509 certificate for any domain I connect to, and I can send OCSP requests and obtain responses to those requests. But when I try to grab the SCTs that should be sent, my code always informs me that there were no SCTs.
I have a strong feeling that it is my code that isn't working, because even when I connect to one of google's websites, such as google.com or gmail.com, I am unable to obtain any SCTs from the connection, despite the fact that Google pioneered certificate transparency.
I'm building a web service to allow salesforce to call to it, the two way SSL is used for security, and salesforce has provided its client certificate: sfdc-client.cert.
In order to test whether salesforce client certificate work or not, I have setup a very simple web on MAC apache and enable SSL and client authentication on ssl config file /etc/apache2/extra/httpd-ssl.conf as below (use self-signed):
SSLCertificateFile "/private/etc/apache2/ssl/server.crt"
SSLCertificateKeyFile "/private/etc/apache2/ssl/server.key"
SSLCACertificateFile "/private/etc/apache2/ssl/sfdc-client.cert"
SSLVerifyClient require
SSLVerifyDepth 10
The first browsing by Chrome, I got "SSL Connection Error", I supposed it's correct in this case.
Then, I have tried to import sfdc-client.cert to key chain access, but it does not work at all because it just supports p12/pfx format.
I also tried to use CURL:
curl https://test.com --cert-type der --cert sfdc-client.cert
but got the error:
curl: (58) unable to use client certificate (no key found or wrong pass phrase?)
I'm totally newbie on this stuff, does anyone know how to test client certificate to make sure it works as above?
First you need to have both the client's certificate and certificate private key to be able to test 2-way SSL authentication.
To test with web browser, follow instructions here: Is there a way to test 2 way ssl through browser?
I have written a SOAP client using OpenSSL on Linux. I basically did some information gathering from OpenSSL website and other online resources and the following code summarises how I send the XML to the SOAP server.
SSL_library_init();
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
SSL* ssl;
BIO* bio = BIO_new_ssl_connect(ctx);
if (bio == NULL) {
SSL_CTX_free(ctx);
return false;
}
BIO_get_ssl(bio, &ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
char target[] = "api.betfair.com:https";
BIO_set_conn_hostname(bio, target);
BIO_set_nbio(bio,1);
while (1) {
if (BIO_do_connect(bio) <= 0) {
if (!BIO_should_retry(bio)) {
cout << "Connect failed." << endl;
BIO_free_all(bio);
SSL_CTX_free(ctx);
return false;
}
} else {
break;
}
}
KeepAliveReq KeepAliveReq(sessionTok,0,iMode);
string strMessage = KeepAliveReq.GetXML(false);
BIO_puts(bio,strMessage.c_str());
This works well enough and has been reliable (if somewhat slow) for a number of weeks. I intentionally omitted the certificate checking phase of the SSL handshake process because at the time I did not really understand the details of it and the server I am sending to is of a well known company. My question is can I assume that my data is being encrypted by the SSL code or not? As far as I can make out from my code, I am not explicitly asking for encryption to occur, I am assuming that this simply occurs as part of the SSL communication process. Has my omission of certificate checking compromised the security of my application with regards to encryption?
Your data is still being encrypted—but the question is, to whom?
The certificate checking process is where we verify that the other party is who they claim to be. When someone orders an SSL certificate, the company who distributes the certificate will undertake measures to ensure they're giving the certificate and key to the rightful owner of the domain (or other entity) it's being ordered for. That company will then sign the certificate with their own details, which in turn are signed by a company your computer already trusts.
When you establish an connection, your computer checks the links to ensure that the certificate is legitimate, i.e. it's been signed by someone your computer trusts (perhaps indirectly through several layers of trust).
Skipping this process means anyone could generate a certificate on their own computer for any given website. Assuming they can then hijack connections you make, they can cause your system to believe it's the well-known company with ease.
You need to check the certificate to be secure.
I am actually working on a protocol security. I need to send the certificate and verify it on the other side.
Now here is what I have planned:
1 Send the certificate chain just like a normal stream of data
2.Capture it on the other side and store it in a char[] buffer
Now, how to verify the certificate from this char[]buffer and extract the needed parameters?
I need it in c/c++.
This blog post about Verifying Using a Certificate Store using OpenSSL shows how to verify certificate against CA.
I am using libcurl in my C application to communicate with an HTTPS server that I have set up. I generated a self-signed certificate on that server that I wish to use with curl.
I am aware of setting CURLOPT_SSL_VERIFYPEER to 0 to bypass the SSL verification, but I wish to add the generated certificate to curl's "valid" CA certificates.
I have tried setting CURLOPT_CAPATH and CURLOPT_SSLCERT to the location of the server SSL public key, but it fails to pass the verification.
How can I add my own CA/Self-signed certificate so that libcurl will successfully validate it?
To add a self-signed certificate, use CURLOPT_CAINFO
To retrieve the SSL public certificate of a site, use
openssl s_client -connect www.site.com:443 | tee logfile
The certificate is the portion marked by ----BEGIN CERTIFICATE---- and
---END CERTIFICATE----.
Save that certificate into a file, and use curl in a manner like so:
CURL* c = curl_easy_init();
curl_easy_setopt(c, CURLOPT_URL, "https://www.site.com");
curl_easy_setopt(c, CURLOPT_CAINFO, "/path/to/the/certificate.crt");
curl_easy_setopt(c, CURLOPT_SSL_VERIFYPEER, 1);
curl_easy_perform(c);
curl_easy_cleanup(c);
First, you kind of mix "Certificate Authority" files and "Certificate" files which confuses me.
How can I add my own CA/Self-signed certificate so that libcurl will
successfully validate it?
This might be seen as a complementary answer to the one above.
In the case you want to add a self-signed CA (every root-CA is self-signed) so that libcurl will successfully validate a website's certificate, which has been generated by the CA, then continue reading.
With CURLOPT_CAINFO you need to pass the "Certificate Authority" file (CA) that was used when generating the (non-CA) certificate of the site you want to verify.
(I do not know if this option works by passing it a non-CA certificate, the documentation is not really clear on this, and the previous answer has 2 up-votes, so if anyone has tested it please comment)
You can also pass a Certificate Authority chain file that contains the CA that was used, in case it was not a root-CA.
Here's a little tutorial I've found that can help you test your solution:
Creating a private root CA:
http://www.flatmtn.com/article/setting-openssl-create-certificates
Creating a site certificate:
http://www.flatmtn.com/article/setting-ssl-certificates-apache