-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Simple C publisher and python client for verifying HMAC-SHA1 signed m…
…essages with MQTT
- Loading branch information
0 parents
commit 6a8e875
Showing
6 changed files
with
308 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Demo code snippets related to MQTT | ||
|
||
msg_signing - C message publisher, signing messages with openssl | ||
- python message consumer, verifying signatures | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
CC=gcc | ||
CFLAGS= -Wall -I. | ||
SOURCES=main.c uglylogging.c | ||
OBJECTS=$(SOURCES:.c=.o) | ||
EXECUTABLE=publisher | ||
LDFLAGS=-lc -lcrypto -lmosquitto | ||
|
||
all: $(SOURCES) $(EXECUTABLE) | ||
|
||
$(EXECUTABLE): $(OBJECTS) | ||
$(CC) $(LDFLAGS) $(OBJECTS) -o $@ | ||
|
||
%.o : %.c | ||
$(CC) -c $(CFLAGS) $< -o $@ | ||
|
||
clean: | ||
rm -rf $(OBJECTS) | ||
rm -rf $(EXECUTABLE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
''' | ||
Example for verifying HMAC-SHA1 signed messages on MQTT topics. | ||
By calculating the HMAC over the entire message body, we can be sure that the message has not been | ||
tampered with, and was produced by someone who knows the shared secret. | ||
Anyone can still read the message of course, and messages can be replayed at will and still | ||
appear genuine. Timestamps and only accepting messages from the "recent" past can help with that | ||
@author: karlp@remake.is | ||
''' | ||
|
||
import hashlib | ||
import hmac | ||
import logging | ||
logging.basicConfig(level=logging.DEBUG, format="%(asctime)s %(levelname)s %(name)s - %(message)s") | ||
log = logging.getLogger("main") | ||
|
||
import mosquitto | ||
|
||
def on_connect(rc): | ||
log.info("Connected") | ||
|
||
def on_message(msg): | ||
""" | ||
Looks for messages on topics like blahblah/signed/>hex_hmac_key_here< | ||
""" | ||
log.info("Received message on topic %s, length: %d bytes", msg.topic, msg.payloadlen) | ||
|
||
if "/signed/" in msg.topic: | ||
log.debug("message is signed! will attempt to verify, msg is: <%s>", msg.payload_str) | ||
topic_remainder, sig = msg.topic.rsplit('/', 1) | ||
log.debug("sig is: <%s>", sig) | ||
key = "karl_loves_you" | ||
rsig = hmac.new(key, msg.payload_str, hashlib.sha1).hexdigest() | ||
if rsig == sig: | ||
log.info("Signatures match, message appears genuine") | ||
else: | ||
log.warn("rsig != sig! message was tampered: %s != %s", rsig, sig) | ||
|
||
else: | ||
log.info("Message is: <%s>", msg.payload_str) | ||
|
||
#create a client object | ||
mqttc = mosquitto.Mosquitto("python_sub_karl_1234") | ||
|
||
#define the callbacks | ||
mqttc.on_message = on_message | ||
mqttc.on_connect = on_connect | ||
|
||
#connect | ||
mqttc.connect("localhost", 1883, 60, True) | ||
|
||
#subscribe to topic test | ||
mqttc.subscribe("#", 2) | ||
|
||
#keep connected to broker | ||
while mqttc.loop() == 0: | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
/* | ||
* Basic demo of sending HMAC signed messages to an MQTT server | ||
* | ||
* The message HMAC is calculated, and put in the topic, like so | ||
* /demo/signed/<hmac_signature_here> | ||
* | ||
* Karl Palsson <karlp@remake.is> | ||
* | ||
* Takes two optional arguments, the MQTT server host, and the shared key | ||
* Default MQTT host is localhost | ||
* Default shared key is "karl_loves_you" | ||
* | ||
* Released into the public domain as demonstration code | ||
*/ | ||
|
||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <stdbool.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
|
||
#include <mosquitto.h> | ||
#include <openssl/err.h> | ||
#include <openssl/hmac.h> | ||
|
||
#include "uglylogging.h" | ||
|
||
#define LOG_TAG __FILE__ | ||
#define DLOG(format, args...) ugly_log(UDEBUG, LOG_TAG, format, ## args) | ||
#define ILOG(format, args...) ugly_log(UINFO, LOG_TAG, format, ## args) | ||
#define fatal(format, args...) ugly_log(UFATAL, LOG_TAG, format, ## args) | ||
|
||
struct mosquitto* mosq; | ||
char *key; | ||
long int last_message_time; | ||
|
||
int setup_mq(const char* host) { | ||
int mq_maj, mq_min, mq_rev; | ||
mosquitto_lib_version(&mq_maj, &mq_min, &mq_rev); | ||
DLOG("You've got mosquitto version major:%d, minor:%d, rev:%d\n", mq_maj, mq_min, mq_rev); | ||
mosquitto_lib_init(); | ||
pid_t pid = getpid(); | ||
char clientid[40]; | ||
|
||
snprintf(clientid, sizeof (clientid), "rme_signed_demo_%d", pid); | ||
mosq = mosquitto_new(clientid, NULL); | ||
|
||
ILOG("Connecting to %s\n", host); | ||
mosquitto_connect(mosq, host, 1883, 15, true); | ||
return 0; | ||
} | ||
|
||
/** | ||
* Demonstrate sending a signed (HMAC) and then encrypted message to MQTT | ||
* @param tt just something that varies between messages, so we can see it when decrypted | ||
* @return | ||
*/ | ||
int send_signed_message(time_t tt, char *shared_key) { | ||
|
||
// Make message... | ||
char data[200]; | ||
sprintf(data, "Signed Message with sequence: %ld", tt); | ||
|
||
DLOG("pub SIGNED: %s\n", data); | ||
unsigned char* hmac; | ||
unsigned int result_len; | ||
|
||
// printf "%s" "message to be signed..." | openssl sha1 -hmac "karl_hmac_key" | ||
hmac = HMAC(EVP_sha1(), shared_key, strlen(shared_key), (unsigned char*)data, strlen(data), NULL, &result_len); | ||
if (hmac == NULL) { | ||
fatal("Couldn't sign the message: %s\n", ERR_error_string(ERR_get_error(), NULL)); | ||
} | ||
|
||
// Add signature to message | ||
char topic[60]; | ||
char *tmp = &topic[0]; | ||
tmp += sprintf(topic, "demo/signed/"); | ||
int i; | ||
for (i = 0; i < result_len; i++) { | ||
sprintf(tmp + (i*2), "%02x", hmac[i]); | ||
} | ||
i = mosquitto_publish(mosq, NULL, topic, strlen(data), (unsigned char*)data, 0, false); | ||
if (i != MOSQ_ERR_SUCCESS) { | ||
fatal("Failed to publish message: %d\n", i); | ||
} | ||
return 0; | ||
} | ||
|
||
int send_insecure_message(time_t tt) { | ||
char msg[128]; | ||
sprintf(msg, "Insecure Message with sequence: %ld", tt); | ||
mosquitto_publish(mosq, NULL, "demo/insecure", strlen(msg), (unsigned char*)msg, 0, false); | ||
DLOG("pub unsigned: %s\n", msg); | ||
return 0; | ||
} | ||
|
||
void run_tasks() { | ||
mosquitto_loop(mosq, -1); | ||
// anything else we like here.... | ||
|
||
time_t tt = time(NULL); | ||
if ((long int) tt > last_message_time + 2) { | ||
last_message_time = tt; | ||
send_insecure_message(tt); | ||
send_signed_message(tt, key); | ||
} | ||
sleep(1); | ||
} | ||
|
||
/* | ||
* Do mad wild shit that makes us metric boatloads of cash money | ||
*/ | ||
int main(int argc, char** argv) { | ||
ugly_init(99); | ||
|
||
if (argc < 2) { | ||
DLOG("(pass a mq host as argument, otherwise we use localhost)\n"); | ||
setup_mq("localhost"); | ||
} else { | ||
DLOG("Connecting to %s\n", argv[1]); | ||
setup_mq(argv[1]); | ||
} | ||
if (argc < 3) { | ||
key = "karl_loves_you"; | ||
DLOG("using default shared key of %s\n", key); | ||
} else { | ||
key = argv[2]; | ||
DLOG("using supplied shared key of %s\n", key); | ||
} | ||
|
||
while (1) { | ||
run_tasks(); | ||
} | ||
|
||
return (EXIT_SUCCESS); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
/* | ||
* UglyLogging. Slow, yet another wheel reinvented, but enough to make the | ||
* rest of our code pretty enough. | ||
* | ||
* Karl Palsson <karlp@remake.is>, ReMake Electric ehf. 2011 | ||
*/ | ||
|
||
#include <stddef.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <stdarg.h> | ||
#include <time.h> | ||
|
||
#include "uglylogging.h" | ||
|
||
static int max_level; | ||
|
||
int ugly_init(int level) { | ||
max_level = level; | ||
return 0; | ||
} | ||
|
||
int ugly_log(int level, const char *tag, const char *format, ...) { | ||
if (level > max_level) { | ||
return 0; | ||
} | ||
va_list args; | ||
va_start(args, format); | ||
time_t mytt = time(NULL); | ||
struct tm *tt; | ||
tt = localtime(&mytt); | ||
fprintf(stderr, "%d-%02d-%02dT%02d:%02d:%02d ", tt->tm_year + 1900, tt->tm_mon + 1, tt->tm_mday, tt->tm_hour, tt->tm_min, tt->tm_sec); | ||
switch (level) { | ||
case UDEBUG: | ||
fprintf(stderr, "DEBUG %s: ", tag); | ||
break; | ||
case UINFO: | ||
fprintf(stderr, "INFO %s: ", tag); | ||
break; | ||
case UWARN: | ||
fprintf(stderr, "WARN %s: ", tag); | ||
break; | ||
case UERROR: | ||
fprintf(stderr, "ERROR %s: ", tag); | ||
break; | ||
case UFATAL: | ||
fprintf(stderr, "FATAL %s: ", tag); | ||
vfprintf(stderr, format, args); | ||
exit(EXIT_FAILURE); | ||
// NEVER GETS HERE!!! | ||
break; | ||
default: | ||
fprintf(stderr, "%d %s: ", level, tag); | ||
break; | ||
} | ||
vfprintf(stderr, format, args); | ||
va_end(args); | ||
return 1; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* Ugly, low performance, configurable level, logging "framework" | ||
* Karl Palsson, ReMake Electric ehf, 2011 | ||
*/ | ||
|
||
#ifndef UGLYLOGGING_H | ||
#define UGLYLOGGING_H | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
|
||
#define UDEBUG 90 | ||
#define UINFO 50 | ||
#define UWARN 30 | ||
#define UERROR 20 | ||
#define UFATAL 10 | ||
|
||
int ugly_init(int level); | ||
int ugly_log(int level, const char *tag, const char *format, ...); | ||
|
||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
#endif /* UGLYLOGGING_H */ | ||
|