Quick Start: Securing Connection Through Certificate-Based Authentication (OpenSSL)

This section helps you to quickly get started with using certificate-based authentication to secure the connection between the device and the cloud with OpenSSL.

Before You Start

This step assumes that you have completed the following tutorials.


Create an Edge Gateway Product

This step is almost the same as what you have done in the aforementioned tutorials. The only difference is that you need to enable Certificate Authentication when you create the edge gateway product as shown in the following screenshot.

../_images/edge_ssl.png


The inverter product does not need to have Certificate Authentication enabled because the inverter connects to the EnOS Cloud through EnOS Edge. You only need to enable the authentication for the connection between the edge and the cloud.


Create the Edge Device

Create an edge device instance named Edge01_Certificate based on the product that you just created.

../_images/edge01_certificate.png


Take note of the device triple of the Edge01_Certificate device, which will be used for creating the certificate signing request (CSR). The following device triple is an example for your reference; you will need to use your own.

  • Product Key: Et***YP6
  • Device Key: UB***rOhJD
  • Device Secret: jgWGPE***B7bShf2P5cz


Create the Sub-device

Follow Connecting a Smart Device to EnOS Cloud to create an inverter device as shown in the following figure:

../_images/INV002.png

Step 1: Create the CSR File and Private Key

Use openssl to create a CSR file named edge.csr and a private key named edge.key with the following command:

openssl req -new -newkey rsa:2048 -out edge.csr -keyout edge.key -subj /C=CN/ST=Shanghai/L=Shanghai/O=EnOS/OU="Edge Service"/CN="UB***rOhJD" -passout pass:123456  -sha256 -batch
  • The CSR file is used for requesting the certificate from EnOS Cloud.
  • The private key is used for decrypting the data that is encrypted by the certificate.


For the guidelines to create an CSR file, see Creating your Certificate Signing Request (CSR) file.

Step 2: Invoke REST API to Request for Certificate

After the CSR file edge.csr is created, invoke the relevant EnOS API to request for the certificate.

  1. In the POM of your Java project, add the following Maven dependency:

    <dependency>
     <groupId>com.envisioniot</groupId>
     <artifactId>enos-dm-api-pojo</artifactId>
     <version>0.2.23</version>
    </dependency>
    
  2. Use the following code snippet to call EnOS API to apply for a certificate

import com.envision.apim.poseidon.config.PConfig;
import com.envision.apim.poseidon.core.Poseidon;
import com.envisioniot.enos.connect_service.v2_1.cert.ApplyCertificateRequest;
import com.envisioniot.enos.connect_service.v2_1.cert.ApplyCertificateResponse;
import com.envisioniot.enos.connect_service.vo.DeviceIdentifier;


import java.io.*;
import java.security.*;
import java.security.cert.CertificateException;



public class applyCert {

  // ISSUE_AUTHORITY indicates the certificate type. Possible values are RSA and ECC.
   public static final String ISSUE_AUTHORITY = "ECC";
  // VALID_DAY indicates the validity period of the certificate.
   public static final Integer VALID_DAY = 300;

  /**
   * Information needed for device authentication: the device key, product key of the device.
   */
   public static final String DEVICE_KEY = "xIhSzeP6lh";
   public static final String PRODUCT_KEY = "rHbNES3c";

   /**
    * The access key and secret key of an application registered on EnOS, used for calling EnOS API. You can find the keys in Application Registration on EnOS Management Console.
    */
   public static final String ACCESS_KEY = "2e0b21b7-1b51-46a5-b501-c3824331b8df";
   public static final String SECRET_KEY = "46e715d8-3c38-4cb6-9d65-b0bdad1ffe89";
  // The URL of the API gateway. You can find it in Help > Environment Information in EnOS Management Console.
   public static final String API_GATEWAY_URL = "https://apim-ppe1.envisioniot.com";
  /**
   * Organization ID. Mouse over the OU name to obtain it in EnOS Management Console.
   */
   public static final String ORG_ID = "o15724268424841";

   /**
    * The following parameters are used to save the generated files:
    * SAVE_CSR_FILE_PATH: The CSR file
    * SAVE_DEVICE_CERT_FILE_PATH: The certificate requested
    * SAVE_ROOT_CERT_FILE_PATH: The root certificate
    */
   public static final String SAVE_CSR_FILE_PATH = "edge.csr";
   public static final String SAVE_DEVICE_CERT_FILE_PATH = "edge.pem";
   public static final String SAVE_ROOT_CERT_FILE_PATH = "cacert.pem";

