Tag Archive: java

The classic Hello World application that runs on the JNIOR!

package helloworld;
public class HelloWorld {
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        System.out.println("hello world");
    }
}

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.


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
-----BEGIN CERTIFICATE-----
MIIC7TCCAlagAwIBAgIEJJmpADANBgkqhkiG9w0BAQsFADCBgTEgMB4GA1UECgwX
SU5URUcgUHJvY2VzcyBHcm91cCBJbmMxFzAVBgNVBAsMDkpOSU9SIENvbnRyb2xz
MR0wGwYDVQQDDBRob25leXBvdC5pbnRlZ3BnLmNvbTElMCMGCSqGSIb3DQEJARYW
YmNsb3V0aWVyMkBjb21jYXN0Lm5ldDAeFw0xNzAzMjIxNzMwMjNaFw0xOTAzMjIx
NzMwMjNaMIGBMSAwHgYDVQQKDBdJTlRFRyBQcm9jZXNzIEdyb3VwIEluYzEXMBUG
A1UECwwOSk5JT1IgQ29udHJvbHMxHTAbBgNVBAMMFGhvbmV5cG90LmludGVncGcu
Y29tMSUwIwYJKoZIhvcNAQkBFhZiY2xvdXRpZXIyQGNvbWNhc3QubmV0MIGfMA0G
CSqGSIb3DQEBAQUAA4GNADCBiQKBgQCplIMXSy68hXjs6lvp91hAcDsG6knZMz1J
PQNajYTbWrflSR0zS68bWaOiceJcQnbUEPOzyQ6AHomhYsaiguxRqwXPlzFWGpUi
oLMDnfcvoluhBh5ru3oaprKHoxT927nhA0tF1eH/wVpZxA13LTza1hQqcHZQ8R68
0wz/deZekQIDAQABo3AwbjAdBgNVHQ4EFgQUKcsDV7zdJueK1eVkwdCHsDtYMIIw
DAYDVR0TBAUwAwEB/zA/BgNVHREEODA2hwQyxSJLghRob25leXBvdC5pbnRlZ3Bn
LmNvbYIIaG9uZXlwb3SCDmhvbmV5cG90X2puaW9yMA0GCSqGSIb3DQEBCwUAA4GB
ACtC4F4zGu6yZfTawRjfc+f1VdcmBfbsq2fYYDJKfFBWFMUgMzepjCFX2FxXpza4
LdqIR16Tpsn8LFmDZ4yNRhqc5/U6J2bbvSbAuZzh9FFPa6w9CcMwALx+X2FRwLoX
Xym25zuOf+uuEJkmmpr9cGcXxnz5x/F+uz+Nsu1DU8LR
-----END CERTIFICATE-----

bruce_dev />

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


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 2.5.4.10
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 2.5.4.11
0050  0C 0E          |  |  |  |  |  UTF8STRING 'JNIOR Controls'
                     |  |  |  |  }
                     |  |  |  }
0060  31 1D          |  |  |  SET {  (29 bytes)
0062  30 1B          |  |  |  |  SEQUENCE {  (27 bytes)
0064  06 03          |  |  |  |  |  OBJECT IDENTIFIER 2.5.4.3
0069  0C 14          |  |  |  |  |  UTF8STRING 'honeypot.integpg.com'
                     |  |  |  |  }
                     |  |  |  }
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 'bcloutier2@comcast.net'
                     |  |  |  |  }
                     |  |  |  }
                     |  |  }
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 2.5.4.10
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 2.5.4.11
00F4  0C 0E          |  |  |  |  |  UTF8STRING 'JNIOR Controls'
                     |  |  |  |  }
                     |  |  |  }
0104  31 1D          |  |  |  SET {  (29 bytes)
0106  30 1B          |  |  |  |  SEQUENCE {  (27 bytes)
0108  06 03          |  |  |  |  |  OBJECT IDENTIFIER 2.5.4.3
010D  0C 14          |  |  |  |  |  UTF8STRING 'honeypot.integpg.com'
                     |  |  |  |  }
                     |  |  |  }
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 'bcloutier2@comcast.net'
                     |  |  |  |  }
                     |  |  |  }
                     |  |  }
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 2.5.29.14
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 2.5.29.19
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 2.5.29.17
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  )..;......&...pg
                     |     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;
import java.net.Socket;
 
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("50.197.34.75", 443);
        dataSocket.setSecure(true);
        
        // Obtain the certificate
        byte[] cert;
        while ((cert = dataSocket.getCertificate()).length == 0)
            System.sleep(100);
        dataSocket.close();
 
        // 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)
        asn.skip();
        if (!asn.hasMoreData())
            System.out.println("Signed Certificate is a sigle object as expected");
        else
            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.


    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.
        asn.descend();
        
        while (asn.hasMoreData()) {
            System.out.println("ASN.1 Object tag: " + asn.getTag());
            System.out.println("ASN.1 Object length: " + asn.getLength());
            System.out.println("");
            asn.skip();
        }
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);
        asn.descend();
        
        // obtain the certificate
        Asn1 tbsCertificate = new Asn1(asn.getData());
        asn.skip();
        Asn1 signatureAlgorithm = new Asn1(asn.getData());
        asn.skip();
        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
        Debug.dump(signatureValue);
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    )..;.... ..&...pg
 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);
        asn.descend();
        
        // obtain the certificate
        byte[] tbsCertificate = asn.getObject();
        asn.skip();
        byte[] signatureAlgorithm = asn.getData();
        asn.skip();
        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);
        Debug.dump(hash);
        System.out.println("");
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()];
        fin.readFully(pubkey);
        fin.close();
        
        byte[] sig = Security.decrypt(signatureValue, 0, pubkey, 0);
        Debug.dump(sig);
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.

        dataSocket.setSecure(true);

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;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.net.Socket;
 
public class Main {
    
    public static void main(String[] args) throws Exception {
 
        // Location services
        String serverHostname = "50.197.34.75";
        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());
        dataSocket.setSoTimeout(5000);
        
        // Negotiate a secure connection
        dataSocket.setSecure(true);
 
        // Issue the HTTP request
        sockout.writeBytes("GET / HTTP/1.1\r\n");
        sockout.writeBytes("Host: " + serverHostname + "\r\n");
        sockout.writeBytes("\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)
                    break;
            
            System.out.println(response);
            if (response.startsWith("Content-Length: ")) 
                length = Integer.parseInt(response.substring(16));
        }
        System.out.println();
 
        // Obtain the entire response (if any)
        response = "";
        if (length > 2) {
            byte[] resp = new byte[length];
            sockin.readFully(resp);
            response = new String(resp, "UTF8");
        }
 
        // Data (should be JSON)
        Debug.dump(response.getBytes());
 
        // Close the Socket
        sockout.close();
        sockin.close();
        dataSocket.close();
    }
        
}
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.

It seems that more often than not these days (at INTEG at least) when we need to store or transfer data we are using the JavaScript Object Notation (JSON). This is also known as ECMA-404 The JSON Data Interchange Standard. I have attached the document. If you are not at all interested in JSON you should at least visit http://www.json.org/ if for no other reason but to see how amazingly clearly and impressively concisely the format is described in just a single page.

JANOS uses JSON in numerous ways. Firstly, it is the data format that we use for the built-in Websockets interface that replaces the original binary JNIOR Protocol. That interface provides remote monitoring and control of the JNIOR. It is the underlying connection that makes the DCP (Dynamic Configuration Pages) possible. Secondly, the MANIFEST command uses JSON as a database format for the manifest.json reference files. And also, the JSON functionality is exposed through the JANOS Runtime Environment where it has been employed by applications for communications, databases, and configuration. The CAT command even has an option (-J) that will format a JSON text (including manifest.json) file making it readable.

From the applications point of view, JSON is handled through the java.util.Json class supplied by the etc/JanosClasses.jar runtime library. The JANOS programming environment is not your standard Java environment. This is one of many classes that we have provided allowing you to benefit from the underlying operating system. I am going to dive into this JSON class to show you what can be achieved and some of the tricks.

  ECMA-404.pdf [ Jul 19 2018, 1.08 MB, MD5: a2e87492ab7c03f557c98c8ecde9c79a ]

I have to admit that I have been recently developing applications that utilize JSON and this forced me to refresh my memory of the java.util.Json class. There are few enhancements to that class that I might implement. So I thought that I would do that here and out in the open. I will be clear though as to what is new for JANOS v1.6.3 and what you already have available in your JNIORs.

So to start I have attached the current JavaDoc for the class. In this there is one new method getBoolean() that I have just added. Before this you needed to use the get() method and cast the returned Object it to a boolean to retrieve the logical. That by itself is not a problem. But, it wouldn’t be clear to you that you could do that.

Ok, in the process I will give the JavaDoc some attention too. Please feel free to jump in and comment.

  Json-JanosRuntime-JavaDOC.pdf [ Jul 19 2018, 190.18 KB, MD5: 7ad7bc53e195b896aba20960e0013d18 ]

By the way, if you are programming and want access to this JavaDoc you need to get the runtime JAR from us. You can develop using the etc/JanosClasses.jar runtime but that does not contain the JavaDoc. Elsewhere I describe how to configure Netbeans to build your application specifically for our runtime. Here I have attached the enhanced Runtime JAR for JANOS v1.6.2. If you configure for it you can confirm that the Json getBoolean() method is absent from the class.

