validating X.509 certificate on linux - c

I have just started working with X.509 certificates. Can any one tell me how to go about validating a certificate on linux? The use case is that my app had downloaded a certificate in a previous session and I have to check if it is still valid (i.e., not expired or revoked since it was stored) before starting a new session. I understand a full sample will not be possible here, but any pointers will be useful.
EDIT: Further investigation revealed another utility called Network Security Services (NSS). How does that compare to OpenSSL in terms of usability? Also, I am looking for programmatic solutions as I will not be able to launch command line utilities.

As others mentioned, you can use openssl verify. According to the documentation, it also checks the validity period.
Programmatically, it could mean hours of searching for kinda bad (or missing) documentation, reading code examples all over the web, and probably a headache.
To properly validate a certificate, you need to inform all the intermediate certificates. Normally you'd also inform the revocation list (CRL), but it's not required.
So, here's what you need to do in terms of code (OpenSSL):
X509_STORE_new - Create a certificate store;
X509_STORE_CTX_new - Create a store context;
X509_STORE_add_cert - Add the CA (and all intermediary) certificate(s) to the trusted list of your certificate store (note: there's a function to lookup/load a list);
X509_STORE_add_crl - Add the revoked certificates to the CRL of your certificate store (note: same as above);
X509_STORE_CTX_init - Initialize your store context informing your certificate store;
X509_STORE_CTX_set_purpose - Define the purpose if you need so;
X509_STORE_CTX_set_cert- Tell the context which certificate you're going to validate;
X509_verify_cert - Finally, validate it;
X509_STORE_CTX_cleanup - If you want to reuse the context to validate another certificate, you clean it up and jump back to (5);
Last but not least, deallocate (1) and (2);
Alternatively, a quick validation can be done with X509_verify. However, be aware that it compares signatures solely.
When I needed it, took me a day of searching, reading and testing. Then I figured out everything I needed was right in the OpenSSL source-code. So, if you need an example, go straight to openssl-xxx/apps/verify.c.
IMPORTANT: NEVER use MD5. To understand the reason, read Creating a rogue CA certificate.

openssl verify will do what you want, if you want a simple tool:
From running:
cd /usr/share/ca-certificates
find . -type f -exec openssl -verify {} \;
Here's a selection of the output:
./telesec.de/deutsche-telekom-root-ca-2.crt: OK
./brasil.gov.br/brasil.gov.br.crt: OK
./cacert.org/cacert.org.crt: OK
./spi-inc.org/spi-ca-2003.crt: /C=US/ST=Indiana/L=Indianapolis/O=Software in the Public Interest/OU=hostmaster/CN=Certification Authority/emailAddress=hostmaster#spi-inc.org
error 10 at 0 depth lookup:certificate has expired
OK
./spi-inc.org/spi-cacert-2008.crt: OK
./signet.pl/signet_ocspklasa3_pem.crt: /C=PL/O=TP Internet Sp. z o.o./CN=CC Signet - CA Klasa 3/serialNumber=Numer wpisu: 4
error 2 at 1 depth lookup:unable to get issuer certificate
./signet.pl/signet_ca3_pem.crt: /C=PL/O=TP Internet Sp. z o.o./CN=CC Signet - CA Klasa 3/serialNumber=Numer wpisu: 4
error 20 at 0 depth lookup:unable to get local issuer certificate
If you'd rather have the results in a larger program, perhaps the gnutls_x509_crt_verify(3), gnutls_x509_crt_get_key_usage(3), gnutls_x509_crt_check_revocation(3) interfaces are easier to use than OpenSSL. (I've never used gnutls, but I have used OpenSSL.)

OCSP is a protocol to check revocation of certificates. Openssl provides certificate chain validation and signature verification APIs. It requires some amount of coding. So i would suggest you to look into Openssl Documentation.
You have to pass the certificate chain and validate it until you reach a root certificate which should be already saved on your machine. This is self signed certificate issued by entities called Root CAs(Certificate authority)
Apart from OCSP there is a outdated method where you have to fetch revocation list namely CRLs and parse that list for the certificate id.
EDIT:
I forgot to mention the openssl command line utility which does the same functionality.

