Add Library

This commit is contained in:
Siwat Sirichai 2019-08-09 09:01:56 +07:00
parent e365b9dbd9
commit 3c47103b39
318 changed files with 56465 additions and 0 deletions

View file

@ -0,0 +1,49 @@
#!/usr/bin/python
import subprocess
import sys
import re
import os
firmware = sys.argv[1]
stacktrace = sys.argv[2]
objdump = os.environ['HOME'] + "/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-objdump"
dump = subprocess.check_output([objdump, '-S',firmware]).split('\n')
funcs = []
start = None
end = None
for line in dump:
#40208544 <_ZN15ESP8266MQTTMesh8setup_APEv>:
match = re.match(r'([0-9a-f]{8})\s+<(.*)>:', line)
if match:
funcs.append([int(match.group(1), 16), match.group(2)])
match = re.match(r'([0-9a-f]{8}):',line)
if match:
add = int(match.group(1), 16)
if not end or add > end:
end = add
if not start or add < start:
start = add
with open(stacktrace, "r") as fh:
in_stack = False
for line in fh:
if re.search(r'>>>stack>>>', line):
in_stack = True
if in_stack:
addrs = re.split(r'[: ]+', line)
for addr in addrs:
try:
add = int(addr, 16)
except:
continue
if add < start or add > end:
#print("Ignoring: %s (%08x, %08x)" % (addr, start, end))
continue
for i in range(0, len(funcs)):
if funcs[i][0] <= add:
continue
print("%s : %s" % (addr, funcs[i-1][1]))
break

View file

@ -0,0 +1,52 @@
#!/bin/bash
#This script is a slightly modified copy of:
#https://github.com/me-no-dev/ESPAsyncTCP/blob/master/ssl/gen_server_cert.sh
cat > ca_cert.conf << EOF
[ req ]
distinguished_name = req_distinguished_name
prompt = no
[ req_distinguished_name ]
O = Espressif Systems
EOF
openssl genrsa -out axTLS.ca_key.pem 2048
openssl req -new -config ./ca_cert.conf -key axTLS.ca_key.pem -out axTLS.ca_x509.req
openssl x509 -req -sha1 -days 5000 -signkey axTLS.ca_key.pem -CAkey axTLS.ca_key.pem -in axTLS.ca_x509.req -out axTLS.ca_x509.pem
cat > certs.conf << EOF
[ req ]
distinguished_name = req_distinguished_name
prompt = no
[ req_distinguished_name ]
O = axTLS on ESP8266
CN = esp8266.local
EOF
openssl genrsa -out axTLS.key_1024.pem 1024
openssl req -new -config ./certs.conf -key axTLS.key_1024.pem -out axTLS.x509_1024.req
openssl x509 -req -sha1 -CAcreateserial -days 5000 -CA axTLS.ca_x509.pem -CAkey axTLS.ca_key.pem -in axTLS.x509_1024.req -out axTLS.x509_1024.pem
openssl rsa -outform DER -in axTLS.key_1024.pem -out axTLS.key_1024
openssl x509 -outform DER -in axTLS.x509_1024.pem -out axTLS.x509_1024.cer
cat axTLS.key_1024 > server.key
cat axTLS.x509_1024.cer > server.cer
python -c 'import os; import hashlib; os.write(1,hashlib.sha1(open("server.cer", "rb").read()).digest())' > fingerprint
echo "const uint8_t ssl_key[] =" > ssl_cert.h
hexdump -v -e '16/1 "_x%02X" "\n"' server.key | sed 's/_/\\/g; s/\\x //g; s/.*/ "&"/' >> ssl_cert.h
echo ";" >> ssl_cert.h
echo "const uint32_t ssl_key_len = `cat server.key | wc -c`;" >> ssl_cert.h
echo "const uint8_t ssl_cert[] =" >> ssl_cert.h
hexdump -v -e '16/1 "_x%02X" "\n"' server.cer | sed 's/_/\\/g; s/\\x //g; s/.*/ "&"/' >> ssl_cert.h
echo ";" >> ssl_cert.h
echo "const uint32_t ssl_cert_len = `cat server.cer | wc -c`;" >> ssl_cert.h
echo "const uint8_t ssl_fingerprint[] =" >> ssl_cert.h
hexdump -v -e '16/1 "_x%02X" "\n"' fingerprint | sed 's/_/\\/g; s/\\x //g; s/.*/ "&"/' >> ssl_cert.h
echo ";" >> ssl_cert.h
rm axTLS.* ca_cert.conf certs.conf

View file