[Download not found]

To get started we could use some examples of JSON with which to work.

You can run the MANIFEST -U command and generate an updated manifest.json for your JNIOR. That file actually is stored in two places: /manifest.json and /flash/manifest.json. One is the backup for the other. Here is what it looks like. I have to apologize as my development JNIOR has a crap load (technical term) of files on it so its a long listing. We’ll use CAT -J to format it.

CODE: SELECT ALL

bruce_dev /> cat -j manifest.json
{
  "model":"410",
  "serno":614070500,
  "vers":"v1.6.3-rc4",
  "date":"12/01/17 13:04:04",
  "files":{
    "/etc/janosclasses.jar":{
      "length":243492,
      "date":1512145376,
      "md5":"ece8d0ebf9b6882e488d1f7c9e764ce0",
      "crc":"bde463c8",
      "sha":"373b88f011b49f65eafd8e293fc185cc2563892e"
    },
    "/flash/serialcontrol.jar":{
      "length":31344,
      "date":1450364184,
      "md5":"b349e02b7efc64c0dfe5eb74292a5ee6",
      "crc":"3a005104"
    },
    "/flash/serialethernet.jar":{
      "length":25266,
      "date":1433505362,
      "md5":"ee5e266bb8418b4223a666bd046a8c56",
      "crc":"c3961df2"
    },
    "/flash/modbusserver.jar":{
      "length":51907,
      "date":1502219129,
      "md5":"77c16d6134dbd7ec93313fbad2b00d93",
      "crc":"b7456b42",
      "sha":"fad4ecc3d1607aafe0a385a10fb5ee90eff521bd"
    },
    "/flash/snmp.jar":{
      "length":239949,
      "date":1493062048,
      "md5":"b77d35c322ef6645f1eca9d22b29400b",
      "crc":"a4073dcb",
      "sha":"44a3c2b41a2375ef603063cc9b04642903dad973"
    },
    "/flash/www/base64.js":{
      "length":3493,
      "date":1433505378,
      "md5":"1138db1b5a6e165beae3ed81739dd2ec",
      "crc":"baceb6f6"
    },
    "/flash/www/configure/index.html":{
      "length":1349,
      "date":1433505382,
      "md5":"0454014aecfd0b7d9e4ce1efe0979139",
      "crc":"11ba5486"
    },
    "/flash/www/jr310applet.jar":{
      "length":287159,
      "date":1441207703,
      "md5":"f9c4840e7244824b75858a1a40dfb163",
      "crc":"3d1d0c72"
    },
    "/flash/www/jniorprotocol.jar":{
      "length":115148,
      "date":1441207710,
      "md5":"404b40c4293bf3c334e3b88e2fe0dd10",
      "crc":"5143ec4f"
    },
    "/flash/www/jniorprotocolhelpers.jar":{
      "length":34991,
      "date":1433505394,
      "md5":"b08e33e0c21e6c075b9b242bf092b68e",
      "crc":"48990308"
    },
    "/flash/www/task/index.html":{
      "length":1415,
      "date":1433505397,
      "md5":"bbdc32dce371881b3eebd15f5b3fce96",
      "crc":"cdbe02e4"
    },
    "/flash/www/taskmanagerinterface.jar":{
      "length":123052,
      "date":1433505400,
      "md5":"077cddccee476fab552d52a5eefd26a7",
      "crc":"647bb4b3"
    },
    "/flash/www/jquery/jquery-1.9.0.min.js":{
      "length":93071,
      "date":1433505404,
      "md5":"2b869ea9c8edd4c2243c5d44f665f632",
      "crc":"6a2a8434"
    },
    "/flash/www/jquery/jquery-ui.css":{
      "length":33441,
      "date":1433505405,
      "md5":"c6bd2971b8e625f2ae43ede9f655a27b",
      "crc":"0497b7a6"
    },
    "/flash/www/jquery/jquery-ui.min.js":{
      "length":96395,
      "date":1433505409,
      "md5":"8f636d4c90ea0abfcbb25528c635bf7d",
      "crc":"820662f5"
    },
    "/flash/www/vendor/bowser/bowser_0.7.2.min.js":{
      "length":3359,
      "date":1433505412,
      "md5":"61a36d48aad1298b17284b53f6ce3fd1",
      "crc":"22deb9e6"
    },
    "/flash/www/text":{
      "length":1336,
      "date":1434044220,
      "md5":"bab65804218b18b9e1a79f2d8e873259",
      "crc":"dda17d61"
    },
    "/flash/www/cycle":{
      "length":419,
      "date":1434044214,
      "md5":"9eb9bbdae70c1f994ebb7f51b18783b8",
      "crc":"9e496eb9"
    },
    "/flash/slaveservice.jar":{
      "length":73323,
      "date":1465435094,
      "md5":"cd6f5e177d75675607e9523d52e133f7",
      "crc":"9a871cd7"
    },
    "/flash/ftp.jar":{
      "length":9563,
      "date":1475783634,
      "md5":"793e460054f07867685e87f98fd402e6",
      "crc":"36fd641e"
    },
    "/flash/task.ini":{
      "length":4311,
      "date":1433782061,
      "md5":"b1f877ac198306b266311eab557ed1dd",
      "crc":"36a57579"
    },
    "/flash/task.jar":{
      "length":102655,
      "date":1434645611,
      "md5":"1979b16970127f2c38912777cb105133",
      "crc":"ed4d6ad7"
    },
    "/flash/jnior.ini":{
      "length":4874,
      "date":1512052838,
      "md5":"90740fe1ddcf0ddf0774c2574e234dfe",
      "crc":"c78e61d7",
      "sha":"76aa475db28479a22e748e6181cf11423988c266"
    },
    "/jniorsys.log":{
      "length":32844,
      "date":1512145587,
      "md5":"be4968cceb2fe0b2bebf50daac17d739",
      "crc":"637fb821",
      "sha":"2b6b56f5e3a731b933cf6e1594dfe1e003674d6b"
    },
    "/jniorboot.log.bak":{
      "length":1041,
      "date":1512074628,
      "md5":"8261c4f9cd12695626755ba6d1b0b9ad",
      "crc":"03e23ea1",
      "sha":"761a2b3fa74a921778d1c6fc438b5bfd0d51bc29"
    },
    "/jniorboot.log":{
      "length":995,
      "date":1512145452,
      "md5":"f053bbba44bea8f6333702fef922d950",
      "crc":"fa976c1c",
      "sha":"c2665669c49028a549a2e30e10b27e8f2aba5861"
    },
    "/flash/benchmark.jar":{
      "length":24351,
      "date":1464873509,
      "md5":"987f4044786771f31e0656cf91ed73f3",
      "crc":"1eed095a"
    },
    "/flash/threadtest.jar":{
      "length":3601,
      "date":1434645124,
      "md5":"902ce61cbd2524ca9b83dea335c395d3",
      "crc":"cd2479ff"
    },
    "/flash/test4to20.jar":{
      "length":3862,
      "date":1434659455,
      "md5":"a2e309c9d6dd112e5303aa76d2470740",
      "crc":"976f8208"
    },
    "/flash/dirs.bat":{
      "length":87,
      "date":1435691869,
      "md5":"531d655733ee668d829f9b3bdad96038",
      "crc":"6a11f77a"
    },
    "/flash/www/console/index.php":{
      "length":4347,
      "date":1438974987,
      "md5":"8728680bbc36d369429f7ca2c73cce7d",
      "crc":"c939c423"
    },
    "/flash/clean.bat":{
      "length":56,
      "date":1436532855,
      "md5":"ac9ce6553e1629412fb426b342440493",
      "crc":"3b661614"
    },
    "/flash/jnior1024.key":{
      "length":887,
      "date":1437746752,
      "md5":"b76b5351a92fdcc8d9b6b38ca62d8d71",
      "crc":"7983e14c"
    },
    "/flash/www/config/md5.js":{
      "length":5693,
      "date":1433505379,
      "md5":"a60fec5a81f207ff99ec1b97e3ccad0e",
      "crc":"e2a43d16"
    },
    "/flash/www/config/node.png":{
      "length":253,
      "date":1440435886,
      "md5":"1a8dbfaf1771a06e48dea0e3dc604392",
      "crc":"799c6dfc"
    },
    "/flash/www/config/tabs-styles.css":{
      "length":970,
      "date":1477590404,
      "md5":"68bca7015f51e26ab42199b5eb17a356",
      "crc":"f8870a33"
    },
    "/flash/www/config/tabs.js":{
      "length":3662,
      "date":1449678641,
      "md5":"ff728c86018341548ee70028062c89e0",
      "crc":"1a813112"
    },
    "/flash/www/config/styles.css":{
      "length":4450,
      "date":1504814044,
      "md5":"9ad78cca1b794dbcf9db3c55f1be5f1b",
      "crc":"acbd2e14",
      "sha":"3cf0bbc864840994a49f62d0ae00df6d8eb47ef3"
    },
    "/flash/www/config/comm.js":{
      "length":3541,
      "date":1507912287,
      "md5":"e7d2e56a443176d6150bbcc8b56e1911",
      "crc":"0ac0ed26",
      "sha":"5e66b96227779c5ef3736a7ca891a43cacffbbf1"
    },
    "/flash/www/config/console.js":{
      "length":5137,
      "date":1504815652,
      "md5":"33289e4b09f462efdb50e8d30d22d791",
      "crc":"b89fe380",
      "sha":"c2f3ea4fc0344d43b0c30b7f60b2b6c79c1f4817"
    },
    "/flash/www/config/config.js":{
      "length":12639,
      "date":1507912576,
      "md5":"75bf22a88d8a23b17de267607b88a14c",
      "crc":"d693e2f4",
      "sha":"cf9e9bcf7cc7d79ae648b241af16ee194199d7b3"
    },
    "/flash/www/config/index.php":{
      "length":22103,
      "date":1510262716,
      "md5":"6fe98e5238c5834d55b0140a7172fec6",
      "crc":"81f11698",
      "sha":"b5b440d43bb19da0396e8ab615161be9200e6180"
    },
    "/flash/www/jnior.ico":{
      "length":3262,
      "date":1439548680,
      "md5":"1c3b3dda6b10c6259fcf7c068b760f09",
      "crc":"051803eb"
    },
    "/flash/www/favicon.ico":{
      "length":156790,
      "date":1486410493,
      "md5":"07cb90c7f3573eff80222269625ed1dd",
      "crc":"7e367afa",
      "sha":"284add71fe3d3ba48fba059b88ff5143d3964b1d"
    },
    "/flash/analogpresets.jar":{
      "length":163902,
      "date":1441372806,
      "md5":"25eacc647412535e320302d3680ce327",
      "crc":"e6b656fc"
    },
    "/flash/www/config/config.css.php":{
      "length":1045,
      "date":1475072901,
      "md5":"1692861e9abd7f8d81f5b7cf8a176046",
      "crc":"4c386a21"
    },
    "/flash/www/config/inputs.png":{
      "length":18047,
      "date":1443116143,
      "md5":"e2151c93b6cdeaa154d15fab486ae61b",
      "crc":"16290877"
    },
    "/flash/www/config/loading.gif":{
      "length":3236,
      "date":1264096270,
      "md5":"d96f6517e00399c37a9765e045eaaf22",
      "crc":"16f442ed"
    },
    "/flash/jtest.jar":{
      "length":1832,
      "date":1511984925,
      "md5":"89f28d11945790915112f0a4880b6adc",
      "crc":"cf00edbe",
      "sha":"df53eab9f4eb1360c7ab48f30298ce7c48b0e440"
    },
    "/flash/www/vendor/angular_1.3.15/angular.min.js":{
      "length":125909,
      "date":1449498838,
      "md5":"ca1a58818682c3e858a585f283ab9beb",
      "crc":"9d8147d7"
    },
    "/flash/www/vendor/bootstrap_3.3.0/css/bootstrap-theme.css":{
      "length":21740,
      "date":1449498835,
      "md5":"c64043a3388612233d7eb947918a9bfc",
      "crc":"638f58a3"
    },
    "/flash/www/vendor/bootstrap_3.3.0/css/bootstrap-theme.css.map":{
      "length":41933,
      "date":1449498838,
      "md5":"c5da8241305bfe7e19919e6e943739eb",
      "crc":"11260772"
    },
    "/flash/www/vendor/bootstrap_3.3.0/css/bootstrap-theme.min.css":{
      "length":19199,
      "date":1449498840,
      "md5":"374df0ad5809a5314b0577802430a272",
      "crc":"8b3c47b7"
    },
    "/flash/www/vendor/bootstrap_3.3.0/css/bootstrap.css":{
      "length":137590,
      "date":1449498845,
      "md5":"ad6381ebfa541b55b0152349c6cabf76",
      "crc":"371e67da"
    },
    "/flash/www/vendor/bootstrap_3.3.0/css/bootstrap.css.map":{
      "length":366866,
      "date":1449498854,
      "md5":"4ba278e0c420d166e5a0eb71545f9509",
      "crc/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.woff":{
      "length":23320,
      "date":1449498858,
      "md5":"68ed1dac06bf0409c18ae7bc62889170",
      "crc":"cec1a35c"
    },
    "/flash/www/vendor/bootstrap_3.3.0/js/bootstrap.min.js":{
      "length":34653,
      "date":1449498862,
      "md5":"281cd50dd9f58c5550620fc148a7bc39",
      "crc":"32d6c689"
    },
    "/flash/www/vendor/bootstrap_3.3.0/js/bootstrap.js":{
      "length":65813,
      "date":1449498862,
      "md5":"d5a03d9cca57637f008124916b86b585",
      "crc":"f504a7b3"
    },
    "/flash/www/vendor/bootstrap_3.3.0/js/npm.js":{
      "length":484,
      "date":1449498863,
      "md5":"ccb7f3909e30b1eb8f65a24393c6e12b",
      "crc":"cc50e34d"
    },
    "/flash/www/vendor/jquery_1.11.1/jquery-1.11.1.min.map":{
      "length":141680,
      "date":1449498870,
      "md5":"ffbeb16578d8cdf58104889baacbbef2",
      "crc":"e4e92bfd"
    },
    "/flash/www/vendor/jquery_1.11.1/jquery-1.11.1.min.js":{
      "length":95786,
      "date":1449498869,
      "md5":"8101d596b2b8fa35fe3a634ea342d7c3",
      "crc":"804ff984"
    },
    "/flash/www/config/integlogo.png":{
      "length":5773,
      "date":1449163436,
      "md5":"9111308273dadea73f5d09a5e02c7311",
      "crc":"60c4e184"
    },
    "/flash/utility.jar":{
      "length":106794,
      "date":1449773066,
      "md5":"ac559b91b537dfa70720a416f32f2960",
      "crc":"888936f1"
    },
    "/flash/generators/json/colour.js":{
      "length":4327,
      "date":1449774238,
      "md5":"c67e10d0e0e698fcdbbbadcaa55600d4",
      "crc":"19e8a38f"
    },
    "/flash/generators/json/ethernet.js":{
      "length":1409,
      "date":1449774238,
      "md5":"1b6bae08feb93f6bd345a3780c3acb69",
      "crc":"848097a7"
    },
    "/flash/generators/json/inputs.js":{
      "length":2825,
      "date":1449774239,
      "md5":"6959db5a769ff3ceea45bf606bda940a",
      "crc":"c544d780"
    },
    "/flash/generators/json/lists.js":{
      "length":12006,
      "date":1449774239,
      "md5":"5cc489ac77db7a3369b2ffc30cbd3a86",
      "crc":"ba761254"
    },
    "/flash/generators/json/logic.js":{
      "length":4404,
      "date":1449774239,
      "md5":"9cd1cf854976ebb69a6c20a7ac88d2f9",
      "crc":"6c2189f9"
    },
    "/flash/generators/json/loops.js":{
      "length":6040,
      "date":1449774239,
      "md5":"e8e9021b5d4eb2e0cc43f11ad5b3bfd7",
      "crc":"b30a758a"
    },
    "/flash/generators/json/math.js":{
      "length":14673,
      "date":1449774240,
      "md5":"fa22c29efc362e02d8f35838fcca46e5",
      "crc":"8fc62e67"
    },
    "/flash/generators/json/other.js":{
      "length":983,
      "date":1449774240,
      "md5":"dd77f555bc9b50ed17a215d7935f10ab",
      "crc":"3e07810d"
    },
    "/flash/generators/json/outputs.js":{
      "length":3861,
      "date":1449774240,
      "md5":"72a118cd7829b5a510e5a901d8863d6e",
      "crc":"bdd5e320"
    },
    "/flash/generators/json/procedures.js":{
      "length":3945,
      "date":1449774240,
      "md5":"cb9fb880bebb3375273353fafc12dc9c",
      "crc":"20d43aad"
    },
    "/flash/generators/json/text.js":{
      "length":1363,
      "date":1449774241,
      "md5":"a0bd39f638202a0800c100b4eac3cbc3",
      "crc":"b17b24d6"
    },
    "/flash/generators/json/timing.js":{
      "length":2638,
      "date":1449774241,
      "md5":"b1ee803dd8e6e00de74e0a3269f0a2ff",
      "crc":"489061b8"
    },
    "/flash/generators/json/variables.js":{
      "length":1500,
      "date":1449774241,
      "md5":"fecce79a400d5e4e1edbe521699fa604",
      "crc":"cb724c91"
    },
    "/flash/generators/json.js":{
      "length":4115,
      "date":1449774238,
      "md5":"cc72f2468eb970110f3f6f0278f43467",
      "crc":"25a98f30"
    },
    "/flash/www/config/link_to.png":{
      "length":259,
      "date":1450466976,
      "md5":"b1ed68183be4f97ce1793139496dbbb4",
      "crc":"a067876a"
    },
    11124a10766",
      "crc":"62d153fb"
    },
    "/flash/public/dcp.zip":{
      "length":181914,
      "date":1504795829,
      "md5":"655e8587293f35f11c5c24fc38201d2f",
      "sha":"5fcfd8e38826e648f98f8d50f3613deb0d6312b6",
      "crc":"da99b7d0"
    },
    "/flash/test.txt":{
      "length":304,
      "date":1495131459,
      "md5":"fc9f1f5e67928ccb9be3aeaa66cd9e52",
      "sha":"6100d999f484f98ab476408c801dd000e579a62c",
      "crc":"765047c5"
    },
    "/flash/dmx.jar":{
      "length":4476,
      "date":1500567859,
      "md5":"3fd35bbe6bbf53a32aecf273275d1839",
      "sha":"4f702a87adb060294b553e6bd212672727d5d25f",
      "crc":"e81db9aa"
    },
    "/flash/juptime.jar":{
      "length":3201,
      "date":1506713589,
      "md5":"d4c2482fae18482727c1b2afabcf94b4",
      "sha":"86268b720b99760a4ebdb803db53f3f7fd18fd18",
      "crc":"44b0878c"
    },
    "/flash/jscan.jar":{
      "length":2189,
      "date":1507141493,
      "md5":"a0a42e17f003cedcac9c8e662ada6b36",
      "sha":"f1cafb56fdae33b66fff9b20cd2ff2705d96da9e",
      "crc":"60f00fe2"
    },
    "/access.log":{
      "length":177,
      "date":1510081848,
      "md5":"914113dd52c4e74d2675eb1094ba10c6",
      "sha":"0212252f4f04ab136ce74ab0425cd7fce26b7c47",
      "crc":"e9a7f8d8"
    },
    "/auxio.log":{
      "length":1589,
      "date":1511288557,
      "md5":"a52713575d5c449ff8e8cdbeb7e10ba6",
      "sha":"22106e83ff429cc08fe16f21dc32623850f5673c",
      "crc":"a29ad191"
    },
    "/jniorio.log":{
      "length":3332,
      "date":1511289076,
      "md5":"d3c685fde34b343f2ba53dd60e4bf11d",
      "sha":"dd001970b69d61ab619745853addaf2910aabb31",
      "crc":"1bbc78de"
    },
    "/flash/hmi.jar":{
      "length":8329,
      "date":1511283865,
      "md5":"1a1b247ccb5e3eb9623d12578c1ba833",
      "sha":"7a1f5868817e8a3e60fe8fb2c4d9ed168e53d141",
      "crc":"fb2a0367"
    },
    "/flash/ckeypad.jar":{
      "length":11194,
      "date":1512145569,
      "md5":"71288ea4ffa40e936dbecfd010fff785",
      "sha":"23f944b627705716697ece761c6c95f8c1f873bb",
      "crc":"3d9fc092"
    }
  }
}
bruce_dev /> 