Related

Can I use the openssl lib to find my server certificate in a buffer containing a certificate chain

My C program receives a certificate chain from a server and stores it in a buffer (certs in DER format). Is it possible to find out where the leaf certificate is stored within this buffer and the length of it by using the openssl library?
I need this information to be able to calculate a checksum based only on the contents of the leaf certificate. Parsing certificate chains seems like a common task, so I suppose there should be support for it by the openssl library.
The solution to my question was to parse the buffer using d2i_x509() to find each certificate.

Microsoft implementation of generating SSL certificate

I am building a server/client application and I would like to use Microsoft's SSL instead of a 3rd party library such as OpenSSL.
I have came across this example code on the MSDN:
Server: https://learn.microsoft.com/en-us/windows/win32/secauthn/using-sspi-with-a-windows-sockets-server
Client: https://learn.microsoft.com/en-us/windows/win32/secauthn/using-sspi-with-a-windows-sockets-client
I am looking through the code and it appears that it is using a function AcquireCredentialsHandle which from my understanding just uses existing credentials (cert?) found on the system.
I would like to, if possible, create my own certificate on the fly each time I connect to the server. This way the cert is changed each time and if anyone were to get my cert then it would only be useful for the specific set of traffic.

azure iothub sdk mqtt sample - error tls certificate

I'm trying to run the azure iothub sdk c sample of the mqtt protocol.
I've compiled hte project but when I run the program it returns some error about SSL routines
This i the complete error:
error:1416F086: SSL routines:tls_process_server_certificate:certificate verify failed
Info: Closing tlsio from a state other than TLSIO_STATE_EXT_OPEN or TLSIO_STATE_EXT_ERROR
I got only this error repeated five times, one for each accepted message ready to be transmitted to the IoTHub.
I've read that I need to set trust to the openssl certs in the sample directory but I've not figured out how to do this task or how to avoid this problem.
Is there someone who has already faced this issue?
This document describes in detail how to prepare your development environment as well as how to run the samples on Linux, Windows or other platforms. Please refer to the section to rebuild you code and then run to test.
Try using the TrustedCerts option. With this option you can pass to the SDK the certificate that is used to validate the server's certificate. This is typically used when either you don't have the root certificate, Baltimore CyberTrust, or your device does not have the concept of a trusted root certificate store. You can find an example of this option being used in
<repositoryRoot>\iothub_client\samples\iothub_client_sample_amqp_shared\iothub_client_sample_amqp_shared.c
https://github.com/Azure/azure-iot-sdk-c/blob/44827986929af7f4fbb41806b880a6da4e13d3e8/iothub_client/samples/iothub_client_sample_amqp_shared/iothub_client_sample_amqp_shared.c#L261

Openssl: certificate verification fails when CApath argument is used in SSL_CTX_load_verify_locations API

I am trying to establish a TLS connection to a server machine. I have created the root CA certificate and the server certificate using openssl CLI commands. I created the server certificate with common name same as its IP address. The common name of the root CA certificate is the FQDN of the server.
I am using openssl library APIs to establish connection to the server.
I am using the API
int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath)
for setting the CA file look up path.
Everything works fine when I use the CAfile argument to specify the path of my CA file, leaving the CApath argument as NULL.
But if I use the CApath argument to specify the path to the directory containing the CA files, leaving the CAfile argument as NULL, the connection fails due to certificate verification error.
When I captured the packets using wireshark, I found that my client code is sending TLS response "Unknown CA" for the "server hello" from the server. I have used the same CA certificate file that I have used in the successful connection.
From my observation while exploring the openssl library source code, I infer that, in my case, the CA files are not being considered valid and hence not being loaded by the library APIs due to some unknown reason.
Can someone tell me the reason and, if possible, a solution for this issue?
I'm posting answer for my own question, because I spent a lot of time for finding a solution for this problem since I didn't get too much information regarding this issue from the internet. And I hope this will help someone else facing the similar issue.
If the CApath is not null, the directory pointed by CApath should contain valid CA certificates. And the most important thing is that the CA file name should be the subject name hash value.
Either the CA files can be renamed to their subject name hash values or softlinks to the CA files can be created with the name same as the CA subject name hash of the CA files.
c_rehash utility can be used to create the necessary links in the CApath. The syntax of this command is quite simple.
c_rehash <CApath>
c_rehash utility may not be available in all linux distros. In that case
openssl x509 -in <CA file name> -noout -subject_hash
can be used to generate the subject name hash(e.g. e5d93f80). Just append ".0" to this value and create a softlink with this name(e5d93f80.0) to the CA file. If there are more than one CA files with same the subject name hash value, their extensions should be different(e.g. e5d93f80.1). The search is performed in the ordering of the extension number.
opensssl has introduced this technique to reduce the the CA file look up time. Otherwise openssl may have to read all files in the CApath to find the matching CA file.

