I'm using cUrl to request data from a corporate website site using a .cer certificate that they sent me.
This is the command:
cUrl --header "Content-Type: text/xml;charset=UTF-8" \
--data #bustaRequestISEE2015ConsultazioneAttestazione.xml \
-o bustaResponseISEE2015ConsultazioneAttestazione.xml \
--cert ./caaffabisrl.cer \
https://istitutonazionaleprevidenzasociale.spcoop.gov.it/PD
When I run it, I get this error message:
curl: (58) could not load PEM client certificate, OpenSSL error error:0906D06C:PEM routines:PEM_read_bio:no start line, (no key found, wrong pass phrase, or wro
ng file format?)
Is there anybody who can help me?
Tks, Cristiano.
It is not possible to connect to a TLS server with curl using only a client certificate, without the client private key. Either they forgot to send you the private key file, or, what they sent you was not the client certificate but the server certificate for verification.
The first thing I would try is using --cacert instead of --cert. That is, tell curl that this is the server's certificate that curl can use to verify that the server is who you think it is.
You can also try removing --cert and not using --cacert, and you will probably get an error that the server is not trusted. Then add the --insecure argument and see if that works. I would not keep that argument, as then you have no proof of who you are talking to.
My guess is that it is the server cert, and that using --cacert instead of --cert will solve the problem.
My guess is that your certificate file is a DER encoded binary certificate instead of base-64 encoded certificate. To covert the from binary to base-64, you can use OpenSSL.
openssl x509 -inform der -in certificate.cer -out certificate.pem
I always forget all the arguments and have the following site bookmarked, as it gives examples of how to convert pretty much any certificate format. https://www.sslshopper.com/ssl-converter.html
First, you need to specify whether you're expected to perform two-way TLS/SSL or MTLS (mutual TLS). This would typically be the reason for sending a certificate. If they sent the server certificate, but you can connect to the server with a browser, you can down load the certificate. If their server is configured to send the server certificate and CA chain, then you can get the entire chain in a single request using "openssl s_client -connect [hostname:port] -showcerts". Save the certs in the console to a file, copying the cert blob(s) to individual cert files (cert1.crt, cert2.crt). However, if they are expecting MTLS and attempting to send a client certificate to you, either you've already generated a private key and CSR (certificate signing request) and send them the CSR. They would have then signed a certificate with their CA certificate using the CSR. The cert they returned would then need to be paired with the private key used to generate the CSR. They should not be generating the public/private key pair and sending them over mail. The private key should be stored security on the one system used to establish the connection. If it's one-way (server ssl only), then your client system (assuming it's not the browser), needs a truststore file, with the CA certificate chain installed and set to trusted. If the platform is Java, read Java's keytool documentation. Note, a keystore is for your systems public/private keypair. A truststore is for the CA certificates that you trust to sign public certificates that your system should trust as being authentic. You need to read any of the PKI x509 overviews by DigiCert, SSLABS, Sectigo, etc.
Related
I'm trying to have a server A communicate with a server B through HTTPS requests. Server B has a certificate that was issued to me by my employer, and connecting to it through both Safari and Chrome works without any issues.
However, when trying to send a request from A to B through Guzzle, I get the following error:
GuzzleHttp/Exception/RequestException with message 'cURL error 60: SSL certificate problem:
unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html)'
I've tried setting the cert file as a parameter ( [verify => '/path/to/cert.pem'] ), but, first of all, I only had .crt, .csr and .key files; I tried making a .pem file through these instructions I found somewhere else:
(optional) Remove the password from the Private Key by following the steps listed below:
openssl rsa -in server.key -out nopassword.key
Note: Enter the pass phrase of the Private Key.
Combine the private key, public certificate and any 3rd party intermediate certificate files:
cat nopassword.key > server.pem
cat server.crt >> server.pem
Note: Repeat this step as needed for third-party certificate chain files, bundles, etc:
cat intermediate.crt >> server.pem
This didn't work – the error's the same. The request works with 'verify' set to false, but that's obviously not an option for production.
Certificates are not something I usually work with, so I'm having a lot of trouble just figuring out where the issue might lie, let alone fix it. Any help would be much appreciated.
Edit
I've also tried the solutions suggested in Guzzle Curl Error 60 SSL unable to get local issuer to no avail.
This was happening because the only certificate I had configured on server B was the End User certificate.
I'm new to this, so my explanation will probably be flawed, but from my understanding End User certificates link back to a trusted Certificate Authority (CA) certificate, with zero or more intermediate certificates in-between. Browsers can figure out this certificate chain, and download the required certificates that are missing; cURL does not.
Therefore, the solution was configuring Server B with the missing certificates. How to do this is a whole different issue, so I won't go into it in this answer.
I am trying to call an URL using curl, I used below command:
curl https://testenvironment/login --cert Qa1Certificate.pem
The result I get is:
curl: (60) Peer certificate cannot be authenticated with known CA certificates
More details here: http://curl.haxx.se/docs/sslcerts.html
curl performs SSL certificate verification by default, using a "bundle"
of Certificate Authority (CA) public keys (CA certs). If the default
bundle file isn't adequate, you can specify an alternate file
using the --cacert option.
If this HTTPS server uses a certificate signed by a CA represented in
the bundle, the certificate verification probably failed due to a
problem with the certificate (it might be expired, or the name might
not match the domain name in the URL).
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.
The Qa1Certificate.pem is placed in the current directory, and I believe that it is not taken into consideration because when I run the same command with a file name which does not exist:
curl https://testenvironment/login --cert ThisFileDoesNotExist.pem
I get the same result.
I am aware that I can obtain what I need using the -k or --insecure options( or other ways of disabling curl's verification of the certificate), but I
want to find out how can I use the certificate in order to perform a successful GET to my test environment.
The test environment uses a self signed certificate which I obtained using openSSL.
TLDR: it's --cacert
From the man page, which should be on your system or on the web:
-E, --cert <certificate[:password]>
(TLS) Tells curl to use the specified client certificate file when getting a file with HTTPS, FTPS or another SSL-based protocol. [snip rest]
Note the words 'client certificate'. --cert is used to specify a certificate and possibly key to authenticate the client, NOT to verify the server.
Now consider another entry on the man page:
--cacert
(TLS) Tells curl to use the specified certificate file to verify the peer. The file may contain multiple CA certificates. The certificate(s) must be in PEM format. Normally curl is built to use a default file for this, so this option is typically used to alter that default file.
This is the option to specify a cert or certs to verify (and specifically to anchor) the server's cert. Since your server cert is selfsigned, the cert is its own anchor/root and effectively is a CA cert, even though the server isn't actually a CA.
That's why the error message you posted includes the words
you can specify an alternate file using the --cacert option.
It does not say --cert.
Whether the client cert (and key) is read depends on the middleware used by the specific build of curl you are running. IME if built with OpenSSL it does give an error if you specify --cert with a nonexistent filename, but a version built with NSS (on Ubuntu 14.04LTS) gives an error only if the server requests client auth, which most servers don't.
I am developing a client/server application with TLS. My idea is to use a certificate on the client so it is authenticated by the server. Also another certificate on the server so the client is also able to authenticate that it is connecting to the right server.
I want first to test and use openssl s_server and openssl s_client to validate the proposal.
Until now I have created a CA private key on the server, I have created a root certificate. With the root certificate I have signed two CSR, so I get one certificate for the server and one certificate for the client.
I also have installed the client certificate + root certificate on the client, and the server certificate + root certificate on the server.
I want now to try to establish a connection between openssl s_server and openssl s_client and verify that they get both authenticated mutually, but I cannot wrap my mind with the documentation on how to do it. Any help or any guide on that?
Once I have that set up, the next step is to test the own developed client against that server, and our own developed server against the s_client. Can we use that for testing?
Thanks
It looks like you are trying to set up a root of trust with (1) s_client and s_server for testing; and (2) programmatically within your code using OpenSSL.
To ensure openssl s_client (or openssl s_server) uses your root, use the following options:
-CAfile option to specify the root
-cert option for the certificate to use
-key option for the private key of the certificate
See the docs on s_client(1) and s_server(1) for details.
To do the same programmatically on the client, you would use:
SSL_CTX_load_verify_locations to load the trusted root
SSL_CTX_use_certificate to specify the client certificate
SSL_CTX_use_PrivateKey to load the private key for the client certificate
To do the same programmatically on the server, you would use:
SSL_CTX_load_verify_locations to load the trusted root
SSL_CTX_use_certificate_chain_file to specify the server certificate
SSL_CTX_use_PrivateKey to load the private key for the server certificate
SSL_CTX_set_client_CA_list to tell the client to send its client certificate
If you don't want to use the parameters for every connection (i.e. the common context), then set it for each SSL connection with, for example, SSL_use_certificate and SSL_use_PrivateKey.
A lot goes on with SSL_CTX_set_client_CA_list. It (1) loads the CA's to the server uses to verify a client, (2) it causes the server to send a list of CAs it accepts when verifing a client, and (3) it triggers the ClientCertificate message at the client if the client has a certificate that satisfies the server's accepted CAs list.
Also see the docs on SSL_CTX_load_verify_locations(3), SSL_CTX_use_certificate(3), SSL_CTX_set_client_CA_list and friends.
The easiest certificate and key format to use is PEM. PEM is the one that uses, for example, ----- BEGIN CERTIFICATE -----. For the server certificate, be sure the file is a concatenation of the server's certificate and any intermediates needed by the client to build the chain.
Having the server send all required certificates is standard practice for a problem known as the "which directory" problem. Its a well known problem in PKI, and its essentially the problem that clients don't know where to go to fetch missing intermediate certificates.
In general, you now know the functions that you need to use. Download a small server like nginx, and see how a production server uses them in practice. You could even use a SQL server like Postgres since it sets up a SSL/TLS server. Simply search the source files for SSL_CTX_load_verify_locations or SSL_load_verify_locations, and you will find the right place.
Though I don't recommend it, you could even look at s_client.c and s_server.c. They are located in <openssl dir>/apps. But the code can be difficult to read at times.
Generate two pairs of certificates/keys, one for the server and one for the client. Also create test.txt with any content.
To set up an SSL server that checks a client certificate, run the following command:
openssl s_server -cert server_cert.pem -key server_key.pem -WWW -port 12345 -CAfile client_cert.pem -verify_return_error -Verify 1
To test the server with client certificate, run the following command:
echo -e 'GET /test.txt HTTP/1.1\r\n\r\n' | openssl s_client -cert client_cert.pem -key client_key.pem -CAfile server_cert.pem -connect localhost:12345 -quiet
Alternatively you can use curl command:
curl -k --cert client_cert.pem --key client_key.pem https://localhost:12345/test.txt
I have a backend server with SSL only as defaut public interface. This server listens on 443 with cert, key and ca files on, ssl verify client is set to true.
On client side, I have client cert, key and a ca file made of 2 CA files catted together (intermediate CA, root CA) in a single ca.pem file. When I do curl request on my backend server, it works fine. I also tested the server / client cert and key with gnutls-serv and openssl s_server to ensure all was valid.
But when I create a keystore on Apigee (client cert and key file [pem format]) and a trustore (ca.pem file), there is an error:
- target.name fsbca-test
- Properties
- Expression ("fsbca-test" equals target.name)
- ExpressionResult true
- Tree TARGET_fsbca-test
- error The Service is temporarily unavailable
- error.cause General SSLEngine problem
- error.cause.cause General SSLEngine problem
- error.class com.apigee.messaging.adaptors.http.HttpAdaptorException
- state TARGET_REQ_FLOW
- type ErrorPoint
If I put SSL verify client to false on my backend, then the request is correctly diverted by Apigee and I get the response.
If I put IgnoreValidationErrors to true in the target endpoints property, then the request is diverted to my backend server but I can see an error in the server's log: "client sent no required SSL certificate while reading c...".
Any ideas about what could be wrong in what I am doing?
Additional track: could it be an issue on Apigee side with the CA file made of 2 certs (it may ignore trailing certificates found in a .pem). If wanted to test pkcs12 and jks but I failed to upload them to Apigee (the API doc page only describes .pem, JAR and cert action). I wrote a small Java client with pkcs12 keystore and jks trustore and it worked fine from my local workstation.
Thank you in advance for any piece of information that could help me.
Regards
Fr
You should upload your certificates separately (one per cert), and you need the entire trust chain of certificates to be stored in your truststore.
Here is the page about SSL to your backend.
EDIT:
Here is a method I know works:
1) Separate certs into separate PEM files. Do not put more than once cert in a file.
2) Validate each cert using openssl:
openssl x509 -noout -text -in <cert file name>
Validate that no certs are expired, and that the Subject and Issuer fields create a chain of all the certs, with identical names.
The server's certificate, the root certificate, and all certificates in between need to be in the truststore.
I am developing a client/server application with TLS. My idea is to use a certificate on the client so it is authenticated by the server. Also another certificate on the server so the client is also able to authenticate that it is connecting to the right server.
I want first to test and use openssl s_server and openssl s_client to validate the proposal.
Until now I have created a CA private key on the server, I have created a root certificate. With the root certificate I have signed two CSR, so I get one certificate for the server and one certificate for the client.
I also have installed the client certificate + root certificate on the client, and the server certificate + root certificate on the server.
I want now to try to establish a connection between openssl s_server and openssl s_client and verify that they get both authenticated mutually, but I cannot wrap my mind with the documentation on how to do it. Any help or any guide on that?
Once I have that set up, the next step is to test the own developed client against that server, and our own developed server against the s_client. Can we use that for testing?
Thanks
It looks like you are trying to set up a root of trust with (1) s_client and s_server for testing; and (2) programmatically within your code using OpenSSL.
To ensure openssl s_client (or openssl s_server) uses your root, use the following options:
-CAfile option to specify the root
-cert option for the certificate to use
-key option for the private key of the certificate
See the docs on s_client(1) and s_server(1) for details.
To do the same programmatically on the client, you would use:
SSL_CTX_load_verify_locations to load the trusted root
SSL_CTX_use_certificate to specify the client certificate
SSL_CTX_use_PrivateKey to load the private key for the client certificate
To do the same programmatically on the server, you would use:
SSL_CTX_load_verify_locations to load the trusted root
SSL_CTX_use_certificate_chain_file to specify the server certificate
SSL_CTX_use_PrivateKey to load the private key for the server certificate
SSL_CTX_set_client_CA_list to tell the client to send its client certificate
If you don't want to use the parameters for every connection (i.e. the common context), then set it for each SSL connection with, for example, SSL_use_certificate and SSL_use_PrivateKey.
A lot goes on with SSL_CTX_set_client_CA_list. It (1) loads the CA's to the server uses to verify a client, (2) it causes the server to send a list of CAs it accepts when verifing a client, and (3) it triggers the ClientCertificate message at the client if the client has a certificate that satisfies the server's accepted CAs list.
Also see the docs on SSL_CTX_load_verify_locations(3), SSL_CTX_use_certificate(3), SSL_CTX_set_client_CA_list and friends.
The easiest certificate and key format to use is PEM. PEM is the one that uses, for example, ----- BEGIN CERTIFICATE -----. For the server certificate, be sure the file is a concatenation of the server's certificate and any intermediates needed by the client to build the chain.
Having the server send all required certificates is standard practice for a problem known as the "which directory" problem. Its a well known problem in PKI, and its essentially the problem that clients don't know where to go to fetch missing intermediate certificates.
In general, you now know the functions that you need to use. Download a small server like nginx, and see how a production server uses them in practice. You could even use a SQL server like Postgres since it sets up a SSL/TLS server. Simply search the source files for SSL_CTX_load_verify_locations or SSL_load_verify_locations, and you will find the right place.
Though I don't recommend it, you could even look at s_client.c and s_server.c. They are located in <openssl dir>/apps. But the code can be difficult to read at times.
Generate two pairs of certificates/keys, one for the server and one for the client. Also create test.txt with any content.
To set up an SSL server that checks a client certificate, run the following command:
openssl s_server -cert server_cert.pem -key server_key.pem -WWW -port 12345 -CAfile client_cert.pem -verify_return_error -Verify 1
To test the server with client certificate, run the following command:
echo -e 'GET /test.txt HTTP/1.1\r\n\r\n' | openssl s_client -cert client_cert.pem -key client_key.pem -CAfile server_cert.pem -connect localhost:12345 -quiet
Alternatively you can use curl command:
curl -k --cert client_cert.pem --key client_key.pem https://localhost:12345/test.txt