I'm trying to connect to our thing on Google Cloud IoT Core, but I get an error when trying to connect using
status = nxd_mqtt_client_secure_connect(&g_mqtt_client0, &broker_address, NXD_MQTT_TLS_PORT, NX_MQTT_tls_setup, 0, NX_TRUE, NX_WAIT_FOREVER);
status = nxd_mqtt_client_secure_connect(&g_mqtt_client0, &broker_address, NXD_MQTT_TLS_PORT,
NX_MQTT_tls_setup, 0, NX_TRUE, NX_WAIT_FOREVER);
I figure out the cause is in nx_secure_tls_session_start.c, function _nx_secure_tls_handshake_process that Fails with 56 (0x38) error (NX_NOT_CONNECTED 0x38)
Then looking at the JWT that is generated, I've checked on jwt.io (a website) and gets me invalid JWT.
Note that I have RootCA certificate, device certificate and device private key (in pem format) and they work just fine with Python (just checking certificates and key are correct, and server address/ TLS is working), in fact the JWT generated in python gets me "genuine" under the same jwt.io website validator.
I dont' get any errors while loading certificates and key on netx secure, so I'm guessing is the way I pad or calculate the JWT is not correct, I'm using the same base64 and JWT create functions that you use in the MQTT_tls google cloud example project.
Root certificate and device certificate are converted first to .der (using openssl) and then to binary array using the hexy.exe tool.
Private key is converted first to pkcs1.pem, then to .der and finally to binary array.
All the CA certificate, device certificate and private key are loaded into some header files and included in my project.
Some code, after I establish an IP layer through Wifi, following:
//> SNTP gets time, I save timestamp and call get_time() when I need it (to generate JWT) - no errors here
//> DNS to get IP address of Google Cloud endpoint - no errors here
//>Init of mqtt packet pool and client - all good
Then init and store of certificates, I get no errors in the following:
status = nx_secure_tls_session_create(&g_mqtt_client0.nxd_mqtt_tls_session, (NX_SECURE_TLS_CRYPTO *) &nx_crypto_tls_ciphers_synergys7, crypto_metadata, sizeof(crypto_metadata));
status = nx_secure_tls_session_create(&g_mqtt_client0.nxd_mqtt_tls_session,
(NX_SECURE_TLS_CRYPTO *) &nx_crypto_tls_ciphers_synergys7,
crypto_metadata,
sizeof(crypto_metadata));
status = nx_secure_tls_session_packet_buffer_set(&g_mqtt_client0.nxd_mqtt_tls_session, tls_packet_buffer, sizeof(tls_packet_buffer));
status = nx_secure_tls_session_packet_buffer_set(&g_mqtt_client0.nxd_mqtt_tls_session,
tls_packet_buffer,
sizeof(tls_packet_buffer));
//---------------------
char *temp_str = "unused";
for(UINT i = 0; i < sizeof(temp_str); i++) { username[i] = temp_str[i]; }
for(UINT i = 0; i < sizeof(temp_str); i++)
{
username[i] = temp_str[i];
}
//Password is the JWT generated using realtime timestamp (epoch) and IoT thing private key //rsa_private_pkcs1, RSA_PRIVATE_LEN jwt_expiration = JWT_EXPIRATION_SECS;
//Password is the JWT generated using realtime timestamp (epoch) and IoT thing private key
//rsa_private_pkcs1, RSA_PRIVATE_LEN
jwt_expiration = JWT_EXPIRATION_SECS;
/* Generate JWT */ if (jwt_create(password, sizeof(password), &jwt_expiration, rsa_private_pkcs1, RSA_PRIVATE_LEN, (CHAR*) &project_id)) { HSP_APP_LOG(HSP_LOG_LEVEL_ERROR,"Unable to create JWT. Aborting.\r\n"); __BKPT(0); }
/* Generate JWT */
if (jwt_create(password, sizeof(password), &jwt_expiration,
rsa_private_pkcs1, RSA_PRIVATE_LEN, (CHAR*) &project_id))
HSP_APP_LOG(HSP_LOG_LEVEL_ERROR,"Unable to create JWT. Aborting.\r\n");
__BKPT(0);
HSP_APP_LOG(HSP_LOG_LEVEL_DEBUG,"JWT token created successfully %s\n============", password); //set login status = nxd_mqtt_client_login_set(&g_mqtt_client0, username, strlen(username), (char *)password, strlen((char *)password)); if(status){ HSP_APP_LOG(HSP_LOG_LEVEL_ERROR,"tnxd_mqtt_client_login_set error %d", status); __BKPT(0); }
HSP_APP_LOG(HSP_LOG_LEVEL_DEBUG,"JWT token created successfully %s\n============", password);
//set login
status = nxd_mqtt_client_login_set(&g_mqtt_client0, username, strlen(username),
(char *)password, strlen((char *)password));
if(status){
HSP_APP_LOG(HSP_LOG_LEVEL_ERROR,"tnxd_mqtt_client_login_set error %d", status);
//---------------------------------- after this, I get back the error described above.
///> In nx_secure_tls_session_start.c ///> function _nx_secure_tls_handshake_process Fails with 56 (0x38) error ///> (NX_NOT_CONNECTED 0x38)
///> In nx_secure_tls_session_start.c
///> function _nx_secure_tls_handshake_process Fails with 56 (0x38) error
///> (NX_NOT_CONNECTED 0x38)
if(status){ HSP_APP_LOG(HSP_LOG_LEVEL_ERROR,"nxd_mqtt_client_secure_connect error %d", status); __BKPT(0); }
HSP_APP_LOG(HSP_LOG_LEVEL_ERROR,"nxd_mqtt_client_secure_connect error %d", status);
I include my project file, so maybe somebody can address me on how to properly generate the JWT, as the following is not getting me a proper JWT.
https://www.filemail.com/d/hacpvrjcfpuxwnd
Is the certs/private key conversion and handling correct?
Do I need to change padding/ crypto functions in the JWT header/payload/signature generation?
Unfortunately I can not find any more info on this topic, as normally a jwt library is used to generate hash and create the token, but I want to make use of the hardware secure engine.
Any info/hints very welcome.
I can share certs/keys if you want to check, but basically If I get a valid JWT generated I think we are half way there.
Generated JWT:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJoNG5oNDQtMSIsImV4cCI6MTYzMDQyMTE3OCwiaWF0IjoxNjMwNDIwODc4fQ==.SbNIiu23b0w9udd8jlICsW/cQqsbMgKvzQlSmga8mseI3hVAwW001YQ9QmLPc7Y3z8bE8ndYJXE3lO4UA39M4D6G/KyrybRnzQkFfevRm4qw8NekOsENPEse25YGNpzydKcVHvomHMBm8r797ApH2Z0Xs3FD2e+EgnS3GkQ4bYVxscMmDFqd/m5IWJPz8mZiwuN3+LXK2gVOF798wObXY7L7q8EWycV2QbeDOQlEkVyG1SFTwudM0Y+Geppsli5uUrscEq5ipT/rgIaIFuqUcvykH9IZm/sLHXh54UYIkaAlHdzGyWTr+50cV4X+9ZWwTcfQdrRcECKIsSgeC/JyHw==
(note the == characters generated, I suspect shouldn't be there)
and so: [0000002235][new_thread0_entry.c:0395] - nxd_mqtt_client_secure_connect error 65541
I'm on S5D9, SSP1.7.8 e2Studio. NetX Duo.
Thanks a lot.
S
Hi S,
Have you try modifying the Base64urlEncoder() in Base64Decode.c to strip the padding, "="? Would it pass checking jwt.io?
The hash/signature would definitely be different without '=', As the Header/payload is available, the receiver could have use it to verify the signature,
Hi,
Yes I've tried but still doesn't pass the jwt.io check. Is there a valid Base64url encoder library that actually works with Google IoT Core?
Also, it has something to do with the pkcs1 padding in the jwt_create() ?
Thanks
Hi Rusty,
When using, GTS LTSR (primary) you need to set r_sce_0 SCE COMMON Driver on r_sce to CRYPTO_WORD_ENDIAN_LITTLE. While verifying an ECC cert, I found it wont pass in ENDIAN_BIG. For RSA certs, both BIG/LITTLE are OK. I dont quite figure out where problem when converting endian.
The (backup) can't be used. It has a ECC 384bit keys. So any cert ecdsa-with-sha384 is not possible.
I ask to use RSA, cause your JWT. uses { "alg" : RS256 ...} You may have to change your device cert to ECC as well.
Also strongly recommend you switch to SSP 2.0.0..
For big endian, before verification, swapping for input parameters is done, in-situ. If the certificate is in ROM (is a const), bytes cannot be swapped, so operations will fail. You cert need to be in RAM.
Sorry my Google account is in a mess, I couldn't set it up to do a proper test..
I can get the AE CLoud2 version of this project :-
https://www.renesas.com/document/apn/synergy-mqtttls-google-cloud-connectivity-solution-application-project?language=en&r=1054626
to connect to mqtt.2030.ltsapis.goog using the minimal root CA set's primary certificate, if I add the TLS SNI :-
mqtt.2030.ltsapis.goog
static NX_SECURE_X509_DNS_NAME dns_name; status = nx_secure_x509_dns_name_initialize(&dns_name, (UCHAR *)p_cfg->p_endpoint, (USHORT)(strlen(p_cfg->p_endpoint))); if (NX_SUCCESS != status) { NX_MQTT_log_msg(p_ctrl, "Unable to initialise SNI DNS name, ret=0x%x\r\n",status); return status; } status = nx_secure_tls_session_sni_extension_set(&(p_ctrl->p_secure_client->nxd_mqtt_tls_session), &dns_name); if (NX_SUCCESS != status) { NX_MQTT_log_msg(p_ctrl, "Unable to add SNI, ret=0x%x\r\n",status); return status; }
The requirements to connect to an LTS MQTT domain are here :-
cloud.google.com/.../mqtt-bridge
Thanks Jeremy, I've updated my e2Studio and SSP to 2.0.0 and trying again now to tls using the primary certificate (ECC) to connect to mqtt.2030.ltsapis.goog.
mqtt.2030.ltsapis.goog.
Couple of questions if you don't mind:
./synergy/ssp/src/framework/sf_el_nx_crypto/nx_crypto_synergys7_ciphersuites.o:(.data.crypto_method_aes_128_gcm_16_sce+0x1c): undefined reference to `_nx_crypto_method_aes_gcm_sce_operation'
collect2.exe: error: ld returned 1 exit status
Thanks a lot,
I had success using SSP 1.7.8 with the google cloud example project. I have migrated the project to SSP 2.0.0 however I have been unsuccessful in connecting using the LTS certificates.
In answer to your questions :-
1) In the application code, the API nx_secure_tls_ecc_initialize() must be calledafter TLS session is created ( nx_secure_tls_session_create() ). This API notifies the TLS session of the type ofcurves used in the system. During the TLS handshake phase, if ECCalgorithm is selected, the client and server exchange ECC curve-related parameters, so ECC can be used for the session.
2) If the certificate is in the correct format in a byte array then it is fine. I have used a similar process before (converted certificate from PEM->DER->Byte array ).
3) Again, for the SNI, the API to add the SNI information needs to be called after the TLS session is created (nx_secure_tls_session_create() )
4) For the compilation issue with SSP 2.0.0, when you enable ECC Cipher, you also need to enable AEAD Cipher for the compilation to be successful. As I said, I have yet to successfully connect to Google with SSP 2.0.0, using the ECC LTS certificates, as there have been some additions to NetX secure, so the configuration is slightly different.
Thanks Jeremy, copied all your suggestions:
As you stated though, now I fail again on the mqtt_secure_connect. Is quite frustrating that this function doesn't return a more precise error, is a generic NX_NOT_CONNECTED : 0x10005.
Do I need to rollback to 1.7.8 or is there a workaround you guys are working on for the new SSP?
I'm also trying to bring up another laptop with a Wifi card that should allow monitoring mode, so maybe I'll be able to see what's going on during the handshake.
Thanks again,
I am currently trying to work out why SSP 2.0.0 will not connect to Google using the ECC certificates.
I have done a bit more digging as to why the SSP 2.0.0. based project won't connect to the Google cloud MQTT Long term domain, and it appears to be an issue with NetX DUO TLS version in SSP 2.0.0, and the integration of the SCE Crypto HW integration that is used.. There have been alot of changes in NetX DUO TLS between SSP 1.7.8 and SSP 2.0.0. In the Wireshark trace when trying to connect I see an Alert :-
and the Alert is labelled as an internal error, and the Alert came from the Synergy device.
After a bit of debugging on the Synergy side, I see the error is coming from a Crypto operation not being successful (the Crypto operation is using the SCE Crypto HW) :-
It is because of this Crypto operation error, that NetX DUO TLS in SSP 2.0.0 signals the Alert.
This issue is not going to be fixed quickly, I have raised the issue with the SSP development team, for them to look at.
As I said, with SSP 1.7.8 I could successfully connect to the Google cloud MQTT Long term domain.
I am still stuck RSA certs, SSP1.7.8/2.0.0. The server FIN after receiving first Application data (41931).
Double check settings project-id etc, No luck.
This my edited version of thr Google Cloud project for the AE-Cloud2 board, for SSP 1.7.8 that I used.
SSP_1_7_8_AE_CLOUD2_Google_Cloud.zip
I used an ethernet connection.
Thanks for the heads up Jeremy.
We will proceed the development under 1.7.8, hoping that this will be sorted in the coming future.
Thanks for the attached project, I'll have a look at it.
Since we have the ability to connect via Wifi module and Sara modem, not at the same time, I was thinking to create an ssp style library that will include all the TLS/ ECC/ Mqtt operations down to the ip interface, and use this when I need it attaching the ip interface either to the wifi module or the modem module. Is this multiple interface attach possible?
I see Interface 0 is the loopback and interface 1 is usually the one attached. Is it possible to attach/detach multiple interfaces to the ip interface?
Thanks a lot for your support,
Yes it is possible to attach multiple physical network interfaces to a single NetX DUO IP instance. The primary physical interface is the that is used in the call to nx_ip_create(), then further phyiscal interface can be added with nx_ip_interface_attach(), and physical interface removed with nx_ip_interface detach() :-
To attach multiple physical interfaces to a single NetX DUO IP instance at the same time, you need to add the NetX DUO source code to the project, and change the property "Maximum Physical Interfaces" to match the number of physical interface that will attached (the default is 1):-
If you are going to have the DHCP client running on multiple network interface at the same time, you would also need to change the properties for the DHCP Client :-
Thanks Jeremy.
Last thing is, we would like to create ECC key pairs into Synergy, keep the private key and send the public(Certificate) back to the cloud securely. The private key will be used to sign the JWT like we do at the moment, public will be sent to the cloud and added to the device thing.
I see there is an ecc create that generates a private key and a public one, is there a function or a process to generate a .csr to send it back to IoT Core?
Will the keys/certificate be kept/generated only in byte array fashion or we can also convert them into DER/PEM? (is not the end of the world if not, will convert back the byte array in the cloud).
Thanks,
I have not seen anywhere in the SSP where a .csr can be generated.The ECC keys used by the SCE driver are in byte array format. They are not in PEM or DER. The public key is an array containing the two points on a curve e.g. for a 256 bit public key there are two 32 byte integers and for the private key one 32 byte integer.
Thanks Jeremy, it was issue with certs loaded unto Gcloud.Now its OK.
While there are no routines in SSP to construct a CSR, if you have a CSR template with fields of fixed size, the problem becomes one of filling in the fields, e.g. common-name, serial no, validity date, public key etc.,, calculating the hash over the template, getting newly generated private key to sign it and filling in the signature field, that is do-able. In this way, the private key stays on the device.
Thanks Yep.
IoT Core requires a key (RSA or ECC) to be wrapped in a X509 certificate.
So in this case, when I create the key pair in the device using SCE, I will keep the private key in binary array (as this is the format I need in the synergy device) but then I need to somehow wrap the public key in a X509 certificate.
This can be done directly on the device (wrapping the public key and sending the certificate) or in the backend of Google cloud with a function of my choice (most probably JS / Python based), so will send the bare public key.
Do you think is better to wrap the public key in the device or in the cloud (in that case I will send the public key instead of the certificate).?
Has this wrapping of ECC public key ever been done into SSP?
I guess there are libraries around to wrap a key, but is there any process I can apply quickly using purely synergy functions?
Thanks a lot
SSP do not have routines to generate a csr or a certificate. Other 3rd party codes has to be added.
wrapping a public key in x509 certificate is essentially generating a csr and getting it signed by a CA.
Here's a link to device Identity project Synergy Device Identity Application Rev.1.02 - Sample Code | Renesas A wrapped private key/public key is generated.
Note the public key is sent outside to be placed in a certificate.
I can get the SSP 2.0.0 version of the project to connect to mqtt.2030.ltsapis.goog using the minimal root CA set's primary certificate, if I change the size of the TLS pre-master secret to 68 :-
SSP_2_0_0_AE_CLOUD2_Google_Cloud.zip