ValueError: invalid key when connecting to AWS IoT Core with umqtt (Micropython) - mqtt

A few days ago I bought a Raspberry Pi Pico W and I am trying to connect it to AWS Iot Core. However, I get stuck when connecting to AWS.
I have gone throught the following steps:
installed Micropython on the Raspberry Pi Pico W, this works!
Created an AWS account.
registered a "Thing" at IoT Core
Downloaded the corresponding certificates & keys: (Certificates: AmazonRootCA1.pem, certificate.pem.crt, Keys: public.pem.key & private.pem.key)
created a policy, which allows the policy all actions. At AWS this policy is activated and has the form:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}
]
}
Attached the certificate to the policy.
Attached the registered Thing to the policy.
transfered the keys and the certificates to the Raspberry Pi Pico W.
Hereafter, I use Thonny to write the following code trying to connect the raspberry pi with AWS.
import time
import network
import urequests
SSID = "XXXX"
PASSWORD = "XXXX"
print("start connecting")
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(SSID, PASSWORD)
print("Connected:", wlan.isconnected())
import sys
import machine
import argparse
from umqtt.simple import MQTTClient
clientId = 'client1'
AWS_ENDPOINT = 'XXXXX.amazonaws.com'
PORT = 8883
certfile = '/certificate.pem.crt'
with open(certfile, 'r') as f:
cert = f.read()
keyfile = '/private.pem.key'
with open(keyfile, 'r') as f:
key = f.read()
print("Key and Certificate files Loaded")
SSL_PARAMS = {'key': key, 'cert': cert, 'server_side': False}
client = MQTTClient(clientId, AWS_ENDPOINT, port=PORT, keepalive=10000, ssl=True, ssl_params=SSL_PARAMS)
print("Client created")
client.connect()
The program runs until:
client.connect()
And gives me the following error:
Traceback (most recent call last):
File "<stdin>", line 38, in <module>
File "/lib/umqtt/simple.py", line 61, in connect
ValueError: invalid key
(line 38 being the client.connect() statement)
The format of the private.pem.key is:
-----BEGIN RSA PRIVATE KEY-----
[block of characters]
-----END RSA PRIVATE KEY-----
I there anyone who knows what I am doing wrong? Thank you in advance for the help!! :)
Kind regards, Benjamin

Sorry - late to the party.
If you haven't got this working you should try to convert the key & cert files to .DER format with OpenSSL
openssl x509 -in certificate.pem.crt -out certificate.der -outform DER
openssl rsa -in private.pem.key -out private.key.der -outform DER
`certfile = '/certificate.der'`
`with open(certfile, 'r') as f:`
`cert = f.read()`
`keyfile = '/private.pem.der'`
`with open(keyfile, 'r') as f:`
`key = f.read()`

Related

iOS swift connect TLS socket with cert per string

I have created an RSA certification using a generated private/public key using this library-
https://github.com/cbaker6/CertificateSigningRequest
thanks to this library I now have a certificate in a PEM string format.
now I want to create an ssl socket that can use this certificate to connect to a remote server that requires an ssl connection.
so for example this is a pseudo code in node.js:
let options = {
key : this.certs.key,
cert: this.certs.cert,
port: this.port,
host : this.host,
rejectUnauthorized: false,
}
console.debug("Start Connect");
this.client = tls.connect(options, () => {
console.debug(this.host + " connected")
});
where the key and the cert are both a PEM string
I tried BlueSSLService lib, but they only support connecting with cert files, no strings.

ESP32 - MQTT to AWS IoT using MicroPython