I can get some small ones say from the protocol we are defining to the Cinema UI project. Here’s the response to a GetInfo request. And, I’ll get the response to a MacroList in a bit.

CODE: SELECT ALL

bruce_dev /> cat -j getinfo.json                                                                
{
  "Message":"GetInfoResponse",
  "Information":"Cinema v2.4.0.473"
}
bruce_dev />

Okay so here is a response to a MacroListRequest that we are using in the Cinema UI implementation. It is just another JSON example that we can work with here.

CODE: SELECT ALL

bruce_dev /> cat inforesponse.json -j
{
  "Message":"GetMacroListResponse",
  "MacroList":[
    "Preshow Start",
    "Preshow End",
    "Flat Start Trailers",
    "Scope Start Trailers",
    "Feature Start",
    "Feature Credits",
    "Feature End",
    "Start Intermission",
    "Stop Intermission",
    "Extend Intermission 15 Seconds",
    "Shorten Intermission 15 Seconds",
    "Intermission End",
    "Fire Alarm",
    "Fire Alarm Clear",
    "Lights Dim",
    "Lights Half",
    "Lights Full",
    "Multiple",
    "Test",
    "ticket sold",
    "no ticket sold",
    "violet",
    "LED Off",
    "LED Green",
    "Core Command 1",
    "Core Command 2",
    "RWB"
  ]
}
bruce_dev /> 

