solokeys / solo2-cli

Solo 2 library and CLI in Rust
https://docs.rs/solo2
Apache License 2.0
169 stars 31 forks source link

Sending fatal alert BadCertificate #86

Closed loopion closed 1 year ago

loopion commented 1 year ago

When doing a "solo2 update" I get a

Downloading latest release from https://github.com/solokeys/solo2/
 WARN  rustls::conn > Sending fatal alert BadCertificate
Error: https://api.github.com/repos/solokeys/solo2/releases/latest: Connection Failed: tls connection init failed: invalid peer certificate contents: invalid peer certificate: UnknownIssuer

Any solution ?

Thank you for your help

needs-coffee commented 1 year ago

Hi @loopion Gonna need more info than this to help. This is a warning about an untrusted or invalid cert for this URL but if i load that URL here its GitHub cert from DigiCert TLS Hybrid ECC SHA384 2020 CA1 - this is from both the browser and app.

What is your OS and version? How are you running this (precompiled binary or cargo install)? Do you have anything on your OS or network that will be tampering with TLS certificates (Deep packet inspection, MITM software)? if you load this url in a browser do you get a warning? if so what is the cert and who is the cert issued by?

A log dump would be helpful - run solo2 update -vv to get a debug dump run solo2 update -vvv to get a more detailed dump that will include the TLS certificate that was used (or tried to be used)

loopion commented 1 year ago

Hi @needs-coffee,

Thanks for your answer and sorry for providing so low details.

MacOS Monterey 12.6 Installed through "cargo install" exactly like on the documentation provided there:

Maybe it's my network as It's my company computer and there is Zscaler and a VPN that probably temper it in between.

Strangely, if I load this URL in my browser I can see the JSON file provided. Certificate Issuer Name is the one from my company. I can see Distribution Point is provided by zscaler.

Here is my solo2 update -vv

 OSX  ~  solo2 update -vv                                                                                         
Downloading latest release from https://github.com/solokeys/solo2/
 DEBUG ureq::stream > connecting to api.github.com:443 at 140.82.121.5:443
 DEBUG rustls::client::hs > No cached session for DnsName(DnsName(DnsName("api.github.com")))
 DEBUG rustls::client::hs > Not resuming any session
 DEBUG rustls::client::hs > Using ciphersuite TLS13_AES_256_GCM_SHA384
 DEBUG rustls::client::tls13 > Not resuming
 DEBUG rustls::client::tls13 > TLS1.3 encrypted extensions: []
 DEBUG rustls::client::hs    > ALPN protocol is None
 WARN  rustls::conn          > Sending fatal alert BadCertificate
Error: https://api.github.com/repos/solokeys/solo2/releases/latest: Connection Failed: tls connection init failed: invalid peer certificate contents: invalid peer certificate: UnknownIssuer

solo2 update -vvv logs

 OSX  ~  solo2 update -vvv
