Certificate issues in nix-shell with flutter app

I’m trying to start a flutter app that was built with flutter-3.0.0 in a podman container.
This app queries a web API on https on a server with a LetsEncrypt certificate.

I figured this is a similar issue where e.g. curl or git can’t find a valid CA-bundle (like on ancient systems where the system’s CA bundle doesn’t know about LetsEncrypt), so I additionally pulled in cacert. It still doesn’t work, and I still get an error like this:

An error occurred which was forwarded to the root.  ERROR: HandshakeException: Handshake error in client (OS Error: 
        CERTIFICATE_VERIFY_FAILED: unable to get local issuer certificate(handshake.cc:393))

The interwebs suggest all kinds of hacks in the flutter app, but in my case the app works everywhere except on nixos. (I tried with steam-run too, but that’s missing libepoxy)

What is the “official” way to add the correct CA-bundle to a pure nix-shell?

Now it looks like this:

### !!! To make this work, we have to run it in pure mode (otherwise the lib path is not overridden/enforced?)
### !!! But: certificates don't appear to work in a pure env? (Because the CA-bundle is not found and it's not clear where it's put)
### Also there is no info whether flutter apps use an env var to point to a CA bundle, so would the following be necessary to work around unavailable certs?
### https://stackoverflow.com/a/69481863/12771809

{ pkgs ? import <nixpkgs> {} }:

(pkgs.buildFHSUserEnv {
  name = "flutterapp";
  targetPkgs = pkgs: with pkgs; [
    thefuck lsd # to mimick our normal shell env // make aliases work
    # cacert
    # at-spi2-core # not explicitly necessary? But how to forward DBUS to pure?
    util-linux
    harfbuzz zlib glib libepoxy atk
    cairo pango gdk-pixbuf gtk3
    xorg.libXdmcp xorg.libXtst
    libselinux libsepol libthai libxkbcommon
  ];

  runScript = "${pkgs.zsh}/bin/zsh";

  profile = ''
    export SSH_AUTH_SOCK=/run/user/$UID/keyring/ssh
    export GIT_SSL_CAINFO=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
    export SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
    export CURL_CA_BUNDLE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt
    unset TZ # use /etc/localtime (as fallback) which is correct
  '';
}).env

Did you solve the issue?

No, unfortunately not. It’s gotten a bit less acute since building this particular app from source in a nix flutter shell works well, but I cannot get the binary to run on my NixOS system if it’s built somewhere else, e.g. in my container CI. Still the same problem.

Inside the FHS env, do you see /etc/ssl/certs/ca-bundle.crt? If not, maybe try symlinking that into place inside as it seems to ignore the env var as you point out.

I did some more experimenting:

In my normal env (i.e. without shell) I have normal cert links:

> ls -la /etc/ssl/certs
drwxr-xr-x root root 4.0 KB Sun Dec  4 23:03:09 2022  .
drwxr-xr-x root root 4.0 KB Sun Dec  4 23:03:09 2022  ..
lrwxrwxrwx root root  35 B  Sun Dec  4 23:03:09 2022  ca-bundle.crt ⇒ /etc/static/ssl/certs/ca-bundle.crt
lrwxrwxrwx root root  41 B  Sun Dec  4 23:03:09 2022  ca-certificates.crt ⇒ /etc/static/ssl/certs/ca-certificates.crt

and it points to the same store path as in my impure shell

> ls -la /etc/static/ssl/certs/ca-certificates.crt
lrwxrwxrwx root root 87 B Thu Jan  1 01:00:01 1970  /etc/static/ssl/certs/ca-certificates.crt ⇒ /nix/store/ba4f8msp39cfvfpw3m7fsalb4psw347z-nss-cacert-3.83/etc/ssl/certs/ca-bundle.
crt

(obviously)

The flutter app fails with the CERT error, curl works fine.

Now if I do the same but

  • make the shell pure
  • with no profile set

I still have the same links, but curl (added as a build input), stopped working,because (interestingly) the shell automatically sets

runenv-chrootenv:jeroen@jnixryz:~/Downloads/u$ env | grep SSL
NIX_SSL_CERT_FILE=/no-cert-file.crt
SSL_CERT_FILE=/no-cert-file.crt

Ok, so I set the profile again:

  profile = ''
    export NIX_SSL_CERT_FILE="/etc/ssl/certs/ca-certificates.crt"
    export SSL_CERT_FILE="/etc/ssl/certs/ca-bundle.crt"
  '';

curl works again, but the flutter app still has the same error.

A variation where I point the SSL vars directly at the store path (suspecting that symlink handling might be funky in flutter?) doesn’t make any difference.

BUT: if I additionally set SSL_CERT_DIR=/etc/ssl/certs, curl stops working again:

curl: (60) SSL certificate problem: unable to get local issuer certificate

Apparently this is checked first and overrides SSL_CERT_FILE, which now begs the question: is the name ca-bundle.crt or ca-certificates.crt not “standard”? => Doesn’t seem like it, at least on an arbitrary NAS I have /etc/ssl/certs/ca-certificates.crt.

So setting SSL_CERT_DIR also breaks curl (or I’m setting it to the wrong relative dir?) and on flutter it doesn’t make a difference.