@ -0,0 +1,61 @@
#!/usr/bin/env python
# This script originally came from:
# https://github.com/marvinroger/async-mqtt-client/blob/master/scripts/get-fingerprint/get-fingerprint.py
import argparse
import ssl
import hashlib
import binascii
import sys
import socket
# The following came from https://tools.ietf.org/html/rfc5754#section-3
# This is crude, but works without requireing additional dependencies
signatures = {
"dsa_sha224": "30 0b 06 09 60 86 48 01 65 03 04 03 01",
"dsa_sha256": "30 0b 06 09 60 86 48 01 65 03 04 03 02",
"rsa_sha224": "30 0d 06 09 2a 86 48 86 f7 0d 01 01 0e 05 00",
"rsa_sha256": "30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00",
"rsa_sha384": "30 0d 06 09 2a 86 48 86 f7 0d 01 01 0c 05 00",
"rsa_sha512": "30 0d 06 09 2a 86 48 86 f7 0d 01 01 0d 05 00",
"ecdsa_sha224": "30 0a 06 08 2a 86 48 ce 3d 04 03 01",
"ecdsa_sha256": "30 0a 06 08 2a 86 48 ce 3d 04 03 02",
"ecdsa_sha384": "30 0a 06 08 2a 86 48 ce 3d 04 03 03",
"ecdsa_sha512": "30 0a 06 08 2a 86 48 ce 3d 04 03 04"
}
parser = argparse.ArgumentParser(description='Compute SSL/TLS fingerprints.')
parser.add_argument('--host', required=True)
parser.add_argument('--port', default=8883)
args = parser.parse_args()
try:
cert_pem = ssl.get_server_certificate((args.host, args.port))
cert_der = ssl.PEM_cert_to_DER_cert(cert_pem)
except socket.error as e:
if str(e).find("[Errno 111]") is not -1:
print("ERROR: Could not connect to %s:%s" % (args.host, args.port))
elif str(e).find("[Errno 104]") is not -1:
print("ERROR: Mosquitto broker does not appear to be using TLS at %s:%s" % (args.host, args.port))
print(e)
sys.exit(1)
matches = []
for k in signatures:
fingerprint = binascii.a2b_hex(signatures[k].replace(" ", ""))
if cert_der.find(fingerprint) is not -1:
matches.append(k)
if not matches:
print("WARNING: Couldn't identify signature algorithm")
else:
print("INFO: Found signature algorithm: " + ", ".join(matches))
for sig in ("rsa_sha384", "rsa_sha512", "ecdsa_sha384", "ecdsa_sha512"):
if sig in matches:
print("ERROR: MQTT broker is using a %s signature which will not work with ESP8266" % (sig))
sha1 = hashlib.sha1(cert_der).hexdigest()
print("const uint8_t MQTT_FINGERPRINT[] = {0x" + ",0x".join([sha1[i:i+2] for i in range(0, len(sha1), 2)]) + "};")

View file