I have registered my ESP32 as a thing on AWS IoT and downloaded its respective certificate and public & private keys. Also verified that those connect properly via the following command in my terminal:
openssl s_client -connect host.iot.region.amazonaws.com:8443 -CAfile AmazonRootCA1.pem -cert certificate.pem.crt -key private.pem.key
This is my (main.py) simple code to connect to AWS IoT using MicroPython
import machine
from network import WLAN
import network
from umqtt.simple import MQTTClient
# AWS endpoint parameters.
HOST = b'HOST' # ex: b'abcdefg1234567'
REGION = b'REGION' # ex: b'us-east-1'
CLIENT_ID = "CLIENT_ID" # Should be unique for each device connected.
AWS_ENDPOINT = b'%s.iot.%s.amazonaws.com' % (HOST, REGION)
keyfile = '/certs/private.pem.key'
with open(keyfile, 'r') as f:
key = f.read()
certfile = "/certs/certificate.pem.crt"
with open(certfile, 'r') as f:
cert = f.read()
# SSL certificates.
SSL_PARAMS = {'key': key,'cert': cert, 'server_side': False}
# Setup WiFi connection.
wlan = network.WLAN( network.STA_IF )
wlan.active( True )
wlan.connect( "SSID", "PASSWORD" )
while not wlan.isconnected():
machine.idle()
# Connect to MQTT broker.
mqtt = MQTTClient( CLIENT_ID, AWS_ENDPOINT, port = 8883, keepalive = 10000, ssl = True, ssl_params = SSL_PARAMS )
mqtt.connect()
# Publish a test MQTT message.
mqtt.publish( topic = 'test', msg = 'hello world', qos = 0 )
But I get this error when I try to connect:
(-17168, 'MBEDTLS_ERR_RSA_PRIVATE_FAILED+MBEDTLS_ERR_MPI_ALLOC_FAILED')
After much effort I got this to work. I had to use an idf3 MicroPython binary,
esp32-idf3-20191220-v1.12.bin
idf4 binaries and idf3 later than v1.12 don't work. There is a problem with not enough heap and memory allocation problems.
----------- EDIT -----------
News update! The new v1.15 release of MicroPython based on idf4 works with AWS MQTT for IoT.

verify a jwt token with lua/openresty

