A Node-RED node to capture certificates from TLS/SSL connections
APACHE-2.0 License
A Node-RED node to capture certificates from TLS/SSL connections
Run the following npm command in your Node-RED user directory (typically ~/.node-red):
npm install node-red-contrib-certificate-grabber
Please buy my wife a coffee to keep her happy, while I am busy developing Node-RED stuff for you ...
This node can be useful in following cases:
The following example flow shows how to capture the certificate being used to secure your Node-RED installation (in case you have setup https):
[{"id":"dd032f207383a627","type":"debug","z":"fbee74db83781e91","name":"Certificate info","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":2260,"y":1540,"wires":[]},{"id":"e81159c3e99fb5f9","type":"inject","z":"fbee74db83781e91","name":"Inject host & port","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"host\":\"localhost\",\"port\":1880}","payloadType":"json","x":1840,"y":1540,"wires":[["f9e2aff0450f02ce"]]},{"id":"f9e2aff0450f02ce","type":"certificate-grabber","z":"fbee74db83781e91","name":"","host":"payload.host","hostType":"msg","port":"payload.port","portType":"msg","timeout":"10","x":2050,"y":1540,"wires":[["dd032f207383a627"]]}]
It works like this:
Inject a message containing 'localhost' and port 1880.
The certificate grabber node wil open a TLS/SSL connection to port 1880 on localhost (where in my case Node-RED is running on https).
During the SSL handshake phase, the (Node-RED) server will share its public certificate with this node (that acts as a client).
This node will send an output message, containing certificate information in the payload.
The msg.payload
contains the following information about the certificate:
-----BEGIN CERTIFICATE-----
<the raw certificate as base64 encoded string>
-----BEGIN CERTIFICATE-----
Moreover the msg.payload
contains some calculated fields for your convenience:
The daysRemaining field could be used for example to monitor how long your Node-RED SSL certificate is still valid:
[{"id":"444baae6b6ddc0b7","type":"inject","z":"fbee74db83781e91","name":"Inject host & port","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"host\":\"localhost\",\"port\":1880}","payloadType":"json","x":600,"y":1620,"wires":[["b585a098132c8d9b"]]},{"id":"b585a098132c8d9b","type":"certificate-grabber","z":"fbee74db83781e91","name":"","host":"payload.host","hostType":"msg","port":"payload.port","portType":"msg","timeout":"10","x":810,"y":1620,"wires":[["28d9f5baa0619f96"]]},{"id":"28d9f5baa0619f96","type":"switch","z":"fbee74db83781e91","name":"daysRemaining","property":"payload.daysRemaining","propertyType":"msg","rules":[{"t":"btwn","v":"1","vt":"num","v2":"5","v2t":"num"},{"t":"lte","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":2,"x":1020,"y":1620,"wires":[["7a4aefe0bdd4beac"],["ebfdce39f8c15bb7"]],"outputLabels":["going to expire","expired"]},{"id":"7a4aefe0bdd4beac","type":"debug","z":"fbee74db83781e91","name":"Warning","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1220,"y":1600,"wires":[]},{"id":"ebfdce39f8c15bb7","type":"debug","z":"fbee74db83781e91","name":"Problem","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1220,"y":1640,"wires":[]}]
This flow checks the msg.payload.daysRemaining
property: a value between 1 and 5 days will result in a warning, and a value below 0 will result in an error. That way you have a couple of days time to make sure to order a new certificate from your CA.
When you want to store the grabbed certificate into a file (as PEM format), that can implemented very easily using a File-Out node:
[{"id":"c61fec9be9f3f9a9","type":"inject","z":"fbee74db83781e91","name":"Inject host & port","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"host\":\"localhost\",\"port\":1880}","payloadType":"json","x":520,"y":1460,"wires":[["6bfc36319a9887bc"]]},{"id":"6bfc36319a9887bc","type":"certificate-grabber","z":"fbee74db83781e91","name":"","host":"payload.host","hostType":"msg","port":"payload.port","portType":"msg","timeout":"10","x":730,"y":1460,"wires":[["637dad61900e7213"]]},{"id":"5d0d2a6ae69d8c95","type":"file","z":"fbee74db83781e91","name":"","filename":"c:\\temp\\grabbedCert.crt","filenameType":"str","appendNewline":false,"createDir":false,"overwriteFile":"true","encoding":"none","x":1210,"y":1460,"wires":[[]]},{"id":"637dad61900e7213","type":"change","z":"fbee74db83781e91","name":"get PEM certificate","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload.pemCertificate","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":950,"y":1460,"wires":[["5d0d2a6ae69d8c95"]]}]
The hostname or IP address to which this node should connect. The hostname value can be specified in the config screen directly or via an input message field.
The port (of the specified host) to which this node should connect. Because a single hostname can have multiple services running (each listening to separate ports), which might use different certificates. The port value can be specified in the config screen directly or via an input message field.
After this timeout (in seconds) the node will stop trying to connect to the specified port on the specified host.