diff --git a/GUIDE.md b/GUIDE.md index 7a3a1a8..dd69d88 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -6,7 +6,7 @@ All setup commands assume you are starting in the project's root directory. 1. Bootstrap - Install the [java](https://openjdk.java.net/), [maven](https://maven.apache.org/), and [ace-java](https://bitbucket.org/marco-tiloca-sics/ace-java) packages: + Install the required packages ([java](https://openjdk.java.net/), [maven](https://maven.apache.org/)): ```bash ./script/bootstrap.sh @@ -14,117 +14,142 @@ All setup commands assume you are starting in the project's root directory. 2. Build - Run unit tests and build the OT Registrar JAR package: + Build and run unit tests for the OT Registrar JAR package: ```bash mvn package ``` - To skip the tests: + Or, to skip the tests: ```bash mvn -DskipTests package ``` - This creates a JAR file at `target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar`. + Either of these creates a JAR file at `target/ot-registrar-0.3-jar-with-dependencies.jar`. ## Run services -The OT Registrar JAR file includes the Registrar, TBD [MASA](https://tools.ietf.org/id/draft-ietf-anima-bootstrapping-keyinfra-16.html#rfc.section.1.2) server, and a simulated [Pledge](https://tools.ietf.org/id/draft-ietf-anima-bootstrapping-keyinfra-16.html#rfc.section.1.2). +The OT Registrar JAR file includes the Registrar, MASA server, and a simulated Pledge. These 3 components are sufficient to do a test run of the system. ### Credentials To run the registrar or MASA server, we need a structured keystore file (in PKCS#12 format) containing the credentials. -See [credentials/README.md](credentials/README.md) for details on how to generate credentials. For this guide, we'll use the -`threadgroup-5f9d307c.p12` credentials provided with OT Registrar. +Details on how to generate credentials will be added at a later time. For this guide, we'll use +credentials provided with OT Registrar in the `credentials` directory. ### Run the registrar -Start the registrar at port 5684, using the `threadgroup-5f9d307c.p12` credentials: +Start the registrar at default CoAPS port 5684, using the default credentials: ```bash -java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.registrar.RegistrarMain -d Thread -f credentials/threadgroup-5f9d307c.p12 -p 5684 +$ ./script/run -registrar ``` Use the `-h` option to learn what arguments are available: -```bash -java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.registrar.RegistrarMain -h -# usage: registrar -d -f -p -# -d,--domainname the domain name -# -f,--file the keystore file in PKCS#12 format -# -h,--help print this message -# -p,--port the port to listen on -# -v,--verbose verbose mode with many logs +```text +$ ./script/run -h +usage: [-registrar | -masa | -pledge] [-h] [-v] [-d ] [-f + ] [-p ] + -d,--domainname the domain name + -f,--keyfile the keystore file in PKCS#12 format + -h,--help print this message + -m,--masaUri force the given MASA URI instead of + the default one + -masa start as cBRSKI/BRSKI MASA + -p,--port the server CoAPS or HTTPS port to + listen on + -pledge start as cBRSKI Pledge + -r,--registrarUri for a Pledge, the Registrar to + connect to + -registrar start as cBRSKI Registrar + -v,--verbose verbose mode with many logs ``` ### Run the MASA server -Start the MASA server at port 5685, using the `threadgroup-5f9d307c.p12` credentials: - -```bash -java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.masa.MASAMain -f credentials/threadgroup-5f9d307c.p12 -p 5685 -``` - -Use the `-h` option to learn what arguments are available: +Start the MASA server in another window or tab at port 9443, using the default credentials: ```bash -java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.masa.MASAMain -h -# usage: masa -a -f -p -# -a,--alias the masa keystore alias -# -f,--file the keystore file in PKCS#12 format -# -h,--help print this message -# -p,--port the port to listen on -# -v,--verbose verbose mode with many logs +$ ./script/run -masa -p 9443 +... ``` ### Run the pledge Use a simulated pledge to test the Registrar. -Start the pledge: +Start the pledge in another shell window or tab, connecting to a specific host and port where the Registrar is expected: ```bash -java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.pledge.PledgeMain -f credentials/threadgroup-5f9d307c.p12 -r "[::1]:5684" -# ... -# > +$ ./script/run -pledge -r "[::1]:5684" +... ``` The pledge enters interactive mode and waits for user commands. Press **Enter** or type `help` to get a list of all available commands: ```text > help -token - request commissioning token -rv - request voucher -attrs - request CSR attributes -enroll - simple enrollment -reenroll - simple reenrollment -reset - reset to initial state +rv - request voucher to Registrar (cBRSKI) +enroll - simple enrollment with Registrar (EST) +reenroll - simple reenrollment with Registrar (EST) +reset - reset Pledge to initial state exit - exit pledge CLI help - print this help message - -done +Done > ``` Use the `exit` command to exit or **Ctrl+c** to force exit. -### Run the Thread Registrar Interface (TRI) +Use `rv` to let the Pledge attempt a cBRSKI Voucher Request: -A TRI is needed to connect Thread devices with a registrar. Please see the [TRI project](https://bitbucket.org/threadgroup/tce-registrar-java) for instructions. +```text +> rv +19:30:24.606 [DTLS-Connection-Handler-5] INFO com.google.openthread.pledge.PledgeCertificateVerifier - registrar provisionally accepted without verification! +Done +``` -> Note: Only Thread Group members can access the TRI project. +Now the Voucher is obtained from MASA, via the Registrar. Mutual trust is established for the active DTLS connection. Use `enroll` to perform the EST-CoAPS enrollment: -There is script [script/run-servers.sh](script/run-servers.sh) that starts all those servers in the background with the default arguments. +```text +> enroll +19:34:58.825 [main] INFO com.google.openthread.pledge.Pledge - enrolled with operational certificate, subject: C=US,ST=CA,L=San Ramon,O=TestVendor,2.5.4.5=#130a41383544333330303031,CN=TestVendor IoT device +19:34:58.827 [main] INFO com.google.openthread.pledge.Pledge - operational certificate (PEM): +-----BEGIN CERTIFICATE----- +MIICEDCCAbegAwIBAgIBAzAKBggqhkjOPQQDAjBTMREwDwYDVQQDDAhkb21haW5j +YTETMBEGA1UECwwKT3BlblRocmVhZDEPMA0GA1UECgwGR29vZ2xlMQswCQYDVQQH +DAJTSDELMAkGA1UEBhMCQ04wHhcNMjQwODI4MTkzNDU4WhcNMjkwODI3MTkzNDU4 +WjB4MR4wHAYDVQQDDBVUZXN0VmVuZG9yIElvVCBkZXZpY2UxEzARBgNVBAUTCkE4 +NUQzMzAwMDExEzARBgNVBAoMClRlc3RWZW5kb3IxEjAQBgNVBAcMCVNhbiBSYW1v +bjELMAkGA1UECAwCQ0ExCzAJBgNVBAYTAlVTMFkwEwYHKoZIzj0CAQYIKoZIzj0D +AQcDQgAEGwAmAr657PJ63qBg2axjNTK0FhT0pI11qn5mUq6TQFF6RjU22zqqbJZl +a7EbDmVRouS+6jIM/8yycqE2NrwQ3aNXMFUwCQYDVR0TBAIwADAfBgNVHSMEGDAW +gBSe2sIzlf9yKOt9rsh9GC356FdvVzAnBgNVHREEIDAeoBwGCSsGAQQBgt8qAaAP +Fg1EZWZhdWx0RG9tYWluMAoGCCqGSM49BAMCA0cAMEQCIDD63H5wYJVvo+sKgt3S +U38XMON3cYz/5KlF1PmxnmJjAiBKujydxak63+L2aZB/H3YoYq0M53xRQMRUGRku +75pjeg== +-----END CERTIFICATE----- + +19:34:58.829 [main] INFO com.google.openthread.pledge.Pledge - operational private key (PEM): +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIPPqdOhhBgm/RdVsd4SVQ2g3/U4KVC2mtP2RzCbgL0oNoAoGCCqGSM49 +AwEHoUQDQgAEGwAmAr657PJ63qBg2axjNTK0FhT0pI11qn5mUq6TQFF6RjU22zqq +bJZla7EbDmVRouS+6jIM/8yycqE2NrwQ3Q== +-----END EC PRIVATE KEY----- + +Done +``` ## The Docker service -You can use `script/run-servers.sh` to run all services in a local host. To avoid having to frequently start and stop all three servers, OT Registrar provides a Docker image to start all services with a single command. +You can use `script/run-servers.sh` to run both Registrar and MASA on the local host. To avoid having to frequently start and stop servers, OT Registrar provides a Docker image to start all services with a single command. _**Note:** Only supported on Linux._ -1. Complete the [setup](#setup) if you haven't already. +1. Do the bootstrap script if you haven't already. 2. Build the Docker image: @@ -132,8 +157,8 @@ _**Note:** Only supported on Linux._ ./script/build-docker-image.sh ``` -3. Start all services: +3. Start all services in a Docker: ```bash - ./script/start-services.sh + ./script/start-service.sh ``` diff --git a/README.md b/README.md index 7ea1e0a..a6b1ff7 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Contributors are required to abide by our [Code of Conduct](CODE_OF_CONDUCT.md). ## Versioning +Release notes for versions are kept in MD files in [releases](releases). OT Registrar follows the [Semantic Versioning guidelines](http://semver.org/) for release cycle transparency and to maintain backwards compatibility. OT Registrar's versioning is independent of the Thread protocol specification version. ## License diff --git a/credentials/keystore_ietf-draft-constrained-brski.p12 b/credentials/ietf-draft-constrained-brski/credentials.p12 similarity index 100% rename from credentials/keystore_ietf-draft-constrained-brski.p12 rename to credentials/ietf-draft-constrained-brski/credentials.p12 diff --git a/credentials/local-masa/test_credentials.p12 b/credentials/local-masa/credentials.p12 similarity index 100% rename from credentials/local-masa/test_credentials.p12 rename to credentials/local-masa/credentials.p12 diff --git a/credentials/siemens-masa/test_credentials.p12 b/credentials/siemens-masa/credentials.p12 similarity index 100% rename from credentials/siemens-masa/test_credentials.p12 rename to credentials/siemens-masa/credentials.p12 diff --git a/pom.xml b/pom.xml index 3473622..e5d3662 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.google.openthread ot-registrar - 0.2 + 0.3 OT Registrar https://openthread.io/ @@ -94,12 +94,6 @@ 2.2.8.Final - - com.fazecast - jSerialComm - [2.0.0,3.0.0) - - diff --git a/releases/ot-registrar-0.2-readme.md b/releases/ot-registrar-0.2-readme.md new file mode 100644 index 0000000..aea1051 --- /dev/null +++ b/releases/ot-registrar-0.2-readme.md @@ -0,0 +1,22 @@ +# OT Registrar 0.2 + +This is the Registrar, MASA and Pledge release optimized for testing the cBRSKI protocol. +See [cBRSKI draft](https://datatracker.ietf.org/doc/html/draft-ietf-anima-constrained-voucher-25). +It is an initial release made in July 2024 by IoTconsultancy.nl. + +## Platform + +Written in Java, the registrar runs where Java does: + +- Linux +- Windows +- macOS +- Raspberry Pi + +## Certificates / Credentials + +Various sets of credentials for testing are present in the `credentials` directory. + +### Hosted Resources of the MASA and Registrar. + +Details can be found in the cBRSKI draft. diff --git a/releases/ot-registrar-0.3-readme.md b/releases/ot-registrar-0.3-readme.md new file mode 100644 index 0000000..89f8817 --- /dev/null +++ b/releases/ot-registrar-0.3-readme.md @@ -0,0 +1,23 @@ +# OT Registrar 0.3 + +This is the Registrar, MASA and Pledge release optimized for testing the cBRSKI protocol. +See [cBRSKI draft](https://datatracker.ietf.org/doc/html/draft-ietf-anima-constrained-voucher-25). +It is a follow-up release made in TBD 2024 by IoTconsultancy.nl for testing cBRSKI Thread devices +in a Github branch of the [OTNS2 simulator](https://github.com/EskoDijk/ot-ns). + +## Platform + +Written in Java, the registrar runs where Java does: + +- Linux +- Windows +- macOS +- Raspberry Pi + +## Certificates / Credentials + +Various sets of credentials for testing are present in the `credentials` directory. + +### Hosted Resources of the MASA and Registrar. + +Details can be found in the cBRSKI draft. diff --git a/script/build.sh b/script/build.sh new file mode 100755 index 0000000..7d46d79 --- /dev/null +++ b/script/build.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# +# Copyright (c) 2024, The OpenThread Registrar Authors. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the copyright holder nor the +# names of its contributors may be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +mvn package -DskipTests diff --git a/script/create-keystore-ietf-draft-constrained-brski.sh b/script/create-keystore-ietf-draft-constrained-brski.sh old mode 100644 new mode 100755 diff --git a/script/helper-cp-run.sh b/script/helper-cp-run.sh index 60dd104..4cffac8 100755 --- a/script/helper-cp-run.sh +++ b/script/helper-cp-run.sh @@ -27,7 +27,7 @@ # POSSIBILITY OF SUCH DAMAGE. # -readonly JAR_FILE=./target/ot-registrar-0.2-jar-with-dependencies.jar +readonly JAR_FILE=./target/ot-registrar-0.3-jar-with-dependencies.jar # test if OT Registrar JAR exists if [ ! -f "${JAR_FILE}" ]; then diff --git a/script/run b/script/run index 5002bec..421731c 100755 --- a/script/run +++ b/script/run @@ -27,11 +27,11 @@ # POSSIBILITY OF SUCH DAMAGE. # -readonly JAR_FILE=./target/ot-registrar-0.2-jar-with-dependencies.jar +readonly JAR_FILE=./target/ot-registrar-0.3-jar-with-dependencies.jar # test if OT Registrar JAR exists if [ ! -f "${JAR_FILE}" ]; then - echo "Please build using 'mvn -DskipTests package' before running." + echo "Please build project using 'mvn -DskipTests package' before running." exit 1 fi diff --git a/src/main/java/com/google/openthread/brski/StatusTelemetry.java b/src/main/java/com/google/openthread/brski/StatusTelemetry.java index b9c9147..8a0b7ac 100644 --- a/src/main/java/com/google/openthread/brski/StatusTelemetry.java +++ b/src/main/java/com/google/openthread/brski/StatusTelemetry.java @@ -57,8 +57,7 @@ public class StatusTelemetry { public String parseResultStatus = ""; /** - * stores the CBOR object as sent by the Pledge, for reference. Null if couldn't be parsed as - * CBOR. + * stores the CBOR object as sent by the Pledge, for reference. Null if it couldn't be parsed as CBOR. */ public CBORObject cbor = null; @@ -67,13 +66,11 @@ protected StatusTelemetry() { } /** - * Create a new StatusTelemetry object with given state info. This is useful to serialize it to - * CBOR or byte[]. + * Create a new StatusTelemetry object with given state info. * * @param isSuccess true if status should indicate success, false otherwise. - * @param reason required human-readable failure reason if isSuccess==false, should be null - * otherwise (but not necessarily). - * @return + * @param reason required human-readable failure reason if isSuccess==false, should be null otherwise (but not necessarily). + * @return New StatusTelemetry object. */ public static StatusTelemetry create(boolean isSuccess, String reason) { StatusTelemetry st = new StatusTelemetry(); @@ -108,16 +105,16 @@ public byte[] serializeToBytes() { } /** - * Deserialize a status telemetry report from CBOR bytes. In case of invalid 'data', i.e. invalid - * CBOR format or invalid report format, flags in the StatusTelemetry object are set to indicate - * this. + * Deserialize a status telemetry report from CBOR bytes. In case of invalid 'data', i.e. invalid CBOR + * format or invalid report format, flags in the StatusTelemetry object are set to indicate this. * - * @param data CBOR bytes - * @return new StatusTelemetry object + * @param data CBOR bytes of an encoded status telemetry object + * @return New StatusTelemetry object */ public static StatusTelemetry deserialize(byte[] data) { StatusTelemetry st = new StatusTelemetry(); st.isValidFormat = true; + try { CBORObject stCbor = CBORObject.DecodeFromBytes(data); if (stCbor == null @@ -166,11 +163,23 @@ public static StatusTelemetry deserialize(byte[] data) { } // evaluate more cases of invalid format. - if (st.status == false && (st.reason == null || st.reason.length() == 0)) { + if (st.isValidFormat && !st.status && (st.reason == null || st.reason.length() == 0)) { st.isValidFormat = false; st.parseResultStatus = "'reason' field must be provided if status==false"; } return st; } + + public String toString() { + String s = "{status=" + this.status; + if (reason != null) { + s += ", reason=" + reason; + } + if (!this.isValidFormat){ + s += " (INVALID: " +this.parseResultStatus+ ")"; + } + s += "}"; + return s; + } } diff --git a/src/main/java/com/google/openthread/registrar/Registrar.java b/src/main/java/com/google/openthread/registrar/Registrar.java index 7df140a..7ec926c 100644 --- a/src/main/java/com/google/openthread/registrar/Registrar.java +++ b/src/main/java/com/google/openthread/registrar/Registrar.java @@ -231,32 +231,21 @@ public void handlePOST(CoapExchange exchange) { // TODO: check latest draft to see if JSON support is mandatory here. if (contentFormat != ExtendedMediaTypeRegistry.APPLICATION_CBOR) { - logger.warn( - "unsupported content-format for voucher status report: content-format=" - + contentFormat); - exchange.respond( - ResponseCode.UNSUPPORTED_CONTENT_FORMAT, + logger.warn("unsupported content-format for voucher status report: content-format=" + contentFormat); + exchange.respond(ResponseCode.UNSUPPORTED_CONTENT_FORMAT, "Only Content Format " + ExtendedMediaTypeRegistry.APPLICATION_CBOR + " supported."); return; } voucherStatus = StatusTelemetry.deserialize(exchange.getRequestPayload()); if (voucherStatus.cbor == null) { - logger.warn( - "decoding CBOR payload failed for voucher status report: " - + voucherStatus.parseResultStatus); - exchange.respond( - ResponseCode.BAD_REQUEST, - "decoding CBOR payload failed for voucher status report: " - + voucherStatus.parseResultStatus); + logger.warn("decoding CBOR payload failed for voucher status report: " + voucherStatus.parseResultStatus); + exchange.respond(ResponseCode.BAD_REQUEST, + "decoding CBOR payload failed for voucher status report: " + voucherStatus.parseResultStatus); return; } - logger.info( - "received voucher status report; status=" - + voucherStatus.status - + ": " - + voucherStatus.toString()); + logger.info("received voucher status report:" + voucherStatus.toString()); // log the result for this Pledge voucherStatusLog.put(clientId, voucherStatus); @@ -270,9 +259,7 @@ public void handlePOST(CoapExchange exchange) { if (voucherStatus.isValidFormat) { // success response exchange.respond(ResponseCode.CHANGED); } else { - exchange.respond( - ResponseCode.BAD_REQUEST, - "payload error: " + voucherStatus.parseResultStatus); // client submitted wrong format. + exchange.respond(ResponseCode.BAD_REQUEST, "error: " + voucherStatus.parseResultStatus); // client submitted wrong format. } } } diff --git a/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java b/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java index 76906ee..496c45a 100644 --- a/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java +++ b/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java @@ -48,7 +48,7 @@ public class IETFConstrainedBrskiTest { public static final String REGISTRAR_URI = "coaps://[::1]:" + ConstantsBrski.DEFAULT_REGISTRAR_COAPS_PORT; public static final String DEFAULT_DOMAIN_NAME = "Thread-Test"; - public static final String CREDENTIALS_KEYSTORE_FILE = "credentials/keystore_ietf-draft-constrained-brski.p12"; + public static final String CREDENTIALS_KEYSTORE_FILE = "credentials/ietf-draft-constrained-brski/credentials.p12"; // the acting entities private DomainCA domainCA; @@ -76,9 +76,7 @@ public static void tearDown() { @Before public void init() throws Exception { // disable debug logging. - ch.qos.logback.classic.Logger rootLogger = - (ch.qos.logback.classic.Logger) - LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME); + ch.qos.logback.classic.Logger rootLogger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME); rootLogger.setLevel(ch.qos.logback.classic.Level.INFO); initEntities(cg); } @@ -92,9 +90,7 @@ protected void initEntities(CredentialGenerator credGen) throws Exception { pledge = new Pledge(credGen.getCredentials(CredentialGenerator.PLEDGE_ALIAS), REGISTRAR_URI); pledge.setLightweightClientCertificates(true); - domainCA = - new DomainCA( - DEFAULT_DOMAIN_NAME, credGen.getCredentials(CredentialGenerator.DOMAINCA_ALIAS)); + domainCA = new DomainCA(DEFAULT_DOMAIN_NAME, credGen.getCredentials(CredentialGenerator.DOMAINCA_ALIAS)); RegistrarBuilder registrarBuilder = new RegistrarBuilder(); registrar = @@ -104,11 +100,7 @@ protected void initEntities(CredentialGenerator credGen) throws Exception { .setTrustAllMasas(true) // or enable this, to trust all MASAs. .build(); registrar.setDomainCA(domainCA); - registrar.setForcedMasaUri( - "localhost:" - + ConstantsBrski - .DEFAULT_MASA_HTTPS_PORT); // force to localhost, don't heed example MASA URI in - // Pledge cert. + registrar.setForcedMasaUri("localhost:" + ConstantsBrski.DEFAULT_MASA_HTTPS_PORT); // force localhost, don't use MASA URI in Pledge IDevID masa.start(); registrar.start();