What is MQTT?

This is what says:

MQTT is a machine-to-machine (M2M)/”Internet of Things” connectivity protocol. It was designed as an extremely lightweight publish/subscribe messaging transport. It is useful for connections with remote locations where a small code footprint is required and/or network bandwidth is at a premium.

Here is a great intro to MQTT.  NOTE:  This application is in development and screenshot may appear different when released.  You can download the latest release here. - 637 KB - MD5: b33ebf0277e02a3612b8795490e1f6ec


Use MQTT with the JNIOR

Currently the MQTT functionality is limited but we are always looking for suggestions.  Currently will publish IO status by default.  When the JNIOR boots up and successfully connects to a broker we will report the current status of the digital IO.  Digital inputs will report state, usage meter and counter values.  Relay outputs will report just state and usage meter values.

To successfully connect to a broker you will need to have selected a broker and entered its information.  Information such as the Host URL, port number and whether the connection should be encrypted.  The JNIOR implements MQTT across a TCP connection.  The default port number for MQTT is 1883 when non-secure connection while it is 8883 when using a secured connection.  There are several public test brokers out there.  Do not use any free broker for sensitive information.  Brokers that require sign up will most likely provide a user name and password.



There are two types of groups, Device Groups and Relay Output Groups.  Both of these concepts are in BETA as of version 1.2 and we are looking for feedback.

Device Groups allow JNIORs to subscribe to topics that contain the Device Group name instead of the Serial Number.  A JNIOR can be part of one or many Device Groups.  By default a JNIOR will subscribe to topics that are meant for it by Serial Number, for instance, jnior/618010001/set/...  The JNIOR may want to be part of the pump stations group for example the JNIOR will subscribe to jnior/pumpstations/set/... topics.

Relay Output Groups allow the specification of more than one relay to be affected at once.  To set relay channel 1 you can publish the jnior/SERIAL_NUMBER/set/digital/outputs/1/state = true.  But maybe you want channels 1 – 3 to be affected at once.  To do this you will define a named Relay Output Group, “lights”, for example.  Then, when the JNIOR receives the jnior/SERIAL_NUMBER/set/digital/outputs/lights/state topic all defined relays will change at once.


Enhance the MQTT implementation!

You can enhance the MQTT implementation on the JNIOR with a custom application.  Any topic that the JNIOR receives that is not part of our native implementation will be posted to the message pump for the consumption by another application.  A custom application may also put topics with payload data to the message pump to be published by the MQTT application.  This way the MQTT application performs the protocol logic while the custom application can worry about the logic.

The key to debugging these days lies in the ability to recreate the failure. Some of the more elusive problems start out as rumors where a user swears that something failed to do what was expected but that he/she cannot prove it. After a while perhaps the issue resurfaces and this time someone is able to collect enough evidence to barely prove that the problem is a real concern. What exactly occurs remains a complete mystery. Eventually someone files a bug report but the developers are clueless and cannot  effectively address the cause.

Sometimes there are suggestions as to what actions may have triggered the problem. The Support Team may take the time to try to recreate the problem on a local system but to no avail. Other issues which stand a better chance of being resolved take precedence. Meanwhile news comes in that the original issue has again occurred and may even now happen in completely different locations and environments. What to do next?

Perhaps it is appropriate to regenerate the application for the user’s site to add logging and other debugging statements in hopes of creating a better record of the events leading up to a future failure. The difficulty here is in deciding what exactly to log and to be logged by what aspects of the system given no real knowledge of the source of the issue. Some guesses are made and the logging is enabled. Some time later which could be weeks the issue reoccurs and the logging proves to have not been useful. It may even be that the content of the logs are now meaningless as the logic behind them has been forgotten. So it is difficult to make progress.

It would be nice to know when the issue is going to occur so you know exactly when you need to start watching for it. Better yet, if the problem occurs you could skip back in time to only a few seconds before and you could solve it! If the issue involves network interaction you could setup a sniffer like Wireshark and set it to collecting detailed network traffic. Now with an external device this may involve the use of a Network Hub as opposed to a Network Switch so you can add a machine running Wireshark that would see all of the traffic. But that is a lot of hardware and it might just not be feasible.

Here’s where JANOS and the JNIOR might surprise you. If the issue is with the JNIOR application you can use the netstat -c command from the Command Line interface to generate a PCAP capture file capturing network traffic. That PCAP file can be downloaded to a PC with Wireshark installed and it will open right up for analysis. And here’s where the magic occurs. It is almost like JANOS knows ahead of time when the issue will occur, that PCAP file can contain traffic from BEFORE the event happened although it has been generated after the fact.

Okay. So it is not magic but the foresight of the operating system which always is capturing network traffic. There is a capture buffer that by default is 512KB and that can be enlarged through the IpConfig/CaptureBuffer Registry Key to as much as 8MB. It is not so much a ‘buffer’ as it is a queue. At any one point in time it contains a significant amount of recent network traffic. You can also set filtering that is to be employed during capture to limit the collected traffic to that of concern and thereby greatly extend the time frames involved. You can also use a filter in generating the PCAP file to limit what you transfer for analysis.

Now what if the event occurs overnight and by the time you realize it the data that you need has been overwritten? A simple utility application can be added to the unit to automatically generate the network PCAP capture file when the event is detected. You can even then have that file emailed to you!

Those of you who may have worked with this aspect of the JNIOR will note that the network capture only includes data from the previous boot if it is not yet begun to wrap around. If the failure involves an assertion that might cause the JNIOR to reboot the information is lost. Well this is true, however, as of JANOS v1.7.1 which now as of this writing a Release Candidate the capture buffer is non-volatile. It will survive a reboot and contain a record of the prior network traffic. The buffer is only reinitialized when power is applied.

It is also possible to configure the JNIOR in Promiscuous Mode wherein it would capture all external network traffic and not only that targeted to the JNIOR. If you couple that with a Network Hub you could utilize the JNIOR to monitor the interaction of other devices on a local network segment. I bet you never thought of JNIOR as a IT debugging tool?

If this aspect of the JNIOR interests you or if you need to utilize it in debugging, please feel free to contact INTEG for support. You may also consult the Registry Key Assignments documentation for details on network capture. This information is supplied as part of the Dynamic Configuration Pages (DCP) served by the JNIOR WebServer accessible by your favorite browser.





Beginning with JANOS v1.6.4 you will be able to adjust the Time-To-Live (TTL) parameter used by the network stack.

The IpConfig/TTL Registry key defines the lifespan of a network packet. The time-to-live value is a kind of upper bound on the time that an IP datagram can exist in the Internet system. The value is reduced with the passage through a router. If it reaches 0 the packet is discarded. The default value has been increased to 128 from the value of 64 used prior to JANOS v1.6.4.

The TTL setting can be considered to limit the maximum radius (in terms of hops) of the network within reach of the JNIOR. The default setting should allow packets to reach the far end of the globe. A low setting would limit access to the unit as only those in the local vicinity could communicate. In this respect the TTL setting can be used to improve device security.

A very low setting of 1 or 2 would constrain the JNIOR to the local network. One must consider the need to reach Doman Name Servers (DNS) and Network Time Servers (NTP). There may also be the requirement for email transfers wherein the JNIOR needs to reach out to a SMTP Server. To help determine the minimum setting you may be able to use your PC’s TRACERT command to detect the hop count involved in reaching those destinations. The JNIOR does not support a route tracing function.

Real World Test

Luckily we have a neat way to test the effect of reducing TTL. We have a JNIOR we call HoneyPot sitting on the open Internet. Naturally it comes under a constant level of attack. For instance there is a fairly constant level of random login attempts on the Telnet port. On the JNIOR the Telnet port provides access to the JANOS command line interface. We log failed login attempts to a @/access.log@ file.

Log files on the JNIOR rollover to BAK files when they reach 64 KB in size. We keep only one BAK file for each log. Typically an application would archive BAK files when longer term logging is desired. A syslog server can be used for the system log @/jniorsys.log@ for longer term logging.

On HoneyPot we have an application that takes the access.log when it rolls over and analyzes the hosts attempting to log into the unit. IP addresses are added to a database (JSON based) covering data from the past 24 hours. The application uses a locating service to identify the geographical location of the host. A simple web page receives the database and uses the Google Maps API to plot these locations.

By default JANOS uses a TTL of 128. The map typically appears as follows:

If we reduce the TTL to 16 the map changes. Note that this seems to thin out the number of hosts able to communication with the unit. It does not seem to create a geographical radius.

The thinning effect is useful but one gets the feeling that systems within our own country may no longer be able to communicate with the unit.

The further reduction of TTL to 12 begins to suggest a geographical radius. Note in the following how the unit now seems to be invisible in China. This might suggest that our friends in far away places might actually be using shortcuts in the network to gain access to systems in the United States.

Of course, for a controller the most important aspect of this kind of security is whether or not YOU can access your own unit. In that case you might also use the IP filtering functionality of the device and limit access to only YOU.

One note. With the TTL limited to 16 the HoneyPot unit had trouble reaching some of the NTP servers for synchronizing the clock. By limiting the radius of the network you may limit the useful services such as DNS and NTP.