So the file actually contains one huge string. Here I will manually wrap it.

{"Message":"GetMacroListResponse","MacroList":["Preshow Start","Preshow End","Flat Start Trailers",
  "Scope Start Trailers","Feature Start","Feature Credits","Feature End","Start Intermission",
  "Stop Intermission","Extend Intermission 15 Seconds","Shorten Intermission 15 Seconds","Intermission End",
  "Fire Alarm","Fire Alarm Clear","Lights Dim","Lights Half","Lights Full","Multiple","Test","ticket sold",
  "no ticket sold","violet","LED Off","LED Green","Core Command 1","Core Command 2","RWB"]}

let’s access the MacroListResponse and fetch data from it. The following program creates a Jason object from the content of the specified File. We need to use a File object here since we can also instantiate a Json object directly from a string. So we can’t just directly specify the filename. Once we have the object we search for the “message” name-value pair and retrieve its String content.

package jtest;
 
import java.io.File;
import java.util.Json;
 
public class Main {
    
    public static void main(String[] args) throws Exception {
        
        // Obtain Json Object from a file
        Json jdb = new Json(new File("inforesponse.json"));
        
        // Fetch String content
        String msg = jdb.getString("Message");
        System.out.println(msg);
        
    }
}
bruce_dev /> jtest
GetMacroListResponse

bruce_dev />

In this JSON object we know that the MacroList is an array of Strings. So it is a simple matter to itemize or list them.

package jtest;
 
import java.io.File;
import java.util.Json;
 
public class Main {
    
    public static void main(String[] args) throws Exception {
        
        // Obtain Json Object from a file
        Json jdb = new Json(new File("inforesponse.json"));
        
        // List the macros
        String[] macros = (String[]) jdb.get("MacroList");
        for (int n = 0; n < macros.length; n++)
            System.out.println(macros[n]);
        
    }
}
bruce_dev /> jtest
GetMacroListResponse

bruce_dev /> jtest
Preshow Start
Preshow End
Flat Start Trailers
Scope Start Trailers
Feature Start
Feature Credits
Feature End
Start Intermission
Stop Intermission
Extend Intermission 15 Seconds
Shorten Intermission 15 Seconds
Intermission End
Fire Alarm
Fire Alarm Clear
Lights Dim
Lights Half
Lights Full
Multiple
Test
ticket sold
no ticket sold
violet
LED Off
LED Green
Core Command 1
Core Command 2
RWB

bruce_dev />

But if we didn’t know it was an array could we figure it out?

package jtest;
 
import java.io.File;
import java.util.Json;
 
public class Main {
    
    public static void main(String[] args) throws Exception {
        
        // Obtain Json Object from a file
        Json jdb = new Json(new File("inforesponse.json"));
        
        // List the macros
        Object obj = jdb.get("MacroList");
 
        if (obj instanceof Object[]) {
            System.out.println("MacroList is an array.");
            
            // first few entries
            for (int n = 0; n < ((Object[]) obj).length && n < 4; n++)
                System.out.println( " " + (n + 1) + ". " + ((Object[]) obj)[n] );
        }  
    }
}
bruce_dev /> jtest
MacroList is an array.
 1. Preshow Start
 2. Preshow End
 3. Flat Start Trailers
 4. Scope Start Trailers

bruce_dev />

It just seems that I can make this a little cleaner. You know, like by providing an isArray() method or something along those lines.

When you are confronted with some JSON and you don’t have an official schema how do you know what is there? The get() methods require that you supply the name (or key) for an object but you might not know what name:value pairs are present. You can enumerate the structure.

Every JSON object encloses 0 or more name:value or string:value pairs in curly braces {}.

The following can enumerate the keys which are guaranteed to be strings identifying each name:value pair. Let’s work now with the MANIFEST database file to decipher its structure.

    public static void main(String[] args) throws Exception {
        
        // Obtain Json Object from a file
        Json jdb = new Json(new File("manifest.json"));
        
        // List top level enties
        Enumeration e = jdb.keys();
        while (e.hasMoreElements()) 
            System.out.println(e.nextElement());
    }
bruce_dev /> jtest
model
serno
vers
date
files

bruce_dev />

We can expand this to show the values associated with these keys. Note that we generically fetch the value Object and explicitly convert it to a string for display.

    public static void main(String[] args) throws Exception {
        
        // Obtain Json Object from a file
        Json jdb = new Json(new File("manifest.json"));
        
        // List top level enties
        Enumeration e = jdb.keys();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
            System.out.printf("%s = %s\n", name, jdb.get(name).toString());
        }
    }
