MbedTLS failing with "The certificate is not correctly signed by the trusted CA" (0x08) connecting to Google Cloud load balancer

mbedTLS version: mbed TLS 2.16.6 branch released 2020-04-14

We are using mbedTLS on ARM target to provide TLS 1.2 for GCP connections. One connection type is using “self-managed” SSL certs and works fine.
The other connection’s end point is Google HTTPS load balancer and is using “Google-managed” SSL certs. This connection fails with flags == 0x08 which is the “not signed by trusted CA” error.

Flag is set in function x509_crt_verify_chain(…) after call to x509_crt_find_parent(…) returns no “parent” pointer.

    /* No parent? We're done here */
    if( parent == NULL )
    {
        *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED;       
        return( 0 );
    }

On this forum I found a post with similar problem ( Mbedtls_ssl_handshake return error -0x2700 ) where the handshake was failing due to CA being set to FALSE.
The OP in that post was able to resolve the problem after modifying the certificate.

I downloaded and compared the two certs and sure enough the one that is working has CA:TRUE and the failing which is Google-managed cert has CA:FALSE.

Google’s online docs ( SSL certificates overview  |  Load Balancing  |  Google Cloud ) list some limitations to Google-managed SSL certs, in particular this line:

“Google Cloud load balancers don’t support client certificate-based authentication (mutual TLS, mTLS).”

We are in communication with Google about the problem but I wanted to ask some questions here:

  1. Is there a known incompatibility between mbedTLS and Google HTTPS load balancers? Google lists “mutual TLS” and “mTLS” as examples of “client certificate-based authentication”. Does mbedTLS fall under same category? Not sure if “mTLS” is/was another name for mbedTLS.

  2. Is there any remedy for CA:FALSE on the client side other than running with “authmode” set to MBEDTLS_SSL_VERIFY_OPTIONAL? What are the security risks with that, MITM, certs spoof, self-signed certs, etc?

Thanks!

Providing an update for others who may run into this. The issue was in the certificate installed on the client. Resolution is essentially the same as in this thread that I quoted above : Mbedtls_ssl_handshake return error -0x2700 - #5 by KennethSong

Need to use certificate that has CA flag set (not be leaf cert) and CN name must match between client cert and server cert. Most of certificates available from Google public certificate repository can be used, check the pki.goog. The expiration dates can be a challenge to embedded devices. Some note from Google on that:

Google’s recommendation for devices that seek to connect to Google services securely:

Blockquote
I’m building a product that connects to Google services. What CA certificates do I need to trust?

Google certificates are issued by different CAs depending on the current business needs and best practices. A certificate chain cannot be considered static.

Developers of applications connecting to Google services must take this into consideration and never hardcode Intermediate or Root Certificate Authorities. Developers should instead build a robust mechanism to update the set of CAs trusted by their applications.

Google services’ certificates can be issued by any of the Certificate Authority from this regularly updated list. Applications connecting to Google services should trust all the Certificate Authorities from that list.
Blockquote

Another useful link for GCP IoT core connections that ultimately lead me to resolution of the problem with certificate on the client.

I don’t have a handshake. Specifically, the problem is described here:
https://forums.mbed.com/t/mbedtls-ssl-handshake-return-error-0x2700/5354

The function

static int function x509_crt_merge_flags_with_cb (x509_crt.c)

returns the value 8 in the flags variable. I went through this function step by step and saw that cur_flags was assigned the value 8 in the line

cur_flags = cur->flags;

. I don’t know where value 8 came from in cur->flags. Since the condition

if( NULL != f_vrfy )

fails (f_vrfy = 0), the

if( ( ret = f_vrfy( p_vrfy, cur->crt, (int) i-1, &cur_flags ) ) != 0 )

line is not called. Probably p_vrfy is not registered? Where does the value 8 come from in cur->flags;?

The problem is solved by inrease memory

Heap_Size EQU 0xD000 ;
minimum required 0xС000. But now Im recieve

got an alert message, type: [2:40]is a fatal alert message (msg 40)