i made stm32 + rtos + lwip/mqtt solution and it works well. Now i want to use it with embed tls secure connection. I did not find any exemples.
lwip mqtt api supports tls comunication. But there are no such example, just simple mqtt client using code LWIP MQTT Client i used.
I tried to enable embedtls and some options in cubemx, LWIP_ALTCP & LWIP_ALTCP_TLS, add LWIP_ALTCP_TLS_MBEDTLS to Path. It compiled.
How to init mbedtls and add tls cert. this link takes a little info altcp tls
Has anyebody some expirience or working example with stm32 lwip/mqtt + tls (mbedtls) for stm32 lwip stack?
UPD.
Here is my code of mqtt client setup:
struct mqtt_connect_client_info_t ci;
memset(&ci, 0, sizeof(ci));
ci.client_id = "lwip_test";
ci.client_user = "";
ci.client_pass = "";
ci.keep_alive = 0;
ci.tls_config = altcp_tls_create_config_client((const u8_t*)test_cert, sizeof(test_cert));
// create client
client = mqtt_client_new();
// connect client
mqtt_client_connect(client, &resolved, port, mqtt_on_connect, (void *)0, &ci);
I give mqtt client ca certificate and length. I have an error in
altcp_tls_create_config_client_common function (altcp_tls_mbedtls.c) with code -4480 (Failed to allocate memory).
ret = mbedtls_x509_crt_parse(conf->ca, ca, ca_len);
if (ret != 0) {
LWIP_DEBUGF(ALTCP_MBEDTLS_DEBUG, ("mbedtls_x509_crt_parse ca failed: %d 0x%x", ret, -1*ret));
altcp_mbedtls_free_config(conf);
return NULL;
}
What i am doing wrong, whitch options else i should set up in mbedtls module?
I use default was generated by CubeMX
This thread helped me together with other examples in https://www.nongnu.org/lwip/2_0_x/group__mqtt.html to make the MQTT client work with MbedTLS 2 way authentication. I can now subscribe/publish to the amazon AWS cloud.
So if anybody is interested, here is what I did.
Generate code from CubeMX with LwIP and MbedTLS enabled. Important is to enable MBEDTLS_PLATFORM_MEMORY, MEMP_MEM_MALLOC and LWIP_ALTCP_TLS_MBEDTLS so the library uses alternative calloc/free functions from LwIP (they are set in the altcp_mbedtls_mem_init() function).
I also use MBEDTLS_ENTROPY_HARDWARE_ALT, MBEDTLS_NO_PLATFORM_ENTROPY and MBEDTLS_CTR_DRBG_C enabled, so the MbedTLS library can use the ctr drbg random number generator (initialized in the altcp_tls_create_config() function).
If you use FreeRTOS with your LwIP as I do, it is necessarry to enable MBEDTLS_THREADING_ALT and then in your code call the mbedtls_threading_set_alt() function to enable mutex handling in the MbedTLS library.
Here is then what I do in my code:
mqtt_client_t *client;
struct mqtt_connect_client_info_t client_info;
ip_addr_t server_ip;
/* Somewhere in the code call this to get IP address of the host */
ip_addr_t ipaddr;
err = dns_gethostbyname("host_name", &ipaddr, mqtt_resolved_cb, NULL);
/* Wait until this callback gets the IP */
static void mqtt_resolved_cb(const char *host, const ip_addr_t *ipaddr,
void *callback_arg)
{
/* If resolved IP is known -> set it */
if (ipaddr->addr != 0)
{
server_ip.addr = ipaddr->addr;
}
}
/* Then call this to start MQTT client */
void mqtt_test(const ip_addr_t *ipaddr, uint16_t port,
const uint8_t *ca_cert_str, size_t ca_cert_len,
const uint8_t *dev_cert_str, size_t dev_cert_len,
const uint8_t *dev_key_str, size_t dev_key_len,
const uint8_t *dev_key_pass_str, size_t dev_key_pass_len)
{
/* Setup an empty client info structure */
memset(&mqtt.client_info, 0, sizeof(mqtt.client_info));
/* Set client information */
mqtt.client_info.client_id = "lwip_test";
mqtt.client_info.client_user = NULL;
mqtt.client_info.client_pass = NULL;
mqtt.client_info.keep_alive = 0;
mqtt.client_info.will_topic = NULL;
mqtt.client_info.will_msg = NULL;
mqtt.client_info.will_retain = 0;
mqtt.client_info.will_qos = 0;
/* Set TLS configuration */
mqtt.client_info.tls_config = altcp_tls_create_config_client_2wayauth(
ca_cert_str, ca_cert_len,
dev_key_str, dev_key_len, dev_key_pass_str, dev_key_pass_len,
dev_cert_str, dev_cert_len);
/* Allocate memory for MQTT client */
mqtt.client = mqtt_client_new();
/* Connect to the server */
if (mqtt.client != NULL)
{
err = mqtt_client_connect(
mqtt.client, ipaddr, port,
mqtt_connection_cb, 0, &mqtt.client_info);
}
}
Then the code continues in the standard mqtt callbacks from the example link above.
Thanks and I hope this can help someone else too.
I have an identical configuration, so I can tell you that if you debug code you'll see that it will crash trying to call calloc, if your environment is equal to mine, you have not that system function.
What I did is using calloc implemented in lwip, in particular into altcp module.
I defined via cubemx MBEDTLS_PLATFORM_MEMORY, in order to activate the define ALTCP_MBEDTLS_PLATFORM_ALLOC in altcp_tls_mbedtls_mem.c, then I was able to use
altcp_mbedtls_mem_init() function that specify to mbedtls to use altcp calloc and free.
This function is called into altcp_tls_create_config_client, so if you are going to use it, you don't have to call altcp_mbedtls_mem_init() twice.
In this way you should be able to correctly allocate memory for mbedtls.
you seem to have a memory allocation problem, you can try to increase the heap memory size in lwipopts.h like the following:
#define MEM_SIZE (50 * 1024)
Related
Currently I'm working on some basic OpenSSL. I'm confused about the basic behavior of SSL_write and SSL_read. In the documentation it is not clearly explained how the data is encrypted / decrypted. What I mean? Is the SSL_write, once the SSL_CTX is set and file descriptor assigned, by default encrypting the data or calling the encryption function, or does this have to be done by hand? Do I have to call some encryption function explicitly? Is the same true for the SSL_read? I need a deeper understanding of what SSL_write / read do automatically and what not, or sources where I can fall back to if I'm having issues.
Here is an example that I'm working with.
Example:
SSL *ssl;
int client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
printf("Connection: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
ssl = SSL_new(ctx); /* get new SSL state with context */
SSL_set_fd(ssl, client); /* set connection socket to SSL state */
Servlet(ssl); /* service connection */
Servlet calls
void Servlet(SSL* ssl)
{
char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho="<html><body><pre>%s</pre></body></html>\n\n";
if ( SSL_accept(ssl) == FAIL ) /* do SSL-protocol accept */
ERR_print_errors_fp(stderr);
else
{
ShowCerts(ssl); /* get any certificates */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get request */
if ( bytes > 0 )
{
buf[bytes] = 0;
printf("Client msg: \"%s\"\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
}
else
ERR_print_errors_fp(stderr);
}
sd = SSL_get_fd(ssl); /* get socket connection */
SSL_free(ssl); /* release SSL state */
close(sd); /* close connection */
}
Do I have to call some encryption function explicitly, is the same true for the SSL_read?
No. Encryption is handled within SSL_write automatically as is decryption in SSL_read. Both use the SSL structure which contains the necessary encryption keys once the TLS handshake is finished.
... sources where I can fall back to if I'm having issues
This depends on the issues you have. Both SSL_read and SSL_write have documentation. There are also easy to find examples. Being able to use a search engine helps also a lot to find more information. And StackOverflow is a good place to get help if things don't work as expected.
I need to send a message from the IoT Hub to the DevKit Device. Based on https://learn.microsoft.com/en-au/azure/iot-hub/iot-hub-devguide-c2d-guidance I want to send a Direct Method as I need to manage a bank of relays.
I have an IoT DevKit and have successfully configured it and are able to send device to IoT Hub messages but am looking for a sample to do this the other way. I currently can only find samples that set the device twin properties, not send direct methods. On the server-side I believe I would use Microsoft.Azure.Devices.ServiceClient to SendAsync a message to the device (happy to be corrected is incorrect).
On the device I think (???) I need to use SetDeviceMethodCallback but I have no idea how to initialise it and receive messages. Ideally, the sample would also include how to send an acknowledgement that the message was received and actioned.
Any help would be appreciated even if just to let me know I am on the right track here. Thanks in advance.
Here is some sample that I used before with the IoT DevKit (=Mxchip) on the device side:
static int DeviceMethodCallback(const char *methodName, const unsigned char *payload, int size, unsigned char **response, int *response_size)
{
LogInfo("Try to invoke method %s", methodName);
const char *responseMessage = "\"Successfully invoke device method\"";
int result = 200;
if (strcmp(methodName, "start") == 0)
{
DoSomething();
}
else if (strcmp(methodName, "stop") == 0)
{
DoSomethingElse();
}
else
{
LogInfo("No method %s found", methodName);
responseMessage = "\"No method found\"";
result = 404;
}
*response_size = strlen(responseMessage) + 1;
*response = (unsigned char *)strdup(responseMessage);
return result;
}
DevKitMQTTClient_SetDeviceMethodCallback(DeviceMethodCallback);
On the services side (where you do the method invocation) here is some C# example
ServiceClient _iothubServiceClient = ServiceClient.CreateFromConnectionString(config["iothubowner_cs"]);
var result = await _iothubServiceClient.InvokeDeviceMethodAsync(deviceid, "start");
var status = result.Status;
i am new to this forum and the whole thing with Processing.
I have a specific question to ask and thanks a lot for your time and thoughts!
How can i connect my Arduino with Ethernet Shield, getting temperature values from a sensor so they can be seen to a processing script?
In a straight Arduino script, one gets the value, connects from the ethernet shield to a server and does what one likes. I have accomplished that.
In my case i want Arduino to just run the script of reading an analog input value from the sensor.
Is it possible?
I have made the serial connection work and read the values alright through the usb, but with ethernet shield? How can i get the value that arduino reads WITHOUT USB/Serial connection?
ps. i am using WAMP server etc, Windows 7
I am trying the UDP connection script example for both arduino and processing from http://arduino.cc/en/Tutorial/UDPSendReceiveString, but
1)i ain't sure if that's what i need,
2)i have excluded from firewall ports 6000, 8888 for my tests and have put the IP address of my Arduino at the Arduino script and "localhost" at the Processing script
THE CODE COPIED FOR BETTER USE HERE
/*
UDPSendReceive.pde:
This sketch receives UDP message strings, prints them to the serial port
and sends an "acknowledge" string back to the sender
A Processing sketch is included at the end of file that can be used to send
and received messages for testing with a computer.
created 21 Aug 2010
by Michael Margolis
This code is in the public domain.
*/
#include <SPI.h> // needed for Arduino versions later than 0018
#include <Ethernet.h>
#include <EthernetUdp.h> // UDP library from: bjoern#cs.stanford.edu 12/30/2008
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192, 168, 1, 177);
unsigned int localPort = 8888; // local port to listen on
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet,
char ReplyBuffer[] = "acknowledged"; // a string to send back
// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;
void setup() {
// start the Ethernet and UDP:
Ethernet.begin(mac,ip);
Udp.begin(localPort);
Serial.begin(9600);
}
void loop() {
// if there's data available, read a packet
int packetSize = Udp.parsePacket();
if(packetSize)
{
Serial.print("Received packet of size ");
Serial.println(packetSize);
Serial.print("From ");
IPAddress remote = Udp.remoteIP();
for (int i =0; i < 4; i++)
{
Serial.print(remote[i], DEC);
if (i < 3)
{
Serial.print(".");
}
}
Serial.print(", port ");
Serial.println(Udp.remotePort());
// read the packet into packetBufffer
Udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
Serial.println("Contents:");
Serial.println(packetBuffer);
// send a reply, to the IP address and port that sent us the packet we received
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
Udp.write(ReplyBuffer);
Udp.endPacket();
}
delay(10);
}
/*
Processing sketch to run with this example
=====================================================
// Processing UDP example to send and receive string data from Arduino
// press any key to send the "Hello Arduino" message
*/
import hypermedia.net.*;
UDP udp; // define the UDP object
void setup() {
udp = new UDP( this, 6000 ); // create a new datagram connection on port 6000
//udp.log( true ); // <-- printout the connection activity
udp.listen( true ); // and wait for incoming message
}
void draw()
{
}
void keyPressed() {
String ip = "192.168.1.177"; // the remote IP address
int port = 8888; // the destination port
udp.send("Hello World", ip, port ); // the message to send
}
void receive( byte[] data ) { // <-- default handler
//void receive( byte[] data, String ip, int port ) { // <-- extended handler
for(int i=0; i < data.length; i++)
print(char(data[i]));
println();
}
Read those values into a file and use that file to send data to processing. http://py.processing.org/reference/createReader.html
Great scheme. Only one problem. It works perfectly on my system. I loaded my Arudino Uno R3 with your Arduino sketch and loaded the Processing sketch as well. Worked like a charm, first try. Didn't change anything on my Arduino, Windows system, Processing (2.0.3), network, etc.
Could be you have a Arduino board problem (unlikely) or an Ethernet shield problem (sadly, more likely). You could have a network problem (even more likely).
Try Wireshark. You will really just be guessing until you take a look at the Wireshark output. Note that Wireshark has filters. You will need them. Filter out all of the non-UDP traffic.
Id like to use srp in my current project. But im kinda at a loss as to how i would implement that with openssl. I got the client side running but i dont know how to write the server side. I also couldnt find any documentation orexample implementations of use. What i want is to store the login information inside a database and then retrieve that data when needed. Im using poco for most of the network part so writing the client was rather easy and i sucessfully tested it against other servers. So i would be gratefull for hints as to how to implement the server side.
There is an example of how to do this in file ssl/ssltest.c in OpenSSL archive.
At a high level you register an authentication callback. This callback is called automatically as necessary during SSL_Accept() to authenticate your users.
From ssltest.c example callback looks like the following:
static int MS_CALLBACK ssl_srp_server_param_cb(SSL *s, int *ad, void *arg)
{
SRP_SERVER_ARG * p = (SRP_SERVER_ARG *) arg;
if (strcmp(p->expected_user, SSL_get_srp_username(s)) != 0)
{
fprintf(stderr, "User %s doesn't exist\n", SSL_get_srp_username(s));
return SSL3_AL_FATAL;
}
if (SSL_set_srp_server_param_pw(s,p->expected_user,p->pass,NULL)<0)
{
*ad = SSL_AD_INTERNAL_ERROR;
return SSL3_AL_FATAL;
}
return SSL_ERROR_NONE;
}
To register you call
SSL_CTX_set_srp_username_callback(s_ctx, ssl_srp_server_param_cb);
The arg parameter of callback function is a void pointer passed to your callback so that you can reference any necessary application context in your application from the callback.
To set arg parameter call SSL_CTX_set_srp_cb_arg(s_ctx, mypointer);
It is really this easy. Be sure SRP ciphers are being included in your cipher list.
There is a way to get feedback on autentication failures that can be used to implement countermeasure against high rate online dictionary attack.
To do this call SSL_CTX_set_info_callback(s_ctx,mynotifycallback) to register your callback. Had success using condition below to filter unrelated notifications.
void mynotifycallback(const SSL *s, int reason, int ret)
{
if (reason & SSL_CB_ALERT && ret & SSL3_AD_BAD_RECORD_MAC && SSL_get_srp_username((SSL *)s))
// authentication failure
}
I'm trying to communicate with the Enttec USB DMX Pro. Mainly receiving DMX.
They released a Visual C++ version here, but I'm a little stumped on what to do to convert to Obj-c. Enttec writes, "Talk to the PRO using FTDI library for Mac, and refer to D2XX programming guide to open and talk to the device." Any example apps for Objective-C out there? Is there an easy way to communicate with the Enttec DMX USB Pro?
I've done a significant amount of work with the FTDI chips on the Mac, so I can provide a little insight here. I've used the single-channel and dual-channel variants of their USB-serial converters, and they all behave the same way.
FTDI has both their Virtual COM Port drivers, which create a serial COM port on your system representing the serial connection attached to their chip, and their D2XX direct communication libraries. You're going to want to work with the latter, which can be downloaded from their site for various platforms.
The D2XX libraries for the Mac come in a standalone .dylib (the latest being libftd2xx.1.2.2.dylib) or a new static library they started shipping recently. Included in that package will be the appropriate header files you need (ftd2xx.h and WinTypes.h) as well.
In your Xcode project, add the .dylib as a framework to be linked in, and add the ftd2xx.h, WinTypes.h, and ftd2xx.cfg files to your project. In your Copy Bundled Frameworks build phase, make sure that libftd2xx.1.2.2.dylib and ftd2xx.cfg are present in that phase. You may also need to adjust the relative path that this library expects, in order for it to function within your app bundle, so you may need to run the following command against it at the command line:
install_name_tool -id #executable_path/../Frameworks/libftd2xx.1.2.2.dylib libftd2xx.1.2.2.dylib
Once your project is all properly configured, you'll want to import the FTDI headers:
#import "ftd2xx.h"
and start to connect to your serial devices. The example you link to in your question has a downloadable C++ sample that shows how they communicate to their device. You can bring across almost all of the C code used there and place it within your Objective-C application. They just look to be using the standard FTDI D2XX commands, which are described in detail within the downloadable D2XX Programmer's Guide.
This is some code that I've lifted from one of my applications, used to connect to one of these devices:
DWORD numDevs = 0;
// Grab the number of attached devices
ftdiPortStatus = FT_ListDevices(&numDevs, NULL, FT_LIST_NUMBER_ONLY);
if (ftdiPortStatus != FT_OK)
{
NSLog(#"Electronics error: Unable to list devices");
return;
}
// Find the device number of the electronics
for (int currentDevice = 0; currentDevice < numDevs; currentDevice++)
{
char Buffer[64];
ftdiPortStatus = FT_ListDevices((PVOID)currentDevice,Buffer,FT_LIST_BY_INDEX|FT_OPEN_BY_DESCRIPTION);
NSString *portDescription = [NSString stringWithCString:Buffer encoding:NSASCIIStringEncoding];
if ( ([portDescription isEqualToString:#"FT232R USB UART"]) && (usbRelayPointer != NULL))
{
// Open the communication with the USB device
ftdiPortStatus = FT_OpenEx("FT232R USB UART",FT_OPEN_BY_DESCRIPTION,usbRelayPointer);
if (ftdiPortStatus != FT_OK)
{
NSLog(#"Electronics error: Can't open USB relay device: %d", (int)ftdiPortStatus);
return;
}
//Turn off bit bang mode
ftdiPortStatus = FT_SetBitMode(*usbRelayPointer, 0x00,0);
if (ftdiPortStatus != FT_OK)
{
NSLog(#"Electronics error: Can't set bit bang mode");
return;
}
// Reset the device
ftdiPortStatus = FT_ResetDevice(*usbRelayPointer);
// Purge transmit and receive buffers
ftdiPortStatus = FT_Purge(*usbRelayPointer, FT_PURGE_RX | FT_PURGE_TX);
// Set the baud rate
ftdiPortStatus = FT_SetBaudRate(*usbRelayPointer, 9600);
// 1 s timeouts on read / write
ftdiPortStatus = FT_SetTimeouts(*usbRelayPointer, 1000, 1000);
// Set to communicate at 8N1
ftdiPortStatus = FT_SetDataCharacteristics(*usbRelayPointer, FT_BITS_8, FT_STOP_BITS_1, FT_PARITY_NONE); // 8N1
// Disable hardware / software flow control
ftdiPortStatus = FT_SetFlowControl(*usbRelayPointer, FT_FLOW_NONE, 0, 0);
// Set the latency of the receive buffer way down (2 ms) to facilitate speedy transmission
ftdiPortStatus = FT_SetLatencyTimer(*usbRelayPointer,2);
if (ftdiPortStatus != FT_OK)
{
NSLog(#"Electronics error: Can't set latency timer");
return;
}
}
}
Disconnection is fairly simple:
ftdiPortStatus = FT_Close(*electronicsPointer);
*electronicsPointer = 0;
if (ftdiPortStatus != FT_OK)
{
return;
}
Writing to the serial device is then pretty easy:
__block DWORD bytesWrittenOrRead;
unsigned char * dataBuffer = (unsigned char *)[command bytes];
//[command getBytes:dataBuffer];
runOnMainQueueWithoutDeadlocking(^{
ftdiPortStatus = FT_Write(electronicsCommPort, dataBuffer, (DWORD)[command length], &bytesWrittenOrRead);
});
if((bytesWrittenOrRead < [command length]) || (ftdiPortStatus != FT_OK))
{
NSLog(#"Bytes written: %d, should be:%d, error: %d", bytesWrittenOrRead, (unsigned int)[command length], ftdiPortStatus);
return NO;
}
(command is an NSData instance, and runOnMainQueueWithoutDeadlocking() is merely a convenience function I use to guarantee execution of a block on the main queue).
You can read raw bytes from the serial interface using something like the following:
NSData *response = nil;
DWORD numberOfCharactersToRead = size;
__block DWORD bytesWrittenOrRead;
__block unsigned char *serialCommunicationBuffer = malloc(numberOfCharactersToRead);
runOnMainQueueWithoutDeadlocking(^{
ftdiPortStatus = FT_Read(electronicsCommPort, serialCommunicationBuffer, (DWORD)numberOfCharactersToRead, &bytesWrittenOrRead);
});
if ((bytesWrittenOrRead < numberOfCharactersToRead) || (ftdiPortStatus != FT_OK))
{
free(serialCommunicationBuffer);
return nil;
}
response = [[NSData alloc] initWithBytes:serialCommunicationBuffer length:numberOfCharactersToRead];
free(serialCommunicationBuffer);
At the end of the above, response will be an NSData instance containing the bytes you've read from the port.
Additionally, I'd suggest that you should always access the FTDI device from the main thread. Even though they say they support multithreaded access, I've found that any kind of non-main-thread access (even guaranteed exclusive accesses from a single thread) cause intermittent crashes on the Mac.
Beyond the cases I've described above, you can consult the D2XX programming guide for the other functions FTDI provides in their C library. Again, you should just need to move over the appropriate code from the samples that have been provided to you by your device manufacturer.
I was running into a similar issue (trying to write to the EntTec Open DMX using Objective-C), without any success. After following #Brad's great answer, I realized that you also need to toggle the BREAK state each time you send a DMX packet.
Here's an example of my loop in some testing code that sends packets with a 20 millisecond delay between frames.
while (1) {
FT_SetBreakOn(usbRelayPointer);
FT_SetBreakOff(usbRelayPointer);
ftdiPortStatus = FT_Write(usbRelayPointer, startCode, 1, &bytesWrittenOrRead);
ftdiPortStatus = FT_Write(usbRelayPointer, dataBuffer, (DWORD)[command length], &bytesWrittenOrRead);
usleep(20000);
}
Hope this helps someone else out there!