So this test fails in that the service that is used to determine a location for an IP address is about 12 hops away. Here we see it is 13 from inside INTEG.

Microsoft Windows [Version 6.1.7601]
Copyright (c) 2009 Microsoft Corporation.  All rights reserved.


Tracing route to []
over a maximum of 30 hops:

  1    <1 ms    <1 ms    <1 ms
  2     1 ms     1 ms     1 ms []
  3    12 ms     9 ms     9 ms
  4    10 ms     9 ms     8 ms []
  5    32 ms    15 ms    15 ms []
  6    28 ms    21 ms    37 ms []
  7    21 ms    20 ms    20 ms []
  8    20 ms    20 ms    19 ms
  9    61 ms    61 ms    72 ms []
 10    62 ms    52 ms    51 ms []
 11    52 ms    53 ms    60 ms
 12     *        *        *     Request timed out.
 13    52 ms    51 ms    51 ms []

Trace complete.


And as a result with TTL restricted to 10 I get a lot of these errors.

04/05/18 08:29:12.949
** Uncaught java/io/IOException thrown: "Unable to connect to remote host"
   in java/io/IOException.<init>:(Ljava/lang/String;)V
   in java/net/PlainSocketImpl.connect:(Ljava/net/InetAddress;I)V
   in java/net/Socket.<init>:(Ljava/net/InetAddress;ILjava/net/InetAddress;IZ)V
   in java/net/Socket.<init>:(Ljava/lang/String;I)V
   in jaccess/JAccess.main:([Ljava/lang/String;)V at line 71

Just a note that I generally create application programs that are not destined for customer deployment with a throws Throwable clause. This insures that every exception is logged to the errors.log file and I don’t need to busy the code with try-catch structures. The application uses the com.integpg.system.Watchdog class which restarts the application after a timeout. You can see this in the system log up until I removed the TTL restriction.

In summary…

Reducing the TTL reduces the “radius” of the the accessible Internet but that does not precisely correspond to a geographic radius. Sites in Russia appear to have access to our Internet vicinity through less hops than some citizens in this country. Still it is a good defense in limiting access to the JNIOR so long as the resources your application uses can still be reached.

I had been thinking about this.

In testing by running with a low TTL we ran into problems where the JNIOR had difficulty reaching services it requires (like NTP) while locations perhaps even in Russia could still reach us. It seems to me that the standard large TTL should still be used for all outgoing communications. But a reduced TTL applied only to incoming connections. Specifically to UDP replies and TCP/IP SYN ACK responses. This would prevent distant (Internet radius wise) hosts from initiating connections or soliciting UDP replies.

The issue with UDP is that the original source TTL is unknown. So we cannot filter on it. The UDP would be received and would be processed. That packet would represent a vulnerability. All we can do is prevent any response from making it back to the malicious host.

I noticed that The JANOS runtime library for applications did not support a means of data encryption and decryption. It isn’t a problem to expose a cipher algorithm for use by applications. I have added the Security.rc4cipher() method for this purpose. I know that RC4 has been rumored to have been broken. For our purposes it remains plenty secure.

Here’s a test program. This requires JANOS v1.6.3-rc4 or later.

package jtest;
import com.integpg.system.Security;
public class Main {
    public static void main(String[] args) throws Exception {
        // source text and cipher key
        String text = "Best thing since sliced bread.";
        byte[] key = "Piece of cake".getBytes();
        // encrypt
        byte[] coded = Security.rc4cipher(text.getBytes(), text.length(), key);
        // encrypted content
        for (int n = 0; n < coded.length; n++) {
            System.out.printf(" %02x", coded[n] & 0xff);
            if (n % 16 == 15 || n == coded.length - 1)
        // decrypt
        byte[] result = Security.rc4cipher(coded, coded.length, key);
        // received message
        String msg = new String(result);

This program outputs the following when run.

bruce_dev /> jtest
 ae 87 ae 84 bc 3e c2 b6 92 0f 25 c0 30 42 03 ef
 96 39 c5 cd b3 99 6f aa 36 ba c8 58 5b fd
Best thing since sliced bread.

bruce_dev />

To be honest I have not confirmed that the encoded string is in fact RC4. But JANOS uses the underlying cipher in many places and it has proven to be accurate there.

Remember PGP? I think that stood for (or stands for) Pretty Good Privacy. This basically was an simple approach to encrypting data for transfer through the email system. It used the RSA Private/Public Key technology. Well JANOS does RSA as part of my SSL/TLSv1.2 implementation. Why shouldn’t I expose that for use by applications. You may need to securely pass information.

Hypothetically the JNIOR could be monitoring doors and conveyors collecting numbers that might be directly related to sales or something that you might consider to be proprietary and quite sensitive. Each day you would like to forward the results to an email account. While the email transfer from the JNIOR is done over a secure connection the data is not stored at the other end in any encrypted format. Nor are you sure that the data is then transferred over any remaining connections securely.

The solution is to encrypt the data at the source and later decrypt. Well you can do that now with RC4 provided that you keep the key private. The same key is used to encrypt and then at the other location to decrypt. It is a risk.

Here the RSA key pair comes to the rescue. So I have exposed it in JANOS v1.6.3. Basically you can encrypt using a public key data which can only be decrypted by the corresponding private key some time later.

So you can use OpenSSL to generate an RSA key pair. Use a 1024-bit key as anything larger will tax the JNIOR a little too much. From that you can export the RSA Public Key in PEM format. It will look like this.

-----END PUBLIC KEY-----

I will show you how you can use this PEM formatted Public Key to encrypt data for transfer. Later you can use the corresponding Private Key that you have kept secret and sequestered to access the data.

The following program uses new extensions to the com.integpg.system.Security class.

Here we are demonstrating encryption using our internal Public Key and then successful decryption using the internal Private Key.

package jtest;
import com.integpg.system.Debug;
import com.integpg.system.Security;
public class Main {
    public static void main(String[] args) throws Exception {
        String msg = "The quick brown fox jumped over the lazy dog.";
        byte[] data = Security.encrypt(msg.getBytes(), msg.length(), Security.PUBKEY);
        System.out.println("encrypted: ");
        byte[] result = Security.decrypt(data, data.length, Security.PRIVKEY);
        System.out.println("decrypted: ");
bruce_dev /> jtest
The quick brown fox jumped over the lazy dog.
 17 66 0a 66 d8 aa 67 7c-a6 41 81 69 b1 c9 d2 82    .f.f..g| .A.i....
 ab a6 9d ef fd 31 7b 67-2a 3a 23 82 05 55 3d dd    .....1{g *:#..U=.
 8a 33 36 2d 5c 61 ae 25-39 b6 40 28 5f 1f de d2    .36-\a.% 9.@(_...
 77 b4 47 9d 53 6c ee 7a-4b e2 29 8c e0 79 06 9f    w.G.Sl.z K.)..y..
 30 3c 2e 6e d0 41 cf 40-a2 2b e5 bd 03 dd d4 b4    0<.n.A.@ .+......
 a2 b4 d1 8b 33 31 f1 2e-84 e0 8d 01 b0 4d 7b 54    ....31.. .....M{T
 65 61 56 44 ee f4 45 fb-4a 39 96 c1 c9 0e 2a 2a    eaVD..E. J9....**
 3d 2b a6 71 a8 89 91 c0-cf 80 0b 3d e3 dc dc 8e    =+.q.... ...=....
 54 68 65 20 71 75 69 63-6b 20 62 72 6f 77 6e 20    The.quic k.brown.
 66 6f 78 20 6a 75 6d 70-65 64 20 6f 76 65 72 20    fox.jump ed.over.
 74 68 65 20 6c 61 7a 79-20 64 6f 67 2e             the.lazy .dog.

bruce_dev />

By the way the dump() method in the com.integpg.system.Debug is also new. I got tired of coding a dump so it will be available now.

I will show you how to use an external Public Key for encryption next.

To show you how to encrypt using a supplied Public Key I will extract the internal public key and apply it as you would one obtained from a file let’s say. The following program uses a method in the class that supplies the Public Key.

package jtest;

import com.integpg.system.Debug;
import com.integpg.system.Security;

public class Main {
    public static void main(String[] args) throws Exception {
        // Let's see the Public Key
        byte[] pubkey = Security.pubkey();
        System.out.println(new String(pubkey));
        String msg = "The quick brown fox jumped over the lazy dog.";
        byte[] data = Security.encrypt(msg.getBytes(), msg.length(), pubkey, 0);
        System.out.println("encrypted: ");
        byte[] result = Security.decrypt(data, data.length, Security.PRIVKEY);
        System.out.println("decrypted: ");
bruce_dev /> jtest
-----END PUBLIC KEY-----

The quick brown fox jumped over the lazy dog.
 a8 35 44 4a 15 4e 1f fe-b4 30 c3 e6 51 38 90 be    .5DJ.N.. .0..Q8..
 e4 4f 7c 5d fb e6 38 16-63 f1 93 ba a5 3f 24 00    .O|]..8. c....?$.
 eb 46 5d 27 25 f1 5a b1-bf 0e 46 f9 5b 1b e9 13    .F]'%.Z. ..F.[...
 ac 6c 77 db bd 1e 22 be-b5 32 6b 5c cc 0b 46 d7    .lw...". .2k\..F.
 3f 1b 30 4c 61 03 eb 2f-dd 84 54 d5 35 86 32 56    ?.0La../ ..T.5.2V
 16 56 7c 41 a3 ef 2f 70-2d 67 3f a5 97 fb 60 c2    .V|A../p -g?...`.
 df 61 5f 5a 76 90 56 db-21 66 6f f3 00 af aa a8    .a_Zv.V. !fo.....
 71 a2 a1 2e 31 7d 82 ab-34 e2 cc 3b 52 64 32 09    q...1}.. 4..;Rd2.
 54 68 65 20 71 75 69 63-6b 20 62 72 6f 77 6e 20    The.quic k.brown.
 66 6f 78 20 6a 75 6d 70-65 64 20 6f 76 65 72 20    fox.jump ed.over.
 74 68 65 20 6c 61 7a 79-20 64 6f 67 2e             the.lazy .dog.

bruce_dev />

You can export the JNIOR’s Public Key now using the CERTMGR command.

bruce_dev /> help certmgr

 -V             Verify installed keys and certificate
 -C [file]      Regenerate Certificate [Install file]
 -S file        Verify signature on certificate
 -K file        Install RSA Key Pair
 -D [file]      Decode and dump certificate [file]
 -E file        Export certificate to file
 -P file        Export public key to file
 -B             Export in binary
 -G [len]       Generate key pair [bit length]
 -R             Restore default credentials

SSL Certificate Management.

bruce_dev />

Here I will export the public key to a file. I’ll show you what is in the file and I’ll use CERTMGR to dump the encoded ASN.1 format for the key.

bruce_dev /> certmgr -p

bruce_dev /> cat
-----END PUBLIC KEY-----

bruce_dev /> certmgr -d

0000  30 81 9F       SEQUENCE {  (159 bytes)
0003  30 0D          |  SEQUENCE {  (13 bytes)
0005  06 09          |  |  OBJECT IDENTIFIER 1.2.840.113549.1.1.1
0010  05 00          |  |  NULL 
                     |  }
0012  03 81 8D       |  BITSTRING[140] Encapsulates {
0000  30 81 89       |  |  SEQUENCE {  (137 bytes)
0003  02 81 81       |  |  |  INTEGER 
                     |  |  |     C4C041EC464939F76304172657BEF7EC0E4685BB5EBDB97C
                     |  |  |     0ABA0A3627B24C87C7E4AEE88A7BB076B5BB80D78DC94987
                     |  |  |     88D28E26A6A5B0774E826E30C6DA05443206DFE522BBAAE3
                     |  |  |     1D7E5279996EEDDD93D065D31DAF2B6D3EADC2E29CD37EE1
                     |  |  |     FAFCC18CCDA35DA1B5D2390EFE4A41FB82845DB14631E9F9
                     |  |  |     4B5E7D4A9D08CF09
0087  02 03          |  |  |  INTEGER 010001
                     |  |  }
                     |  }

bruce_dev />

You might see now that you can take and send it to another JNIOR that can load it as the pubkey for encryption as demonstrated.


And, the encryption and decryption does not support use of a private key PEM format.

Why limit key size to 1024-bits on the JNIOR?

A 1024-bit Private Key operation (encrypting a single block of 128 bytes) on the JNIOR take about 3.4 seconds. The same operation using a 2048-bit key takes almost 26 seconds. That will cause browsers to timeout when trying to use HTTPS among other things.

A 2048-bit key can be installed on the JNIOR. You need a 2048-bit key pair which you can generated with OpenSSL.

OpenSSL> genpkey -out private.pem -des3 -algorithm rsa rsa_keygen_bits:2048
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
OpenSSL> genpkey -out private.pem -des3 -algorithm rsa -pkeyopt rsa_keygen_bits:
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

Move the resulting private.pem file onto the JNIOR and run the CERTMGR -K command to load it.

bruce_dev /> certmgr -k private.pem
Passphrase: *****
keys installed

bruce_dev />

Now let’s validate that it works.

bruce_dev /> certmgr -v            
2048-bit key pair verifies
private key operation requires about 25.7 seconds
certificate verifies 
certificate not valid with current keys

bruce_dev />

Oh, and we can update the certificate. That would likely happen automatically at some point but we can force it.

bruce_dev /> certmgr -c
certificate updated

bruce_dev /> certmgr -v
2048-bit key pair verifies
private key operation requires about 25.7 seconds
certificate verifies 

bruce_dev />

Let’s run the program mentioned earlier to see if it succeeds.

bruce_dev /> jtest
-----END PUBLIC KEY-----

The quick brown fox jumped over the lazy dog.
 41 2b 02 92 30 d5 50 7c-92 b6 95 eb 8c 8d f4 76    A+..0.P| .......v
 f1 22 0a c5 63 48 f7 1b-af 85 47 4e 1d b2 0d bc    ."..cH.. ..GN....
 5b 6a f9 6d c7 1a c5 90-69 f9 28 4c 93 e1 8c 2e    [j.m.... i.(L....
 3f 5b 95 26 9d c4 ae 15-15 84 74 1e c4 a5 21 29    ?[.&.... ..t...!)
 e2 e0 c8 f7 f0 3e 99 aa-ed a9 36 ab 18 4f f8 ca    .....>.. ..6..O..
 cc 23 b3 57 d2 5c d6 6f-fa 83 2b 44 82 a5 ab ef    .#.W.\.o ..+D....
 c7 44 98 14 6d 8e 58 a2-05 b9 e0 9c 87 fc 52 22    .D..m.X. ......R"
 ee 46 38 2e 32 4e 4d c1-92 cd fc 3d 80 1c 81 19    .F8.2NM. ...=....
 1b 95 56 93 ff 4a 06 e0-9e c2 30 0c 83 ee 01 08    ..V..J.. ..0.....
 8f 98 d7 f3 50 b5 2b 80-0c 9b 23 8b 45 df 56 85    ....P.+. ..#.E.V.
 60 06 30 e3 35 a1 3c 82-19 57 b6 7e cf a2 02 e4    `.0.5.<. .W.~....
 55 3f b4 3c a8 39 77 79-0f f0 d6 aa da 1d b4 73    U?.<.9wy .......s
 7e ef 13 54 a8 d7 b0 a1-d2 67 0a 66 08 b9 81 13    ~..T.... .g.f....
 11 17 c2 d4 be 98 b5 fe-50 34 49 ab da cf 75 d7    ........ P4I...u.
 c1 b5 18 4e 32 27 2f e4-81 35 51 4a 62 42 6e a1    ...N2'/. .5QJbBn.
 47 67 e5 e4 c4 2c 70 c2-9b ea d8 09 5a 52 fd cb    Gg...,p. ....ZR..
 54 68 65 20 71 75 69 63-6b 20 62 72 6f 77 6e 20    The.quic k.brown.
 66 6f 78 20 6a 75 6d 70-65 64 20 6f 76 65 72 20    fox.jump ed.over.
 74 68 65 20 6c 61 7a 79-20 64 6f 67 2e             the.lazy .dog.

bruce_dev />

If you are *REAL* patient the 2048-bit key works with SSL/TLS.

This took a couple of minutes to come up and the browser did once tell me that the site was taking too long to respond. This was with Chrome.

The bottom line is that a 1024-bit key is really secure enough for controller device like the JNIOR.


As we are concerned about export restrictions the exposed cryptography functions demonstrated in this topic will remain unavailable for the time being. This may change should we decide to create a version of the product for shipment and use in the USA only.

Please feel free to offer your perspectives on this issue.

In the Programming Tips I show you how to make an outgoing secure connection using SSS/TLSv1.2. A secure connection encrypts data with a 128-bit key that is itself securely negotiated. So the information that you exchange cannot be read from the wire as it passes. But Windows still says “Not Secure” sometimes. Why is that?

By “Not Secure” Windows is really telling you that the connection is Not Trusted. The data is still encrypted but Windows doesn’t recognize the connected client. If you have connected to a JNIOR using the HTTPS URL before you might heave seen a Privacy Error page that you must bypass in order to access the unit. This occurs as the browser receives a certificate from the JNIOR which is not traceable through a Root Certificate Authority in its database. The JNIOR certificates are self-signed and not issued by such an authority. Ergo the privacy concern.

When your application makes an outgoing connection the destination sends a copy of its certificate. Can you verify that certificate as the browser does? Well, with limitations you can. I have added a method in the Socket class allowing you to retrieve that certificate.

Once you indicate that the connection should be secure there is a brief period in which the negotiations transpire. The following code waits for a certificate. The getCertificate() method returns an empty byte array until a certificate has been received.

CODE: Select All

bruce_dev /> jtest
 30 82 02 ed 30 82 02 56-a0 03 02 01 02 02 04 24    0...0..V .......$
 99 a9 00 30 0d 06 09 2a-86 48 86 f7 0d 01 01 0b    ...0...* .H......
 05 00 30 81 81 31 20 30-1e 06 03 55 04 0a 0c 17    ..0..1.0 ...U....
 49 4e 54 45 47 20 50 72-6f 63 65 73 73 20 47 72    INTEG.Pr ocess.Gr
 6f 75 70 20 49 6e 63 31-17 30 15 06 03 55 04 0b    oup.Inc1 .0...U..
 0c 0e 4a 4e 49 4f 52 20-43 6f 6e 74 72 6f 6c 73    ..JNIOR. Controls
 31 1d 30 1b 06 03 55 04-03 0c 14 68 6f 6e 65 79    1.0...U. ...honey
 70 6f 74 2e 69 6e 74 65-67 70 67 2e 63 6f 6d 31    pot.inte gpg.com1
 25 30 23 06 09 2a 86 48-86 f7 0d 01 09 01 16 16    %0#..*.H ........
 62 63 6c 6f 75 74 69 65-72 32 40 63 6f 6d 63 61    bcloutie r2@comca
 73 74 2e 6e 65 74 30 1e-17 0d 31 37 30 33 32 32    st.net0. ..170322
 31 37 33 30 32 33 5a 17-0d 31 39 30 33 32 32 31    173023Z. .1903221
 37 33 30 32 33 5a 30 81-81 31 20 30 1e 06 03 55    73023Z0. .1.0...U
 04 0a 0c 17 49 4e 54 45-47 20 50 72 6f 63 65 73    ....INTE G.Proces
 73 20 47 72 6f 75 70 20-49 6e 63 31 17 30 15 06    s.Group. Inc1.0..
 03 55 04 0b 0c 0e 4a 4e-49 4f 52 20 43 6f 6e 74    .U....JN IOR.Cont
 72 6f 6c 73 31 1d 30 1b-06 03 55 04 03 0c 14 68    rols1.0. ..U....h
 6f 6e 65 79 70 6f 74 2e-69 6e 74 65 67 70 67 2e    oneypot. integpg.
 63 6f 6d 31 25 30 23 06-09 2a 86 48 86 f7 0d 01    com1%0#. .*.H....
 09 01 16 16 62 63 6c 6f-75 74 69 65 72 32 40 63    ....bclo utier2@c
 6f 6d 63 61 73 74 2e 6e-65 74 30 81 9f 30 0d 06    omcast.n et0..0..
 09 2a 86 48 86 f7 0d 01-01 01 05 00 03 81 8d 00    .*.H.... ........
 30 81 89 02 81 81 00 a9-94 83 17 4b 2e bc 85 78    0....... ...K...x
 ec ea 5b e9 f7 58 40 70-3b 06 ea 49 d9 33 3d 49    ..[..X@p ;..I.3=I
 3d 03 5a 8d 84 db 5a b7-e5 49 1d 33 4b af 1b 59    =.Z...Z. .I.3K..Y
 a3 a2 71 e2 5c 42 76 d4-10 f3 b3 c9 0e 80 1e 89    ..q.\Bv. ........
 a1 62 c6 a2 82 ec 51 ab-05 cf 97 31 56 1a 95 22    .b....Q. ...1V.."
 a0 b3 03 9d f7 2f a2 5b-a1 06 1e 6b bb 7a 1a a6    ...../.[ ...k.z..
 b2 87 a3 14 fd db b9 e1-03 4b 45 d5 e1 ff c1 5a    ........ .KE....Z
 59 c4 0d 77 2d 3c da d6-14 2a 70 76 50 f1 1e bc    Y..w-<.. .*pvP...
 d3 0c ff 75 e6 5e 91 02-03 01 00 01 a3 70 30 6e    ...u.^.. .....p0n
 30 1d 06 03 55 1d 0e 04-16 04 14 29 cb 03 57 bc    0...U... ...)..W.
 dd 26 e7 8a d5 e5 64 c1-d0 87 b0 3b 58 30 82 30    .&....d. ...;X0.0
 0c 06 03 55 1d 13 04 05-30 03 01 01 ff 30 3f 06    ...U.... 0....0?.
 03 55 1d 11 04 38 30 36-87 04 32 c5 22 4b 82 14    .U...806 ..2."K..
 68 6f 6e 65 79 70 6f 74-2e 69 6e 74 65 67 70 67    honeypot .integpg
 2e 63 6f 6d 82 08 68 6f-6e 65 79 70 6f 74 82 0e    .com..ho neypot..
 68 6f 6e 65 79 70 6f 74-5f 6a 6e 69 6f 72 30 0d    honeypot _jnior0.
 06 09 2a 86 48 86 f7 0d-01 01 0b 05 00 03 81 81    ..*.H... ........
 00 2b 42 e0 5e 33 1a ee-b2 65 f4 da c1 18 df 73    .+B.^3.. .e.....s
 e7 f5 55 d7 26 05 f6 ec-ab 67 d8 60 32 4a 7c 50    ..U.&... .g.`2J|P
 56 14 c5 20 33 37 a9 8c-21 57 d8 5c 57 a7 36 b8    V...37.. !W.\W.6.
 2d da 88 47 5e 93 a6 c9-fc 2c 59 83 67 8c 8d 46    -..G^... .,Y.g..F
 1a 9c e7 f5 3a 27 66 db-bd 26 c0 b9 9c e1 f4 51    ....:'f. .&.....Q
 4f 6b ac 3d 09 c3 30 00-bc 7e 5f 61 51 c0 ba 17    Ok.=..0. .~_aQ...
 5f 29 b6 e7 3b 8e 7f eb-ae 10 99 26 9a 9a fd 70    _)..;... ...&...p
 67 17 c6 7c f9 c7 f1 7e-bb 3f 8d b2 ed 43 53 c2    g..|...~ .?...CS.
 d1                                                 .

bruce_dev /> 

So you can see here that we receive something that looks to have the company name in it. This is the certificate and unfortunately it is in a binary ASN.1 format. That at this point is not very useful. You would have a lot of work to do if you were to parse information out of that.

So let’s see if I can help in that department.

Since in this example we attempt to connect to the HoneyPot I can separately pull its certificate in PEM format. In that form it looks like this.

bruce_dev /> cat flash/honeypot.cer

bruce_dev />

There is a nice option in the CERTMGR command to dump that in some meaningful form.

CODE: Select All

bruce_dev /> certmgr -d flash/honeypot.cer

0000  30 82 02 ED    SEQUENCE {  (749 bytes)
0004  30 82 02 56    |  SEQUENCE {  (598 bytes)
0008  A0 03          |  |  [0] EXPLICIT {  (3 bytes)
000A  02 01          |  |  |  INTEGER 02
                     |  |  }
000D  02 04          |  |  INTEGER 2499A900
0013  30 0D          |  |  SEQUENCE {  (13 bytes)
0015  06 09          |  |  |  OBJECT IDENTIFIER 1.2.840.113549.1.1.11
0020  05 00          |  |  |  NULL 
                     |  |  }
0022  30 81 81       |  |  SEQUENCE {  (129 bytes)
0025  31 20          |  |  |  SET {  (32 bytes)
0027  30 1E          |  |  |  |  SEQUENCE {  (30 bytes)
0029  06 03          |  |  |  |  |  OBJECT IDENTIFIER
002E  0C 17          |  |  |  |  |  UTF8STRING 'INTEG Process Group Inc'
                     |  |  |  |  }
                     |  |  |  }
0047  31 17          |  |  |  SET {  (23 bytes)
0049  30 15          |  |  |  |  SEQUENCE {  (21 bytes)
004B  06 03          |  |  |  |  |  OBJECT IDENTIFIER
0050  0C 0E          |  |  |  |  |  UTF8STRING 'JNIOR Controls'
                     |  |  |  |  }
                     |  |  |  }
0060  31 1D          |  |  |  SET {  (29 bytes)
0062  30 1B          |  |  |  |  SEQUENCE {  (27 bytes)
0064  06 03          |  |  |  |  |  OBJECT IDENTIFIER
0069  0C 14          |  |  |  |  |  UTF8STRING ''
                     |  |  |  |  }
                     |  |  |  }
007F  31 25          |  |  |  SET {  (37 bytes)
0081  30 23          |  |  |  |  SEQUENCE {  (35 bytes)
0083  06 09          |  |  |  |  |  OBJECT IDENTIFIER 1.2.840.113549.1.9.1
008E  16 16          |  |  |  |  |  IA5STRING ''
                     |  |  |  |  }
                     |  |  |  }
                     |  |  }
00A6  30 1E          |  |  SEQUENCE {  (30 bytes)
00A8  17 0D          |  |  |  UTCTIME[13] 170322173023Z
00B7  17 0D          |  |  |  UTCTIME[13] 190322173023Z
                     |  |  }
00C6  30 81 81       |  |  SEQUENCE {  (129 bytes)
00C9  31 20          |  |  |  SET {  (32 bytes)
00CB  30 1E          |  |  |  |  SEQUENCE {  (30 bytes)
00CD  06 03          |  |  |  |  |  OBJECT IDENTIFIER
00D2  0C 17          |  |  |  |  |  UTF8STRING 'INTEG Process Group Inc'
                     |  |  |  |  }
                     |  |  |  }
00EB  31 17          |  |  |  SET {  (23 bytes)
00ED  30 15          |  |  |  |  SEQUENCE {  (21 bytes)
00EF  06 03          |  |  |  |  |  OBJECT IDENTIFIER
00F4  0C 0E          |  |  |  |  |  UTF8STRING 'JNIOR Controls'
                     |  |  |  |  }
                     |  |  |  }
0104  31 1D          |  |  |  SET {  (29 bytes)
0106  30 1B          |  |  |  |  SEQUENCE {  (27 bytes)
0108  06 03          |  |  |  |  |  OBJECT IDENTIFIER
010D  0C 14          |  |  |  |  |  UTF8STRING ''
                     |  |  |  |  }
                     |  |  |  }
0123  31 25          |  |  |  SET {  (37 bytes)
0125  30 23          |  |  |  |  SEQUENCE {  (35 bytes)
0127  06 09          |  |  |  |  |  OBJECT IDENTIFIER 1.2.840.113549.1.9.1
0132  16 16          |  |  |  |  |  IA5STRING ''
                     |  |  |  |  }
                     |  |  |  }
                     |  |  }
014A  30 81 9F       |  |  SEQUENCE {  (159 bytes)
014D  30 0D          |  |  |  SEQUENCE {  (13 bytes)
014F  06 09          |  |  |  |  OBJECT IDENTIFIER 1.2.840.113549.1.1.1
015A  05 00          |  |  |  |  NULL 
                     |  |  |  }
015C  03 81 8D       |  |  |  BITSTRING[140] Encapsulates {
0000  30 81 89       |  |  |  |  SEQUENCE {  (137 bytes)
0003  02 81 81       |  |  |  |  |  INTEGER 
                     |  |  |  |  |     A99483174B2EBC8578ECEA5BE9F75840703B06EA49D9333D
                     |  |  |  |  |     493D035A8D84DB5AB7E5491D334BAF1B59A3A271E25C4276
                     |  |  |  |  |     D410F3B3C90E801E89A162C6A282EC51AB05CF9731561A95
                     |  |  |  |  |     22A0B3039DF72FA25BA1061E6BBB7A1AA6B287A314FDDBB9
                     |  |  |  |  |     E1034B45D5E1FFC15A59C40D772D3CDAD6142A707650F11E
                     |  |  |  |  |     BCD30CFF75E65E91
0087  02 03          |  |  |  |  |  INTEGER 010001
                     |  |  |  |  }
                     |  |  |  }
                     |  |  }
01EC  A3 70          |  |  [3] EXPLICIT {  (112 bytes)
01EE  30 6E          |  |  |  SEQUENCE {  (110 bytes)
01F0  30 1D          |  |  |  |  SEQUENCE {  (29 bytes)
01F2  06 03          |  |  |  |  |  OBJECT IDENTIFIER
01F7  04 16          |  |  |  |  |  OCTETSTRING[22] Encapsulates {
0000  04 14          |  |  |  |  |  |  OCTETSTRING[20] 
                     |  |  |  |  |  |     29CB0357BCDD26E78AD5E564C1D087B0  )..W..&....d....
                     |  |  |  |  |  |     3B583082                          ;X0.
                     |  |  |  |  |  }
                     |  |  |  |  }
020F  30 0C          |  |  |  |  SEQUENCE {  (12 bytes)
0211  06 03          |  |  |  |  |  OBJECT IDENTIFIER
0216  04 05          |  |  |  |  |  OCTETSTRING[5] Encapsulates {
0000  30 03          |  |  |  |  |  |  SEQUENCE {  (3 bytes)
0002  01 01          |  |  |  |  |  |  |  BOOLEAN TRUE(255)
                     |  |  |  |  |  |  }
                     |  |  |  |  |  }
                     |  |  |  |  }
021D  30 3F          |  |  |  |  SEQUENCE {  (63 bytes)
021F  06 03          |  |  |  |  |  OBJECT IDENTIFIER
0224  04 38          |  |  |  |  |  OCTETSTRING[56] Encapsulates {
0000  30 36          |  |  |  |  |  |  SEQUENCE {  (54 bytes)
0002  87 04          |  |  |  |  |  |  |  [7] 32C5224B  2."K
0008  82 14          |  |  |  |  |  |  |  [2] 
                     |  |  |  |  |  |  |     686F6E6579706F742E696E7465677067  honeypot.integpg
                     |  |  |  |  |  |  |     2E636F6D                          .com
001E  82 08          |  |  |  |  |  |  |  [2] 686F6E6579706F74  honeypot
0028  82 0E          |  |  |  |  |  |  |  [2] 686F6E6579706F745F6A6E696F72  honeypot_jnior
                     |  |  |  |  |  |  }
                     |  |  |  |  |  }
                     |  |  |  |  }
                     |  |  |  }
                     |  |  }
                     |  }
025E  30 0D          |  SEQUENCE {  (13 bytes)
0260  06 09          |  |  OBJECT IDENTIFIER 1.2.840.113549.1.1.11
026B  05 00          |  |  NULL 
                     |  }
026D  03 81 81       |  BITSTRING[128]  0 unused bits
                     |     2B42E05E331AEEB265F4DAC118DF73E7  +B.^3...e.....s.
                     |     F555D72605F6ECAB67D860324A7C5056  .U.&....g.`2J|PV
                     |     14C5203337A98C2157D85C57A736B82D  .. 37..!W.\W.6.-
                     |     DA88475E93A6C9FC2C5983678C8D461A  ..G^....,Y.g..F.
                     |     9CE7F53A2766DBBD26C0B99CE1F4514F  ...:'f..&.....QO
                     |     6BAC3D09C33000BC7E5F6151C0BA175F  k.=..0..~_aQ..._
                     |     29B6E73B8E7FEBAE1099269A9AFD7067  )..;......&
                     |     17C67CF9C7F17EBB3F8DB2ED4353C2D1  ..|...~.?...CS..

bruce_dev />

Uh, This is still likely quite cryptic for your use. ASN.1 is fun. You might notice the hexadecimal in this dump follows that dumped by our application in the prior post. This demonstrates the inherent structure in the ASN.1 Certificate Format.

So if I am going to be of any help there is more work to be done.

After thinking about some kind of conversion from ASN.1 to JSON I have decided to stick with ASN.1 for this purpose. I’ll develop an ASN1 class that will help with parsing. The reason to hang with ASN.1 is that you will be able to confirm signatures.

That reminds me too that, I should write something about Signing. Since you now have access to RSA cryptography…

Alright. A couple of posts back we extracted the certificate from our secure connection. I dumped it in binary and also using CERTMGR to see the ASN.1 structure.

First of all the certificate is delivered in DER format. This defines the binary encoding used to transfer the signed certificate and that we see in the dump. A standard ASN.1 definition for a signed certificate is compiled into DER. The format defined for these certificates is x509 which is defined in RFC 5280. You may also need information contained in RFC 5246 which is the latest for TLSv1.2.

Okay so that is a lot of work and if you have to read all of that then forget it, right? Let me try to gloss over it and drive to doing something meaningful with this binary certificate stuff.

I have started to pull together an Asn1 class which will help us work with the DER encoded binary data. It was apparent from the CERTMGR dump that there is some structure to it. I’ll try to vaguely describe that from the top down.

First notice that the whole signed certificate as obtained from the connection is enclosed in a SEQUENCE. That is an ASN.1 object which in DER has a tag (ASN_SEQUENCE), a length, and data or content. From the RFCs we expect the following structure.

Certificate  ::=  SEQUENCE  {
    tbsCertificate       TBSCertificate,
    signatureAlgorithm   AlgorithmIdentifier,
    signatureValue       BIT STRING  }

So the top SEQUENCE contains three objects. Here “TBS” stands for To Be Signed. So the tbsCertificate is the Certificate to be signed or that has been signed. It is information that by itself is a SEQUENCE of objects. The signatureAlgorithm defines the procedure used in the signing. That is a SEQUENCE too with some objects within. And, the signatureValue turns out to be some tacked on bit data in a BITSTRING. That we will see is the actual signature.

So let’s modify our little program that gets the target host’s certificate to use my prototype Asn1 class. We will first confirm that the initial SEQUENCE covers all of the signed certificate and then itemize its content.

package jtest;
import com.integpg.system.Debug;
public class Main {
    public static void main(String[] args) throws Exception {
        // Establish a Secure Socket, get streams, and set a timeout
        Socket dataSocket = new Socket("", 443);
        // Obtain the certificate
        byte[] cert;
        while ((cert = dataSocket.getCertificate()).length == 0)
        // analyze
        Asn1 asn = new Asn1(cert);
        // details about the object
        System.out.println("Overall Signed Certificate Length: " + cert.length);
        System.out.println("ASN.1 Object tag: " + asn.getTag());
        System.out.printf("ASN.1 Object flags: 0x%02x\n", asn.getFlags());
        System.out.println("ASN.1 Object content size: " + asn.getLength());
        // skip the object and check for more data (should be only 1 object)
        if (!asn.hasMoreData())
            System.out.println("Signed Certificate is a sigle object as expected");
            System.out.println("Something is wrong!");
bruce_dev /> jtest
Overall Signed Certificate Length: 753
ASN.1 Object tag: 16
ASN.1 Object flags: 0x20
ASN.1 Object content size: 749
Signed Certificate is a sigle object as expected

bruce_dev />

This demonstrates that the SEQUENCE object contains the entire signed certificate. 753 bytes were delivered and aside from the 4-byte header (tag and length) the content covers the rest of the data. The tag of 16 tells us it is a SEQUENCE and the flag 0x20 tells us it is a CONSTRUCT.

Here are tags and flags that I have defined in the Asn1 class.

CODE: Select All

    static public final int ASN_BOOLEAN = 1;
    static public final int ASN_INTEGER = 2;
    static public final int ASN_BITSTRING = 3;
    static public final int ASN_OCTETSTRING = 4;
    static public final int ASN_NULL = 5;
    static public final int ASN_OBJECTID = 6;
    static public final int ASN_OBJECTDESC = 7;
    static public final int ASN_INSTANCEOF = 8;
    static public final int ASN_REAL = 9;
    static public final int ASN_ENUM = 10;
    static public final int ASN_EMBEDDED = 11;
    static public final int ASN_UTF8STRING = 12;
    static public final int ASN_RELATIVEOID = 13;
    static public final int ASN_SEQUENCE = 16;
    static public final int ASN_SET = 17;
    static public final int ASN_NUMERIC = 18;
    static public final int ASN_PRINTABLE = 19;
    static public final int ASN_T61 = 20;
    static public final int ASN_VIDEOTEX = 21;
    static public final int ASN_IA5STRING = 22;
    static public final int ASN_UTCTIME = 23;
    static public final int ASN_GENTIME = 24;
    static public final int ASN_GRAPHIC = 25;
    static public final int ASN_VISIBLESTR = 26;
    static public final int ASN_GENSTRING = 27;
    static public final int ASN_UNIVSTRING = 28;
    static public final int ASN_CHARSTR = 29;
    static public final int ASN_BMPSTR = 30;
    static public final int ASN_HIGHFORM = 31;

    static public final int ASN_CONSTRUCT = 0x20;
    static public final int ASN_APPLICATION = 0x40;
    static public final int ASN_CONTEXT = 0x80;
    static public final int ASN_PRIVATE = 0xC0;

So let’s look into the overall SEQUENCE and see that those three objects are to be found. We’ll just list the tags for the objects we find. Her are the changes to our test program.

        // analyze
        Asn1 asn = new Asn1(cert);
        // descend into the SEQUENCE object and itemize the objects it contains.
        while (asn.hasMoreData()) {
            System.out.println("ASN.1 Object tag: " + asn.getTag());
            System.out.println("ASN.1 Object length: " + asn.getLength());
bruce_dev /> jtest
ASN.1 Object tag: 16
ASN.1 Object length: 598

ASN.1 Object tag: 16
ASN.1 Object length: 13

ASN.1 Object tag: 3
ASN.1 Object length: 129

bruce_dev />

So there are three parts. Two SEQUENCEs and a BITSTRING. Those correspond to tbsCertificate, signatureAlgorithm and signatureVauerespectively which is what is expected.

Certificate  ::=  SEQUENCE  {
    tbsCertificate       TBSCertificate,
    signatureAlgorithm   AlgorithmIdentifier,
    signatureValue       BIT STRING  }

Let’s extract the key parts of this signed certificate and dump the signatureValue.

        // analyze
        Asn1 asn = new Asn1(cert);
        // obtain the certificate
        Asn1 tbsCertificate = new Asn1(asn.getData());
        Asn1 signatureAlgorithm = new Asn1(asn.getData());
        byte[] bitstring = asn.getData();
        // remove leading unused bit count supplied with BITSTRING
        byte[] signatureValue = new byte[bitstring.length - 1];
        ArrayUtils.arraycopy(bitstring, 1, signatureValue, 0, signatureValue.length);
        // dump the signature
bruce_dev /> jtest
 2b 42 e0 5e 33 1a ee b2-65 f4 da c1 18 df 73 e7    +B.^3... e.....s.
 f5 55 d7 26 05 f6 ec ab-67 d8 60 32 4a 7c 50 56    .U.&.... g.`2J|PV
 14 c5 20 33 37 a9 8c 21-57 d8 5c 57 a7 36 b8 2d    ...37..! W.\W.6.-
 da 88 47 5e 93 a6 c9 fc-2c 59 83 67 8c 8d 46 1a    ..G^.... ,Y.g..F.
 9c e7 f5 3a 27 66 db bd-26 c0 b9 9c e1 f4 51 4f    ...:'f.. &.....QO
 6b ac 3d 09 c3 30 00 bc-7e 5f 61 51 c0 ba 17 5f    k.=..0.. ~_aQ..._
 29 b6 e7 3b 8e 7f eb ae-10 99 26 9a 9a fd 70 67    )..;.... ..&
 17 c6 7c f9 c7 f1 7e bb-3f 8d b2 ed 43 53 c2 d1    ..|...~. ?...CS..

bruce_dev />

We see from the CERTMGR dump a few posts back that this is correct.

How can we check the signature?

To start since I know this is from our HoneyPot unit I will grab the public key directly from the JNIOR. I’ll save this in a pubkey.pem file. Since this is a self-signed certificate this public key is already in the tbsCertificate but to avoid the complexity of digging in to get it we’ll start with a handy copy of the key. We can also tell that this certificate’s signature was done with RSA encryption and the SHA256 or SHA2 hash. There are other signature algorithms. This is the one that the JNIOR used. So to keep it simple we’ll just work with that right now.

The Certificate Signing procedure is “simple”. When the certificate was signed the JNIOR

  1. computed the SHA256 hash over the ASN.1 DER encoded tbsCertificate object
  2. built a simple ASN.1 structure defining the algorithm with an OID and storing the hash as an OCTET STRING
  3. encrypted the DER encoded hash value using the JNIOR’s RSA Private Key
  4. appended the signingAlgorithm information and the signatureValue to the tbsCertificate creating the signed certificate.

So to verify the Signed Certificate we can reverse the process. So we will do the following:

  1. extract the tbsCertificate ASN.1 DER encoding from the signed certificate
  2. calculate the SHA256 over the tbsCertificate block
  3. obtain the BIT STRING appended to the signed certificate
  4. decrypt the BIT String using the JNIOR’s RSA Public Key
  5. look into the resulting ASN.1 structure for the stored copy of the hash
  6. if our calculated hash matches that stored then the certificate verifies
        // analyze
        Asn1 asn = new Asn1(cert);
        // obtain the certificate
        byte[] tbsCertificate = asn.getObject();
        byte[] signatureAlgorithm = asn.getData();
        byte[] bitstring = asn.getData();
        // remove leading unused bit count supplied with BITSTRING
        byte[] signatureValue = new byte[bitstring.length - 1];
        ArrayUtils.arraycopy(bitstring, 1, signatureValue, 0, signatureValue.length);

Here we parse the signed certificate to extract both the tbsCertificate and the signatureValue. Note that I used getObject() from the Asn1class to not only get the certificate content but also the header for the ASN.1 SEQUENCE. The hash includes all of it.

Next we calculate the SHA256 for the tbsCertificate block. The SHA256 methods are exposed in JANOS v1.6.3 and later.

        // calculate SHA-256 on tbsCertificate and signatureAlgorithm
        byte[] hash = Security.hashMessage256(tbsCertificate);
bruce_dev /> jtest
 db 67 e8 3b 8a 7e c1 ab-ef 76 16 0b 2b 45 e1 26    .g.;.~.. .v..+E.&
 c6 fa eb 31 4a 1c d0 5f-23 b0 a7 0f 7a 03 5b e6    ...1J.._ #...z.[.

Finally we read the HoneyPot’s public key from the file and perform the RSA decryption. This dumps the decrypted BIT STRING content.

        // fetch the HoneyPot public key
        File keyfile = new File("/flash/pubkey.pem");
        DataInputStream fin = new DataInputStream(new FileInputStream(keyfile));
        byte[] pubkey = new byte[fin.available()];
        byte[] sig = Security.decrypt(signatureValue, 0, pubkey, 0);
bruce_dev /> jtest
 db 67 e8 3b 8a 7e c1 ab-ef 76 16 0b 2b 45 e1 26    .g.;.~.. .v..+E.&
 c6 fa eb 31 4a 1c d0 5f-23 b0 a7 0f 7a 03 5b e6    ...1J.._ #...z.[.

 30 31 30 0d 06 09 60 86-48 01 65 03 04 02 01 05    010...`. H.e.....
 00 04 20 db 67 e8 3b 8a-7e c1 ab ef 76 16 0b 2b    ....g.;. ~...v..+
 45 e1 26 c6 fa eb 31 4a-1c d0 5f 23 b0 a7 0f 7a    E.&...1J .._#...z
 03 5b e6                                           .[.

bruce_dev />

If the public key properly decrypts the signingValue you will see a valid ASN.1 DER encoded structure. Manually we see that it starts with a SEQUENCE and the length is 49 bytes. In that SEQUENCE there is another of just 13 bytes. That contains the OID. After that there is a 32 byte OCTET STRING containing the hash.

So just by eye we see that the last 32 bytes of the decrypted signingValue do match the calculated SHA256 hash. We have verified the signature!

One of the parts of the tbsCertificate defines the Issuer and the other the Subject of the certificate. Since the JNIOR creates a self-signed certificate the Issuer and Subject are the same.

If you look back to the CERTMGR dump of the certificate you see that INTEG Process Group Inc appears twice. The first is for the Issuer and the second the Subject. There is a SEQUENCE following that which contains a BIT STRING that encapsulates two INTEGERs. That is the Subject’s RSA Public Key. That would match the HoneyPot’s Public Key. We could have gone into the certificate for that key. But that works ONLY for a self-signed certificate like this.

More generally the Issuer signs the Certificate using the Issuer’s RSA Private (and highly secret) Key and the Issuer is not the same as the Subject. In that case the Issuer’s RSA Public Key is NOT in the certificate. We would need to find an independent source for the key. Windows, for instance, looks to the Trusted Root Certificate Authorities store for another certificate, one for the Issuer where the public key can be found.

It can even be more complex as there might be a chain of trust. If the certificate is signed by an Issuer that is likely not to be found in the system’s certificate store then an additional one or more certificates might be transmitted during TLS negotiation. We would have to follow the chain verifying each certificate until we reached a trusted certificate from the system’s store or otherwise.

The JNIOR does not contain a specific trusted certificate store for this purpose. If we were to be verifying certificates in this way we would need to create something or otherwise rely on a remote system.

We showed you how to make an Outgoing HTTP Request. If you would like to make a secure connection you need only add a single line of code.


Here I will securely connect from my development JNIOR to the external HoneyPot JNIOR. From the example in the other topic I have modified the host and the request to attempt to access the JNIOR.

package jtest;
import com.integpg.system.Debug;
public class Main {
    public static void main(String[] args) throws Exception {
        // Location services
        String serverHostname = "";
        int port = 443;
        // Establish a Socket, get streams, and set a timeout
        Socket dataSocket = new Socket(serverHostname, port);
        DataOutputStream sockout = new DataOutputStream(dataSocket.getOutputStream());
        DataInputStream sockin = new DataInputStream(dataSocket.getInputStream());
        // Negotiate a secure connection
        // Issue the HTTP request
        sockout.writeBytes("GET / HTTP/1.1\r\n");
        sockout.writeBytes("Host: " + serverHostname + "\r\n");
        // Process the response header
        int length = 0;
        String response;
        while ((response = sockin.readLine()) != null) {
            // Header ends with blank line
            if (response.length() == 0)
            if (response.startsWith("Content-Length: ")) 
                length = Integer.parseInt(response.substring(16));
        // Obtain the entire response (if any)
        response = "";
        if (length > 2) {
            byte[] resp = new byte[length];
            response = new String(resp, "UTF8");
        // Data (should be JSON)
        // Close the Socket
bruce_dev /> jtest
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Digest realm="JANOS Web Server", qop=auth, nonce="66d0bb430469f01e9153358cfa7f"
Content-Length: 99

 3c 48 54 4d 4c 3e 3c 48-45 41 44 3e 3c 54 49 54    <HTML><H EAD><TIT
 4c 45 3e 34 30 31 20 55-6e 61 75 74 68 6f 72 69    LE>401.U nauthori
 7a 65 64 3c 2f 54 49 54-4c 45 3e 0d 0a 3c 2f 48    zed</TIT LE>..</H
 45 41 44 3e 3c 42 4f 44-59 3e 3c 68 31 3e 34 30    EAD><BOD Y><h1>40
 31 20 55 6e 61 75 74 68-6f 72 69 7a 65 64 3c 2f    1.Unauth orized</
 68 31 3e 3c 2f 42 4f 44-59 3e 3c 2f 48 54 4d 4c    h1></BOD Y></HTML
 3e 0d 0a                                           >..

bruce_dev />

So we get the response expected. But was it done securely? Here’s the transaction from the Wireshark point of view.

While JANOS strives to create a secure environment we generally fall short in that arena when it comes to applications. An application can listen for connections and process its own custom protocol. That is not so complicated to do but it is another big step to insure some level of security. We hardly ever get that done.

If the custom protocol first requires a username and password, you can use the method that JANOS provides User.validate() to validate the login. The issue here is that the username and password are transferred in the clear unless the protocol requires a secure SSL/TLS connection.

When an application implements the client side of a connection there is the User.digestMD5() method that can be used in combination with a NONCE to transfer credentials securely. Unfortunately we don’t have method available to validate digest encoded credentials on the server side.

By the way, I think it is better to transfer the username and password in the clear than to not implement authentication at all. Note also that the vast majority of our applications run on a physically secure network.

Still we can certainly ramp this up a level.

Also, applications run with Administrator privileges and merely authenticate the supplied username and password. The supplied account then does not limit the application. So you can define a guest level account solely for authenticating access. If those credentials are then compromised perhaps by being transferred in the clear they are really not a security issue otherwise. In other words, you shouldn’t use an administrator account to log into these application protocols. In addition, an application protocol shouldn’t implement capabilities that compromise the security of the JNIOR by allowing configuration changes.

We’ve been using a “nonce” string to encrypt credentials for transfer over clear text channels. The approach was first employed as an option in the JNIOR Protocol. It works like this.

Nonce String

The “nonce string” is any string of random (usually printable) characters. It is generated by the server and supplied to the client either upon request or as part of an announcement on connection. The nonce can only be used once to authenticate a set of credentials. It should only be valid for a brief period of time, usually 1 or 2 minutes.

The Hash

The client uses an MD5 message digest function to obtain a hash from a combination of username, password and nonce. Our procedure combines the username followed by the nonce followed by the password each separated by a colon ‘:’. Therefore:

hash = MD5( username + ":" + nonce + ":" + password )

The hash produced here is a 16 byte binary array. It is converted to a 32 character hexadecimal (case-insensitive) representation before it is used.

Encoded Credentials

The credentials are then supplied with the username in plain text as follows:

encoded_credentials = username + ":" + hash_hexadecimal

The encoded credentials string is supplied to the server for authentication. The server takes the username from the string and looks up the password for the account. It then uses the nonce it supplied to calculate the digest as defined above. If the calculated digest matches that sent by the client the login is valid.

Since it is practicably impossible to reverse the hash to determine the password for the account this limits risk when transmitted in the clear. It does not matter if the attacker knows the nonce. It is imperative that the nonce be single use and if possible only valid for the one socket connection. This is to prevent a replay attack where the encoded credentials are repeated by the attacker to gain access.

An issue with the above is that applications do not have access to user account passwords in clear text in order to calculate the digest. JANOS needs to provide some assistance here. A validation method is needed.

So it can be done. The following takes encoded credentials as if they were from a client to which we had supplied the random nonce. We then process the authentication without access to the password for the user.

package jtest;
import com.integpg.system.ArrayUtils;
import com.integpg.system.User;
import java.util.StringTokenizer;
public class Main {
    public static void main(String[] args) throws Exception {
        // supplied encoded credentials and original nonce
        String creds = "jnior:4f163e3fdaee54babdc0a8aaad7df1c1";
        String nonce = "jhfjh23k4k3489ysf989(*(98a98a9835h2k3";
        // parse credentials
        StringTokenizer tokenizer = new StringTokenizer(creds, ":");
        String username = tokenizer.nextToken();
        String digest = tokenizer.nextToken();
        // obtain binary digest
        byte[] hash = new byte[16];
        for (int n = 0; n < 16; n++)
            hash[n] = (byte)Integer.parseInt(digest.substring(2*n, 2*(n+1)), 16);
        // obtain digest using digestMD5()
        int userid = User.getUserID(username);
        byte[] hash2 = User.digestMD5(userid, username + ":" + nonce + ":", "");
        // compare hashes
        if (ArrayUtils.arrayComp(hash, 0, hash2, 0, hash.length))
            System.out.println("Login successful!");
bruce_dev /> jtest
Login successful!

bruce_dev />

I am sure there are other ways to parse the credentials and to convert the hexadecimal string to a byte[]. JANOS does not implement the String.split() method. You can use Regex.

As an alternative to processing the hexadecimal string you could convert hash2 into the hex string and compare. I am not sure which is faster.

Here’s the split done using Regex.

    // parse credentials
        String[] parts = Pattern.compile(":").split(creds);
        String username = parts[0];
        String digest = parts[1];

I had thought that I had implemented the String.split() method but no. I am probably thinking of the split() function in the PHP scripting.

And here’s another way to convert the hexadecimal digest string into the byte array.

        // obtain binary digest
        byte[] hash = new byte[16];
        for (int n = 0; n < 32; n++)
            hash[n/2] = (byte)(16 * hash[n/2] + Character.digit(digest.charAt(n), 16));

The JNIOR captures network traffic continuously. A large queue is established at boot and a record of network packets is kept. Once the queue fills the oldest packets are dropped. Depending on your network usage that queue might contain the past hour of traffic or much more.

The NETSTAT -C command generates a network capture file /temp/network.pcapng on demand containing the content of the capture queue. For example:

HoneyPot /> netstat -c
LAN connection active (100 Mbps)
 generating capture file...
 /temp/network.pcapng created
 collected 4791 packets from the previous 16 minutes
HoneyPot />

You can download this file to your personal computer. If you have Wireshark installed you will likely be able to double-click this PCAPNG file and it will open right up for viewing and analysis.

By the way you can download Wireshark for free from

Notice that in my example only the past 16 minutes were captured. First of all the capture begins at boot. So if your JNIOR has only been up for 16 minutes that is all that you will get. This, I think, was the case here.

It is important also to note that when you access the DCP you are also using the network. That means that all of the packets involved with your browser access will also be captured. If you leave the DCP up to monitor the status of your JNIOR all of that traffic takes up space in the capture buffer. If you are interested in analyzing the JNIOR interaction with another device that DCP traffic will limit the amount of information you can capture relative to that other device.

One solution is to not use the network to monitor the JNIOR by using the RS-232 (COM) port. But for that you have to be physically at the JNIOR and have the ability to use a serial connection. A better solution is to use capture filtering.

With the JNIOR you can both filter the packets that are to be retained in the capture buffer and filter the packets that you extract into the /temp/network.pcapng file. For example I will set this JNIOR up to ignore HTTP (Port 80) traffic and capture everything else. I can then use the DCP without loading the capture buffer with packets that we are not interested in.

HoneyPot /> netstat -f !80
LAN connection active (100 Mbps)
 capture filter set
HoneyPot />

This tells JANOS to only accept packets into the capture buffer that DO NOT reference port 80. This takes effect immediately (provided there isn’t a syntax error). The next /temp/network.pcapng file that I generate will no longer contain HTTP communications and therefore nothing to do with the DCP. There will be many more packets from a longer period of time all pertaining to other communications that might help with my debugging.

The NETSTAT -F command basically sets the IpConfig/CaptureFilter Registry key. If you mouseover that key in the Registry tab of the DCP and hit F1 you will see the documentation for filtering and the syntax for these filters. These details are in the Registry Key Assignmentsdocumentation. The current version of that documented is distributed as part of the DCP. It will be present on every Series 4 JNIOR that is up to date.

Network Filtering

The content of a network capture or the network clients allowed to interact with the JNIOR can be controlled through dynamic filtering. These filters can be quite simple or, if needed, much more sophisticated.

The IpConfig/CaptureFilter Registry key may optionally define a filter which is applied to incoming packet data prior to capture. There is limited storage for captured information and by filtering you can extend the capture period and the amount of pertinent information collected.

A filter may also be used in generating the network.pcap capture file from the capture buffer. Here the filter allows you to extract only pertinent information and otherwise keep file sizes at a manageable level.

The IpConfig/Allow Registry key may optionally define a filter which is applied to incoming connections. In this case the referenced IP addresses refer to the incoming source IP addresses, those of clients. Referenced port numbers refer only to destination ports, those available on the JNIOR.

IP Address Filters

To filter packets referencing a specific IP address you need only include the IP address in the format “nnn.nnn.nnn.nnn” in the filter string. Any packet that references this IP address either as the source or the destination address will be selected for inclusion. All other packets will be excluded unless covered by some other part of the filter.

To exclude packets referencing a certain IP address you can prefix a ‘!’ exclamation point to the address like this “!nnn.nnn.nnn.nnn”. All packets that do reference the IP address as either a source or destination address will NOT be selected for inclusion. This can also be written as “NOT nnn.nnn.nnn.nnn”.

Note that an IP address is identified by its format, four decimal values between 0 and 255 separated by the ‘.’ period.

The domain syntax allows a range of IP addresses associated with a netmask to be specified. The format is “nnn.nnn.nnn.nnn/mm” where ‘mm’ specifies the number of high order bits in the netmask. For example, “” specifies any IP address in the domain that contains IP addresses through and uses a netmask of “”. This would be useful in selecting only local traffic for instance.

MAC Address Filters

Although less often required you can filter on a specific MAC address. The MAC address is included in the filter string in the format “hh:hh:hh:hh:hh:hh”. The format is six hexadecimal values (0-9a-f or 0-9A-F) separated by the ‘:’ colon. For instance most INTEG Series 4 JNIORs have MAC address formatted as “9C:8D:1A:hh:hh:hh” where the lower three bytes are assigned in some sequence.

As with IP addressing, packets with MAC addresses may be excluded by writing the filter as “!hh:hh:hh:hh:hh:hh” or “NOT hh:hh:hh:hh:hh:hh”. Again a MAC address is identified by its format.

TCP/UDP Port Filters

A port is specified in the filter string as a decimal value between 1 and 65535 inclusive. No punctuation is used. The capture filter does not distinguish between a TCP or UDP port number. A port may be excluded using the negation “!nnn” or “NOT nnn”.

There are standard ports assigned for various functions. The capture filter knows some of them by name. Some may be reconfigured through the Registry. As a convenience the port may be specified using its protocol name. The capture will be filtered on the port as configured at the time the filter is compiled (at boot or upon NETSTAT command). JANOS recognizes these port names where the default values are shown in parentheses: SMTP (25), NTP (123), JNIOR (9200), FTP (21), HTTP (80), HTTPS (443), TELNET (23), and BEACON (4444). These ports may be excluded using the same negation syntax as previously shown.

Boolean Constants

The capture filter will also recognize the terms TRUE and FALSE. True indicates that the packet is to be included and False otherwise.

Logical Operations

To filter on a single IP address, MAC address or port (or to exclude a single item) the filter need only specify the address or port in the associated format. The following would select the communications involved in an email transfer. If this is used as an incoming filter, only email transactions would be captured. If this is used with NETSTAT –C in generating the PCAPNG file, the file would only include email communications.

            NETSTAT –C SMTP
            netstat –c 25

Note that filters (and also commands) are not case-sensitive. Either form above will create a PCAPNG file with just email communications. This assumes that you have not reconfigured the SMTP port. If you have set Email/Port to another port (587 for instance) then the first line will extract your email communications and the second will not. Although the second filter might show an application trying to use the incorrect port.

Filters often need to be slightly more complex in order to include the collection of communications needed. The syntax allows you to specify any number of addresses or ports in any combination using AND, OR and XOR logic. As an alternative you may use the notation ‘&&” and ‘||’ for AND or OR respectively.

As an example perhaps you want to filter only email communications with the SERVER.

            netstat –c && smtp

If you want to also include BEACON communications you might write the filter as:

            netstat –c AND smtp OR beacon

But here you might question the order of precedence of the logical operations. The capture filters do not support an order of precedence but perform the operations from left to right. So this would be calculated as follows:

            netstat –c ( && SMTP) || BEACON

And this would have done what we had said. If there is some question you can use the parentheses in the filter as shown. The following will create the same subset of packets but would not if we were to exclude the parentheses:

            netstat –c BEACON || ( && SMTP)

A parentheses grouping can be negated as you would expect. The following will create a capture of all activity EXCEPT email communications with the SERVER.

            netstat –c !( && smtp)

Finally if we had wanted to mask these email communications from the overall capture buffer we can install this filter using the command:

           netstat –f !( && smtp)

This would result in the following Registry setting and would filter out matching communications until such time as the filter is removed.

            IpConfig/CaptureFilter = !( && smtp)

The JNIOR will only capture packets that are addressed to it. That would include broadcasts.

Ok. Well perhaps it is undocumented (and you didn’t hear it from me) but you can set the IpConfig/Promiscuous Registry Key to true. The JNIOR then will capture (subject to any filtering) all traffic including packets not addressed to the JNIOR. But for this to be of any use you will need to be using a Network Hub instead of a Network Switch. There is a difference. The latter “switch” will only pass packets to the JNIOR that are addressed to it in addition to any broadcasts. If you are interested in other traffic you need to use the “hub” which passes all traffic to all connected devices.

The Series 4 JNIOR with a hub then can be a valuable network debugging tool useful in sniffing traffic between two other devices (connected via hubs). It would allow you to remotely use the features of Wireshark.

The JNIOR can create a network capture! This network capture can be loaded in a sniffer application such as Wireshark for protocol analysis. To do this simply follow a few steps.

  2. Execute the netstat -r command. This step is optional. If you are going to conduct a test procedure then you migth want to execute this command so that only the traffic that occurs during your test will be captured.
  3. Conduct your test
  4. Use the telnet connection to execute the netstat -c command. This will create the capture file with the network buffer content.
  5. Use the DCP and the folders tab to pull the resulting network.ngpcap file. It is in the temp directory. It will be removed when the unit reboots!