   private static void applyCertToDevice() throws IOException {
      // Read the generated CSR file
       String certificateRequest = readFile(SAVE_CSR_FILE_PATH);
      // Configure the parameter of the request to bind the certificate to the device
       ApplyCertificateRequest applyCertificateRequest = createApplyCertParam(certificateRequest);
      // Make a request using EnOS API
       ApplyCertificateResponse certRsp =
               Poseidon.config(PConfig.init().appKey(ACCESS_KEY).appSecret(SECRET_KEY).debug())
                       .url(API_GATEWAY_URL)
                       .getResponse(applyCertificateRequest, ApplyCertificateResponse.class);
      // Obtain the certificate and the root certificate of the device
       if (certRsp.success()) {
          // Save the device certificate
           saveFile(certRsp.getData().getCert(), SAVE_DEVICE_CERT_FILE_PATH);
          // Save the root certificate
           saveFile(certRsp.getData().getCaCert(), SAVE_ROOT_CERT_FILE_PATH);
       }
   }
  /**
   * Read CSR file
   */
   private static String readFile(String path) {
       try (InputStream inputStream = new FileInputStream(path);
            Reader inputStreamReader = new InputStreamReader(inputStream);
            BufferedReader reader = new BufferedReader(inputStreamReader)) {
           StringBuilder sb = new StringBuilder();
           String line;
           while ((line = reader.readLine()) != null) {
               sb.append(line).append("\n");
           }
           return sb.toString();
       } catch (IOException e) {
           e.printStackTrace();
       }
       return "";
   }


   private static ApplyCertificateRequest createApplyCertParam(String certificateRequest) {
       ApplyCertificateRequest applyCertificateRequest = new ApplyCertificateRequest();
       applyCertificateRequest.setCsr(certificateRequest);
      /*
       * Make sure the value of ISSUE_AUTHORITY is consistent with the CSR certificate type.
       */
       applyCertificateRequest.setIssueAuthority(ISSUE_AUTHORITY);
      /*
       * Make sure the validity period of the certificate is less than the maximum validity period of the device.
       */
       applyCertificateRequest.setValidDay(VALID_DAY);
      /*
       * Device identity
       */
       DeviceIdentifier deviceIdentifier = new DeviceIdentifier();
      /*
       * Use one of the following methods to identify a device:
       * ASSET_ID
       * PRODUCT_KEY + DEVICE_KEY
       */
       deviceIdentifier.setKey(PRODUCT_KEY, DEVICE_KEY);
       applyCertificateRequest.setDevice(deviceIdentifier);
       applyCertificateRequest.setOrgId(ORG_ID);
       return applyCertificateRequest;
   }
   public static void main(String[] args) throws NoSuchAlgorithmException, CertificateException, SignatureException, InvalidKeyException, IOException, KeyStoreException {
      //Generate certificate
       applyCertToDevice();
  }

  /*
   * Save the certificate
   */
   public static void saveFile(String fileContent, String filePath) throws IOException {
       File fp = new File(filePath);
       try (OutputStream os = new FileOutputStream(fp)) {
           os.write(fileContent.getBytes());
       }
   }
 }

Step 3: Use Keytool to Generate the JKS File

Run the following commands to generate the edge.jks file with keytool, which is a built-in Java tool whose PATH is %JAVA_HOME%\bin\keytool.

a. Check file

[root@DemoMachine cert]# ll
total 12
-rw-r--r-- 1 root root 1395 Nov 28 19:51 cacert.pem
-rw-r--r-- 1 root root 1858 Nov 28 19:51 edge.key
-rw-r--r-- 1 root root 1416 Nov 28 20:08 edge.pem

b. Export the certificate and private key as a .p12 file

[root@DemoMachine cert]# openssl pkcs12 -export -in edge.pem -inkey edge.key -out edge.p12 -name edge -CAfile cacert.pem -caname cacert
Enter pass phrase for edge.key:
Enter Export Password:
Verifying - Enter Export Password:

c. Check the generated .p12 file

[root@DemoMachine cert]# ll
total 16
-rw-r--r-- 1 root root 1395 Nov 28 19:51 cacert.pem
-rw-r--r-- 1 root root 1858 Nov 28 19:51 edge.key
-rw-r--r-- 1 root root 2654 Nov 28 20:19 edge.p12
-rw-r--r-- 1 root root 1416 Nov 28 20:08 edge.pem

d. Import the .p12 file into the keystore

[root@DemoMachine cert]# keytool -importkeystore -deststorepass 123456 -destkeypass 123456 -destkeystore edge.jks -srckeystore edge.p12 -srcstoretype PKCS12 -srcstorepass 123456 -alias edge
Importing keystore edge.p12 to edge.jks...