i've a jwt token from an aws cognito login process. this token needs to be sent from the application to some other apis (via cookie or bearer header, i've not yet decided).
the receiving apis has been proxied behind nginx/openresty, so i'm thinking to validate the jwt token before the upstream
i'm using this library (the seems the most updated)
https://github.com/cdbattags/lua-resty-jwt
then i followed these steps:
download the jwks file from my account
wget https://cognito-idp.eu-west-1.amazonaws.com/eu-west-1_5zCVSiMVH/.well-known/jwks.json
convert the jwks to pem with jwks2pem
cat jwks.json| jwks2pem > key.pem
then this code
local jwt = require "resty.jwt"
local key = [[ -----BEGIN PUBLIC KEY-----
(content of key.pem)
-----END PUBLIC KEY-----
]]
local jwt_token = ""
local jwt_obj = jwt:load_jwt(jwt_token)
local verified = jwt:verify_jwt_obj(key, jwt_obj)
ngx.say(cjson.encode(jwt_obj))```
the code fails:
$ resty jwt.lua
{"valid":false,"reason":"invalid algorithm: RS256","verified":false}
where i'm wrong?
ok, the problem is the key.
i've successfully obtained the pem key from jwks with this other tool https://www.npmjs.com/package/jwk-to-pem
the validation now works

APNS_CERTIFICATE - Push Notification does not send in production

I've had this issue for about 2 weeks, when I suddenly stopped sending notifications in production. I am using the django-push-notifications library and by django admin I can send a test message, but it does not send messages through the system.
On my local computer, everything works flawlessly. I discovered a command to test the certificate:
openssl s_client -connect gateway.push.apple.com:2195 -cert apns-cert.pem
With this one I had the return: Timeout: 7200 (sec) Verify return
code: 20 (unable to get local issuer certificate) Extended master
secret: yes
So with a lot of research, I discovered that I needed to put the path of "CA":
openssl s_client -CApath /etc/ssl/certs/ -connect gateway.push.apple.com:2195 -cert apns-cert.pem
Who was taking me to: Verify return code: 0 (ok)
However, for use in the library, I needed to put the full path of a .pem file. Then I found this command:
ls /etc/ssl/certs/Entrust*
I tested all the .pem files that were there, until I reached what appeared to have worked perfectly:
openssl s_client -CAfile /etc/ssl/certs/Entrust.net_Premium_2048_Secure_Server_CA.pem -connect gateway.push.apple.com:2195 -cert apns-cert.pem
Soon, I formatted my PUSH_NOTIFICATIONS_SETTINGS:
PUSH_NOTIFICATIONS_SETTINGS = {
"GCM_API_KEY": "xxxx",
"APNS_CERTIFICATE": os.path.join(BASE_DIR, "apns-cert.pem"),
"APNS_CA_CERTIFICATES": "/etc/ssl/certs/Entrust.net_Premium_2048_Secure_Server_CA.pem",
"APNS_ERROR_TIMEOUT": 3,
}
IOS_VERIFY_RECEIPT_API = 'https://buy.itunes.apple.com/verifyReceipt'
ANDROID_VERIFY_RECEIPT_API = 'https://www.googleapis.com/androidpublisher/v2/applications/{packageName}/purchases/subscriptions/{subscriptionId}/tokens/{token}'
Unfortunately it still does not send PUSH, and no error because I have configured it to pop errors to send by email.
PS: Remembering that by sending a test text via django admin: OK. Sending via sandbox (debug): OK.
In fact it was not an SSL issue, it was a bulk upload error by the library.
The tokens registered in the system were expired and the library does not know how to work with it and canceled the action, causing no other token to be attempted. I corrected the problem by looping and ignoring the individual error by sending a test to my email:
def send_push(self):
errors = []
# IOS
queryset_ios = APNSDevice.objects.filter(user=self.authentication)
for device in queryset_ios:
try:
device.send_message(self.subject, badge=1, sound=self.kind.sound)
except APNSServerError as e:
errors.append(APNS_ERROR_MESSAGES[e.status])
except Exception:
pass
# ANDROID
queryset_android = GCMDevice.objects.filter(user=self.authentication)
extra = {'notification': self.pk, 'kind': self.kind.kind, 'sound': self.kind.sound}
for device in queryset_android:
try:
queryset_android.send_message(self.subject, badge=1, extra=extra)
except GCMError as e:
errors.append(str(e))
except Exception:
pass
if errors:
send_mail("Push Error",
"Push: %s \n User: %s \n\n Errors: %s" % (self.subject, self.authentication.full_name, errors),
settings.DEFAULT_FROM_EMAIL, ["my#mail.com"])

Getting an error while Connecting to APNS server

source: www.raywenderlich.com/32960/apple-push-notification-services-in-ios-6-tutorial-part-1
Terminal Command:
Initiums-iMac:Desktop initium$ openssl s_client -connect
gateway.sandbox.push.apple.com:2195
-cert PushChatCert.pem -key PushChatKey.pem
Terminal Response:
CONNECTED(00000003) depth=1 /C=US/O=Entrust,
Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009
Entrust, Inc./CN=Entrust Certification Authority - L1C
verify error:num=20:unable to get local issuer certificate
verify return:0
3122:error:14094410:SSL routines:SSL3_READ_BYTES:sslv3 alert handshake
failure:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/s3_pkt.c:1106:SSL
alert number 40
3122:error:140790E5:SSL routines:SSL23_WRITE:ssl handshake
failure:/SourceCache/OpenSSL098/OpenSSL098-47.2/src/ssl/s23_lib.c:182:
Following the tutorial www.raywenderlich.com/32960, I think I faced the same issue... almost.
Anyways, I think it was because I had goofed up with the .p12 file specifically.
Did you export the correct private key from inside "Keychain Access > Keys"?
This part comes under "Generating the Certificate Signing Request (CSR)" where you have to export the private key as a p12 file.
Delete all the unnecessary certificates and keys, start from scratch and closely follow the tutorial.

Resources