@ -0,0 +1,201 @@
#!/usr/bin/python3
import paho.mqtt.client as mqtt
import os
import sys
import argparse
import datetime
import hashlib
import base64
import time
import ssl
import re
import queue
topic = "esp8266-"
inTopic = topic + "in"
outTopic = topic + "out"
send_topic = ""
name=""
passw=""
q = queue.Queue();
def regex(pattern, txt, group):
group.clear()
match = re.search(pattern, txt)
if match:
if match.groupdict():
for k,v in match.groupdict().items():
group[k] = v
else:
group.extend(match.groups())
return True
return False
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
client.subscribe("{}/#".format(outTopic))
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
#esp8266-out/mesh_esp8266-6/check=MD5 Passed
match = []
if regex(r'/([0-9a-f]+)/ota/erase$', msg.topic, match):
q.put(["erase", match[0]])
elif regex(r'([0-9a-f]+)/ota/md5/([0-9a-f]+)', msg.topic, match):
q.put(["md5", match[0], match[1], msg.payload])
elif regex(r'([0-9a-f]+)/ota/check$', msg.topic, match):
q.put(["check", match[0], msg.payload])
else:
#print("%s %-30s = %s" % (str(datetime.datetime.now()), msg.topic, str(msg.payload)));
pass
def wait_for(nodes, msgtype, maxTime, retries=0, pubcmd=None):
seen = {}
origTime = time.time()
startTime = origTime
while True:
try:
msg = q.get(True, 0.1)
if msg[0] == msgtype and (not nodes or msg[1] in nodes):
node = msg[1]
seen[node] = msg
else:
print("Got unexpected {} for node {}".format(msgtype, msg[1], msg))
except queue.Empty:
if time.time() - startTime < maxTime:
continue
if retries:
retries -= 1
print("{} node(s) missed the message, retrying".format(len(nodes) - len(seen.keys())))
client.publish(pubcmd[0], pubcmd[1])
startTime = time.time()
else:
print("{} node(s) missed the message and no retires left".format(len(nodes) - len(seen.keys())))
if nodes and len(seen.keys()) == len(nodes):
break
#print("Elapsed time waiting for {} messages: {} seconds".format(msgtype, time.time() - origTime))
return seen
def send_firmware(client, data, nodes):
md5 = base64.b64encode(hashlib.md5(data).digest())
payload = "md5:%s,len:%d" %(md5.decode(), len(data))
print("Erasing...")
client.publish("{}start".format(send_topic), payload)
nodes = list(wait_for(nodes, 'erase', 10).keys())
print("Updating firmware on the following nodes:\n\t{}".format("\n\t".join(nodes)))
pos = 0
while len(data):
d = data[0:768]
b64d = base64.b64encode(d)
data = data[768:]
client.publish("{}{}".format(send_topic, str(pos)), b64d)
expected_md5 = hashlib.md5(d).hexdigest().encode('utf-8')
seen = {}
retries = 1
seen = wait_for(nodes, 'md5', 1.0, 1, ["{}{}".format(send_topic, str(pos)), b64d])
for node in nodes:
if node not in seen:
print("No MD5 found for {} at 0x{}".format(node, pos))
return
addr = int(seen[node][2], 16)
md5 = seen[node][3]
if pos != addr:
print("Got unexpected address 0x{} (expected: 0x{}) from node {}".format(addr, pos, node))
return
if md5 != expected_md5:
print("Got unexpected md5 for node {} at 0x{}".format(node, addr))
print("\t {} (expected: {})".format(md5, expected_md5))
return
pos += len(d)
if pos % (768 * 13) == 0:
print("Transmitted %d bytes" % (pos))
print("Completed send")
client.publish("{}check".format(send_topic), "")
seen = wait_for(nodes, 'check', 5)
err = False
for node in nodes:
if node not in seen:
print("No verify result found for {}".format(node))
err = True
if seen[node][2] != b'MD5 Passed':
print("Node {} did not pass final MD5 check: {}".format(node, seen[node][2]))
err = True
if err:
return
print("Checksum verified. Flashing and rebooting now...")
client.publish("{}flash".format(send_topic), "")
def main():
global inTopic, outTopic, name, passw, send_topic
parser = argparse.ArgumentParser()
parser.add_argument("--bin", help="Input file");
parser.add_argument("--id", help="Firmware ID (n HEX)");
parser.add_argument("--broker", help="MQTT broker");
parser.add_argument("--port", help="MQTT broker port");
parser.add_argument("--user", help="MQTT broker user");
parser.add_argument("--password", help="MQTT broker password");
parser.add_argument("--ssl", help="MQTT broker SSL support");
parser.add_argument("--topic", help="MQTT mesh topic base (default: {}".format(topic))
parser.add_argument("--intopic", help="MQTT mesh in-topic (default: {}".format(inTopic))
parser.add_argument("--outtopic", help="MQTT mesh out-topic (default: {}".format(outTopic))
parser.add_argument("--node", help=("Specific node to send firmware to"))
args = parser.parse_args()
if not os.path.isfile(args.bin):
print("File: " + args.bin + " does not exist")
sys.exit(1)
if args.topic:
inTopic = args.topic + "in"
outTopic = args.topic + "out"
if args.intopic:
inTopic = args.intopic
if args.outtopic:
outTopic = args.outtopic
if args.id:
send_topic = "{}/ota/{}/".format(inTopic, args.id)
elif args.node:
send_topic = "{}/ota/{}/".format(inTopic, args.node)
else:
print("Must specify either --id or --node")
sys.exit(1)
print("File: {}".format(args.bin))
print("Sending to topic: {}".format(send_topic))
print("Listening to topic: {}".format(outTopic))
if not args.broker:
args.broker = "127.0.0.1"
if not args.port:
args.port = 1883
if args.user:
name = args.user
if args.password:
passw = args.password
client = mqtt.Client()
if args.ssl:
client.tls_set(ca_certs=None, certfile=None, keyfile=None, cert_reqs=ssl.CERT_REQUIRED,tls_version=ssl.PROTOCOL_TLS, ciphers=None)
if (args.user) or (args.password):
client.username_pw_set(name,passw)
client.on_connect = on_connect
client.on_message = on_message
client.connect(args.broker, args.port, 60)
client.loop_start()
fh = open(args.bin, "rb")
data = fh.read();
fh.close()
send_firmware(client, data, [args.node] if args.node else [])
client.loop_stop()
client.disconnect()
main()