jnthn / p6-io-socket-async-ssl

Asynchronous TLS sockets in Raku
11 stars 19 forks source link

On Windows still " Server certificate verification failed: unable to get local issuer certificate" with Cro #47

Open wahnwitz opened 4 years ago

wahnwitz commented 4 years ago

I can confirm that I can install and test IO::Socket::Async::SSL:ver<0.7.5> successfully.

==> Testing: IO::Socket::Async::SSL:ver<0.7.5>
==> Testing [OK] for IO::Socket::Async::SSL:ver<0.7.5>
==> Installing: IO::Socket::Async::SSL:ver<0.7.5>

Test with:

use Cro::HTTP;
my $resp = await Cro::HTTP::Client.get('https://www.perl6.org/');

await runs out of time.

E:\Development\CZDS\Download>perl6 test.pl6
Tried to get the result of a broken Promise
  in block  at C:\rakudo\share\perl6\site\sources\0609EA0BB03C70C2C15DB4B144D7041C1059D14C (Cro::TLS) line 108

Original exception:
    An operation first awaited:
      in block  at C:\rakudo\share\perl6\site\sources\70DD524CA8827A911588D5FFEB621C3FD9423B96 (IO::Socket::Async::SSL) line 323

    Died with the exception:
        Server certificate verification failed: unable to get local issuer certificate
          in block  at C:\rakudo\share\perl6\site\sources\70DD524CA8827A911588D5FFEB621C3FD9423B96 (IO::Socket::Async::SSL) line 323
jnthn commented 4 years ago

I don't see it mentioned here, but I recall it being mentioned that this wasn't a problem with the some other Raku HTTP client. I took a look into why and...they don't do certificate verification, it seems. :scream_cat:

Thus one can, I guess, pass :insecure and to this module and get the same result (e.g. it works), though that's a really bad idea. It seems the underlying issue is that SSL_CTX_set_default_verify_paths on Windows doesn't really do anything useful since there isn't anything to hand in the right kind of format for it to load; this post on SO hints at what we might do to resolve this.

jnthn commented 4 years ago

This code seems to work for getting certificates from the Windows certificate store:

#!/usr/bin/env perl6
use NativeCall;

my constant HStore = Pointer;
sub CertOpenSystemStoreA(Pointer, Str) returns HStore
        is native('Crypt32.dll') {*}
sub CertCloseStore(HStore, int32)
        is native('Crypt32.dll') {*}

my class PContext is repr('CStruct') {
    has int32 $.cert-encoding-type;
    has Pointer $.cert-encoded;
    has int32 $.cert-encoded-bytes;
    # There's further properties, but we don't need to access them
}
sub CertEnumCertificatesInStore(HStore, PContext) returns PContext
        is native('Crypt32.dll') {*}
sub CertFreeCertificateContext(PContext)
        is native('Crypt32.dll') {*}

my $win-cert-store = CertOpenSystemStoreA(Pointer, "ROOT");
my $p-context = PContext;
while $p-context = CertEnumCertificatesInStore($win-cert-store, $p-context) {
    note $p-context;
}
CertFreeCertificateContext($p-context);
CertCloseStore($win-cert-store, 0);

Now it's a matter of figuring out how to integrate it.