[crazy?] completely neutered self-signed certificate verification administering akash hosting providers?
Of course I should talk with akash, which is my plan, but I'm posting here at the moment. Akash is a blockchain hosting provider. They recently added support for GPU compute. I'm writing code to verify connections to akash nodes by renters. Provider certificates are registered on-chain and used for client communications, but I don't understand how the protocol produces security. The code clients use for verifying a provider certificate when executing administrative actions is here: https://github.com/akash-network/provider/blob/44c85af39a56a43830efbdcbe7a2f... I don't understand how the verification provides security. -> I am not very familiar with TLS and X509 and am very, very, very confused. <- The first and primary authentication is that the common name is the account address in bech32 format. It reports a hijacked certificate if this is not the case:
// validation var prov sdk.Address if prov, err = sdk.AccAddressFromBech32(cert.Subject.CommonName); err != nil { return errors.Wrap(err, "tls: invalid certificate's subject common name") }
// 1. CommonName in issuer and Subject must be the same if cert.Subject.CommonName != cert.Issuer.CommonName { return errors.Wrap(err, "tls: invalid certificate's issuer common name") }
if !c.addr.Equals(prov) { return errors.Errorf("tls: hijacked certificate") }
I don't understand how this helps prove the provider owns the certificate. Couldn't anybody set the common name of a certificate to an account address? Wouldn't it be important here to sign material with the private key of the account, rather than using the address? Then it verifies the certificate is active on-chain, but it compares only the serial number rather than a fingerprint:
// 2. serial number must be in if cert.SerialNumber == nil { return errors.Wrap(err, "tls: invalid certificate serial number") }
// 3. look up certificate on chain. it must not be revoked var resp *ctypes.QueryCertificatesResponse resp, err = c.cclient.Certificates( context.Background(), &ctypes.QueryCertificatesRequest{ Filter: ctypes.CertificateFilter{ Owner: prov.String(), Serial: cert.SerialNumber.String(), State: "valid", }, }, ) if err != nil { return errors.Wrap(err, "tls: unable to fetch certificate from chain") } if (len(resp.Certificates) != 1) || !resp.Certificates[0].Certificate.IsState(ctypes.CertificateValid) { return errors.New("tls: attempt to use non-existing or revoked certificate") }
I don't understand how this helps prove the provider owns the certificate. Couldn't anybody set the serial number of a certificate to the value active on-chain? Wouldn't it be necessary to use a digest of the certificate to verify it is the same one? Finally, it places the certificate in a pool of its own, and uses that same pool to verify that same certificate:
certPool := x509.NewCertPool() certPool.AddCert(cert)
opts := x509.VerifyOptions{ DNSName: c.host.Hostname(), Roots: certPool, CurrentTime: time.Now(), KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, MaxConstraintComparisions: 0, }
if _, err = cert.Verify(opts); err != nil { return errors.Wrap(err, "tls: unable to verify certificate") }
I don't understand how this helps prove the provider owns the certificate. Couldn't anybody craft a certificate that verifies itself? Shouldn't there be some cryptographic path between the on-chain material and the off-chain material? Note: every provider and every provider's hostname can be enumerated on-chain, so an attacker can easily identify if there are providers that are easy to intercept, or enumerate all providers to intercept them all. (Might be this cli command, haven't verified: https://github.com/akash-network/docs/blob/master/cli/provider-services_quer... ) To me it looks like this system could have the function of making it very easy to intercept and mutate traffic between all akash providers and clients, optionally presenting a fake provider to clients that pretends to be the real one.
Looks like the on-chain response for the certificate query includes bytearrays for the certificate and pubkey. So either I'm mis-seeing/mis-understanding something, or it's simply a bug in that function, or these bytes are verified elsewhere. https://github.com/akash-network/akash-api/blob/60498f7c84cfef78ebbfce97a818...
https://github.com/akash-network/support/issues/109 Clients Do Not Authenticate Provider Certificates #109 xloem opened this issue now **Describe the bug** The [current client peer certificate verification code](https://github.com/akash-network/provider/blob/44c85af39a56a43830efbdcbe7a2f...) completely ignores the on-chain certificate and public key data, allowing a network adversary to provide a false certificate to any client. **To Reproduce** Note: I have not tested this, but it looks like you could generate a certificate with matching owner address and serial number to any active one on-chain, and offer it to a client in a machine-in-the-middle attack, and it would be accepted because the certificate is not sufficiently verified. All communications could be logged, and fake responses provided. **Expected behavior** It looks like the code should retrieve the certificate and public key fields from the QueryCertificatesResponse object and compare them with the data from the network [here](https://github.com/akash-network/provider/blob/44c85af39a56a43830efbdcbe7a2f...). **Additional context** I'm a crazy old software developer and I [spammed a mailing list about this issue](https://lists.cpunks.org/pipermail/cypherpunks/2023-July/115544.html).
participants (1)
-
Undescribed Horrific Abuse, One Victim & Survivor of Many