Warning:
The JKS keystore uses a proprietary format. You are recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore edge.jks -destkeystore edge.jks -deststoretype pkcs12".

e. Check the JKS file

[root@DemoMachine cert]# ll
total 20
-rw-r--r-- 1 root root 1395 Nov 28 19:51 cacert.pem
-rw-r--r-- 1 root root 2356 Nov 28 20:20 edge.jks
-rw-r--r-- 1 root root 1858 Nov 28 19:51 edge.key
-rw-r--r-- 1 root root 2654 Nov 28 20:19 edge.p12
-rw-r--r-- 1 root root 1416 Nov 28 20:08 edge.pem

f. Verify that the JSK has one trusted certificate entry

[root@DemoMachine cert]# keytool -list --keystore edge.jks
Enter keystore password:
Keystore type: jks
Keystore provider: SUN

Your keystore contains 1 entry

edge, Nov 28, 2018, PrivateKeyEntry,
Certificate fingerprint (SHA1): 38:16:5A:1F:1D:68:44:44:FE:56:1A:84:36:31:85:CB:14:5B:9C:5E

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore edge.jks -destkeystore edge.jks -deststoretype pkcs12".

g. Import the cacert root certificate into the keystore

[root@DemoMachine cert]# keytool -import -trustcacerts -alias cacert -file cacert.pem -keystore edge.jks -storepass 123456
Owner: EMAILADDRESS=ca@eniot.io, CN=EnOS CA, OU=EnOS CA, O=EnOS, L=Shanghai, ST=Shanghai, C=CN
Issuer: EMAILADDRESS=ca@eniot.io, CN=EnOS CA, OU=EnOS CA, O=EnOS, L=Shanghai, ST=Shanghai, C=CN
Serial number: 8c54a99157c8ef28
Valid from: Mon Nov 19 18:20:27 CST 2018 until: Thu Nov 16 18:20:27 CST 2028
Certificate fingerprints:
     MD5:  4E:BF:2A:53:85:1E:21:97:70:72:AD:DF:A5:79:51:3F
     SHA1: 96:BC:6B:F0:15:CD:BB:03:52:12:A2:C6:C4:BD:20:69:71:4A:75:C2
     SHA256: 81:B0:E3:01:D3:2B:48:E7:CF:CC:BC:07:9A:AD:49:74:EF:92:97:A1:D4:46:E2:4E:56:94:14:32:A7:09:FA:9F
Signature algorithm name: SHA256withRSA
Subject Public Key Algorithm: 2048-bit RSA key
Version: 3

Extensions:

#1: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: AE 4F F7 AF A7 19 7B 0B   AE 2E 79 0F B4 7B E5 AE  .O........y.....
0010: 8C F4 54 0D                                        ..T.
]
]

#2: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:true
  PathLen:2147483647
]

#3: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: AE 4F F7 AF A7 19 7B 0B   AE 2E 79 0F B4 7B E5 AE  .O........y.....
0010: 8C F4 54 0D                                        ..T.
]
]

Trust this certificate? [no]:  yes
Certificate was added to keystore

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore edge.jks -destkeystore edge.jks -deststoretype pkcs12".

h. Verify that the JKS has two trusted certificate entries

[root@DemoMachine cert]# keytool -list --keystore edge.jks
Enter keystore password:
Keystore type: jks
Keystore provider: SUN

Your keystore contains 2 entries

cacert, Nov 28, 2018, trustedCertEntry,
Certificate fingerprint (SHA1): 96:BC:6B:F0:15:CD:BB:03:52:12:A2:C6:C4:BD:20:69:71:4A:75:C2
edge, Nov 28, 2018, PrivateKeyEntry,
Certificate fingerprint (SHA1): 38:16:5A:1F:1D:68:44:44:FE:56:1A:84:36:31:85:CB:14:5B:9C:5E

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore edge.jks -destkeystore edge.jks -deststoretype pkcs12".
[root@DemoMachine cert]#

Step 4: Use SDK to Connect to EnOS


You can use either MQTT SDK or HTTP SDK to connect.

MQTT SDK

Add the following Maven dependency to your Java project. The version of the MQTT SDK must be 2.2.5 or later.

<dependency>
    <groupId>com.envisioniot</groupId>
    <artifactId>enos-mqtt</artifactId>
    <version>2.2.16</version>
</dependency>


The code sample to connect EnOS Edge to EnOS is as follows. Replace the code snippet in Step 5 of Connecting a Non-smart Device to EnOS Cloud via Edge.