bruce_dev /> jtest
model = 410
serno = 614070500
vers = v1.6.3-rc4
date = 12/01/17 13:04:04
files = {"/etc/janosclasses.jar":{"length":243492,"date":1512145376,"md5":"ece8d0ebf9b6882e488d1f7c9e764ce0","crc":"bde463c8","sha":"373b88f011b49f65eafd8e293fc185cc2563892e"},"/flash/serialcontrol.jar":{"length":31344,"date":1450364184,"md5":"b349e02b7efc64c0dfe5eb74292a5ee6","crc":"3a005104"},"/flash/serialethernet.jar":{"length":25266,"date":1433505362,"md5":"ee5e266bb8418b4223a666bd046a8c56","crc":"c3961df2"},"/flash/modbusserver.jar":{"length":51907,"date":1502219129,"md5":"77c16d6134dbd7ec93313fbad2b00d93","crc":"b7456b42","sha":"fad4ecc3d1607aafe0a385a10fb5ee90eff521bd"},"/flash/snmp.jar":{"length":239949,"date":1493062048,"md5":"b77d35c322ef6645f1eca9d22b29400b","crc":"a4073dcb","sha":"44a3c2b41a2375ef603063cc9b04642903dad973"},"/flash/www/base64.js":{"length":3493,"date":1433505378,"md5":"1138db1b5a6e165beae3ed81739dd2ec","crc":"baceb6f6"},"/flash/www/configure/index.html":{"length":1349,"date":1433505382,"md5":"0454014aecfd0b7d9e4ce1efe0979139","crc":"11ba5486"},"/flash/www/jr310applet.jar":{"length":287159,"date":1441207703,"md5":"f9c4840e7244824b75858a1a40dfb163","crc":"3d1d0c72"},"/flash/www/jniorprotocol.jar":{"length":115148,"date":1441207710,"md5":"404b40c4293bf3c334e3b88e2fe0dd10","crc":"5143ec4f"},"/flash/www/jniorprotocolhelpers.jar":{"length":34991,"date":1433505394,"md5":"b08e33e0c21e6c075b9b242bf092b68e","crc":"48990308"},"/flash/www/task/index.html":{"length":1415,"date":1433505397,"md5":"bbdc32dce371881b3eebd15f5b3fce96","crc":"cdbe02e4"},"/flash/www/taskmanagerinterface.jar":{"length":123052,"date":1433505400,"md5":"077cddccee476fab552d52a5eefd26a7","crc":"647bb4b3"},"/flash/www/jquery/jquery-1.9.0.min.js":{"length":93071,"date":1433505404,"md5":"2b869ea9c8edd4c2243c5d44f665f632","crc":"6a2a8434"},"/flash/www/jquery/jquery-ui.css":{"length":33441,"date":1433505405,"md5":"c6bd2971b8e625f2ae43ede9f655a27b","crc":"0497b7a6"},"/flash/www/jquery/jquery-ui.min.js":{"length":96395,"date":1433505409,"md5":"8f636d4c90ea0abfcbb25528c635bf7d","crc":"820662f5"},"/flash/www/vendor/bowser/bowser_0.7.2.min.js":{"length":3359,"date":1433505412,"md5":"61a36d48aad1298b17284b53f6ce3fd1","crc":"22deb9e6"},"/flash/www/text":{"length":1336,"date":1434044220,"md5":"bab65804218b18b9e1a79f2d8e873259","crc":"dda17d61"},"/flash/www/cycle":{"length":419,"date":1434044214,"md5":"9eb9bbdae70c1f994ebb7f51b18783b8","crc":"9e496eb9"},"/flash/slaveservice.jar":{"length":73323,"date":1465435094,"md5":"cd6f5e177d75675607e9523d52e133f7","crc":"9a871cd7"},"/flash/ftp.jar":{"length":9563,"date":1475783634,"md5":"793e460054f07867685e87f98fd402e6","crc":"36fd641e"},"/flash/task.ini":{"length":4311,"date":1433782061,"md5":"b1f877ac198306b266311eab557ed1dd","crc":"36a57579"},"/flash/task.jar":{"length":102655,"date":1434645611,"md5":"1979b16970127f2c38912777cb105133","crc":"ed4d6ad7"},"/flash/jnior.ini":{"length":4874,"date":1512052838,"md5":"90740fe1ddcf0ddf0774c2574e234dfe","crc":"c78e61d7","sha":"76aa475db28479a22e748e6181cf11423988c266"},"/jniorsys.log":{"length":32844,"date":1512145587,"md5":"be4968cceb2fe0b2bebf50daac17d739","crc":"637fb821","sha":"2b6b56f5e3a731b933cf6e1594dfe1e003674d6b"},"/jniorboot.log.bak":{"length":1041,"date":1512074628,"md5":"8261c4f9cd12695626755ba6d1b0b9ad","crc":"03e23ea1","sha":"761a2b3fa74a921778d1c6fc438b5bfd0d51bc29"},"/jniorboot.log":{"length":995,"date":1512145452,"md5":"f053bbba44bea8f6333702fef922d950","crc":"fa976c1c","sha":"c2665669c49028a549a2e30e10b27e8f2aba5861"},"/flash/benchmark.jar":{"length":24351,"date":1464873509,"md5":"987f4044786771f31e0656cf91ed73f3","crc":"1eed095a"},"/flash/threadtest.jar":{"length":3601,"date":1434645124,"md5":"902ce61cbd2524ca9b83dea335c395d3","crc":"cd2479ff"},"/flash/test4to20.jar":{"length":3862,"date":1434659455,"md5":"a2e309c9d6dd112e5303aa76d2470740","crc":"976f8208"},"/flash/dirs.bat":{"length":87,"date":1435691869,"md5":"531d655733ee668d829f9b3bdad96038","crc":"6a11f77a"},"/flash/www/console/index.php":{"length":4347,"date":1438974987,"md5":"8728680bbc36d369429f7ca2c73cce7d","crc":"c939c423"},"/flash/clean.bat":{"length":56,"date":1436532855,"md5":"ac9ce6553e1629412fb426b342440493","crc":"3b661614"},"/flash/jnior1024.key":{"length":887,"date":1437746752,"md5":"b76b5351a92fdcc8d9b6b38ca62d8d71","crc":"7983e14c"},"/flash/www/config/md5.js":{"length":5693,"date":1433505379,"md5":"a60fec5a81f207ff99ec1b97e3ccad0e","crc":"e2a43d16"},"/flash/www/config/node.png":{"length":253,"date":1440435886,"md5":"1a8dbfaf1771a06e48dea0e3dc604392","crc":"799c6dfc"},"/flash/www/config/tabs-styles.css":{"length":970,"date":1477590404,"md5":"68bca7015f51e26ab42199b5eb17a356","crc":"f8870a33"},"/flash/www/config/tabs.js":{"length":3662,"date":1449678641,"md5":"ff728c86018341548ee70028062c89e0","crc":"1a813112"},"/flash/www/config/styles.css":{"length":4450,"date":1504814044,"md5":"9ad78cca1b794dbcf9db3c55f1be5f1b","crc":"acbd2e14","sha":"3cf0bbc864840994a49f62d0ae00df6d8eb47ef3"},"/flash/www/config/comm.js":{"length":3541,"date":1507912287,"md5":"e7d2e56a443176d6150bbcc8b56e1911","crc":"0ac0ed26","sha":"5e66b96227779c5ef3736a7ca891a43cacffbbf1"},"/flash/www/config/console.js":{"length":5137,"date":1504815652,"md5":"33289e4b09f462efdb50e8d30d22d791","crc":"b89fe380","sha":"c2f3ea4fc0344d43b0c30b7f60b2b6c79c1f4817"},"/flash/www/config/config.js":{"length":12639,"date":1507912576,"md5":"75bf22a88d8a23b17de267607b88a14c","crc":"d693e2f4","sha":"cf9e9bcf7cc7d79ae648b241af16ee194199d7b3"},"/flash/www/config/index.php":{"length":22103,"date":1510262716,"md5":"6fe98e5238c5834d55b0140a7172fec6","crc":"81f11698","sha":"b5b440d43bb19da0396e8ab615161be9200e6180"},"/flash/www/jnior.ico":{"length":3262,"date":1439548680,"md5":"1c3b3dda6b10c6259fcf7c068b760f09","crc":"051803eb"},"/flash/www/favicon.ico":{"length":156790,"date":1486410493,"md5":"07cb90c7f3573eff80222269625ed1dd","crc":"7e367afa","sha":"284add71fe3d3ba48fba059b88ff5143d3964b1d"},"/flash/analogpresets.jar":{"length":163902,"date":1441372806,"md5":"25eacc647412535e320302d3680ce327","crc":"e6b656fc"},"/flash/www/config/config.css.php":{"length":1045,"date":1475072901,"md5":"1692861e9abd7f8d81f5b7cf8a176046","crc":"4c386a21"},"/flash/www/config/inputs.png":{"length":18047,"date":1443116143,"md5":"e2151c93b6cdeaa154d15fab486ae61b","crc":"16290877"},"/flash/www/config/loading.gif":{"length":3236,"date":1264096270,"md5":"d96f6517e00399c37a9765e045eaaf22","crc":"16f442ed"},"/flash/jtest.jar":{"length":1832,"date":1511984925,"md5":"89f28d11945790915112f0a4880b6adc","crc":"cf00edbe","sha":"df53eab9f4eb1360c7ab48f30298ce7c48b0e440"},"/flash/www/vendor/angular_1.3.15/angular.min.js":{"length":125909,"date":1449498838,"md5":"ca1a58818682c3e858a585f283ab9beb","crc":"9d8147d7"},"/flash/www/vendor/bootstrap_3.3.0/css/bootstrap-theme.css":{"length":21740,"date":1449498835,"md5":"c64043a3388612233d7eb947918a9bfc","crc":"638f58a3"},"/flash/www/vendor/bootstrap_3.3.0/css/bootstrap-theme.css.map":{"length":41933,"date":1449498838,"md5":"c5da8241305bfe7e19919e6e943739eb","crc":"11260772"},"/flash/www/vendor/bootstrap_3.3.0/css/bootstrap-theme.min.css":{"length":19199,"date":1449498840,"md5":"374df0ad5809a5314b0577802430a272","crc":"8b3c47b7"},"/flash/www/vendor/bootstrap_3.3.0/css/bootstrap.css":{"length":137590,"date":1449498845,"md5":"ad6381ebfa541b55b0152349c6cabf76","crc":"371e67da"},"/flash/www/vendor/bootstrap_3.3.0/css/bootstrap.css.map":{"length":366866,"date":1449498854,"md5":"4ba278e0c420d166e5a0eb71545f9509","crc":"b7c9868d"},"/flash/www/vendor/bootstrap_3.3.0/css/bootstrap.min.css":{"length":114011,"date":1449498852,"md5":"78e7f91c0c4cca415e0683626aa23925","crc":"34387388"},"/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.eot":{"length":20335,"date":1449498855,"md5":"7ad17c6085dee9a33787bac28fb23d46","crc":"f171b590"},"/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.svg":{"length":62926,"date":1449498857,"md5":"ff423a4251cf2986555523dfe315c42b","crc":"385cd4ad"},"/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.ttf":{"length":41280,"date":1449498858,"md5":"e49d52e74b7689a0727def99da31f3eb","crc":"0617f1ff"},"/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.woff":{"length":23320,"date":1449498858,"md5":"68ed1dac06bf0409c18ae7bc62889170","crc":"cec1a35c"},"/flash/www/vendor/bootstrap_3.3.0/js/bootstrap.min.js":{"length":34653,"date":1449498862,"md5":"281cd50dd9f58c5550620fc148a7bc39","crc":"32d6c689"},"/flash/www/vendor/bootstrap_3.3.0/js/bootstrap.js":{"length":65813,"date":1449498862,"md5":"d5a03d9cca57637f008124916b86b585","crc":"f504a7b3"},"/flash/www/vendor/bootstrap_3.3.0/js/npm.js":{"length":484,"date":1449498863,"md5":"ccb7f3909e30b1eb8f65a24393c6e12b","crc":"cc50e34d"},"/flash/www/vendor/jquery_1.11.1/jquery-1.11.1.min.map":{"length":141680,"date":1449498870,"md5":"ffbeb16578d8cdf58104889baacbbef2","crc":"e4e92bfd"},"/flash/www/vendor/jquery_1.11.1/jquery-1.11.1.min.js":{"length":95786,"date":1449498869,"md5":"8101d596b2b8fa35fe3a634ea342d7c3","crc":"804ff984"},"/flash/www/config/integlogo.png":{"length":5773,"date":1449163436,"md5":"9111308273dadea73f5d09a5e02c7311","crc":"60c4e184"},"/flash/utility.jar":{"length":106794,"date":1449773066,"md5":"ac559b91b537dfa70720a416f32f2960","crc":"888936f1"},"/flash/generators/json/colour.js":{"length":4327,"date":1449774238,"md5":"c67e10d0e0e698fcdbbbadcaa55600d4","crc":"19e8a38f"},"/flash/generators/json/ethernet.js":{"length":1409,"date":1449774238,"md5":"1b6bae08feb93f6bd345a3780c3acb69","crc":"848097a7"},"/flash/generators/json/inputs.js":{"length":2825,"date":1449774239,"md5":"6959db5a769ff3ceea45bf606bda940a","crc":"c544d780"},"/flash/generators/json/lists.js":{"length":12006,"date":1449774239,"md5":"5cc489ac77db7a3369b2ffc30cbd3a86","crc":"ba761254"},"/flash/generators/json/logic.js":{"length":4404,"date":1449774239,"md5":"9cd1cf854976ebb69a6c20a7ac88d2f9","crc":"6c2189f9"},"/flash/generators/json/loops.js":{"length":6040,"date":1449774239,"md5":"e8e9021b5d4eb2e0cc43f11ad5b3bfd7","crc":"b30a758a"},"/flash/generators/json/math.js":{"length":14673,"date":1449774240,"md5":"fa22c29efc362e02d8f35838fcca46e5","crc":"8fc62e67"},"/flash/generators/json/other.js":{"length":983,"date":1449774240,"md5":"dd77f555bc9b50ed17a215d7935f10ab","crc":"3e07810d"},"/flash/generators/json/outputs.js":{"length":3861,"date":1449774240,"md5":"72a118cd7829b5a510e5a901d8863d6e","crc":"bdd5e320"},"/flash/generators/json/procedures.js":{"length":3945,"date":1449774240,"md5":"cb9fb880bebb3375273353fafc12dc9c","crc":"20d43aad"},"/flash/generators/json/text.js":{"length":1363,"date":1449774241,"md5":"a0bd39f638202a0800c100b4eac3cbc3","crc":"b17b24d6"},"/flash/generators/json/timing.js":{"length":2638,"date":1449774241,"md5":"b1ee803dd8e6e00de74e0a3269f0a2ff","crc":"489061b8"},"/flash/generators/json/variables.js":{"length":1500,"date":1449774241,"md5":"fecce79a400d5e4e1edbe521699fa604","crc":"cb724c91"},"/flash/generators/json.js":{"length":4115,"date":1449774238,"md5":"cc72f2468eb970110f3f6f0278f43467","crc":"25a98f30"},"/flash/www/config/link_to.png":{"length":259,"date":1450466976,"md5":"b1ed68183be4f97ce1793139496dbbb4","crc":"a067876a"},"/flash/www/config/collapsed.png":{"length":232,"date":1452087215,"md5":"ef7dd392142824ec54b7b7188717411c","crc":"c7bd8428"},"/flash/www/config/linked.png":{"length":174,"date":1452088114,"md5":"56d2755d08a0857ff6e7750c4b2822dd","crc":"ff59187e"},"/flash/www/config/expanded.png":{"length":238,"date":1452097812,"md5":"905b26e96849524dd6c37e1878f66779","crc":"68686921"},"/flash/www/config/registry.js":{"length":8276,"date":1452271284,"md5":"fc35855793b2bbfe577e420f34cb0dda","crc":"6c73e25a"},"/flash/www/config/deletex.png":{"length":240,"date":1452284181,"md5":"2750f1e60d0222d7f3c0752207fb41e7","crc":"386b823b"},"/flash/www/config/modules.js":{"length":13520,"date":1484149578,"md5":"5d79964a8ca70cc7dc0504c343be3e3c","crc":"3c09b9e2","sha":"d6f0b3ec60796662acd105694ef39543e3dc50a2"},"/flash/www/logging.php":{"length":4853,"date":1463582298,"md5":"170c17bd0962f434eebe699129491912","crc":"dce15f4e"},"/flash/www/slaving.zip":{"length":113815,"date":1465493787,"md5":"b3e85080154b5a7dc10078a6c6fe75c7","crc":"975c987e"},"/flash/0-10vtest.jar":{"length":5053,"date":1438104444,"md5":"3a7be82077e29c598bdd8694d47805f4","crc":"05e27897"},"/flash/4routtest.jar":{"length":2993,"date":1373644405,"md5":"14381605ec8f2f0d0dbe34843b7178b8","crc":"8240fc03"},"/flash/environ.jar":{"length":3881,"date":1476102546,"md5":"8d738f0145516d287174a00dda32dabc","crc":"ff1ecc8b"},"/flash/current.key":{"length":898,"date":1455116261,"md5":"035a0d79bd6c8258c12111479fe7353e","crc":"cbdd8ffe"},"/flash/serialtest.jar":{"length":4532,"date":1457448880,"md5":"48fc4bd9421a5cf275b42235d2f4e2cb","crc":"6d86943b"},"/flash/intellij.jar":{"length":969,"date":1464918560,"md5":"aea445862e32190fa61abc5d97e5b25f","crc":"959a1596"},"/flash/jmodule.jar":{"length":5580,"date":1465240063,"md5":"af7d42f427d0e711c4a79c8e1c1d341d","crc":"40058988"},"/flash/udptest.jar":{"length":5811,"date":1465328251,"md5":"5bbc399b4eb1f5ec427ccbf93c8b135d","crc":"3d976325"},"/flash/buffer.jar":{"length":95325,"date":1467321013,"md5":"0c66b2a130de483b64b91d87471eb952","crc":"5d0819e2"},"/flash/display.jar":{"length":2992,"date":1468953410,"md5":"efcfc78470e98842f52579c81c088a2d","crc":"5ec67fd0"},"/flash/rz.jar":{"length":13079,"date":1469638127,"md5":"c4b7e9f4072d64e3dde9fe5a62406a1e","crc":"20367148"},"/flash/www/config/folder.png":{"length":329,"date":1454662486,"md5":"316b7810fa502618b4e85788a82617a8","crc":"55f20187"},"/flash/www/config/file.png":{"length":286,"date":1454662486,"md5":"1b75c23448e9c6eed675404f6130491d","crc":"d327c449"},"/flash/www/config/warning.png":{"length":3068,"date":1332275646,"md5":"9c96d831cfc50fdedfdc980bc2abb2cf","crc":"e90bb05a"},"/flash/www/config/folders.js":{"length":19270,"date":1504815735,"md5":"c7a59ef1aea3aad95d3315627d3a3b29","crc":"6b1adf25","sha":"93d7e851c9a1a65ed45b7c1bbe4368d3d941b32f"},"/flash/clktest.jar":{"length":2616,"date":1470249535,"md5":"345b4a9a22ec05bc89bb291b7b047e0e","crc":"270f1d8b"},"/flash/timesearch.jar":{"length":4180,"date":1471371624,"md5":"bf719e65d8f4be9d7348a621ac69bc2b","crc":"25075aa7"},"/flash/janosruntime_1.5.1.jar":{"length":1621696,"date":1472744987,"md5":"b8beb71b94b36129534ef4d6ec13f5ab","crc":"abc7b327"},"/flash/www/config/relays.js":{"length":4189,"date":1484587793,"md5":"803af5c2431b8f58c110260b3f317838","crc":"ee9ab3af","sha":"21ec766fe220bd0618b43050851f9cd67dd1bf54"},"/flash/www/config/temperature.js":{"length":2870,"date":1475245816,"md5":"262c339513007cd746ee01da9a4a843f","crc":"d062a444"},"/flash/www/config/dimmer.js":{"length":8255,"date":1475265861,"md5":"e7213c6fb8c263ac71acb766e62dc4ce","crc":"b9edf051"},"/flash/www/config/range.css":{"length":2212,"date":1475499110,"md5":"6932c76ab79879ea4c5d826d9cb60db9","crc":"3334dfd1"},"/flash/www/config/analog.js":{"length":7267,"date":1484587793,"md5":"87abcaf68dea5e2e203326a55bc2bca5","crc":"9766b532","sha":"dd788111904d41826164ea151f78dd4b3e3b84e6"},"/flash/www/config/ledon.png":{"length":626,"date":1475506220,"md5":"6018d69896fcba49da54c39d8ee19803","crc":"32a65f15"},"/flash/www/config/panel.js":{"length":2038,"date":1475509052,"md5":"e0631cb06777f63f0a071f7aa5d198d0","crc":"a38a7db3"},"/flash/www/config/ledoff.png":{"length":757,"date":1475509575,"md5":"4bb71e412a20ae6f098a29b195b10e13","crc":"3fd16f7a"},"/flash/jpanel.jar":{"length":3142,"date":1358430294,"md5":"39825ccddf7b61c1ad41d261d84f4950","crc":"446bee7f"},"/flash/www/config/syslog.js":{"length":1929,"date":1496773328,"md5":"4e8ecca50284c2aeae8e8b90db27ded8","crc":"ac2a2541","sha":"e413d70cc2bb6717448bc84c2980abc764bc3dd6"},"/flash/www/config/peers.js":{"length":5885,"date":1505835290,"md5":"2536fc521f916341b98183f6ce0b2453","crc":"f2a44392","sha":"5d949b8daa8e5081f19c88e42af968b24955e02c"},"/flash/www/index.php":{"length":356,"date":1477657721,"md5":"3ba20cf61f44f9ace09104261acf2711","crc":"7f8eaed3"},"/flash/www/www.zip":{"length":85751,"date":1477663620,"md5":"296baa71d70bf40c1ad6ee0c71066c49","crc":"69922bd1"},"/flash/www/download1.php":{"length":465,"date":1480616431,"md5":"1f69c84031dbdbe9aeecd634c0ab9607","sha":"9770a8f6534f17f86eeb332309b7cbe07441022e","crc":"c7b59619"},"/flash/www/short.php":{"length":273,"date":1481120537,"md5":"2fb318c42bd07c0ec34551502bc20c73","sha":"9b9831ca6abda2a14a922e058430fe114b8b34e0","crc":"fbca8ae2"},"/flash/ctrlc.jar":{"length":1510,"date":1482421756,"md5":"b7ce2da5b761674e626ae62c4b9edbcc","sha":"51a17a3f092333a0a48aa8e6dcebe0ce99cef3de","crc":"bd2a0810"},"/flash/www.zip":{"length":87642,"date":1510262835,"md5":"b2cb6f23c2fc91d8f5d79a6e62c5ee10","sha":"a24717087011d3b87b1135ad27556c2337598d98","crc":"df0db0a9"},"/flash/www/config/favicon.ico":{"length":766,"date":1486410493,"md5":"07cb90c7f3573eff80222269625ed1dd","sha":"284add71fe3d3ba48fba059b88ff5143d3964b1d","crc":"7e367afa"},"/flash/www/map.html":{"length":1170,"date":1485380108,"md5":"901c9971c3c591b3d736cd91516960de","sha":"5ded94156ca71884af1afae0fcaf1e78d3bac23d","crc":"71f8c837"},"/flash/jmanifest.jar":{"length":5651,"date":1485192866,"md5":"dfb84226c647a42295d9f671cfb99fa5","sha":"a7331cca377c1f96e400ddd5044c01a175ee230f","crc":"1a64c6d6"},"/flash/jping.jar":{"length":2174,"date":1485201152,"md5":"0d533008847888e0dfcf497c0cff1a96","sha":"75fbff5a973b8dac3408fdda46e47e708b585e58","crc":"f1203f43"},"/flash/jaccess.jar":{"length":4820,"date":1485805203,"md5":"29ce866873686dd133a724e4db29c690","sha":"239bf75c1597a25fdbbbb78798fe72971ca15f63","crc":"e5ae0d1c"},"/flash/somepath/path2/testx.php":{"length":5282,"date":1486397961,"md5":"ce1a071b258c936c65679d6bb67db198","sha":"30342828ebaeb69cd8ecefd75f2dd01e80c6388b","crc":"ecd9251a"},"/flash/bruce_dev.cer":{"length":902,"date":1487172768,"md5":"e9917f27384ddee36817c04c8cde9199","sha":"4b2b82a042a0019679c1b071956278f6ddd1f27b","crc":"115ed2ae"},"/flash/www/config/registrydoc.css":{"length":21460,"date":1504201641,"md5":"15423ca727b03e6b1581910c6ca2eab5","sha":"f521b53a4518e7490768d2a8ae0e707c1dfb943b","crc":"0d5fd8c9"},"/flash/www/config/registrydoc.html":{"length":169108,"date":1509114127,"md5":"e30fe001dfab22c848d1d440f79c96db","sha":"a6edec26f5cbfd249e9f1b3947e92a4766d3bacb","crc":"25c25ccc"},"/flash/www/panel/comm.js":{"length":4715,"date":1498074333,"md5":"44aa80868230fbfeee0a3c48c390896d","sha":"37b479f65e7e8221d6fd9349439a8193cc645ba7","crc":"0d5e92bd"},"/flash/www/panel/index.php":{"length":2648,"date":1501526934,"md5":"923ce6739971521191f9000662f38323","sha":"a35d1d5f24da487be376595b46598e162e0f5310","crc":"ffd86d7b"},"/flash/www/panel/panel.js":{"length":993,"date":1501527049,"md5":"9d9a2cbb435ffe8af5bd9d8c0598dccd","sha":"2ef881dc8d90b4b0fb80a59d717c7125ca23fb04","crc":"4fcd0f37"},"/flash/www/panel/panel.css":{"length":2586,"date":1501527291,"md5":"2a3a66d14d7bc6d4b01dfbd745205c7d","sha":"886770297a07a594b88430d5db4ae9e23738d118","crc":"2dd8a81d"},"/flash/www/graphr.zip":{"length":556637,"date":1506536442,"md5":"891b1dfa8d774b85aefcbd8791abe11f","sha":"e5d204333658bd5c2f7c5b5ff682911124a10766","crc":"62d153fb"},"/flash/public/dcp.zip":{"length":181914,"date":1504795829,"md5":"655e8587293f35f11c5c24fc38201d2f","sha":"5fcfd8e38826e648f98f8d50f3613deb0d6312b6","crc":"da99b7d0"},"/flash/test.txt":{"length":304,"date":1495131459,"md5":"fc9f1f5e67928ccb9be3aeaa66cd9e52","sha":"6100d999f484f98ab476408c801dd000e579a62c","crc":"765047c5"},"/flash/dmx.jar":{"length":4476,"date":1500567859,"md5":"3fd35bbe6bbf53a32aecf273275d1839","sha":"4f702a87adb060294b553e6bd212672727d5d25f","crc":"e81db9aa"},"/flash/juptime.jar":{"length":3201,"date":1506713589,"md5":"d4c2482fae18482727c1b2afabcf94b4","sha":"86268b720b99760a4ebdb803db53f3f7fd18fd18","crc":"44b0878c"},"/flash/jscan.jar":{"length":2189,"date":1507141493,"md5":"a0a42e17f003cedcac9c8e662ada6b36","sha":"f1cafb56fdae33b66fff9b20cd2ff2705d96da9e","crc":"60f00fe2"},"/access.log":{"length":177,"date":1510081848,"md5":"914113dd52c4e74d2675eb1094ba10c6","sha":"0212252f4f04ab136ce74ab0425cd7fce26b7c47","crc":"e9a7f8d8"},"/auxio.log":{"length":1589,"date":1511288557,"md5":"a52713575d5c449ff8e8cdbeb7e10ba6","sha":"22106e83ff429cc08fe16f21dc32623850f5673c","crc":"a29ad191"},"/jniorio.log":{"length":3332,"date":1511289076,"md5":"d3c685fde34b343f2ba53dd60e4bf11d","sha":"dd001970b69d61ab619745853addaf2910aabb31","crc":"1bbc78de"},"/flash/hmi.jar":{"length":8329,"date":1511283865,"md5":"1a1b247ccb5e3eb9623d12578c1ba833","sha":"7a1f5868817e8a3e60fe8fb2c4d9ed168e53d141","crc":"fb2a0367"},"/flash/ckeypad.jar":{"length":11194,"date":1512145569,"md5":"71288ea4ffa40e936dbecfd010fff785","sha":"23f944b627705716697ece761c6c95f8c1f873bb","crc":"3d9fc092"}}