Downloading latest release from https://github.com/solokeys/solo2/
 DEBUG ureq::stream > connecting to api.github.com:443 at 140.82.121.5:443
 DEBUG rustls::client::hs > No cached session for DnsName(DnsName(DnsName("api.github.com")))
 DEBUG rustls::client::hs > Not resuming any session
 TRACE rustls::client::hs > Sending ClientHello Message {
    version: TLSv1_0,
    payload: Handshake {
        parsed: HandshakeMessagePayload {
            typ: ClientHello,
            payload: ClientHello(
                ClientHelloPayload {
                    client_version: TLSv1_2,
                    random: 3db64abd6bc2f382b1e6879dcabb6c6fa3532008e3eec69efc8ca972a9e177ad,
                    session_id: 8bea628706c836848286616223cdc0faa17a50bb6a8c37c9b493074d853cb584,
                    cipher_suites: [
                        TLS13_AES_256_GCM_SHA384,
                        TLS13_AES_128_GCM_SHA256,
                        TLS13_CHACHA20_POLY1305_SHA256,
                        TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
                        TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                        TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
                        TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
                        TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                        TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
                        TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                    ],
                    compression_methods: [
                        Null,
                    ],
                    extensions: [
                        SupportedVersions(
                            [
                                TLSv1_3,
                                TLSv1_2,
                            ],
                        ),
                        ECPointFormats(
                            [
                                Uncompressed,
                            ],
                        ),
                        NamedGroups(
                            [
                                X25519,
                                secp256r1,
                                secp384r1,
                            ],
                        ),
                        SignatureAlgorithms(
                            [
                                ECDSA_NISTP384_SHA384,
                                ECDSA_NISTP256_SHA256,
                                ED25519,
                                RSA_PSS_SHA512,
                                RSA_PSS_SHA384,
                                RSA_PSS_SHA256,
                                RSA_PKCS1_SHA512,
                                RSA_PKCS1_SHA384,
                                RSA_PKCS1_SHA256,
                            ],
                        ),
                        ExtendedMasterSecretRequest,
                        CertificateStatusRequest(
                            OCSP(
                                OCSPCertificateStatusRequest {
                                    responder_ids: [],
                                    extensions: ,
                                },
                            ),
                        ),
                        ServerName(
                            [
                                ServerName {
                                    typ: HostName,
                                    payload: HostName(
                                        (
                                            6170692e6769746875622e636f6d,
                                            DnsName(
                                                "api.github.com",
                                            ),
                                        ),
                                    ),
                                },
                            ],
                        ),
                        SignedCertificateTimestampRequest,
                        KeyShare(
                            [
                                KeyShareEntry {
                                    group: X25519,
                                    payload: 1cffa97bd6db55b97999d3e479d9b34c1c92c9a184e5d0b68fbcece3fce2b922,
                                },
                            ],
                        ),
                        PresharedKeyModes(
                            [
                                PSK_DHE_KE,
                            ],
                        ),
                        SessionTicket(
                            Request,
                        ),
                    ],
                },
            ),
        },
        encoded: 010000ec03033db64abd6bc2f382b1e6879dcabb6c6fa3532008e3eec69efc8ca972a9e177ad208bea628706c836848286616223cdc0faa17a50bb6a8c37c9b493074d853cb5840014130213011303c02cc02bcca9c030c02fcca800ff0100008f002b00050403040303000b00020100000a00080006001d00170018000d001400120503040308070806080508040601050104010017000000050005010000000000000013001100000e6170692e6769746875622e636f6d00120000003300260024001d00201cffa97bd6db55b97999d3e479d9b34c1c92c9a184e5d0b68fbcece3fce2b922002d0002010100230000,
    },
}
 TRACE rustls::client::hs > Got HRR HelloRetryRequest { legacy_version: TLSv1_2, session_id: 8bea628706c836848286616223cdc0faa17a50bb6a8c37c9b493074d853cb584, cipher_suite: TLS13_AES_256_GCM_SHA384, extensions: [SupportedVersions(TLSv1_3), KeyShare(secp256r1)] }
 TRACE rustls::client::hs > Sending ClientHello Message {
    version: TLSv1_2,
    payload: Handshake {
        parsed: HandshakeMessagePayload {
            typ: ClientHello,
            payload: ClientHello(
                ClientHelloPayload {
                    client_version: TLSv1_2,
                    random: 3db64abd6bc2f382b1e6879dcabb6c6fa3532008e3eec69efc8ca972a9e177ad,
                    session_id: 8bea628706c836848286616223cdc0faa17a50bb6a8c37c9b493074d853cb584,
                    cipher_suites: [
                        TLS13_AES_256_GCM_SHA384,
                        TLS13_AES_128_GCM_SHA256,
                        TLS13_CHACHA20_POLY1305_SHA256,
                        TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
                        TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
                        TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
                        TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
                        TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
                        TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
                        TLS_EMPTY_RENEGOTIATION_INFO_SCSV,
                    ],
                    compression_methods: [
                        Null,
                    ],
                    extensions: [
                        SupportedVersions(
                            [
                                TLSv1_3,
                                TLSv1_2,
                            ],
                        ),
                        ECPointFormats(
                            [
                                Uncompressed,
                            ],
                        ),
                        NamedGroups(
                            [
                                X25519,
                                secp256r1,
                                secp384r1,
                            ],
                        ),
                        SignatureAlgorithms(
                            [
                                ECDSA_NISTP384_SHA384,
                                ECDSA_NISTP256_SHA256,
                                ED25519,
                                RSA_PSS_SHA512,
                                RSA_PSS_SHA384,
                                RSA_PSS_SHA256,
                                RSA_PKCS1_SHA512,
                                RSA_PKCS1_SHA384,
                                RSA_PKCS1_SHA256,
                            ],
                        ),
                        ExtendedMasterSecretRequest,
                        CertificateStatusRequest(
                            OCSP(
                                OCSPCertificateStatusRequest {
                                    responder_ids: [],
                                    extensions: ,
                                },
                            ),
                        ),
                        ServerName(
                            [
                                ServerName {
                                    typ: HostName,
                                    payload: HostName(
                                        (
                                            6170692e6769746875622e636f6d,
                                            DnsName(
                                                "api.github.com",
                                            ),
                                        ),
                                    ),
                                },
                            ],
                        ),
                        SignedCertificateTimestampRequest,
                        KeyShare(
                            [
                                KeyShareEntry {
                                    group: secp256r1,
                                    payload: 048d67eeedbf4d14de1a771486d265859b9c7b1c28e894cdfcdd75dde2dca48771191e8072b48f609018922b1aaf33c44de538abee7cb20447c645f53cdceccf72,
                                },
                            ],
                        ),
                        PresharedKeyModes(
                            [
                                PSK_DHE_KE,
                            ],
                        ),
                        SessionTicket(
                            Request,
                        ),
                    ],
                },
            ),
        },
        encoded: 0100010d03033db64abd6bc2f382b1e6879dcabb6c6fa3532008e3eec69efc8ca972a9e177ad208bea628706c836848286616223cdc0faa17a50bb6a8c37c9b493074d853cb5840014130213011303c02cc02bcca9c030c02fcca800ff010000b0002b00050403040303000b00020100000a00080006001d00170018000d001400120503040308070806080508040601050104010017000000050005010000000000000013001100000e6170692e6769746875622e636f6d0012000000330047004500170041048d67eeedbf4d14de1a771486d265859b9c7b1c28e894cdfcdd75dde2dca48771191e8072b48f609018922b1aaf33c44de538abee7cb20447c645f53cdceccf72002d0002010100230000,
    },
}
 TRACE rustls::conn       > Dropping CCS
 TRACE rustls::client::hs > We got ServerHello ServerHelloPayload {
    legacy_version: TLSv1_2,
    random: 0c0584aa4d35f40fd63067b81e2c164b3925d022756059c1798bd1f688ef3b38,
    session_id: 8bea628706c836848286616223cdc0faa17a50bb6a8c37c9b493074d853cb584,
    cipher_suite: TLS13_AES_256_GCM_SHA384,
    compression_method: Null,
    extensions: [
        SupportedVersions(
            TLSv1_3,
        ),
        KeyShare(
            KeyShareEntry {
                group: secp256r1,
                payload: 04df31aa7f64f8a7790e39474b03758cf1c1a67d3a55c2a06c6f913e3130e157a571da277d0e84f27d208da63f137efc140ba72afa8325b8f82a8da74d7cd7a173,
            },
        ),
    ],
}
 DEBUG rustls::client::hs > Using ciphersuite TLS13_AES_256_GCM_SHA384
 DEBUG rustls::client::tls13 > Not resuming
 TRACE rustls::client::client_conn > EarlyData rejected
 DEBUG rustls::client::tls13       > TLS1.3 encrypted extensions: []
 DEBUG rustls::client::hs          > ALPN protocol is None
 TRACE rustls::client::tls13       > Server cert is [Certifi")]
 WARN  rustls::conn                > Sending fatal alert BadCertificate
Error: https://api.github.com/repos/solokeys/solo2/releases/latest: Connection Failed: tls connection init failed: invalid peer certificate contents: invalid peer certificate: UnknownIssuer
needs-coffee commented 1 year ago

Yep this is what i thought was happening. The TLS communication from your computer is being MITM'ed by your companies (?paypal) firewall so they can inspect all the traffic in and out of their network and devices. Pretty much standard in enterprise devices and networks.

The company has configured their root CA cert as trusted by your device (you will see an addition with the name of your company in SSL certs in keychain) which allows the browser to trust the certificates they are issuing so it loads in the browser just fine (with your company cert as the upstream trusted as they MITMed it)

A cursory look at he source code for the solo2-cli it looks like the ureq crate that performs the TLS connection is set by default to its tls trust setting that uses the webkit-pki roots crate issued by Mozilla as the list of trusted roots - this means any locally installed root certs (your companies) are not trusted by the solo2-cli so will be rejected.

If the solo2-cli used ureq in the native-tls configuration it would use your OS cert store and this would work for you.

My advice would be to use a non work device and connection to update the key, It will probably work if you disconnect from zscaler/VPN then your network connection wont be proxied through your company. Also this serves as a reminder not to use your work device for personal things as they can see all the network data.

loopion commented 1 year ago

Thanks for the confirmation. It's in fact to be used for my professional usage :-) as I'd like to use my Solokey for this purpose. Thanks a lot for identifying this.