Forum: Ruby certificate verify failed

Posted by Charles Rajesh (scrajesh)
on 2010-09-01 09:02
Am using a X509 PEM certificate with the key for integrating a payment
gateway api.
But am not able to establish the SSL connection as the certificate
verification fails..

http.use_ssl = true
#certificate file
http.cert = OpenSSL::X509::Certificate.new(File.read('sdk-cert.pem'))
#private key for that certificate
http.key = OpenSSL::PKey::RSA.new(File.read('sdk-key.pem'))
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
http.start{http.request_get(uri.path){|res| print res.body }}

Error: (via Web)
OpenSSL::SSL::SSLError in TestController#test

certificate verify failed

I get the following error while i verified through command-line using
OpenSSL:
>openssl verify sdk-cert.pem
"error 20 at 0 depth lookup:unable to get local issuer certificate"

Is there anything missing in the certificate ?? kindly help to sort out
the issue..
Posted by Brian Candler (candlerb)
on 2010-09-01 10:37
Charles Rajesh wrote:
> 
> Am using a X509 PEM certificate with the key for integrating a payment
> gateway api.
> But am not able to establish the SSL connection as the certificate
> verification fails..

It looks like there are two certificate verifications going on:

* the server verifying your client certificate
* the ruby client verifying the server's certificate

and possibly it's the second which is failing. Is the server's 
certificate signed by a standard CA, or your own CA, or self-signed?

Try the following on the command line:

    openssl s_client -connect server.host.name:443

What does the verify result show? If it's not 0 (OK) then an error will 
be shown. What is it?

If the server.host.name certificate is signed by your own CA, then try

    openssl s_client -CAfile /path/to/cacert.pem -connect 
server.host.name:443

where cacert.pem is your CA's root certificate.

If that verifies, then use http.ca_file = .... to do the same in the 
Ruby client. You can see this documented in 
/usr/lib/ruby/1.8/net/https.rb (or wherever it is on your system)

Or, you could install your CA's cert into openssl's global certificate 
directory. How to do this varies from system to system, and may involve 
you using the c_rehash script.

HTH,

Brian.
Posted by Brian Candler (candlerb)
on 2010-09-01 10:38
Charles Rajesh wrote:
> I get the following error while i verified through command-line using
> OpenSSL:
>>openssl verify sdk-cert.pem
> "error 20 at 0 depth lookup:unable to get local issuer certificate"

Ah, you did step 1 already. Retry using:

  openssl s_client -CApath /path/to/cacert.pem -connect foo.bar:443

where cacert.pem is the issuer certificate (i.e. the certificate of the 
CA which signed your server's certificate)

If the certificate is self-signed, you could try using a copy of the 
server's certificate here.
Posted by Charles Rajesh (scrajesh)
on 2010-09-01 15:02
Thanx Brian for your points..

1) I checked whether the certificate is signed using the following cmd:
>openssl x509 -text -in sdk-cert.pem
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 3389 (0xd3d)
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=US.....
        Validity
            Not Before: Feb 23 16:28:12 2005 GMT
            Not After : Feb 21 16:28:12 2015 GMT
        Subject: CN=sdk-cert_api1.sdk.com...
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
            RSA Public Key: (1024 bit)
                Modulus (1024 bit):
                    00:a8:f8:c7:5d:e3:
                    ..................
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints:
                CA:FALSE
    Signature Algorithm: sha1WithRSAEncryption
        09:31:0e:a5:c9:d8:69:0e:49:bd:99:46:49:75:a0:04:9e:19:
        ......................................................
-----BEGIN CERTIFICATE-----
MIIClDCCAf2gAwIBAgICDT0wDQYJ..........
......................................
-----END CERTIFICATE-----

2) Here am not sure whether the certificate is signed or not..
-- Also i tried the following cmd as you mentioned:
> openssl s_client -connect www.paypal.com:443
Loading 'screen' into random state - done
CONNECTED(00000764)
depth=2 /C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 
VeriSign, I
nc. - For authorized use only/CN=VeriSign Class 3 Public Primary 
Certification A
uthority - G5
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
 0 
s:/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/2.5.4.15=V1.
 ...............................
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIFxzCCBK+gAwIBAgIQa1UJlCEr.........................
........................................
-----END CERTIFICATE-----
subject=/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/2.5.4.15=
.......................................................
---
No client certificate CA names sent
---
SSL handshake has read 4404 bytes and written 314 bytes
---
New, TLSv1/SSLv3, Cipher is DES-CBC3-SHA
Server public key is 1024 bit
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : DES-CBC3-SHA
    Session-ID: 
9BCA761FFA3C4DF596207BAEAA01328583E40418AFCC2273851B209B7D61850B

    Session-ID-ctx:
    Master-Key: 
D0DA9C2D6649033D39A7E248B53CC2D90FEFCC6F64E73794A8AF8D0095426899
04FA4B4FEBB3498AE2098E33FEA6C84E
    Key-Arg   : None
    Start Time: 1283333209
    Timeout   : 300 (sec)
    Verify return code: 20 (unable to get local issuer certificate)
---
read:errno=10054

--> Again am getting the same issue at last..