bruce_dev />

So beyond identification header information such as model, serial number, JANOS version and timestamp the last entry files appears to be another JSON Object, That seems to be the database content.

In manifest.json the files element is another JSON Object. So let’s load that and enumerate the keys it contains.

    public static void main(String[] args) throws Exception {
        
        // Obtain Json Object from a file
        Json j = new Json(new File("manifest.json"));
        Json jdb = (Json) j.get("files");
        
        // List top level enties
        Enumeration e = jdb.keys();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
            System.out.println(name);
        }
    }

CODE: SELECT ALL

bruce_dev /> jtest
/etc/janosclasses.jar
/flash/serialcontrol.jar
/flash/serialethernet.jar
/flash/modbusserver.jar
/flash/snmp.jar
/flash/www/base64.js
/flash/www/configure/index.html
/flash/www/jr310applet.jar
/flash/www/jniorprotocol.jar
/flash/www/jniorprotocolhelpers.jar
/flash/www/task/index.html
/flash/www/taskmanagerinterface.jar
/flash/www/jquery/jquery-1.9.0.min.js
/flash/www/jquery/jquery-ui.css
/flash/www/jquery/jquery-ui.min.js
/flash/www/vendor/bowser/bowser_0.7.2.min.js
/flash/www/text
/flash/www/cycle
/flash/slaveservice.jar
/flash/ftp.jar
/flash/task.ini
/flash/task.jar
/flash/jnior.ini
/jniorsys.log
/jniorboot.log.bak
/jniorboot.log
/flash/benchmark.jar
/flash/threadtest.jar
/flash/test4to20.jar
/flash/dirs.bat
/flash/www/console/index.php
/flash/clean.bat
/flash/jnior1024.key
/flash/www/config/md5.js
/flash/www/config/node.png
/flash/www/config/tabs-styles.css
/flash/www/config/tabs.js
/flash/www/config/styles.css
/flash/www/config/comm.js
/flash/www/config/console.js
/flash/www/config/config.js
/flash/www/config/index.php
/flash/www/jnior.ico
/flash/www/favicon.ico
/flash/analogpresets.jar
/flash/www/config/config.css.php
/flash/www/config/inputs.png
/flash/www/config/loading.gif
/flash/jtest.jar
/flash/www/vendor/angular_1.3.15/angular.min.js
/flash/www/vendor/bootstrap_3.3.0/css/bootstrap-theme.css
/flash/www/vendor/bootstrap_3.3.0/css/bootstrap-theme.css.map
/flash/www/vendor/bootstrap_3.3.0/css/bootstrap-theme.min.css
/flash/www/vendor/bootstrap_3.3.0/css/bootstrap.css
/flash/www/vendor/bootstrap_3.3.0/css/bootstrap.css.map
/flash/www/vendor/bootstrap_3.3.0/css/bootstrap.min.css
/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.eot
/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.svg
/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.ttf
/flash/www/vendor/bootstrap_3.3.0/fonts/glyphicons-halflings-regular.woff
/flash/www/vendor/bootstrap_3.3.0/js/bootstrap.min.js
/flash/www/vendor/bootstrap_3.3.0/js/bootstrap.js
/flash/www/vendor/bootstrap_3.3.0/js/npm.js
/flash/www/vendor/jquery_1.11.1/jquery-1.11.1.min.map
/flash/www/vendor/jquery_1.11.1/jquery-1.11.1.min.js
/flash/www/config/integlogo.png
/flash/utility.jar
/flash/generators/json/colour.js
/flash/generators/json/ethernet.js
/flash/generators/json/inputs.js
/flash/generators/json/lists.js
/flash/generators/json/logic.js
/flash/generators/json/loops.js
/flash/generators/json/math.js
/flash/generators/json/other.js
/flash/generators/json/outputs.js
/flash/generators/json/procedures.js
/flash/generators/json/text.js
/flash/generators/json/timing.js
/flash/generators/json/variables.js
/flash/generators/json.js
/flash/www/config/link_to.png
/flash/www/config/collapsed.png
/flash/www/config/linked.png
/flash/www/config/expanded.png
/flash/www/config/registry.js
/flash/www/config/deletex.png
/flash/www/config/modules.js
/flash/www/logging.php
/flash/www/slaving.zip
/flash/0-10vtest.jar
/flash/4routtest.jar
/flash/environ.jar
/flash/current.key
/flash/serialtest.jar
/flash/intellij.jar
/flash/jmodule.jar
/flash/udptest.jar
/flash/buffer.jar
/flash/display.jar
/flash/rz.jar
/flash/www/config/folder.png
/flash/www/config/file.png
/flash/www/config/warning.png
/flash/www/config/folders.js
/flash/clktest.jar
/flash/timesearch.jar
/flash/janosruntime_1.5.1.jar
/flash/www/config/relays.js
/flash/www/config/temperature.js
/flash/www/config/dimmer.js
/flash/www/config/range.css
/flash/www/config/analog.js
/flash/www/config/ledon.png
/flash/www/config/panel.js
/flash/www/config/ledoff.png
/flash/jpanel.jar
/flash/www/config/syslog.js
/flash/www/config/peers.js
/flash/www/index.php
/flash/www/www.zip
/flash/www/download1.php
/flash/www/short.php
/flash/ctrlc.jar
/flash/www.zip
/flash/www/config/favicon.ico
/flash/www/map.html
/flash/jmanifest.jar
/flash/jping.jar
/flash/jaccess.jar
/flash/somepath/path2/testx.php
/flash/bruce_dev.cer
/flash/www/config/registrydoc.css
/flash/www/config/registrydoc.html
/flash/www/panel/comm.js
/flash/www/panel/index.php
/flash/www/panel/panel.js
/flash/www/panel/panel.css
/flash/www/graphr.zip
/flash/public/dcp.zip
/flash/test.txt
/flash/dmx.jar
/flash/juptime.jar
/flash/jscan.jar
/access.log
/auxio.log
/jniorio.log
/flash/hmi.jar
/flash/ckeypad.jar

