Ruby Net HTTP Post: Certificate Verify Failed - ssl

Ruby 2.0, Rails 4.0.2
I have read a number of SO posts about the error I'm getting, and I'm still confused. Here's what I'm trying to do.
I'm running a Rails app on an Ubuntu server: https://rails.example.com. It has a PositiveSSL certificate for the domain from Comodo.
From within that Rails app, I'm trying to post data to a form on another one of my servers: https://api.example.com. It also has a PositiveSSL certificate.
Here's my code:
require 'net/http'
require 'uri'
uri = URI('https://app.pilotpro.com/scripts/migrate.php')
Net::HTTP.start(uri.host, uri.port,
:use_ssl => uri.scheme == 'https') do |http|
request = Net::HTTP::Get.new uri
response = http.request request
logger.info "::: #{response}"
end
This results in this error:
OpenSSL::SSL::SSLError at /test
SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B:
certificate verify failed
I don't get any SSL errors when I view these sites in my web browser, but I think I'm supposed to do something to tell my request about the certificate on the API server, but I am unsure.
Can someone give me some direction on what steps I need to take to make this request not fail?

openssl s_client -connect app.pilotpro.com:443 -CApath /etc/ssl/certs/ gives:
Certificate chain
0 s:/OU=Domain Control Validated/OU=PositiveSSL/CN=app.pilotpro.com
i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=PositiveSSL CA 2
That is the complete chain, which means, that your client expects to have PositiveSSL CA 2 as a trusted Root-CA in the CA store. But, this is not the case because this CA is just an intermediate CA so your HTTPS server should send all the intermediate CAs on the path to the trusted Root-CA.
So this is not a client-side, but a server-side problem. See also http://www.positivessl.com/ssl-certificate-support/cert_installation/apache-ssl.php
The reason you get no errors if you access it from browsers might be, that browsers cache intermediate CAs. So if the browser once connected to a host which provided the correct certificate chain it can from now on deal with hosts which omit the needed chain. With firefox you might try access with a fresh browser profile, which does not have any certificates cached.

Related

Is it possible to use self-signed server certificates alongside a valid trust chain?

I'm working on a project and I've hit a bit of a snag getting access to just a simple Flask page over HTTPS.
I have the following certificates/keys that must be used:
A PKI certificate (with non-exportable key) on a smart card
An intermediate certificate (without key) that signed the PKI above
A root certificate (without key) that signed the intermediate certificate above
I'm dabbling with using these concepts for the first time, but as I understand it, this is the trust chain:
User PKI > Intermediate > Root CA
At this point, I have a very small Flask application:
import ssl
from flask import Flask
app = Flask(__name__)
#app.route("/")
def main():
return "Hello World"
if __name__ == '__main__':
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
ctx.verify_mode = ssl.CERT_REQUIRED
ctx.load_verify_locations('intermediate.pem')
ctx.load_cert_chain('localhost.crt', 'localhost.key')
app.run(ssl_context=ctx)
Both intermediate and the Root CA that signed it are installed on the machine; further, inspecting certificates in the browser shows the user certificates available from the smart card as well. The problem, I believe, occurs with the localhost.crt/.key. No browser will allow me to reach the page, but they do allow me to select a certificate to compare to the intermediate certificate. For example, Firefox presents me with:
An error occurred during a connection to 127.0.0.1:5000. Peer does not recognize and trust the CA that issued your certificate. Error code: SSL_ERROR_UNKNOWN_CA_ALERT
When inspecting, the certificate that is of issue is the intermediate.pem. From what I can gather in the error message, it sounds like this chain does not agree:
User PKI > Self-Signed Server > Self-Signed Root
I could be wrong, but I am not sure unfortunately. Which chain is failing? Why? And how do I overcome it? I cannot get a server certificate signed by the Root CA either, so ideally for testing I would need to use self-signed server certificates.

BIg-F5 and Apache SSL configuration

Configure Apache and F5 loadbalancer.
From Apache layer we generate CSR and get the trusted cer as:
1) .cer
2) .p7b
Then I convert the .cer and .p7b file to .crt file and configure in our apache as keyfile, certificate and chain.
We are facing some issue while configuring the SSL between F5 and Apache. Our flow is:
Client(SSL) -> F5 (SSL drops ) -> (recreate ssl to apache layer) -> Apache webserver.
1) create CSR from apache web layer, get sign as trusted from the company (not external)
2) configure in ssl.conf and ciphersuite
Now initiate a request using openssl it is throwing:
depth = 1
DC = net
DC = racb
CN = XXXXXX
CA 1 verify error:num=20:unable to get local issuer certificate read from 0x1b9c8d0 [0x1ca04f3] (5 bytes => 5 (0x5))
In order to verify it I modified the /etc/hosts entry as xxx.xxx.xxx.net as 127.0.0.1 and move the chain certificate to /etc/pki/ca-trust/source/anchor and update-ca-trust extract and run the openssl which is return with error code=0 and waiting in SSL session.
What mistake we are doing in F5 no idea.
Can someone throw the lights?
If you're setting up a bridging config, you need both an SSL Client Profile (typically you take your Apache key/cert/chain) and an SSL Server Profile, and both are chosen on the Virtual Server configuration.
For the Client Profile you first need to import the private key, the certificate(s) and of course you have to see on the Certificates screen that the private key matches the certificate.
Usually for the Server Profile, if we know that we can trust the backend server, instead of setting up something with certificates of your own, we just choose the unsecure-compatible profile and it will work in almost all cases.
If there is no need to setup SNI, it's enough to make it work.

