ESP32 + SIM7000x - connect to AWS IoT MQTTT server - mqtt

Currently, I have a working 'thing' on AWS, whitch is connected via WIFI or an ethernet port. In there, I can simply pass my CA cert, public and private keys and tell the MQTTClient to use that client with those certificates.
Now, I want a backup in case of no wifi or internet. Thus I tought, a SIM7000x would do. For HTTPS calls, it works like a real champ. Also for plain MQTT connections without any kind of authentication methods, it works just fine.
Now I am using the TinyGSM library on the ESP32, if I just modify that example for the MQTT a bit, with my mqtt server at home to be used, it works just fine.
but I want to be able to connect to an MQTTS server on AWS IoT. This needs 3 certificates. 1 CA certificate, 1 public and 1 private certificate.
On my current code, without the SIM module, it looks like this:
#include <WiFiClientSecure.h>
#include <MQTTClient.h>
WiFiClientSecure net = WiFiClientSecure();
MQTTClient mqttClient = MQTTClient(384); // larger buffer
...
void connectToAWS() {
// Configure WiFiClientSecure to use the AWS IoT device credentials (from secrets file)
net.setCACert(AWS_CA_CERTIFICATE); // Amazon root CA
net.setCertificate(AWS_CERT); // Device certificate
net.setPrivateKey(AWS_PRIVATE_CERT); // Device private key
// Connect to the MQTT broker on the AWS endpoint we defined earlier
mqttClient.begin(AWS_IOT_ENDPOINT, AWS_IOT_ENDPOINT_PORT, net);
Serial.println("Connecting to AWS IoT");
unsigned long timeout = millis();
while (!mqttClient.connect("myThingName")) {
if (millis() - timeout > 5000) {
Serial.println("AWS IoT Timeout");
}
Serial.print(".");
vTaskDelay(100);
}
Serial.println("Connected to AWS IoT!");
}
I want to be able to do the same on the SIM module, preferred by using the tinygsm library.
Now I have found that I could use some AT commands to tell the module, here are the files and upload them to the storage of the SIM. But that didn't work.
The simcom docs tell the following:
Step 1: Configure SSL version by AT+CSSLCFG=“sslversion”,<ssl_ctx_index>,<sslversion>.
Step 2: Configure SSL authentication mode by AT+CSSLCFG=“authmode”,<ssl_ctx_index>, <authmode>.
Step 3: Configure the flag of ignore local time by
AT+CSSLCFG=“ignorlocaltime”,<ssl_ctx_index>,<ignoreltime>.
Step 4: Configure the max time in SSL negotiation stage by
AT+CSSLCFG=“negotiatetime”,<ssl_ctx_index>,<negotiatetime>.
Step 5: Configure the server root CA by AT+CSSLCFG=“cacert”,<ssl_ctx_index>,<ca_file>.
Step 6: Configure the client certificate by AT+CSSLCFG=“clientcert”,<ssl_ctx_index>,<clientcert_file>.
Step 7: Configure the client key by AT+CSSLCFG=“clientkey”,<ssl_ctx_index>,<clientkey_file>.
Step 8: Download the certificate into the module by AT+CCERTDOWN.
Step 9: Delete the certificate from the module by AT+CCERTDELE.
Step 10: List the certificates by AT+CCERTLIST
I tried those steps, but at step 5, I get "operation not allowed".
So the only issue I'm currently facing is the X.509 certificate chain that needs to work on that SIM module for the MQTT connections. I also have API calls, those should NOT use that keychain.

Related

Cannot to EMQX Cloud Broker via unsecure Web Sockets - secure ws works