bruce_dev />

So here we see that there is basically an entry for every file on the JNIOR. The files are defined by their absolute path from the root.

Let’s enumerate the content of the first file entry. I’ll just break in the loop to do one.

    public static void main(String[] args) throws Exception {
        
        // Obtain Json Object from a file
        Json j = new Json(new File("manifest.json"));
        Json jdb = (Json) j.get("files");
        
        // List top level enties
        Enumeration e = jdb.keys();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
            System.out.printf("%s = %s\n", name, jdb.get(name).toString());
            break;
        }
    }
bruce_dev /> jtest
/etc/janosclasses.jar = {"length":243492,"date":1512145376,"md5":"ece8d0ebf9b6882e488d1f7c9e764ce0","crc":"bde463c8","sha":"373b88f011b49f65eafd8e293fc185cc2563892e"}

bruce_dev />

So the file entry is yet another JSON Object/ It looks to contain file information.

Okay. Let’s see what it has to say about the first file.

    public static void main(String[] args) throws Exception {
        
        // Obtain Json Object from a file
        Json j = new Json(new File("manifest.json"));
        Json jdb = (Json) j.get("files");
        
        // Get first entry whatever it is and enumerate it
        Enumeration e = jdb.keys();
        while (e.hasMoreElements()) {
            String name = (String) e.nextElement();
            System.out.println(name);
 
            Json jfile = (Json) jdb.get(name);
            Enumeration efile = jfile.keys();
            while (efile.hasMoreElements()) {
                String name2 = (String) efile.nextElement();
                System.out.printf("   %s = %s\n", name2, jfile.get(name2));
            }            
            
            break;
        }
    }

We see the file size in bytes, some kind of encoded date, and three difference checksums or digests (MD5, CRC, and SHA). The CRC is CRC32 by teh way and SHA is SHA1.

The date is in Unix format GMT timezone.

So that pretty much is the structure of the MANIFEST database. That is a good example of using the JSON format for database storage.

By the way, the JanosClasses.jar file was just changed. The database has an earlier reference. So the date and checksum don’t match. This is how MANIFEST knows to indicate that the file has been “Modified”.

bruce_dev /> manifest etc
JNIOR Manifest      Tue Dec 05 15:26:12 EST 2017
  Size                  MD5                  File Specification
 265756   f26d0f63dd5cc055dad699f117bb4f17  [Modified] /etc/JanosClasses.jar
End of Manifest (1 files listed)

bruce_dev />

We could update our database with a MANIFEST -U command and examine it again. If we did you would see that the MD5 then matches.

 

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));