Still am not sure whether the way am using the certificates while 
connecting the server is correct or not?

NB: The PEM certificate file has both the private key & the certificate.
    The Key file has only the private key that is specified in the 
certificate
    - file.
    If there's no CA (as mentioned in the above logs), is there any 
workaround
    - to solve the same ?

Am totally blocked with this stuff.. Kindly enlighten me in resolving 
this issue..


~ Charles
Posted by Brian Candler (candlerb)
on 2010-09-01 15:33
Charles Rajesh wrote:
> 
> Thanx Brian for your points..
> 
> 1) I checked whether the certificate is signed using the following cmd:
>>openssl x509 -text -in sdk-cert.pem

You need to look at the certificate of the *other side* that you are 
connecting to (openssl s_client -connect whatever.com:443)

> 2) Here am not sure whether the certificate is signed or not..
> -- Also i tried the following cmd as you mentioned:
>> openssl s_client -connect www.paypal.com:443
> Loading 'screen' into random state - done
> CONNECTED(00000764)
> depth=2 /C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 
> VeriSign, I
> nc. - For authorized use only/CN=VeriSign Class 3 Public Primary 
> Certification A
> uthority - G5
> verify error:num=20:unable to get local issuer certificate

OK that's good. So this means:

(1) you're trying to connect to www.paypal.com

(2) www.paypal.com presents a certificate signed by VeriSign

(3) openssl doesn't have a copy of VeriSign's root certificate, so 
cannot verify PayPal's certificate.

You need a copy of Verisign's certificate stored on your machine. 
Normally your machine would come with it pre-installed.

What platform are you running this under? For example, Ubuntu has a 
package called "ca-certificates", which installs links in 
/etc/ssl/certs. You can make a fully verified SSL connection like this:

openssl s_client -CApath /etc/ssl/certs -connect www.paypal.com:443
...
    Verify return code: 0 (ok)
---

Once you've got that working, then you can do the equivalent in Ruby, 
e.g. using http.ca_path = "/etc/ssl/certs"

> NB: The PEM certificate file has both the private key & the certificate.

That's *your* private key and certificate, which you're presenting to 
Paypal to prove your identity.

The problem is in the other direction, with Paypal presenting *their* 
certificate to you to prove their identity. (Which of course they have 
to do: you wouldn't want someone impersonating Paypal to intercept the 
connection and collect all these credit card details you're sending 
them!)

Regards,

Brian.
Posted by Charles Rajesh (scrajesh)
on 2010-09-01 17:33
Again thanx a ton Brian..

Still i've few more doubts..

1) Am working with Windows XP SP3
 > using Ruby1.8.6

2) I did the following cmd to find the client side certificate location 
folder
>openssl version -d
OPENSSLDIR: "C:/lan/ssl"
-- But I didn't find the above path in my system! is there anyother way 
to find it ?

3) I tried the following cmd in my Linux(i686 athlon i386 GNU/Linux) 
machine
> openssl s_client -CApath /usr/share/ssl -connect www.paypal.com:443
-- I got a "Verify return code: 0 (ok)" for the above cmd

4) From your previous detailed explanation i very well understood my 
issue and the ssl verification flow. So if i've the server's certificate 
in my app's root(in case of RoR app, in Win XP), i'd be able to 
successfully connect to paypal..?? Or is it enough to supply the openssl 
certificates path of windows somewhere in the code..??

>> So far I was doubting the issue with the PEM certifcate which now am clear that it's only for my identification.. thanx a ton for your patience in explaining me.

Guess your next reply would resolve my issue.. kindly help me out..
Posted by Brian Candler (candlerb)
on 2010-09-01 17:48
Charles Rajesh wrote:
> 2) I did the following cmd to find the client side certificate location 
> folder
>>openssl version -d
> OPENSSLDIR: "C:/lan/ssl"
> -- But I didn't find the above path in my system! is there anyother way 
> to find it ?

dir /s perhaps?

Is it cygwin, or some native Win32 openssl? Maybe it even could be 
configured to use the Windows cert store, I have no idea.

> 3) I tried the following cmd in my Linux(i686 athlon i386 GNU/Linux) 
> machine
>> openssl s_client -CApath /usr/share/ssl -connect www.paypal.com:443
> -- I got a "Verify return code: 0 (ok)" for the above cmd

So your app should work on Linux with

  http.ca_path = "/usr/share/ssl"

> 4) From your previous detailed explanation i very well understood my 
> issue and the ssl verification flow. So if i've the server's certificate 
> in my app's root(in case of RoR app, in Win XP), i'd be able to 
> successfully connect to paypal..?? Or is it enough to supply the openssl 
> certificates path of windows somewhere in the code..??

You need to supply the collection of known trusted root CA certificates 
(which includes Verisign's certificate).

At worst, you could copy verisign's cert, or the whole CA bundle, from 
Ubuntu to XP. I expect there's a cleaner Windowsy way, but as I hate 
Windows and don't use it, I'm afraid I can't help you there.

Regards,

Brian.
Posted by Charles Rajesh (scrajesh)
on 2010-09-01 18:57
Thanx a lot Brian for all your help..

As you said, i'll try the same in Linux machine itself..

thanx & regards,
~ Charles S.
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.