SSL Certificate error : Invalid CA

Can someone explain why this site https://whatsmychaincert.com/?www.uts.edu.au gives an error in certificate chain:
An error occurred when building the chain for this certificate. The certificate might lack necessary meta-data or its certificate authority might be malfunctioning. Details:
The chain contains an untrusted certificate without standard CA issuer information (subject = "C=BM, O=QuoVadis Limited, CN=QuoVadis Global SSL ICA G3"; issuer = "C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 2 G3"; error code = 20)
But if I test the same thing on other verification sites like: https://www.sslshopper.com/ssl-checker.html & https://www.digicert.com/help/ there are no issues reported ?
Will appreciate any help here.
This site whatsmychaincert is not trusting the root certificate because, as said in the error message, it doesn't know the issuer "C=BM, O=QuoVadis Limited, CN=QuoVadis Root CA 2 G3"
However both other sites know this issuer and say the certificate is valid. When testing with SSL Labs that most people use to check that kind of things, it also says everything is ok ( https://www.ssllabs.com/ssltest/analyze.html?d=www.uts.edu.au ). SSL Labs gives lots of details, including all certificates sent by the web server, then you exactly see the behavior.

Cannot perform HTTPS local tunnel fith Fiddler2 - Problems with certificates

I am trying to create an HTTPS-tunnel on my machine. My intention is having all requests to https://localhost:8888/<something> (the port where Fiddler is listening to) be directed to https://myserver.net/<something>. I am using the following script as per Fiddler doc:
static function OnBeforeRequest(oSession: Session) {
// <Fiddler 2 preexisting code>
// HTTPS redirect -----------------------
if (oSession.HTTPMethodIs("CONNECT") &&
(oSession.PathAndQuery == "localhost:8888"))
{
oSession.PathAndQuery = "myserver.net:443";
}
if (oSession.HostnameIs("localhost"))
oSession.hostname = "myserver.net";
// --------------------------------------
// <Fiddler 2 preexisting code>
}
Also in Fiddler settings I checked the decryption check and installed certificates as you can see in the image below:
I restart Fiddler, it prompts me to install its fake certificates, I agree. I can see the certificate in my Windows Certificate System Repository when using certmgr. It is a self-signed certificate.
So What I do is opening a browser and type: https://localhost:8888/mypage.html, and what I get is an error. Internet Explorer reports this:
Error: Mismatched Address. The security certificate presented by this
website was issued for a different website's address. This problem
might indicate an attempt to fool you or intercept any data...
When I get certificate info (basically the certificate presented by the contacted host is being rejected, the same certificate can be displayed), I can see that the rejected certificate was issued by Fiddler and the subject is myserver.net.
So the certificate is ok because it is certifying myserver.net, I see that the problem is that probably my browser was expecting a certificate whose subject is localhost. Is it true?
How to handle this situation?
Assumption
I can understand that the problem is a certificate being issued for a website which I did not ask for. So the solution would be using a certificate certifying localhost:8888?
A certificate is valid if it is directly or indirectly (via intermediate certificates) signed by a trusted CA and if the hostname matches the certificate. If the last condition would not be enforced anybody with a valid certificate from a trusted CA could incorporate any other site.
To make use of fiddler and not run into this problem you should configure your browser to use fiddler as a web proxy and then use the real URL inside the browser instead of ip:port of fiddler.

OpenSSL Failed for Specific Provider?

Our production (Heroku) and development (local) instances have been working when accessing a https endpoint. However, within the past 2 days, we started getting the dreaded OpenSSL error:
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
I've read through a lot of OpenSSL failed posts on StackOverflow and http://railsapps.github.io/openssl-certificate-verify-failed.html.
I have updated to the latest OpenSSL and confirmed it by running the following:
ruby -ropenssl -e 'p OpenSSL::OPENSSL_VERSION'
"OpenSSL 1.0.1e 11 Feb 2013"
However, I'm still getting this error:
OpenSSL::SSL::SSLError: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed
when I call hash = JSON.parse(open(_url).read) where the _url points to a https endpoint.
I don't seem to have problems accessing some providers. For example, when I issue: curl -I https://d2chzxaqi4y7f8.cloudfront.net/gems/rake-0.9.2.2.gem, it seems to work.
I also tried this in irb and it seems to work:
require 'open-uri'
open 'https://google.com'
=> #<File:/var/folders/dv/s_2dq32n0ggcn65kn61jtmc80000gn/T/open-uri20130630-887-y2cg2q>
Is this something the endpoint provider needs to fix or something with my local and production implementation of OpenSSL?
A certificate verification failure indicates that your Ruby instance was unable to find a way to chain the endpoint's certificate up to a trusted root that it is aware of. This can be a few different things:
The endpoint may have changed certificate providers and their new source is not in the default trust tore.
The endpoint may not have the proper intermediates installed.
The endpoint may have an untrusted certificate on it.
To narrow it down you can try loading the endpoint via a web browser. Do you get an untrusted error then? If so, time to contact your provider. If not, you'll need to look at the certificate and see what root it's using. Then you'll want to add that to the Ruby list of trusted certs (which is sourced differently depending on how you compiled it and on what platform).