I'm using Angular 14 and the ngx-mqtt front-end lib.
Here's my connection string which works fine:
getEmqxCloudConnection(): IMqttServiceOptions {
return {
hostname: 'xx.xx.xx.182',
port: 8083,
path: '/mqtt',
clean: true, // retain
connectTimeout: 4000,
reconnectPeriod: 4000,
clientId: 'HarBrowserTest1',
username: 'myUser',
password: 'myPass',
protocol: 'ws',
connectOnCreate: false,
};
}
As per their Broker dashboard the available ports are:
Ports: 1883(mqtt), 8883(mqtts), 8083(ws), 8084(wss)
I have already imported our SSL Certificate into the EMQX Dashboard, yet when I change my conn string to port: 8084 and protocol: 'wss' - IT DOESN'T CONNECT !
They have some screenshots here showing their Client Tool, but for reason every one shows port=1883 (a mistake maybe). https://docs.emqx.com/en/cloud/latest/connect_to_deployments/mqttx.html#connection-configuration
In my Chrome browser network tab, here's what I see for the std insecure ws - A successful ws conn to the Mqtt Broker.
Here is the certificate UI which I used to imported the PEM-Encoded cert body and key:
This will most likely be down to the certificate you have used for the broker.
First unless you have created the certificate just right (using the correct SAN entries) that include the IP address as the principal for the certificate, then the connection will get rejected because the certificate doesn't match the hostname/IP address the broker is using to connect.
Second, if it is a self signed certificate then the browser will just reject it, unless you have manually imported the CA (or if it really is self signed the cert it's self) into the browsers trust store and marked it as trusted. The browser will NOT show you a warning and ask to accept for a WebSocket connection like it does with a webpage, it will just fail with an error in the console and nothing else.
P.S. - You should not hard code the client id in web apps, this is because client ids must be unique across ALL clients, so hardcoding it means that everybody that visits the page will use the same client id and each new connection will kick off the last one (and probably end up in a reconnect fight)
If you check the logs of EMQX, maybe you can get more helpful information.
The following are possible reasons for common TLS connection failures.
First of all, as mentioned in the previous answer, your certificate may have a domain name or IP address set as CN or SAN when it is issued, but the address you specified when connecting does not match the values of the CN and SAN fields.
In this case, the TLS client will think that the server you are connecting to may not be what you really expect, so it will refuse the connection.
We have three ways to solve it:
Turn off the verification of the peer certificate, if your client has this option. However, we do not recommend this as it increases the security risk.
Reissue a certificate that matches your server address
Set the SNI field (full name Server Name Indication) when the client connects, so that TLS will check whether the SNI matches the CN and SAN fields of the certificate, instead of your actual connection address.
The second possible reason is that your certificate path is incomplete, such as the lack of intermediate certificates, or the client does not specify a trusted root certificate, its keyword in the EMQX log is unknown_ca.
For more TLS error reasons, you can refer to SSL Connection Error.
In a browser environment, you should use a server certificate issued by a CA Signed than a self-signed certificate.
Self-Signed SSL Vs Trusted CA Signed SSL Certificate, see the https://cheapsslsecurity.com/blog/self-signed-ssl-versus-trusted-ca-signed-ssl-certificate/

Delphi SSL connection using a certificate on a smart card

I'm trying to access a certain API and I have been provided with a smart card which contains the certificate that I'm supposed to use to establish a SSL connection with the said API. I'm trying to do this through a Delphi appliction.
The following is the info of the certificate:
The certificate used to establish a secure connection is stored on a
smart card and it can be accessed from the PKI Applet using PKSC#11
API. The certificate is loaded in the slot / token structure on the
PKI Applet. After the certificate is extracted from the smart card (in
DER format) it can be used as a standard X.509 certificate for TLS/SSL
and HTTPS protocols.
I'm able to extract the certificate (via pkcs11CertificateStorage tool from SecureBlackbox) but I'm hvaing trouble using it for a SSL connection with Delphi.
Here's a simplified version of what I'm doing to attach the certificate to the request (using ipWorks REST component):
var
CertStorage: TsbxCertificateStorage;
ipwREST1: TipwREST;
// ...
CertStorage.Open('pkcs11://user:' + Pin + '#/' + StorageFilename + '?slot=0'+ RO);
ipwREST1.SSLCertEncodedB := CertStorage.Certificates[0].Bytes;
ipwREST1.Get('https://...');
The error that I get from the REST component:
273: Could not acquire security credentials: error 0x8009030E
Which led me to the error explanation by the component developer:
When using a certificate for client authentication, ensure the certificate's private keys are accessible. The certificate in the Windows certificate store must contain the corresponding private keys, and be marked as exportable.
and I'm not sure how to interpret this.
I've tried saving the certificate in a file, using openSSL to convert to PEM and attaching it in other ways but with no success.
I feel like I'm missing something in my approach. Any help would be appreciated, thanks.

Which SSL-certificate can insure a secure TCP-connection between C# listener on Amazon Lightsail instance and iOS app?

I created a simple .NET Core Console application on C# which uses TcpListener to accept connections on a specific port and return an answer.
I bought an AWS Lightsail instance and deploy my server application manually via RDP. The instance has a static IP-address and a domain name like ec2-<IP>.eu-central-1.compute.amazonaws.com (as I discovered via reverse DNS lookup). The client is an iOS application and it needs a secure TCP connection to transfer data to server and vice versa. iOS app is not working with my self-signed certificate - it needs to use certificate from trusted CA, so the question is: where I can get the trusted SSL-certificate for Amazon Lightsail instance mentioned above?
I created a package to help with sockets and iOS using Obj-C. Also included is a very good resource for creating a certificate that will work. You will actually probably need to create a certificate authority, and intermediate certificate authority, and server/client certificates, check out the link:
https://github.com/eamonwhiter73/IOSObjCWebSockets/tree/master

Titanium - "The certificate for this server is invalid. You might be connecting to a server that is pretending to be DOMAIN.COM”

I am developing an app for iOS using Titanium Appcelerator.
I am struggling with securing the connections to my server. I bought a UCC certificate to protect my server (and other websites) and installed it. When I go on any browser, it displays that the connection is secured.
Now, when I try to create a connection from the app to my server, I get the following error:
The certificate for this server is invalid. You might be connecting to
a server that is pretending to be DOMAIN.COM
I've tried with other secured domains, and it works fine.
I am using Ti.Network.createHTTPClient to create my connections.
Does anyone have any idea about that problem? Is there something I'm missing here?
You should use a securityManager to communicate with a secured website. Below is the simple example from the documentation. The certificate should be provided as a X.509 certificate file in DER binary format.
Disclaimer: The appcelerator.https module is a paid feature!
// Require in the module
var https = require('appcelerator.https'),
securityManager,
httpClient;
// Use the module to create a Security Manager that authenticates the specified URLs
securityManager = https.createX509CertificatePinningSecurityManager([
{
url: "https://dashboard.appcelerator.com",
serverCertificate: "dashboard.appcelerator.com.der"
},
{
url: "https://www.wellsfargo.com",
serverCertificate: "wellsfargo.der"
}
]);
// Create an HTTP client the same way you always have
// but pass in the optional Security Manager that was created previously.
httpClient = Ti.Network.createHTTPClient({
onload: function(e) {
Ti.API.info("Received text: " + this.responseText);
},
onerror: function(e) {
Ti.API.error(e.error);
},
timeout : 5000,
// Set this property before calling the `open` method.
securityManager: securityManager
});
// Prepare the HTTPS connection in the same way you always have
// and the Security Manager will authenticate all servers for
// which it was configured before any communication happens.
httpClient.open("GET", "https://dashboard.appcelerator.com");
// Send the request in the same way you always have.
// Throws a Security Exception if authentication fails.
httpClient.send();
I found the reason why in my case the connection was refused. The catch was that I hadn't concatenated the two cert files given by godaddy, which doesn't seem to be a problem on browser, but was breaking the chain of trust for the app. Correcting that part fixed the issue, using:
cat gd_bundle-g1-g2.crt >> my_server.crt
to create the full crt file.
Note: The first cert file is downloadable on Godaddy's website, but is also attached when you download your crt file.

Can establish https connection without certificat on client device?

I want to do Client/Server communication with HTTP/HTTPS encapsulation.
The HTTPS mode is used just for encryption data, i don't need authentification.
For HTTPS connection, I created and installed certificat on server side. Is it possible to connect to server even if client has no certificat? (I think Yes but....)
PS: I developed client on Windows, Android and iOS
Thanks
Yes if the cert is signed by a recognized CA (Certificate Authority), no if self-signed.
If you look in the Keychain under System Roots you will find over 200 CAs.

Resources