Do you want the application to accept incoming network connection?

I have two C binaries which tries to open network connection for communication.
This is for external communication. When i run that for the first time, OS X' firewall pops up the message as given in title. How can I get rid of this?
I suspect this is related to code-signing? How to do code-sign this binary?
Basically I have to build this binary in one Mac machine, and distribute outside app store.
How can I get rid of the firewall pop up if the OS X firewall is enabled in the machine?
You can resolve this by signing the offending application binary yourself.
Disclaimer: Signing an application yourself will make an application appear more
secure to the operating system, when in reality it isn’t. Only sign applications
that you are 100% sure are not spyware or otherwise malicious. If you have any
doubts, just uninstall/reinstall.
Part 1: Create a Signing Identity
The solution I’m going for – signing the app myself – requires that I create a Signing Identity, also known as Signing Certificate. This is very easy to do:
Open Applications > Utilities > Keychain Access.
From the Keychain Access menu, choose Certificate Assistant > Create a Certificate.
Fill in a name for the certificate. This name appears in the Keychain Access utility as the name of the certificate. This is also the name you will use when referencing this certificate. Personally, I used the name, “My Signing Identity.”
Choose Code Signing from the Certificate Type menu.
Choose Self Signed Root from the Type popup menu.
Check the Let me override defaults checkbox.
Click Continue.
Specify a serial number for the certificate. Any number will do as long as you have no other certificate with the same name and serial number.
Click Continue.
Fill in the information for the certificate. You can use real or fake data, I used real data personally.
Click Continue.
Accept the defaults for the rest of the dialogs.
Once completed, you will see your certificate in Keychain Access. Verify the name you picked, and you’re done with this step. Well done!
Step 2: (Re-)Sign your application
Now you have to sign your application. To do this, open up Terminal again and use the following command:
codesign -s "My Signing Identity" -f /path/to/your/binary/app
A dialog will appear, click "Allow".
Now start your application again. You will get the accept incoming connections dialog one last time. Click "Allow".
From now on you should no longer get the warnings anymore! Now it is possible to enjoy the security of your firewall being active without the inconvenience of having to click "allow" constantly.
Credit: The original source which served as a starting place for this updated and annotated solution guide was http://silvanolte.com/blog/2011/01/18/do-you-want-the-application-to-accept-incoming-network-connections/
In my case this alert appeared when i run Python project from PyCharm after updating MacOS to 10.15 Cataline. I fixed it with
codesign -vvv /Applications/PyCharm.app/
I was trying to apply this solution to fix python as used by Arduino OTA, I found another solution describing self-signing the app that stated $(which python) as the file path to sign, but in my case that resolved to /usr/bin/python. Self-signing this not only required I drop to Rootless mode to allow writing to /usr/bin, but when I went back and tested it, python was STILL asking for permission to allow incoming connections!
The correct python file to self-sign is in fact (in my case at least) /System/Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app
Once I self-signed this correct file path, the Arduino OTA process no longer required me clicking allow incoming connections - Hoorah!
Hope that helps someone.

Resources