public static boolean IS_ECC_CONNECT = true; //The value of this parameter is false for RSA certificate and true for ECC certificate.
public static final String DEVICE_KEY = "yourDeviceKey";
public static final String PRODUCT_KEY = "yourProductKey";
public static final String DEVICE_SECRET = "yourDeviceSecret";
public static final String JKS_PASSWORD = "yourJksPassword";
public static final String JKS_FILE_NAME = "edge.jks";
public static final String SSL_CONNECT_URL = "ssl://MqttBrokerUrl:18883";


private static void connectEnos() {
    DefaultProfile defaultProfile = new DefaultProfile(SSL_CONNECT_URL, PRODUCT_KEY, DEVICE_KEY,DEVICE_SECRET);
    // Configure the connection
    defaultProfile.setConnectionTimeout(60).setKeepAlive(180).setAutoReconnect(false)
            .setSSLSecured(true)
            // Configure bi-directional authentication, the JKS file and password
            .setSSLJksPath(JKS_FILE_NAME, JKS_PASSWORD)
            // Configure whether to use ECC certificate to connect to EnOS
            .setEccConnect(IS_ECC_CONNECT);
    final MqttClient mqttClient = new MqttClient(defaultProfile);
    mqttClient.connect(new ConnCallback() {
        @Override
        public void connectComplete(boolean reconnect) {
            System.out.println("connect success");
        }

        @Override
        public void connectLost(Throwable cause) {
            System.out.println("connect lost");
        }

        @Override
        public void connectFailed(Throwable cause) {
            System.out.println("onConnectFailed : " + cause);
        }
    });
}

HTTP SDK

Add the following Maven dependency to your Java project. The version of the HTTP SDK must be 0.1.9 or later.

<dependency>
    <groupId>com.envisioniot</groupId>
    <artifactId>enos-http</artifactId>
    <version>0.2.1</version>
</dependency>


The code sample to connect EnOS Edge to EnOS is as follows. Replace the code snippet in Step 5 of Connecting a Non-smart Device to EnOS Cloud via Edge.

public class HttpBiDirectionalAuthenticate {
    // EnOS HTTP Broker URL, which can be obtained from Environment Information page in EnOS Console
    // ssl port 8443
    static final String BROKER_URL = "https://broker_url:8443/";

    // Device credentials, which can be obtained from Device Details page in EnOS Console
    static final String PRODUCT_KEY = "productKey";
    static final String DEVICE_KEY = "deviceKey";
    static final String DEVICE_SECRET = "deviceSecret";

    private static String jksPath = "jskPath";
    private static String jksPassword = "jskPassword";

    /** Ecc cert flag
     * if use ECC certificate, chose true
     * if use RSA certificate, chose false */
    static final boolean IS_ECC_CONNECT = false;

    public static void main(String[] args) throws EnvisionException {
        // construct a static device credential via ProductKey, DeviceKey and DeviceSecret
        StaticDeviceCredential credential = new StaticDeviceCredential(
                PRODUCT_KEY, DEVICE_KEY, DEVICE_SECRET);

        // construct a http connection
        SessionConfiguration configuration = SessionConfiguration
                .builder()
                .lifetime(30_000)
                .sslSecured(true)
                .isEccConnect(IS_ECC_CONNECT)
                .jksPath(jksPath)
                .jksPassword(jksPassword)
                .build();

        HttpConnection connection = new HttpConnection.Builder(BROKER_URL, credential)
                .sessionConfiguration(configuration)
                .build();

        MeasurepointPostRequest request = buildMeasurepointPostRequest();

        try
        {
            MeasurepointPostResponse response = connection.publish(request, null);
            System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(response));
        } catch (EnvisionException | IOException e)
        {
            e.printStackTrace();
        }
    }

    private static MeasurepointPostRequest buildMeasurepointPostRequest()
    {
        // Measurepoints are defined in ThingModel
        return MeasurepointPostRequest.builder()
                .addMeasurePoint("Int_value", 100)
                .addMeasurePoint("DI_value_01", 5)
                .build();
    }
}

Step 5: Start the Sample Program

Run the code snippet in the previous step after you have replaced the original one in Connecting a Non-smart Device to EnOS Cloud via Edge.

Step 6: Check the Device Connection Status

After you run the sample program, the edge device logs in and adds sub-devices into its topology, and proxies the sub-devices to connect to the cloud. The device connection status is shown in the following figure:

../_images/device_list.png

Step 7: Check Device Data

Go to the console, select Device Management > Device Assets, click the view icon go to Device Details, open the Measurement Points tab, select a measurement point, and click the View Data icon to check the historical data records.