From 329d2d473144b319f54ce3287df088bbe528678c Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Wed, 26 Jun 2024 14:39:46 +0200 Subject: [PATCH 01/25] [src] removed CSRAttrs, not used in cBRSKI --- .../openthread/brski/CBORSerializer.java | 2 +- .../openthread/brski/JSONSerializer.java | 55 +++---- .../com/google/openthread/brski/Voucher.java | 13 +- .../openthread/brski/VoucherRequest.java | 6 +- .../com/google/openthread/pledge/Pledge.java | 62 +------- .../google/openthread/pledge/PledgeMain.java | 4 - .../openthread/registrar/CSRAttributes.java | 117 --------------- .../openthread/registrar/Registrar.java | 49 +----- src/main/resources/attributes.json | 13 -- .../openthread/brski/ExamplePayloadsTest.java | 14 -- .../registrar/CSRAttributesTest.java | 142 ------------------ .../openthread/registrar/FunctionalTest.java | 16 -- .../registrar/IETFConstrainedBrskiTest.java | 43 ++++-- 13 files changed, 64 insertions(+), 472 deletions(-) delete mode 100644 src/main/java/com/google/openthread/registrar/CSRAttributes.java delete mode 100644 src/main/resources/attributes.json delete mode 100644 src/test/java/com/google/openthread/registrar/CSRAttributesTest.java diff --git a/src/main/java/com/google/openthread/brski/CBORSerializer.java b/src/main/java/com/google/openthread/brski/CBORSerializer.java index 9cefcd3..9edc112 100644 --- a/src/main/java/com/google/openthread/brski/CBORSerializer.java +++ b/src/main/java/com/google/openthread/brski/CBORSerializer.java @@ -58,7 +58,7 @@ public CBORObject toCBOR(Voucher voucher) { Object keyObj = voucher.getKey(voucher.getName()); if (keyObj instanceof Integer) { parentSid = (Integer) keyObj; - }else { + } else { parentSid = 0; } CBORObject cbor = CBORObject.NewMap(); diff --git a/src/main/java/com/google/openthread/brski/JSONSerializer.java b/src/main/java/com/google/openthread/brski/JSONSerializer.java index def222b..aed69b0 100644 --- a/src/main/java/com/google/openthread/brski/JSONSerializer.java +++ b/src/main/java/com/google/openthread/brski/JSONSerializer.java @@ -65,35 +65,27 @@ public String toJSON(Voucher voucher) { HashMap container = new HashMap(); if (voucher.assertion != null) - add(container, Voucher.ASSERTION, voucher.isConstrained() ? - Integer.valueOf(voucher.assertion.getValue()) : voucher.assertion.toString()); - - if (voucher.createdOn != null) { add( container, - Voucher.CREATED_ON, - Voucher.dateToYoungFormat(voucher.createdOn)); + Voucher.ASSERTION, + voucher.isConstrained() + ? Integer.valueOf(voucher.assertion.getValue()) + : voucher.assertion.toString()); + + if (voucher.createdOn != null) { + add(container, Voucher.CREATED_ON, Voucher.dateToYoungFormat(voucher.createdOn)); } - add( - container, - Voucher.DOMAIN_CERT_REVOCATION_CHECKS, - voucher.domainCertRevocationChecks); + add(container, Voucher.DOMAIN_CERT_REVOCATION_CHECKS, voucher.domainCertRevocationChecks); if (voucher.expiresOn != null) { - add( - container, - Voucher.EXPIRES_ON, - Voucher.dateToYoungFormat(voucher.expiresOn)); + add(container, Voucher.EXPIRES_ON, Voucher.dateToYoungFormat(voucher.expiresOn)); } add(container, Voucher.IDEVID_ISSUER, voucher.idevidIssuer); if (voucher.lastRenewalDate != null) { - add( - container, - Voucher.LAST_RENEWAL_DATE, - Voucher.dateToYoungFormat(voucher.lastRenewalDate)); + add(container, Voucher.LAST_RENEWAL_DATE, Voucher.dateToYoungFormat(voucher.lastRenewalDate)); } add(container, Voucher.NONCE, voucher.nonce); @@ -102,20 +94,11 @@ public String toJSON(Voucher voucher) { add(container, Voucher.PINNED_DOMAIN_SPKI, voucher.pinnedDomainSPKI); - add( - container, - Voucher.PRIOR_SIGNED_VOUCHER_REQUEST, - voucher.priorSignedVoucherRequest); + add(container, Voucher.PRIOR_SIGNED_VOUCHER_REQUEST, voucher.priorSignedVoucherRequest); - add( - container, - Voucher.PROXIMITY_REGISTRAR_CERT, - voucher.proximityRegistrarCert); + add(container, Voucher.PROXIMITY_REGISTRAR_CERT, voucher.proximityRegistrarCert); - add( - container, - Voucher.PROXIMITY_REGISTRAR_SPKI, - voucher.proximityRegistrarSPKI); + add(container, Voucher.PROXIMITY_REGISTRAR_SPKI, voucher.proximityRegistrarSPKI); add(container, Voucher.SERIAL_NUMBER, voucher.serialNumber); @@ -152,8 +135,7 @@ public Voucher fromJSON(String json) { voucher.createdOn = Voucher.dateFromYoungFormat(leaf.toString()); } - if ((leaf = get(container, Voucher.DOMAIN_CERT_REVOCATION_CHECKS)) - != null) { + if ((leaf = get(container, Voucher.DOMAIN_CERT_REVOCATION_CHECKS)) != null) { voucher.domainCertRevocationChecks = leaf.equals(Boolean.TRUE); } @@ -181,18 +163,15 @@ public Voucher fromJSON(String json) { voucher.pinnedDomainSPKI = (byte[]) leaf; } - if ((leaf = getBytes(container, Voucher.PRIOR_SIGNED_VOUCHER_REQUEST)) - != null) { + if ((leaf = getBytes(container, Voucher.PRIOR_SIGNED_VOUCHER_REQUEST)) != null) { voucher.priorSignedVoucherRequest = (byte[]) leaf; } - if ((leaf = getBytes(container, Voucher.PROXIMITY_REGISTRAR_CERT)) - != null) { + if ((leaf = getBytes(container, Voucher.PROXIMITY_REGISTRAR_CERT)) != null) { voucher.proximityRegistrarCert = (byte[]) leaf; } - if ((leaf = getBytes(container, Voucher.PROXIMITY_REGISTRAR_SPKI)) - != null) { + if ((leaf = getBytes(container, Voucher.PROXIMITY_REGISTRAR_SPKI)) != null) { voucher.proximityRegistrarSPKI = (byte[]) leaf; } diff --git a/src/main/java/com/google/openthread/brski/Voucher.java b/src/main/java/com/google/openthread/brski/Voucher.java index 4ccb1c6..d4eea53 100644 --- a/src/main/java/com/google/openthread/brski/Voucher.java +++ b/src/main/java/com/google/openthread/brski/Voucher.java @@ -217,10 +217,11 @@ public String toString() { public static final String VOUCHER = "ietf-voucher:voucher"; public static final String VOUCHER_CONSTRAINED = "ietf-voucher-constrained:voucher"; - + public static final String VOUCHER_REQUEST = "ietf-voucher-request:voucher"; - public static final String VOUCHER_REQUEST_CONSTRAINED = "ietf-voucher-request-constrained:voucher"; + public static final String VOUCHER_REQUEST_CONSTRAINED = + "ietf-voucher-request-constrained:voucher"; public static final String ASSERTION = "assertion"; @@ -322,12 +323,10 @@ public void setConstrained(boolean isConstrained) { } public String getName() { - if (isConstrained()) - return VOUCHER_CONSTRAINED; - else - return VOUCHER; + if (isConstrained()) return VOUCHER_CONSTRAINED; + else return VOUCHER; } - + public String toString() { JSONSerializer jsonSerializer = new JSONSerializer(); return jsonSerializer.toJSON(this); diff --git a/src/main/java/com/google/openthread/brski/VoucherRequest.java b/src/main/java/com/google/openthread/brski/VoucherRequest.java index b209f8e..54e5d9e 100644 --- a/src/main/java/com/google/openthread/brski/VoucherRequest.java +++ b/src/main/java/com/google/openthread/brski/VoucherRequest.java @@ -83,9 +83,7 @@ public boolean validate() { @Override public String getName() { - if (isConstrained()) - return VOUCHER_REQUEST_CONSTRAINED; - else - return VOUCHER_REQUEST; + if (isConstrained()) return VOUCHER_REQUEST_CONSTRAINED; + else return VOUCHER_REQUEST; } } diff --git a/src/main/java/com/google/openthread/pledge/Pledge.java b/src/main/java/com/google/openthread/pledge/Pledge.java index 9bac9df..9dc9d73 100644 --- a/src/main/java/com/google/openthread/pledge/Pledge.java +++ b/src/main/java/com/google/openthread/pledge/Pledge.java @@ -67,13 +67,11 @@ import java.util.Set; import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.ASN1Primitive; import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.DERIA5String; import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DLSequence; -import org.bouncycastle.asn1.est.CsrAttrs; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; @@ -333,52 +331,6 @@ public Voucher requestVoucher(VoucherRequest req) // EST protocol - /** - * Request CSR attributes before sending CSR. - * - * @throws IllegalStateException - * @throws PledgeException - */ - public void requestCSRAttributes() - throws IllegalStateException, PledgeException, ConnectorException, IOException { - if (certState != CertState.ACCEPT) { - throw new IllegalStateException("should successfully get voucher first"); - } - - CoapResponse response = sendRequestCSRAttributes(); - if (response == null) { - throw new PledgeException("request CSR Attributes failed: null response"); - } - if (response.getCode() != ResponseCode.CONTENT) { - logger.warn( - "CSR attributes request failed: " + response.getCode().toString(), response.getCode()); - return; - } - - if (response.getOptions().getContentFormat() - != ExtendedMediaTypeRegistry.APPLICATION_CSRATTRS) { - logger.warn( - "expect CSR attributes in format[%d], but got [%d]", - ExtendedMediaTypeRegistry.APPLICATION_CSRATTRS, response.getOptions().getContentFormat()); - return; - } - - byte[] payload = response.getPayload(); - if (payload == null) { - throw new PledgeException("unexpected null payload"); - } - - try { - // CBORObject cbor = CBORObject.DecodeFromBytes(payload); - csrAttrs = CsrAttrs.getInstance(ASN1Primitive.fromByteArray(payload)); - if (csrAttrs.size() == 0) { - throw new PledgeException("CSR Attributes response has no entry!"); - } - } catch (Exception e) { - logger.warn("bad CSR attributes response" + e.getMessage()); - } - } - // /.well-known/est/cacerts public void requestCACertificate() { // TODO(wgtdkp): @@ -581,7 +533,7 @@ public static byte[] generateNonce() { random.nextBytes(nonce); return nonce; } - + public VoucherRequest getLastPvr() { return this.lastPvr; } @@ -589,11 +541,11 @@ public VoucherRequest getLastPvr() { public byte[] getLastPvrCoseSigned() { return this.lastPvrCoseSigned; } - + public byte[] getLastVoucherCoseSigned() { return this.lastVoucherCoseSigned; } - + private void init(Credentials creds, String hostURI, boolean isLightweightClientCerts) throws PledgeException { @@ -624,7 +576,6 @@ private void init(Credentials creds, String hostURI, boolean isLightweightClient operationalKeyPair = null; operationalCertificate = null; certState = CertState.NO_CONTACT; - csrAttrs = null; X509Certificate[] clientCertChain = this.certificateChain; if (isLightweightClientCerts) @@ -647,11 +598,6 @@ private CoapResponse sendRequestVoucher(VoucherRequest voucherRequest) return post(payload, ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_COSE_CBOR); } - private CoapResponse sendRequestCSRAttributes() throws IOException, ConnectorException { - setURI(getESTPath() + "/" + Constants.CSR_ATTRIBUTES); - return get(); - } - private CoapResponse sendCSR(PKCS10CertificationRequest csr, String resource) throws IOException, ConnectorException { setURI(getESTPath() + "/" + resource); @@ -786,8 +732,6 @@ private String getBRSKIPath() { private CertState certState = CertState.NO_CONTACT; - private CsrAttrs csrAttrs; - private VoucherRequest lastPvr = null; private byte[] lastPvrCoseSigned = null; private byte[] lastVoucherCoseSigned = null; diff --git a/src/main/java/com/google/openthread/pledge/PledgeMain.java b/src/main/java/com/google/openthread/pledge/PledgeMain.java index 2aeadba..fdbc835 100644 --- a/src/main/java/com/google/openthread/pledge/PledgeMain.java +++ b/src/main/java/com/google/openthread/pledge/PledgeMain.java @@ -136,7 +136,6 @@ private static void run(Pledge pledge, Commissioner commissioner) { final String help = "token - request commissioning token\n" + "rv - request voucher\n" - + "attrs - request CSR attributes\n" + "enroll - simple enrollment\n" + "reenroll - simple reenrollment\n" + "reset - reset to initial state\n" @@ -158,9 +157,6 @@ private static void run(Pledge pledge, Commissioner commissioner) { case "rv": pledge.requestVoucher(); break; - case "attrs": - pledge.requestCSRAttributes(); - break; case "enroll": pledge.enroll(); break; diff --git a/src/main/java/com/google/openthread/registrar/CSRAttributes.java b/src/main/java/com/google/openthread/registrar/CSRAttributes.java deleted file mode 100644 index 5389767..0000000 --- a/src/main/java/com/google/openthread/registrar/CSRAttributes.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2019, 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. - */ - -package com.google.openthread.registrar; - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.List; -import org.bouncycastle.asn1.ASN1EncodableVector; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.DERSet; -import org.bouncycastle.asn1.est.AttrOrOID; -import org.bouncycastle.asn1.pkcs.Attribute; - -public class CSRAttributes { - public static final String DEFAULT_FILE = "attributes.json"; - - public CSRAttributes(String filename) throws RegistrarException { - try (InputStream in = getClass().getClassLoader().getResourceAsStream(filename)) { - attrAndOids = initAttrAndOids(new JsonParser().parse(new InputStreamReader(in))); - } catch (IOException e) { - throw new RegistrarException(e.getMessage()); - } - } - - public CSRAttributes(InputStream in) throws RegistrarException { - attrAndOids = initAttrAndOids(new JsonParser().parse(new InputStreamReader(in))); - } - - public AttrOrOID[] getAttrAndOids() { - return attrAndOids; - } - - private AttrOrOID[] initAttrAndOids(final JsonElement element) throws RegistrarException { - List list = new ArrayList<>(); - try { - JsonArray array = element.getAsJsonArray(); - for (JsonElement item : array) { - if (item.isJsonObject()) { - JsonObject attrs = item.getAsJsonObject(); - for (String type : attrs.keySet()) { - JsonElement val = attrs.get(type); - if (val.isJsonArray()) { - list.add(new AttrOrOID(makeAttr(type, jsonArrayToStrings(val.getAsJsonArray())))); - } else { - list.add(new AttrOrOID(makeAttr(type, val.getAsString()))); - } - } - } else { - String oid = item.getAsString(); - list.add(new AttrOrOID(makeOid(oid))); - } - } - } catch (RuntimeException e) { - throw new RegistrarException("attributes file error: " + e.getMessage()); - } - - return list.toArray(new AttrOrOID[list.size()]); - } - - private static ASN1ObjectIdentifier makeOid(final String oid) { - return new ASN1ObjectIdentifier(oid); - } - - private static Attribute makeAttr(final String type, final String val) { - return new Attribute(makeOid(type), new DERSet(makeOid(val))); - } - - private static Attribute makeAttr(final String type, final List vals) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (String val : vals) { - v.add(makeOid(val)); - } - return new Attribute(makeOid(type), new DERSet(v)); - } - - private static List jsonArrayToStrings(JsonArray arr) { - List ret = new ArrayList<>(); - for (JsonElement element : arr) { - ret.add(element.getAsString()); - } - return ret; - } - - private AttrOrOID[] attrAndOids; -} diff --git a/src/main/java/com/google/openthread/registrar/Registrar.java b/src/main/java/com/google/openthread/registrar/Registrar.java index f075e17..4d52ed1 100644 --- a/src/main/java/com/google/openthread/registrar/Registrar.java +++ b/src/main/java/com/google/openthread/registrar/Registrar.java @@ -69,7 +69,6 @@ import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; -import org.bouncycastle.asn1.est.CsrAttrs; import org.bouncycastle.pkcs.PKCS10CertificationRequest; import org.bouncycastle.util.encoders.Hex; import org.eclipse.californium.core.CoapClient; @@ -144,7 +143,6 @@ public class Registrar extends CoapServer { throw new RegistrarException("(yet) unsupported certificate chain: length < 2"); } - this.csrAttributes = new CSRAttributes(CSRAttributes.DEFAULT_FILE); } catch (Exception e) { throw new RegistrarException(e.getMessage()); } @@ -411,8 +409,7 @@ public void handlePOST(CoapExchange exchange) { || forcedVoucherRequestFormat == ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_COSE_JSON); VoucherRequest req = new VoucherRequest(); - if (!isJsonRVR) - req.setConstrained(true); + if (!isJsonRVR) req.setConstrained(true); req.assertion = pledgeReq.assertion; // assertion copied from PVR // Note, section 5.5: assertion MAY be omitted. @@ -483,7 +480,7 @@ pledgeReq.proximityRegistrarSPKI, getCertificate().getPublicKey().getEncoded())) // store last sent RVR. lastRvr = req; - + // use CMS or COSE signing of the voucher request. byte[] payload; boolean isCms = @@ -544,7 +541,7 @@ pledgeReq.proximityRegistrarSPKI, getCertificate().getPublicKey().getEncoded())) // store last sent COSE-signed RVR. lastRvrCoseSigned = payload; - + RestfulVoucherResponse response = null; if (isHttpToMasa) { MASAConnectorHttp masaClient = new MASAConnectorHttp(masaTrustAnchors); @@ -754,34 +751,6 @@ public ReenrollResource() { } } - public final class CsrAttrsResource extends CoapResource { - public CsrAttrsResource() { - super(Constants.CSR_ATTRIBUTES); - } - - @Override - public void handleGET(CoapExchange exchange) { - try { - RequestDumper.dump(logger, getURI(), exchange.getRequestPayload()); - - CsrAttrs csrAttrs = getCsrAttrs(); - - // No base64 encoding - exchange.respond( - ResponseCode.CONTENT, - csrAttrs.getEncoded(), - ExtendedMediaTypeRegistry.APPLICATION_CSRATTRS); - } catch (IOException e) { - logger.warn("CSR attribute request failed: " + e.getMessage()); - exchange.respond(ResponseCode.BAD_REQUEST); - } - } - - private CsrAttrs getCsrAttrs() { - return new CsrAttrs(csrAttributes.getAttrAndOids()); - } - } - public final class CrtsResource extends CoapResource { public CrtsResource() { super(Constants.CA_CERTIFICATES); @@ -923,6 +892,7 @@ public StatusTelemetry getEnrollStatusLogEntry(Principal client) { /** * get the last RVR that was sent to MASA. + * * @return last sent RVR, or null if none sent yet. */ public VoucherRequest getLastRvr() { @@ -931,12 +901,13 @@ public VoucherRequest getLastRvr() { /** * get the last COSE-signed RVR that was sent to MASA. + * * @return byte array encoding the last sent COSE-signed RVR, or null if none sent yet. */ public byte[] getLastRvrCoseSigned() { return this.lastRvrCoseSigned; } - + /** * get the Registrar's EE certificate * @@ -963,7 +934,6 @@ private void initResources() { VoucherRequestResource rv = new VoucherRequestResource(); VoucherStatusResource vs = new VoucherStatusResource(); EnrollStatusResource es = new EnrollStatusResource(); - CsrAttrsResource att = new CsrAttrsResource(); CrtsResource crts = new CrtsResource(); EnrollResource enroll = new EnrollResource(); ReenrollResource reenroll = new ReenrollResource(); @@ -972,7 +942,6 @@ private void initResources() { // EST and BRSKI and CoRE well-known resources est.add(enroll); est.add(reenroll); - est.add(att); est.add(crts); brski.add(rv); brski.add(vs); @@ -1027,8 +996,6 @@ private void initEndpoint() { // credentials used as a HTTP/CoAP client towards MASA. private Credentials masaClientCredentials; - private CSRAttributes csrAttributes; - protected int forcedVoucherRequestFormat = -1; protected boolean isHttpToMasa = true; @@ -1045,8 +1012,8 @@ private void initEndpoint() { protected Map voucherLog = new HashMap(); private VoucherRequest lastRvr = null; - + private byte[] lastRvrCoseSigned = null; - + private static Logger logger = LoggerFactory.getLogger(Registrar.class); } diff --git a/src/main/resources/attributes.json b/src/main/resources/attributes.json deleted file mode 100644 index a99629d..0000000 --- a/src/main/resources/attributes.json +++ /dev/null @@ -1,13 +0,0 @@ -/* - * The attributes config file for registrar, attributes listed - * below will be sent back to pledge as the response of CSR attributes request. - * All keys are represented as OID string, learn from http://www.oid-info.com/ - */ - -[ - // Attribute - {"1.2.840.10045.2.1" : "1.2.840.10045.3.1.7"}, - - // OID - "1.2.840.10045.4.3.2" -] diff --git a/src/test/java/com/google/openthread/brski/ExamplePayloadsTest.java b/src/test/java/com/google/openthread/brski/ExamplePayloadsTest.java index 0c55792..e9d52c4 100644 --- a/src/test/java/com/google/openthread/brski/ExamplePayloadsTest.java +++ b/src/test/java/com/google/openthread/brski/ExamplePayloadsTest.java @@ -35,9 +35,7 @@ import com.upokecenter.cbor.CBORObject; import java.security.KeyPair; import java.util.Date; -import org.bouncycastle.asn1.est.CsrAttrs; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; -import org.bouncycastle.util.encoders.Hex; import org.junit.Assert; import org.junit.Test; import org.slf4j.Logger; @@ -79,18 +77,6 @@ public void voucherExamplePayload() throws Exception { logger.info(new CBORSerializer().toCBOR(cv).toString()); } - @Test - public void csrAttrsExamplePayload() throws Exception { - CSRAttributes attrs = new CSRAttributes(CSRAttributes.DEFAULT_FILE); - - CsrAttrs csrAttrs = new CsrAttrs(attrs.getAttrAndOids()); - CBORObject resp = CBORObject.FromObject(csrAttrs.getEncoded()); - logger.info("example CSR attributes response:"); - logger.info(resp.toString()); - logger.info("the CBOR encoded:"); - logger.info(Hex.toHexString(resp.EncodeToBytes())); - } - @Test public void comTokenExamplePayload() throws Exception { KeyPair kp = SecurityUtils.genKeyPair(); diff --git a/src/test/java/com/google/openthread/registrar/CSRAttributesTest.java b/src/test/java/com/google/openthread/registrar/CSRAttributesTest.java deleted file mode 100644 index e826715..0000000 --- a/src/test/java/com/google/openthread/registrar/CSRAttributesTest.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2019, 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. - */ - -package com.google.openthread.registrar; - -import static org.junit.Assert.assertTrue; - -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.est.AttrOrOID; -import org.junit.Assert; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -public class CSRAttributesTest { - - @Rule public ExpectedException thrown = ExpectedException.none(); - - @Test - public void testLoad() throws Exception { - CSRAttributes attr = new CSRAttributes(CSRAttributes.DEFAULT_FILE); - assertTrue(attr.getAttrAndOids().length > 1); - } - - @Test - public void testAttrs() throws Exception { - CSRAttributes attr = new CSRAttributes(CSRAttributes.DEFAULT_FILE); - for (AttrOrOID entry : attr.getAttrAndOids()) { - if (entry.getAttribute() != null) { - System.out.println( - entry.getAttribute().getAttrType().getId() - + "=" - + ASN1ObjectIdentifier.getInstance( - entry.getAttribute().getAttrValues().getObjectAt(0)) - .getId()); - } else if (entry.getOid() != null) { - System.out.println(entry.getOid().getId()); - } else { - throw new Exception("unexpected attribute"); - } - } - } - - @Test - public void testVerifyAttrs() throws Exception { - String jsonStr = - "[\n" - + " // Attribute\n" - + " {\"1.2.840.10045.2.1\" : \"1.2.840.10045.3.1.7\"},\n" - + "\n" - + " // OID\n" - + " \"1.2.840.10045.4.3.2\"\n" - + "]"; - - try (InputStream in = new ByteArrayInputStream(jsonStr.getBytes())) { - CSRAttributes attr = new CSRAttributes(in); - - Assert.assertEquals(attr.getAttrAndOids().length, 2); - - for (AttrOrOID entry : attr.getAttrAndOids()) { - if (entry.getAttribute() != null) { - Assert.assertTrue(entry.getAttribute().getAttrType().getId().equals("1.2.840.10045.2.1")); - Assert.assertTrue( - ASN1ObjectIdentifier.getInstance(entry.getAttribute().getAttrValues().getObjectAt(0)) - .getId() - .equals("1.2.840.10045.3.1.7")); - } else if (entry.getOid() != null) { - Assert.assertTrue(entry.getOid().getId().equals("1.2.840.10045.4.3.2")); - } else { - throw new Exception("unexpected attribute"); - } - } - } - } - - @Test - public void testMultiValues() throws Exception { - String jsonStr = - "[{\"1.2.840.10045.2.1\" : [\"1.2.840.10045.3.1.7\", \"1.2.840.10045.3.1.8\"]}]"; - - try (InputStream in = new ByteArrayInputStream(jsonStr.getBytes())) { - CSRAttributes attr = new CSRAttributes(in); - - Assert.assertEquals(attr.getAttrAndOids().length, 1); - - for (AttrOrOID entry : attr.getAttrAndOids()) { - if (entry.getAttribute() != null) { - Assert.assertTrue(entry.getAttribute().getAttrType().getId().equals("1.2.840.10045.2.1")); - Assert.assertTrue( - ASN1ObjectIdentifier.getInstance(entry.getAttribute().getAttrValues().getObjectAt(0)) - .getId() - .equals("1.2.840.10045.3.1.7")); - Assert.assertTrue( - ASN1ObjectIdentifier.getInstance(entry.getAttribute().getAttrValues().getObjectAt(1)) - .getId() - .equals("1.2.840.10045.3.1.8")); - } else { - throw new Exception("unexpected attribute"); - } - } - } - } - - @Test - public void testCheckedException() throws Exception { - thrown.expect(RegistrarException.class); - - String jsonStr = - "[{\"1.2.840.10045.2.1\" : [\"1.2.840.10045.3.1.7\", \"1.2.840.10045.3.1.8\"]}, []]"; - try (InputStream in = new ByteArrayInputStream(jsonStr.getBytes())) { - CSRAttributes attr = new CSRAttributes(in); - assertTrue(attr.getAttrAndOids().length > 1); - } - } -} diff --git a/src/test/java/com/google/openthread/registrar/FunctionalTest.java b/src/test/java/com/google/openthread/registrar/FunctionalTest.java index 8c53a4d..e75acaa 100644 --- a/src/test/java/com/google/openthread/registrar/FunctionalTest.java +++ b/src/test/java/com/google/openthread/registrar/FunctionalTest.java @@ -176,22 +176,6 @@ public void testVoucherRequest() throws Exception { Assert.assertEquals(ResponseCode.CHANGED, pledge.sendVoucherStatusTelemetry(true, null)); } - /** - * Test BRSKI voucher request while first requesting CSR attributes. The returned attributes - * aren't used. Requesting this is not recommended anymore for constrained Pledges, but tested - * here nevertheless. - * - * @throws Exception - */ - @Test - public void testCsrAttrsRequest() throws Exception { - Voucher voucher = pledge.requestVoucher(); - pledge.requestCSRAttributes(); - Assert.assertTrue(voucher.validate()); - VerifyPledge(pledge); - Assert.assertEquals(ResponseCode.CHANGED, pledge.sendVoucherStatusTelemetry(true, null)); - } - @Test public void testEnroll() throws Exception { Voucher voucher = pledge.requestVoucher(); diff --git a/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java b/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java index 2624fd6..0d85194 100644 --- a/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java +++ b/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java @@ -42,10 +42,9 @@ import org.slf4j.LoggerFactory; /** - * This test code is to specifically produce the COSE examples in the Appendix of - * IETF draft "Constrained BRSKI" - see + * This test code is to specifically produce the COSE examples in the Appendix of IETF draft + * "Constrained BRSKI" - see * https://datatracker.ietf.org/doc/html/draft-ietf-anima-constrained-voucher - * */ public class IETFConstrainedBrskiTest { @@ -53,8 +52,9 @@ public class IETFConstrainedBrskiTest { "coaps://[::1]:" + Constants.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/keystore_ietf-draft-constrained-brski.p12"; + // the acting entities private DomainCA domainCA; private Registrar registrar; @@ -80,7 +80,9 @@ 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); } @@ -106,7 +108,11 @@ protected void initEntities(CredentialGenerator credGen) throws Exception { .setTrustAllMasas(true) // or enable this, to trust all MASAs. .build(); registrar.setDomainCA(domainCA); - registrar.setForcedMasaUri("localhost:" + Constants.DEFAULT_MASA_HTTPS_PORT); // force to localhost, don't heed example MASA URI in Pledge cert. + registrar.setForcedMasaUri( + "localhost:" + + Constants + .DEFAULT_MASA_HTTPS_PORT); // force to localhost, don't heed example MASA URI in + // Pledge cert. masa.start(); registrar.start(); @@ -135,17 +141,22 @@ public void testVoucherRequestAndDisplayArtifacts() throws Exception { Assert.assertTrue(voucher.validate()); VerifyPledge(pledge); Assert.assertEquals(ResponseCode.CHANGED, pledge.sendVoucherStatusTelemetry(true, null)); - + // display the artifacts. logger.info("Pledge Voucher Request (PVR) sent by Pledge:\n" + pledge.getLastPvr().toString()); - logger.info("Pledge Voucher Request (PVR) sent by Pledge as Hex string:\n" + Hex.toHexString(pledge.getLastPvrCoseSigned())); - - logger.info("Registrar Voucher Request (RVR) sent by Registrar:\n" + registrar.getLastRvr().toString()); - logger.info("Registrar Voucher Request (RVR) sent by Registrar as Hex string:\n" + Hex.toHexString(registrar.getLastRvrCoseSigned())); - + logger.info( + "Pledge Voucher Request (PVR) sent by Pledge as Hex string:\n" + + Hex.toHexString(pledge.getLastPvrCoseSigned())); + + logger.info( + "Registrar Voucher Request (RVR) sent by Registrar:\n" + registrar.getLastRvr().toString()); + logger.info( + "Registrar Voucher Request (RVR) sent by Registrar as Hex string:\n" + + Hex.toHexString(registrar.getLastRvrCoseSigned())); + logger.info("Voucher created by MASA:\n" + voucher); - logger.info("Voucher created by MASA as Hex string:\n" + Hex.toHexString(pledge.getLastVoucherCoseSigned())); - + logger.info( + "Voucher created by MASA as Hex string:\n" + + Hex.toHexString(pledge.getLastVoucherCoseSigned())); } - } From 3129b717234983457ebb541a6f97c48dfee35e6d Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Wed, 26 Jun 2024 15:07:59 +0200 Subject: [PATCH 02/25] [src] remove Commissioner class, tests and related ace-java dependency (was used for CWT-like/token function) --- pom.xml | 30 +-- .../openthread/commissioner/Commissioner.java | 201 ------------------ .../CommissionerCertificateVerifier.java | 52 ----- .../commissioner/CommissionerException.java | 43 ---- .../commissioner/ThreadCoapClient.java | 111 ---------- .../commissioner/tlv/CommissionerIdTlv.java | 16 -- .../openthread/commissioner/tlv/TLV.java | 97 --------- .../openthread/commissioner/tlv/TLVset.java | 147 ------------- .../google/openthread/domainca/DomainCA.java | 42 ---- .../google/openthread/pledge/PledgeMain.java | 32 +-- .../openthread/registrar/Registrar.java | 76 +------ .../tools/HardwarePledgeTestSuite.java | 19 -- .../openthread/brski/ExamplePayloadsTest.java | 9 - .../openthread/registrar/FunctionalTest.java | 14 -- 14 files changed, 10 insertions(+), 879 deletions(-) delete mode 100644 src/main/java/com/google/openthread/commissioner/Commissioner.java delete mode 100644 src/main/java/com/google/openthread/commissioner/CommissionerCertificateVerifier.java delete mode 100644 src/main/java/com/google/openthread/commissioner/CommissionerException.java delete mode 100644 src/main/java/com/google/openthread/commissioner/ThreadCoapClient.java delete mode 100644 src/main/java/com/google/openthread/commissioner/tlv/CommissionerIdTlv.java delete mode 100644 src/main/java/com/google/openthread/commissioner/tlv/TLV.java delete mode 100644 src/main/java/com/google/openthread/commissioner/tlv/TLVset.java diff --git a/pom.xml b/pom.xml index 4f24f41..9a1e461 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.google.openthread ot-registrar - 0.1-SNAPSHOT + 0.2 OT Registrar https://openthread.io/ @@ -27,6 +27,7 @@ junit ${junit.version} + com.upokecenter cbor @@ -88,18 +89,6 @@ 2.17.1 - - se.sics - ace - 0.0.1-SNAPSHOT - - - org.slf4j - slf4j-log4j12 - - - - io.undertow undertow-core @@ -172,7 +161,7 @@ - com.google.openthread.registrar.RegistrarMain + com.google.openthread.main.OtRegistrarMain @@ -186,19 +175,6 @@ - - - com.coveo - fmt-maven-plugin - 2.9 - - - - format - - - - diff --git a/src/main/java/com/google/openthread/commissioner/Commissioner.java b/src/main/java/com/google/openthread/commissioner/Commissioner.java deleted file mode 100644 index d1f0d03..0000000 --- a/src/main/java/com/google/openthread/commissioner/Commissioner.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2019, 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. - */ - -package com.google.openthread.commissioner; - -import COSE.CoseException; -import COSE.OneKey; -import com.google.openthread.*; -import com.upokecenter.cbor.CBORObject; -import java.io.IOException; -import java.math.BigInteger; -import java.security.GeneralSecurityException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.cert.X509Certificate; -import org.eclipse.californium.core.CoapClient; -import org.eclipse.californium.core.CoapResponse; -import org.eclipse.californium.core.coap.CoAP; -import org.eclipse.californium.core.network.CoapEndpoint; -import org.eclipse.californium.elements.exception.ConnectorException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import se.sics.ace.cwt.CWT; -import se.sics.ace.cwt.CwtCryptoCtx; - -public class Commissioner { - - /** Constructing commissioner with credentials */ - public Commissioner(Credentials creds) throws CommissionerException, GeneralSecurityException { - if (creds.getCertificateChain().length < 2) { - throw new CommissionerException("bad certificate chain"); - } - - this.privateKey = creds.getPrivateKey(); - this.certificateChain = creds.getCertificateChain(); - this.certVerifier = new CommissionerCertificateVerifier(getDomainCertificate()); - this.client = new CoapClient(); - initEndpoint(); - } - - public boolean start(String borderAgentHost) { - baClient = new ThreadCoapClient(borderAgentHost, comTok); - try { - CoapResponse resp = baClient.sendCOMM_PET_req("JavaCommissioner" + allocateClientId()); - if (resp == null || !resp.isSuccess()) { - logger.warn("Petitioning unsuccessfull: " + resp); - return false; - } - } catch (Exception ex) { - logger.warn("Petitioning error to " + borderAgentHost, ex); - return false; - } - return true; - } - - public void shutdown() { - client.shutdown(); - } - - public CWT requestToken(String domainName, String registrarURI) - throws CommissionerException, IOException, ConnectorException { - // 0. build COM_TOK.req - CBORObject req = genTokenRequest(domainName, getCertificate().getPublicKey()); - - // 1. send COM_TOK.req & receive COM_TOK.rsp - CoapResponse response = sendTokenRequest(req, registrarURI); - if (response.getCode() != CoAP.ResponseCode.CHANGED) { - throw new CommissionerException("request token failed: " + response.getCode()); - } - - if (response.getOptions().getContentFormat() - != ExtendedMediaTypeRegistry.APPLICATION_COSE_SIGN1) { - throw new CommissionerException( - String.format( - "expect COM_TOK in format[%d], but got [%d]", - ExtendedMediaTypeRegistry.APPLICATION_COSE_SIGN1, - response.getOptions().getContentFormat())); - } - - // 2. verify - byte[] rawToken = response.getPayload(); - if (rawToken == null) { - throw new CommissionerException("unexpected null payload"); - } - - CWT comTok; - try { - comTok = verifyToken(rawToken); - } catch (Exception e) { - throw new CommissionerException("COM_TOK verification failed: " + e.getMessage()); - } - - CBORObject aud = comTok.getClaim(se.sics.ace.Constants.AUD); - if (!aud.AsString().equals(domainName)) { - throw new CommissionerException("COM_TOK domain names not match"); - } - // TODO(wgtdkp): extract and verify other claims - - this.comTok = comTok; - return comTok; - } - - public static CBORObject genTokenRequest(String domainName, PublicKey publicKey) - throws CommissionerException { - CBORObject req = CBORObject.NewMap(); - req.Add(se.sics.ace.Constants.GRANT_TYPE, se.sics.ace.Constants.GT_CLI_CRED); - req.Add(se.sics.ace.Constants.CLIENT_ID, "com-" + allocateClientId().toString()); - req.Add(se.sics.ace.Constants.AUD, domainName); - - // TODO(wgtdkp): support truncated subject key id - // req.Add(se.sics.ace.Constants.REQ_CNF, getTruncatedSubjectKeyId(16)); - - CBORObject cnf = CBORObject.NewMap(); - try { - cnf.Add(se.sics.ace.Constants.COSE_KEY, new OneKey(publicKey, null).AsCBOR()); - } catch (CoseException e) { - throw new CommissionerException("public key error: " + e.getMessage()); - } - - req.Add(se.sics.ace.Constants.REQ_CNF, cnf); - return req; - } - - public CoapResponse sendTokenRequest(CBORObject req, String registrarURI) - throws IOException, ConnectorException { - client.setURI(registrarURI + Constants.CCM_PATH); - return client.post(req.EncodeToBytes(), ExtendedMediaTypeRegistry.APPLICATION_CWT); - } - - public CWT verifyToken(byte[] rawToken) throws Exception { - PublicKey publicKey = getDomainCertificate().getPublicKey(); - OneKey pubKey = new OneKey(publicKey, null); - CwtCryptoCtx ctx = CwtCryptoCtx.sign1Verify(pubKey, null); - return CWT.processCOSE(rawToken, ctx); - } - - // TODO(wgtdkp): Use X509ExtensionUtils.truncatedSubjectKeyId - /* - public byte[] getTruncatedSubjectKeyId(int length) throws CommissionerException { - byte[] keyId = getCertificate().getExtensionValue("2.5.29.14"); - if (keyId.length < length) { - throw new CommissionerException("subject key identifier is shorter than " + length); - } - return Arrays.copyOf(keyId, length); - } - */ - - public static synchronized BigInteger allocateClientId() { - clientId = clientId.add(BigInteger.ONE); - return clientId; - } - - X509Certificate getCertificate() { - return certificateChain[0]; - } - - X509Certificate getDomainCertificate() { - return certificateChain[certificateChain.length - 1]; - } - - private void initEndpoint() { - CoapEndpoint endpoint = - SecurityUtils.genCoapClientEndPoint( - new X509Certificate[] {}, privateKey, certificateChain, certVerifier, false); - client.setEndpoint(endpoint); - } - - protected ThreadCoapClient baClient = null; - protected CoapClient client = null; - protected CWT comTok = null; - private static BigInteger clientId = BigInteger.ZERO; - private PrivateKey privateKey; - private X509Certificate[] certificateChain; - private CommissionerCertificateVerifier certVerifier; - private static Logger logger = LoggerFactory.getLogger(Commissioner.class); -} diff --git a/src/main/java/com/google/openthread/commissioner/CommissionerCertificateVerifier.java b/src/main/java/com/google/openthread/commissioner/CommissionerCertificateVerifier.java deleted file mode 100644 index 6e1c7e2..0000000 --- a/src/main/java/com/google/openthread/commissioner/CommissionerCertificateVerifier.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2019, 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. - */ - -package com.google.openthread.commissioner; - -import com.google.openthread.pledge.PledgeCertificateVerifier; -import java.security.cert.TrustAnchor; -import java.security.cert.X509Certificate; -import java.util.HashSet; -import java.util.Set; -import org.slf4j.LoggerFactory; - -public class CommissionerCertificateVerifier extends PledgeCertificateVerifier { - - public CommissionerCertificateVerifier(X509Certificate trustCert) { - super(makeTrustAnchors(trustCert)); - - setDoVerification(true); - logger = LoggerFactory.getLogger(CommissionerCertificateVerifier.class); - } - - private static Set makeTrustAnchors(X509Certificate cert) { - Set trustAnchors = new HashSet<>(); - trustAnchors.add(new TrustAnchor(cert, null)); - return trustAnchors; - } -} diff --git a/src/main/java/com/google/openthread/commissioner/CommissionerException.java b/src/main/java/com/google/openthread/commissioner/CommissionerException.java deleted file mode 100644 index 7c63e20..0000000 --- a/src/main/java/com/google/openthread/commissioner/CommissionerException.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2019, 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. - */ - -package com.google.openthread.commissioner; - -public class CommissionerException extends Exception { - - /** - * Constructor. - * - * @param msg the error message - */ - public CommissionerException(String msg) { - super(msg); - } - - private static final long serialVersionUID = 1938406732110361797L; -} diff --git a/src/main/java/com/google/openthread/commissioner/ThreadCoapClient.java b/src/main/java/com/google/openthread/commissioner/ThreadCoapClient.java deleted file mode 100644 index f504f54..0000000 --- a/src/main/java/com/google/openthread/commissioner/ThreadCoapClient.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.google.openthread.commissioner; - -import COSE.CoseException; -import com.google.openthread.Constants; -import com.google.openthread.commissioner.tlv.*; -import java.io.IOException; -import org.eclipse.californium.core.CoapClient; -import org.eclipse.californium.core.CoapResponse; -import org.eclipse.californium.core.coap.MediaTypeRegistry; -import org.eclipse.californium.elements.exception.ConnectorException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import se.sics.ace.cwt.CWT; - -/** - * * A Commissioner Coap client that can send Thread-specific management commands to a Border Agent - * (BA), for CCM or non-CCM networks. It can generate signed messages, by using a Token. - */ -public class ThreadCoapClient extends CoapClient { - - protected boolean doIncludeCOM_TOK = true; - protected boolean doIncludeCOM_TOK_SIG = true; - protected boolean doUDP_TX_Encapsulation = false; - protected String server; - protected CWT comTok = null; - - private static Logger logger = LoggerFactory.getLogger(ThreadCoapClient.class); - private static int signingSequenceNumber = 0; - - public ThreadCoapClient(String serverEndPoint) { - doIncludeCOM_TOK = false; - doIncludeCOM_TOK_SIG = false; - server = serverEndPoint; - } - - public ThreadCoapClient(String serverEndPoint, CWT token) { - comTok = token; - server = serverEndPoint; - } - - public void setIncludeCOM_TOK(boolean isInclude) { - this.doIncludeCOM_TOK = isInclude; - } - - public void setIncludeCOM_TOK_SIG(boolean isInclude) { - this.doIncludeCOM_TOK_SIG = isInclude; - } - - public void setUDP_TX_Encapsulation(boolean doEncapsulate) { - throw new UnsupportedOperationException(); - } - - /** - * send a TMF request with TLV payload to the server endpoint. - * - * @param uri the CoAP request Uri-Path - * @param tlvs the TLVs payload - * @throws IOException - * @throws CoseException - * @throws ConnectorException - */ - public CoapResponse sendTMFRequest(final String uri, TLVset tlvs) - throws IOException, CoseException, ConnectorException { - logger.trace( - "sendTMFRequest(Uri={},TLVs={},COM_TOK={},COM_TOK_SIG={},udpTx={},seq={})", - uri, - tlvs, - doIncludeCOM_TOK, - doIncludeCOM_TOK_SIG, - doUDP_TX_Encapsulation, - signingSequenceNumber); - - // sign URIs and TLVs with COM_TOK_SIG - if (doIncludeCOM_TOK_SIG) signCoap(uri, tlvs); - - if (doIncludeCOM_TOK) { - // NOTE: for commands in /n,/a,/b namespace the "TLVA_COMMISSIONER_TOKEN" would - // need to be added. - // its value is equal to TLVC_COMMISSIONER_TOKEN so we don't check for that - // here. - tlvs.put(TLV.C_COMMISSIONER_TOKEN, comTok.encode().EncodeToBytes()); - } - - // create the coap request - this.setURI(server + "/" + uri); - return this.post(tlvs.serialize(), MediaTypeRegistry.APPLICATION_OCTET_STREAM); - } - - /** - * send COMM_PET.req message - * - * @param commissionerId - * @return - */ - public CoapResponse sendCOMM_PET_req(String commissionerId) - throws IOException, CoseException, ConnectorException { - TLVset tlvs = new TLVset(); - tlvs.put(new CommissionerIdTlv(commissionerId)); - return sendTMFRequest(Constants.COMM_PET_REQ_PATH, tlvs); - } - - /** - * Sign the set of TLVs by adding a COM_TOK_SIG TLV to it. - * - * @param uri - * @param tlvs - */ - protected void signCoap(String uri, TLVset tlvs) { - // TODO - } -} diff --git a/src/main/java/com/google/openthread/commissioner/tlv/CommissionerIdTlv.java b/src/main/java/com/google/openthread/commissioner/tlv/CommissionerIdTlv.java deleted file mode 100644 index f021250..0000000 --- a/src/main/java/com/google/openthread/commissioner/tlv/CommissionerIdTlv.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.google.openthread.commissioner.tlv; - -/** Commissioner ID TLV */ -public class CommissionerIdTlv extends TLV { - - public String id; - - public CommissionerIdTlv(String commissionerId) { - super(TLV.C_COMMISSIONER_SESSION_ID); - this.id = commissionerId; - } - - public byte[] V() { - return id.getBytes(); - } -} diff --git a/src/main/java/com/google/openthread/commissioner/tlv/TLV.java b/src/main/java/com/google/openthread/commissioner/tlv/TLV.java deleted file mode 100644 index 8fb583f..0000000 --- a/src/main/java/com/google/openthread/commissioner/tlv/TLV.java +++ /dev/null @@ -1,97 +0,0 @@ -package com.google.openthread.commissioner.tlv; - -import org.bouncycastle.util.encoders.Hex; - -/** Single TLV element base class */ -public abstract class TLV { - - // "C" TLV namespace - public static final int C_COMMISSIONER_ID = 10; - public static final int C_COMMISSIONER_SESSION_ID = 11; - public static final int C_JOINER_DTLS_ENCAPSULATION = 17; - public static final int C_JOINER_UDP_PORT = 18; - public static final int C_JOINER_IID = 19; - public static final int C_JOINER_ROUTER_LOCATOR = 20; - public static final int C_UDP_ENCAPSULATION = 48; - public static final int C_IPV6_ADDRESS = 49; - public static final int C_COMMISSIONER_TOKEN = 63; - public static final int C_COMMISSIONER_SIGNATURE = 64; - - // "A" TLV namespace - public static final int A_TIMEOUT = 11; - public static final int A_IPV6_ADDRESSES = 14; - public static final int A_COMMISSIONER_TOKEN = C_COMMISSIONER_TOKEN; - public static final int A_COMMISSIONER_SIGNATURE = C_COMMISSIONER_SIGNATURE; - - public int T; - - public TLV(int type) { - this.T = type; - } - - public int L() { - return V().length; - } - - public abstract byte[] V(); - - /** whether this TLV is valid currently, or not */ - public boolean isValid = true; - - /** - * Returns the value as a hexadecimal string. - * - * @return the hexadecimal code string - */ - public String toHexString() { - return Hex.toHexString(V()); - } - - /** - * util method to fit int number n into the byte array of given length - * - * @param n - * @param b - */ - protected void toB(int n, byte[] b) { - for (int i = b.length - 1; i >= 0; i--) { - b[i] = (byte) (n & 255); - n >>>= 8; - } - } - - /** - * util method to fit int number n into the byte array of given length sz - * - * @param n - * @param sz size to fit it in (bytes) - */ - protected byte[] toB(int n, int sz) { - byte[] b = new byte[sz]; - for (int i = b.length - 1; i >= 0; i--) { - b[i] = (byte) (n & 255); - n >>>= 8; - } - return b; - } - - /** - * util method to convert byte array of given length into int - * - * @param b - * @param mustBeLen the length that b MUST be, else error. - * @return parsed b into an uint, or -1 in case of error or len(b) != mustBeLen. - */ - protected int toI(byte[] b, int mustBeLen) { - if (b.length != mustBeLen) { - isValid = false; - return -1; - } - int n = 0; - for (int i = 0; i < b.length; i++) { - n <<= 8; - n += ((int) (b[i] & 0xFF)); - } - return n; - } -} diff --git a/src/main/java/com/google/openthread/commissioner/tlv/TLVset.java b/src/main/java/com/google/openthread/commissioner/tlv/TLVset.java deleted file mode 100644 index b4b3222..0000000 --- a/src/main/java/com/google/openthread/commissioner/tlv/TLVset.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.google.openthread.commissioner.tlv; - -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.nio.charset.Charset; -import java.util.Arrays; -import java.util.HashMap; -import org.bouncycastle.util.encoders.Hex; - -/** Class to parse a byte[] into a generic set of TLVs and store them as HashMap */ -public class TLVset extends HashMap { - - private static final long serialVersionUID = 3955356716921778844L; - - /** whether this TLVset is valid; becomes false after failed parsing */ - public boolean isValid = true; - - /** error message in case isValid==false */ - public String err = null; - - private static final Charset UTF8_CHARSET = Charset.forName("UTF-8"); - - /** create a new, empty TLVset with no TLVs in */ - public TLVset() { - // - } - - /** copy constructor */ - public TLVset(TLVset t) { - super(t); - } - - /** put convenience-wrapper with String value */ - public byte[] put(Integer key, String valueStr) { - return this.put(key, valueStr.getBytes(UTF8_CHARSET)); - } - - /** put convenience-wrapper with uint32 value */ - public byte[] put(Integer key, int value) { - byte[] b = ByteBuffer.allocate(4).putInt(value).array(); - return this.put(key, b); - } - - /** put convenience-wrapper with zero or more IPv6 addresses */ - public byte[] put(Integer key, InetAddress[] addrs) { - byte[] b = new byte[addrs.length * 16]; - for (int i = 0; i < addrs.length; i++) { - System.arraycopy(addrs[i].getAddress(), 0, b, i * 16, 16); - } - return this.put(key, b); - } - - public byte[] put(TLV tlv) { - return this.put(tlv.T, tlv.V()); - } - - public String getAsString(Integer key) { - return new String(this.get(key)); - } - - /** - * serialize TLVset into byte array - * - * @return byte array serialized form - */ - public byte[] serialize() { - byte[] buf = new byte[8192 * 2]; // allocate some 'more than enough' space - int i = 0; // pointer into buffer - Integer[] keys = this.keySet().toArray(new Integer[0]); - Arrays.sort(keys); - for (Integer t : keys) { - buf[i] = (byte) (t & 0xFF); - i++; - int L = this.get(t).length; - if (L > 254) { - buf[i] = (byte) 0xFF; - buf[i + 1] = (byte) (L >> 8); - buf[i + 2] = (byte) (L & 0xFF); - i += 3; - } else { - buf[i] = (byte) L; - i++; - } - System.arraycopy(this.get(t), 0, buf, i, L); - i += L; - } - if (i == 0) return new byte[] {}; - byte[] s = new byte[i]; // create end result of length 'i' - System.arraycopy(buf, 0, s, 0, i); // from buffer - return s; - } - - public String toString() { - return this.toString(""); - } - - public String toString(String indentSpace) { - StringBuilder sb = new StringBuilder(); - sb.append(indentSpace + "{\n"); - for (Integer key : this.keySet()) { - sb.append( - indentSpace - + " " - + key - + ": " - + Hex.toHexString(this.get(key)) - + " (" - + this.get(key).length - + " bytes)\n"); - } - sb.append(indentSpace + "}"); - return sb.toString(); - } - - /** - * parse a byte array set of TLVs into a TLVset structure - * - * @param b byte array to parse - * @return new TLVset with all the TLVs in it - */ - public static TLVset parse(byte[] b) { - TLVset tlvs = new TLVset(); - int i = 0; - try { - while (i < b.length) { - byte[] v = null; - int t = (0xFF & b[i]); - int L = (0xFF & b[i + 1]); - if (L == 255) { - L = ((0xFF & b[i + 2]) << 8) + (0xFF & b[i + 3]); - v = Arrays.copyOfRange(b, i + 4, i + 4 + L); - i += (L + 4); - } else { - v = Arrays.copyOfRange(b, i + 2, i + 2 + L); - i += (L + 2); - } - - // store found tlv - tlvs.put(t, v); - } - } catch (Exception e) { - tlvs.isValid = false; - tlvs.err = e.getMessage(); - } - return tlvs; - } -} diff --git a/src/main/java/com/google/openthread/domainca/DomainCA.java b/src/main/java/com/google/openthread/domainca/DomainCA.java index 949b210..f063c59 100644 --- a/src/main/java/com/google/openthread/domainca/DomainCA.java +++ b/src/main/java/com/google/openthread/domainca/DomainCA.java @@ -73,8 +73,6 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder; import org.bouncycastle.pkcs.PKCS10CertificationRequest; -import se.sics.ace.cwt.CWT; -import se.sics.ace.cwt.CwtCryptoCtx; public class DomainCA { @@ -197,46 +195,6 @@ THREAD_DOMAIN_NAME_OID_ASN1, new DERTaggedObject(0, new DERIA5String(domainName) return cert; } - public CBORObject signCommissionerToken(CBORObject token) throws Exception { - return signCommissionerToken( - token, - privateKey, - SecurityUtils.COSE_SIGNATURE_ALGORITHM, - SecurityUtils.getSubjectKeyId(getCertificate())); - } - - public static CBORObject signCommissionerToken( - CBORObject token, PrivateKey signingKey, CBORObject signingAlg, byte[] subjectKeyId) - throws Exception { - Map claims = new HashMap<>(); - - Object aud = token.get(CBORObject.FromObject(se.sics.ace.Constants.AUD)); - claims.put(se.sics.ace.Constants.AUD, CBORObject.FromObject(aud)); - - // TODO(wgtdkp): verify the COSE_KEY with commissioner certificate presented by - // DTLS handshake - CBORObject cnf = CBORObject.NewMap(); - CBORObject tokenCnf = token.get(CBORObject.FromObject(se.sics.ace.Constants.REQ_CNF)); - cnf.Add( - se.sics.ace.Constants.COSE_KEY, - tokenCnf.get(CBORObject.FromObject(se.sics.ace.Constants.COSE_KEY))); - claims.put(se.sics.ace.Constants.CNF, cnf); - - String keyId = new String(subjectKeyId); - claims.put(se.sics.ace.Constants.ISS, CBORObject.FromObject(keyId)); - - // see rfc8392 NumericDate format - Date expire = - new Date(System.currentTimeMillis() + 3600 * 24 * 1000 * Constants.COM_TOK_VALIDITY); - claims.put(se.sics.ace.Constants.EXP, CBORObject.FromObject(expire.getTime())); - - OneKey oneKey = new OneKey(null, signingKey); - CwtCryptoCtx ctx = CwtCryptoCtx.sign1Create(oneKey, signingAlg); - - CWT cwt = new CWT(claims); - return cwt.encode(ctx); - } - public X500Name getSubjectName() { return new X500Name(getCertificate().getIssuerX500Principal().getName()); } diff --git a/src/main/java/com/google/openthread/pledge/PledgeMain.java b/src/main/java/com/google/openthread/pledge/PledgeMain.java index fdbc835..1a81b8e 100644 --- a/src/main/java/com/google/openthread/pledge/PledgeMain.java +++ b/src/main/java/com/google/openthread/pledge/PledgeMain.java @@ -29,7 +29,6 @@ package com.google.openthread.pledge; import com.google.openthread.Credentials; -import com.google.openthread.commissioner.Commissioner; import com.google.openthread.tools.CredentialGenerator; import java.security.KeyStoreException; import java.util.Scanner; @@ -102,25 +101,8 @@ public static void main(String args[]) { } Pledge pledge = new Pledge(cred, registrarUri); - cred = - new Credentials( - keyStoreFile, CredentialGenerator.COMMISSIONER_ALIAS, CredentialGenerator.PASSWORD); - Commissioner commissioner = null; - if (cred != null && cred.getPrivateKey() != null && cred.getCertificateChain() != null) { - commissioner = new Commissioner(cred); - } else { - String msg = "can't find commissioner key or certificate"; - msg += ": expect alias=" + CredentialGenerator.COMMISSIONER_ALIAS; - msg += ", password=" + CredentialGenerator.PASSWORD; - msg += "; commissioner disabled"; - System.err.println(msg); - } - - run(pledge, commissioner); + run(pledge); - if (commissioner != null) { - commissioner.shutdown(); - } pledge.shutdown(); } catch (IllegalArgumentException e) { System.err.println("error: " + e.getMessage()); @@ -131,11 +113,10 @@ public static void main(String args[]) { } } - private static void run(Pledge pledge, Commissioner commissioner) { + private static void run(Pledge pledge) { final String DOMAIN_NAME = "TestDomainTCE"; final String help = - "token - request commissioning token\n" - + "rv - request voucher\n" + "rv - request voucher\n" + "enroll - simple enrollment\n" + "reenroll - simple reenrollment\n" + "reset - reset to initial state\n" @@ -147,13 +128,6 @@ private static void run(Pledge pledge, Commissioner commissioner) { try { System.out.print("> "); switch (scanner.nextLine().trim()) { - case "token": - if (commissioner != null) { - commissioner.requestToken(DOMAIN_NAME, pledge.getHostURI()); - } else { - throw new Exception("invalid commissioner"); - } - break; case "rv": pledge.requestVoucher(); break; diff --git a/src/main/java/com/google/openthread/registrar/Registrar.java b/src/main/java/com/google/openthread/registrar/Registrar.java index 4d52ed1..1361b24 100644 --- a/src/main/java/com/google/openthread/registrar/Registrar.java +++ b/src/main/java/com/google/openthread/registrar/Registrar.java @@ -112,9 +112,9 @@ public class Registrar extends CoapServer { /** * Constructing registrar with specified settings, credentials and listening port. * - * @param privateKey the private key used for DTLS connection from Pledge - * @param certificateChain the certificate chain leading up to domain CA and including domain CA - * certificate, used for DTLS connection from Pledge. + * @param creds the credentials used to serve the DTLS connection from Pledge. Includes + * the certificate chain leading up to domain CA and including domain CA + * certificate. * @param masaTrustAnchors pre-installed MASA trust anchors that are trusted only when given. If * null, ALL MASAs will be trusted (for interop testing). * @param masaClientCreds credentials to use towards MASA client in Credentials format @@ -655,7 +655,7 @@ public final class MASAConnectorHttp { /** * Send new Voucher Request to MASA. * - * @param the media type string of the body + * @param requestMediaType the media type string of the body * @param body the Voucher Request in bytes * @param masaURI the MASA URI (without URI path, without https:// scheme) to send it to * @return null if any error happens @@ -772,42 +772,6 @@ public void handleGET(CoapExchange exchange) { } } - public final class CommissionerTokenResource extends CoapResource { - public CommissionerTokenResource() { - super(Constants.COM_TOK); - } - - @Override - public void handlePOST(CoapExchange exchange) { - try { - int contentFormat = exchange.getRequestOptions().getContentFormat(); - RequestDumper.dump(logger, getURI(), exchange.getRequestPayload()); - - if (contentFormat != ExtendedMediaTypeRegistry.APPLICATION_CWT) { - exchange.respond( - ResponseCode.UNSUPPORTED_CONTENT_FORMAT, - "Only Content Format " + ExtendedMediaTypeRegistry.APPLICATION_CWT + " supported."); - return; - } - - // TODO(wgtdkp): verify the COM_TOK.req - CBORObject req = CBORObject.DecodeFromBytes(exchange.getRequestPayload()); - validateComTokenReq(req); - - CBORObject signedToken = domainCA.signCommissionerToken(req); - byte[] encodedToken = signedToken.EncodeToBytes(); - logger.info( - "response token[len={}] : {}", encodedToken.length, Hex.toHexString(encodedToken)); - - exchange.respond( - ResponseCode.CHANGED, encodedToken, ExtendedMediaTypeRegistry.APPLICATION_COSE_SIGN1); - } catch (Exception e) { - logger.warn("commissioner token request failed: " + e.getMessage(), e); - exchange.respond(ResponseCode.BAD_REQUEST, e.getMessage()); - } - } - } - public final class WellknownCoreResource extends CoapResource { public WellknownCoreResource() { super(Constants.CORE); @@ -822,35 +786,6 @@ public void handleGET(CoapExchange exchange) { } } - public static void validateComTokenReq(CBORObject req) throws RegistrarException { - CBORObject grantType = req.get(CBORObject.FromObject(se.sics.ace.Constants.GRANT_TYPE)); - if (grantType == null) { - throw new RegistrarException("missing grant-type"); - } else if (grantType.AsInt32() != se.sics.ace.Constants.GT_CLI_CRED) { - throw new RegistrarException("COM_TOK.req grant-type is wrong: " + grantType.AsInt32()); - } - - CBORObject clientId = req.get(CBORObject.FromObject(se.sics.ace.Constants.CLIENT_ID)); - if (clientId == null) { - throw new RegistrarException("missing client-id"); - } - - CBORObject reqAud = req.get(CBORObject.FromObject(se.sics.ace.Constants.AUD)); - if (reqAud == null) { - throw new RegistrarException("missing req-aud"); - } - - CBORObject reqCnf = req.get(CBORObject.FromObject(se.sics.ace.Constants.REQ_CNF)); - if (reqCnf == null) { - throw new RegistrarException("missing req-cnf"); - } - - CBORObject coseKey = reqCnf.get(CBORObject.FromObject(se.sics.ace.Constants.COSE_KEY)); - if (coseKey == null) { - throw new RegistrarException("missing cose-key in req-cnf"); - } - } - /** * return a List of all clients that ever used this Registrar. * @@ -949,9 +884,6 @@ private void initResources() { wellKnown.add(core); wellKnown.add(est); wellKnown.add(brski); - // Commissioning FIXME ccm not defined in IANA well-known space, can place it in - // /.well-known/thread/ccm/tokenrequest - wellKnown.add(new CommissionerTokenResource()); this.add(wellKnown); // 'hello' test resource diff --git a/src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java b/src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java index 054c166..e0a5cfe 100644 --- a/src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java +++ b/src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java @@ -32,7 +32,6 @@ import com.google.openthread.*; import com.google.openthread.brski.*; -import com.google.openthread.commissioner.*; import com.google.openthread.domainca.*; import com.google.openthread.masa.*; import com.google.openthread.pledge.*; @@ -41,7 +40,6 @@ import org.junit.*; import org.junit.runners.*; import org.slf4j.*; -import se.sics.ace.cwt.CWT; /** * A tool to test a Hardware Pledge DUT (OpenThread CLI device) against the Registrar/MASA. The @@ -79,7 +77,6 @@ public class HardwarePledgeTestSuite { private static final String REGISTRAR_URI = "[::1]:" + Constants.DEFAULT_REGISTRAR_COAPS_PORT; private DomainCA domainCA; private Registrar registrar; - private Commissioner commissioner; private MASA masa; private static PledgeHardware pledge; private static CredentialGenerator credGen; @@ -124,7 +121,6 @@ public void init() throws Exception { registrar.setDomainCA(domainCA); // for local testing we force the MASA URI to localhost. registrar.setForcedMasaUri(Constants.DEFAULT_MASA_URI); - commissioner = new Commissioner(credGen.getCredentials(CredentialGenerator.COMMISSIONER_ALIAS)); masa.start(); registrar.start(); @@ -133,7 +129,6 @@ public void init() throws Exception { @After public void finalize() throws Exception { assertTrue(pledge.execCommandDone("thread stop")); - commissioner.shutdown(); registrar.stop(); masa.stop(); } @@ -243,18 +238,4 @@ public void test_5_06_NKP_TC_02() throws Exception { assertNotEquals("disabled", pledge.execCommand("state")); // verify thread is started assertEquals("false", pledge.execCommand("singleton")); // verify I joined with BR. } - - /** RE-TC-01: */ - @Test - public void test_5_07_RE_TC_01() throws Exception { - assertTrue(false); - } - - @Test - public void test_5_12_COMM_TC_01() throws Exception { - - CWT token = commissioner.requestToken(THREAD_DOMAIN_NAME, REGISTRAR_URI); - assertTrue(token.getClaims().size() > 0); - assertTrue(commissioner.start(BORDER_ROUTER_AUTHORITY)); - } } diff --git a/src/test/java/com/google/openthread/brski/ExamplePayloadsTest.java b/src/test/java/com/google/openthread/brski/ExamplePayloadsTest.java index e9d52c4..9773788 100644 --- a/src/test/java/com/google/openthread/brski/ExamplePayloadsTest.java +++ b/src/test/java/com/google/openthread/brski/ExamplePayloadsTest.java @@ -29,7 +29,6 @@ package com.google.openthread.brski; import com.google.openthread.*; -import com.google.openthread.commissioner.*; import com.google.openthread.pledge.*; import com.google.openthread.registrar.*; import com.upokecenter.cbor.CBORObject; @@ -76,12 +75,4 @@ public void voucherExamplePayload() throws Exception { logger.info("example constrained voucher payload:"); logger.info(new CBORSerializer().toCBOR(cv).toString()); } - - @Test - public void comTokenExamplePayload() throws Exception { - KeyPair kp = SecurityUtils.genKeyPair(); - CBORObject req = Commissioner.genTokenRequest("OpenThread-TCE-TEST", kp.getPublic()); - logger.info("example COM_TOK.req payload:"); - logger.info(req.toString()); - } } diff --git a/src/test/java/com/google/openthread/registrar/FunctionalTest.java b/src/test/java/com/google/openthread/registrar/FunctionalTest.java index e75acaa..fc54ffe 100644 --- a/src/test/java/com/google/openthread/registrar/FunctionalTest.java +++ b/src/test/java/com/google/openthread/registrar/FunctionalTest.java @@ -32,7 +32,6 @@ import com.google.openthread.*; import com.google.openthread.brski.*; -import com.google.openthread.commissioner.*; import com.google.openthread.domainca.*; import com.google.openthread.masa.*; import com.google.openthread.pledge.*; @@ -49,7 +48,6 @@ import org.junit.rules.ExpectedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import se.sics.ace.cwt.CWT; public class FunctionalTest { @@ -61,7 +59,6 @@ public class FunctionalTest { // the acting entities private DomainCA domainCA; private Registrar registrar; - private Commissioner commissioner; private Pledge pledge; private MASA masa; @@ -109,8 +106,6 @@ protected void initEntities(CredentialGenerator credGen) throws Exception { .build(); registrar.setDomainCA(domainCA); - commissioner = new Commissioner(credGen.getCredentials(CredentialGenerator.COMMISSIONER_ALIAS)); - masa.start(); registrar.start(); } @@ -122,7 +117,6 @@ public void finalize() { protected void stopEntities() { pledge.shutdown(); - commissioner.shutdown(); registrar.stop(); masa.stop(); } @@ -311,14 +305,6 @@ public void testReset() throws Exception { VerifyEnroll(pledge); } - @Test - public void testCommissionerTokenRequest() throws Exception { - CWT comTok = commissioner.requestToken("TestDomainTCE", REGISTRAR_URI); - // TODO check result more; try 'bad commissioner' cases. - Assert.assertTrue(comTok.getClaims().size() > 0); - Assert.assertTrue(comTok.isValid(System.currentTimeMillis() + 500000)); - } - @Test public void testMultiPledges() throws Exception { PledgeThread[] threads = new PledgeThread[12]; From 8ce105c150c0d8140e2c93b024fd166b24d6d7e1 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Wed, 26 Jun 2024 16:00:13 +0200 Subject: [PATCH 03/25] [pom.xml] bump versions to avoid log4j related performance WARNING msg. --- pom.xml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 9a1e461..8f32277 100644 --- a/pom.xml +++ b/pom.xml @@ -86,7 +86,7 @@ org.apache.logging.log4j log4j-core - 2.17.1 + 2.23.1 @@ -130,7 +130,14 @@ maven-jar-plugin - 3.0.2 + 3.3.0 + + + + true + + + maven-install-plugin From 7fe2960a958952c51cbce0dc26549700d18320dd Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Wed, 26 Jun 2024 16:03:38 +0200 Subject: [PATCH 04/25] removal of ACE, doc updates, src format updates, and new generic-main function WIP. --- .github/workflows/build.yml | 2 +- .gitignore | 17 +- AUTHORS | 1 + CONTRIBUTING.md | 24 ++- GUIDE.md | 2 +- README.md | 8 +- script/bootstrap.sh | 13 -- script/run | 38 ++++ .../openthread/main/OtRegistrarMain.java | 164 ++++++++++++++++++ .../openthread/registrar/Registrar.java | 115 ++++++------ .../registrar/RegistrarBuilder.java | 20 +-- .../openthread/registrar/FunctionalTest.java | 45 +++-- 12 files changed, 314 insertions(+), 135 deletions(-) create mode 100755 script/run create mode 100644 src/main/java/com/google/openthread/main/OtRegistrarMain.java diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bf1cf62..90f4fc4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,7 +43,7 @@ jobs: package-test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Bootstrap run: script/bootstrap.sh - name: Package diff --git a/.gitignore b/.gitignore index 796d983..a8ca5db 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ -# Compiled class file +# Compiled class files *.class -# Log file +# Log files *.log logs @@ -11,7 +11,7 @@ logs # Mobile Tools for Java (J2ME) .mtj.tmp/ -# Package Files # +# Package Files *.jar *.war *.nar @@ -28,22 +28,15 @@ hs_err_pid* # maven target -# idea +# IDE files .idea .project *.iml - -# vscode .vscode - .settings -# utils +# auto-generated config files Californium.properties -thread-registrar.iml # Mac OS X .DS_Store - -# Thread Registrar Interface -tri diff --git a/AUTHORS b/AUTHORS index 3a4f4fb..d00e3fa 100644 --- a/AUTHORS +++ b/AUTHORS @@ -8,3 +8,4 @@ # Authors who wish to be recognized in this file should add themselves (or # their employer, as appropriate). Google Inc. +IoTconsultancy.nl diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1218a87..52c3046 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,15 +12,15 @@ Help us keep OpenThread open and inclusive. Please read and follow our [Code of ## Bugs -If you find a bug in the source code, you can help us by [submitting a GitHub Issue](https://github.com/openthread/ot-registrar/issues/new). Even better, you can [submit a Pull Request](#submitting-a-pull-request) with a fix. +If you find a bug in the source code, you can help us by [submitting a GitHub Issue](https://github.com/EskoDijk/ot-registrar/issues/new). Even better, you can [submit a Pull Request](#submitting-a-pull-request) with a fix. ## New features -You can request a new feature by [submitting a GitHub Issue](https://github.com/openthread/ot-registrar/issues/new). +You can request a new feature by [submitting a GitHub Issue](https://github.com/EskoDijk/ot-registrar/issues/new). If you would like to implement a new feature, please consider the scope of the new feature: -* *Large feature* — [Submit a GitHub Issue](https://github.com/openthread/ot-registrar/issues/new) with your proposal so that the community can review and provide feedback first. Early feedback helps to ensure your proposal is accepted by the community, better coordinate our efforts, and minimize duplicated work. +* *Large feature* — [Submit a GitHub Issue](https://github.com/EskoDijk/ot-registrar/issues/new) with your proposal so that the community can review and provide feedback first. Early feedback helps to ensure your proposal is accepted by the community, better coordinate our efforts, and minimize duplicated work. * *Small feature* — Can be implemented and directly [submitted as a Pull Request](#submitting-a-pull-request) without a proposal. @@ -32,17 +32,17 @@ The OpenThread Project follows the "Fork-and-Pull" model for accepting contribut Setup your GitHub fork and continuous integration services: -1. Fork the [OT Registrar repository](https://github.com/openthread/ot-registrar) by clicking **Fork** on the web UI. -2. Enable [Travis CI](https://travis-ci.org/) by logging into the respective service with your GitHub account and enabling your newly created fork. We use Travis CI for Linux-based continuous integration checks. All contributions must pass these checks to be accepted. +1. Fork the [OT Registrar repository](https://github.com/EskoDijk/ot-registrar) by clicking **Fork** on the web UI. +2. Enable GitHub CI by logging into your GitHub account and enabling it on your newly created fork. We use CI for Linux-based continuous integration checks. All contributions must pass these checks to be accepted. Setup your local development environment: ```bash # Clone your fork -git clone git@github.com:/ot-registrar.git +git clone https://@github.com/EskoDijk/ot-registrar.git # Configure upstream alias -git remote add upstream git@github.com:openthread/ot-registrar.git +git remote add upstream https://@github.com/EskoDijk/ot-registrar.git ``` ### Submitting a pull request @@ -99,11 +99,7 @@ This will open up a text editor where you can specify which commits to squash. #### Coding conventions and style -OT Registrar uses and enforces the [Google Java Style](https://google.github.io/styleguide/javaguide.html) on all code. OT Registrar will automatically reformat the code when building the project with [maven](https://maven.apache.org). Use command `mvn com.coveo:fmt-maven-plugin:format` and `mvn com.coveo:fmt-maven-plugin:check` to explicitly reformat code and check for code-style compliance, respectively. - -As part of the cleanup process, also run `mvn com.coveo:fmt-maven-plugin:check` to ensure that your code passes the baseline code style checks. - -Make sure to include any code format changes in your commits. +OT Registrar does not use the [Google Java Style](https://google.github.io/styleguide/javaguide.html) at this moment. The reason is that it introduces a very narrow line width, which makes code hard to read on normal-size desktop monitors that can handle long line lengths. #### Push and test @@ -115,8 +111,8 @@ git checkout git push origin ``` -This will trigger the Travis Continuous Integration (CI) checks. You can view the results in the respective services. Note that the integration checks will report failures on occasion. If a failure occurs, you may try rerunning the test using the Travis web UI. +This will trigger Github Continuous Integration (CI) checks. You can view the results in the respective services. #### Submit the pull request -Once you've validated the Travis CI results, go to the page for your fork on GitHub, select your development branch, and click the **Pull Request** button. If you need to make any adjustments to your pull request, push the updates to GitHub. Your pull request will automatically track the changes on your development branch and update. +Once you've validated the CI results, go to the page for your fork on GitHub, select your development branch, and click the **Pull Request** button. If you need to make any adjustments to your pull request, push the updates to GitHub. Your pull request will automatically track the changes on your development branch and update. diff --git a/GUIDE.md b/GUIDE.md index 0a8952b..7a3a1a8 100644 --- a/GUIDE.md +++ b/GUIDE.md @@ -30,7 +30,7 @@ All setup commands assume you are starting in the project's root directory. ## Run services -The OT Registrar JAR file includes the [Registrar](https://tools.ietf.org/id/draft-ietf-anima-bootstrapping-keyinfra-16.html#rfc.section.1.2), [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, 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). ### Credentials diff --git a/README.md b/README.md index ce24910..7ea1e0a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # OpenThread Registrar -Per [Thread](https://www.threadgroup.org/) 1.2 specification and [Bootstrapping Remote Secure Key Infrastructures (BRSKI)](https://tools.ietf.org/html/draft-ietf-anima-bootstrapping-keyinfra-16), a Domain Registrar securely registry new devices into a Thread Domain with zero-touch. +The [Constrained Bootstrapping Remote Secure Key Infrastructures (cBRSKI)](https://datatracker.ietf.org/doc/html/draft-ietf-anima-constrained-voucher) IETF draft defines a Domain Registrar for securely onboarding new IoT devices into a network domain with zero-touch. -OpenThread's implementation of a Domain Registrar is called OpenThread Registrar (OT Registrar). +OpenThread's implementation of a cBRSKI Domain Registrar, used for onboarding Thread devices, is called OpenThread Registrar (OT Registrar). > Note: OT Registrar is still under development. We do not recommend using it in production yet. @@ -18,10 +18,10 @@ Contributors are required to abide by our [Code of Conduct](CODE_OF_CONDUCT.md). ## Versioning -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 but will clearly indicate which version of the specification it currently supports. +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 OT Registrar is released under the [BSD 3-Clause license](LICENSE). See the [`LICENSE`](LICENSE) file for more information. -Please only use the OpenThread and OT Registrar name and marks when accurately referencing this software distribution. Do not use the marks in a way that suggests you are endorsed by or otherwise affiliated with Nest, Google, or The Thread Group. +Please only use the OpenThread and OT Registrar name and marks when accurately referencing this software distribution. Do not use the marks in a way that suggests you are endorsed by or otherwise affiliated with Nest, Google, or Thread Group. diff --git a/script/bootstrap.sh b/script/bootstrap.sh index 552adee..2c3f6a0 100755 --- a/script/bootstrap.sh +++ b/script/bootstrap.sh @@ -29,8 +29,6 @@ set -e -ACE_REPO=https://bitbucket.org/marco-tiloca-sics/ace-java - ## Test if we has the given command. ## Args: $1, the command. has_command() { @@ -61,15 +59,4 @@ install_toolchain() { mvn -verion } -install_ace() { - if [ ! -d ace ]; then - git clone $ACE_REPO ace - fi - cd ace - mvn -DskipTests install - cd - - rm -rf ace -} - install_toolchain -install_ace diff --git a/script/run b/script/run new file mode 100755 index 0000000..b6aa470 --- /dev/null +++ b/script/run @@ -0,0 +1,38 @@ +#!/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. +# + +readonly JAR_FILE=./target/ot-registrar-0.2-jar-with-dependencies.jar + +# test if Registrar JAR exists +if [ ! -f "${JAR_FILE}" ]; then + echo "Please build using 'mvn -DskipTests package' before running." + exit 1 +fi + +java -jar $JAR_FILE $@ diff --git a/src/main/java/com/google/openthread/main/OtRegistrarMain.java b/src/main/java/com/google/openthread/main/OtRegistrarMain.java new file mode 100644 index 0000000..b169655 --- /dev/null +++ b/src/main/java/com/google/openthread/main/OtRegistrarMain.java @@ -0,0 +1,164 @@ +/* + * 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. + */ + +package com.google.openthread.main; + +import com.google.openthread.Credentials; +import com.google.openthread.LoggerInitializer; +import com.google.openthread.domainca.DomainCA; +import com.google.openthread.registrar.Registrar; +import com.google.openthread.registrar.RegistrarBuilder; +import com.google.openthread.tools.CredentialGenerator; +import java.security.KeyStoreException; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.CommandLineParser; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class OtRegistrarMain { + + private static Logger logger = LoggerFactory.getLogger(OtRegistrarMain.class); + + public static void main(String args[]) { + + final String HELP_FORMAT = "[-registrar | -masa | -pledge] [-h] [-v] [-d ] [-f ] [-p ]"; + + HelpFormatter helper = new HelpFormatter(); + Options options = new Options(); + + Option registrarOpt = + Option.builder("registrar") + .desc("start as cBRSKI Registrar") + .build(); + + Option masaOpt = + Option.builder("masa") + .desc("start as cBRSKI/BRSKI MASA") + .build(); + + Option pledgeOpt = + Option.builder("pledge") + .desc("start as cBRSKI Pledge") + .build(); + + Option domainNameOpt = + Option.builder("d") + .longOpt("domainname") + .hasArg() + .argName("domain-name") + .desc("the domain name") + .build(); + + Option fileOpt = + Option.builder("f") + .longOpt("file") + .hasArg() + .argName("keystore-file") + .desc("the keystore file in PKCS#12 format") + .build(); + + Option optPort = + Option.builder("p") + .longOpt("port") + .hasArg() + .argName("udp-port") + .desc("the port to listen on") + .build(); + + Option optVerbose = + Option.builder("v") + .longOpt("verbose") + .desc("verbose mode with many logs") + .build(); + + Option optForceMasaUri = + Option.builder("m") + .longOpt("masa") + .hasArg() + .argName("force-masa-uri") + .desc("force the given MASA URI instead of the default one") + .build(); + + Option helpOpt = + Option.builder("h").longOpt("help").hasArg(false).desc("print this message").build(); + + options + .addOption(registrarOpt) + .addOption(masaOpt) + .addOption(pledgeOpt) + .addOption(domainNameOpt) + .addOption(fileOpt) + .addOption(optPort) + .addOption(optVerbose) + .addOption(optForceMasaUri) + .addOption(helpOpt); + + try { + CommandLineParser parser = new DefaultParser(); + CommandLine cmd = parser.parse(options, args); + + LoggerInitializer.Init(cmd.hasOption('v')); + + if (cmd.hasOption('h')) { + helper.printHelp(HELP_FORMAT, options); + return; + } + + String keyStoreFile = cmd.getOptionValue('f'); + if (keyStoreFile == null) { + keyStoreFile = "credentials/default.p12"; + } + + String port = cmd.getOptionValue('p'); + if (port == null) { + port = "5683"; + } + + String domainName = cmd.getOptionValue('d'); + if (domainName == null) { + domainName = "DefaultDomain"; + } + + if (cmd.hasOption('m')) { + // FIXME registrar.setForcedMasaUri(cmd.getOptionValue('m')); + } + + logger.info("using keystore: {}", keyStoreFile); + + } catch (Exception e) { + logger.error(e.getMessage(), e); + helper.printHelp(HELP_FORMAT, options); + return; + } + + } +} diff --git a/src/main/java/com/google/openthread/registrar/Registrar.java b/src/main/java/com/google/openthread/registrar/Registrar.java index 1361b24..e8e2220 100644 --- a/src/main/java/com/google/openthread/registrar/Registrar.java +++ b/src/main/java/com/google/openthread/registrar/Registrar.java @@ -112,14 +112,11 @@ public class Registrar extends CoapServer { /** * Constructing registrar with specified settings, credentials and listening port. * - * @param creds the credentials used to serve the DTLS connection from Pledge. Includes - * the certificate chain leading up to domain CA and including domain CA - * certificate. - * @param masaTrustAnchors pre-installed MASA trust anchors that are trusted only when given. If - * null, ALL MASAs will be trusted (for interop testing). - * @param masaClientCreds credentials to use towards MASA client in Credentials format - * @param port the CoAP port to listen on - * @param isHttpToMasa whether to use HTTP requests to MASA (true, default) or CoAP (false) + * @param creds the credentials used to serve the DTLS connection from Pledge. Includes the certificate chain leading up to domain CA and including domain CA certificate. + * @param masaTrustAnchors pre-installed MASA trust anchors that are trusted only when given. If null, ALL MASAs will be trusted (for interop testing). + * @param masaClientCreds credentials to use towards MASA client in Credentials format + * @param port the CoAP port to listen on + * @param isHttpToMasa whether to use HTTP requests to MASA (true, default) or CoAP (false) * @throws RegistrarException */ Registrar( @@ -170,11 +167,9 @@ public void setDomainCA(DomainCA domainCA) { } /** - * By default the Registrar mimics the Pledge's Voucher Request format, when requesting to MASA. - * This method changes that to force the Registrar to use one format only. + * By default the Registrar mimics the Pledge's Voucher Request format, when requesting to MASA. This method changes that to force the Registrar to use one format only. * - * @param mediaType one of Constants.HTTP_APPLICATION_VOUCHER_CMS_JSON or - * Constants.HTTP_APPLICATION_VOUCHER_COSE_CBOR, or "" to force nothing. + * @param mediaType one of Constants.HTTP_APPLICATION_VOUCHER_CMS_JSON or Constants.HTTP_APPLICATION_VOUCHER_COSE_CBOR, or "" to force nothing. * @return */ public void setForcedRequestFormat(String mediaType) { @@ -194,17 +189,18 @@ public void setForcedRequestFormat(String mediaType) { } /** - * Override the MASA URI encoded in a Pledge's IDevID certificate, by setting a forced MASA-URI - * that is always applied. Used typically for testing, or a deployment-specific override of the - * MASA-URI. By default, no particular URI is forced but rather the MASA URI is taken from the - * Pledge IDevID certificate. + * Override the MASA URI encoded in a Pledge's IDevID certificate, by setting a forced MASA-URI that is always applied. Used typically for testing, or a deployment-specific override of the MASA-URI. + * By default, no particular URI is forced but rather the MASA URI is taken from the Pledge IDevID certificate. * * @param uri new MASA URI to always use, or "" to not force any MASA URI. * @return */ public void setForcedMasaUri(String uri) { - if (uri.length() == 0) this.setForcedMasaUri = null; - else this.setForcedMasaUri = uri; + if (uri.length() == 0) { + this.setForcedMasaUri = null; + } else { + this.setForcedMasaUri = uri; + } } public int getListenPort() { @@ -407,9 +403,11 @@ public void handlePOST(CoapExchange exchange) { boolean isJsonRVR = (forcedVoucherRequestFormat == ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_CMS_JSON || forcedVoucherRequestFormat - == ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_COSE_JSON); + == ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_COSE_JSON); VoucherRequest req = new VoucherRequest(); - if (!isJsonRVR) req.setConstrained(true); + if (!isJsonRVR) { + req.setConstrained(true); + } req.assertion = pledgeReq.assertion; // assertion copied from PVR // Note, section 5.5: assertion MAY be omitted. @@ -475,8 +473,11 @@ pledgeReq.proximityRegistrarSPKI, getCertificate().getPublicKey().getEncoded())) byte[] content = null; // Uses CBOR or JSON voucher request format. - if (isJsonRVR) content = new JSONSerializer().serialize(req); - else content = new CBORSerializer().serialize(req); + if (isJsonRVR) { + content = new JSONSerializer().serialize(req); + } else { + content = new CBORSerializer().serialize(req); + } // store last sent RVR. lastRvr = req; @@ -486,17 +487,15 @@ pledgeReq.proximityRegistrarSPKI, getCertificate().getPublicKey().getEncoded())) boolean isCms = (forcedVoucherRequestFormat == ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_CMS_CBOR || forcedVoucherRequestFormat - == ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_CMS_JSON); + == ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_CMS_JSON); if (isCms) { // CMS signing. - requestMediaType = - isJsonRVR - ? Constants.HTTP_APPLICATION_VOUCHER_CMS_JSON - : Constants.HTTP_APPLICATION_VOUCHER_CMS_CBOR; - requestContentFormat = - isJsonRVR - ? ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_CMS_JSON - : ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_CMS_CBOR; + requestMediaType = isJsonRVR + ? Constants.HTTP_APPLICATION_VOUCHER_CMS_JSON + : Constants.HTTP_APPLICATION_VOUCHER_CMS_CBOR; + requestContentFormat = isJsonRVR + ? ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_CMS_JSON + : ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_CMS_CBOR; try { payload = SecurityUtils.genCMSSignedMessage( @@ -604,7 +603,9 @@ pledgeReq.proximityRegistrarSPKI, getCertificate().getPublicKey().getEncoded())) } } - /** CoAP-based MASA connector, acts as client towards MASA. */ + /** + * CoAP-based MASA connector, acts as client towards MASA. + */ public final class MASAConnector extends CoapClient { MASAConnector(X509Certificate[] trustAnchors) { @@ -612,12 +613,11 @@ public final class MASAConnector extends CoapClient { } /** - * Send new Voucher Request to MASA. Note that the present format used is not standardized, but - * custom to OT-Registrar and OT-Masa. + * Send new Voucher Request to MASA. Note that the present format used is not standardized, but custom to OT-Registrar and OT-Masa. * * @param requestContentFormat the CoAP content-format of the request - * @param payload the Voucher Request in cbor format - * @param masaURI the MASA URI (without URI path, without coaps:// scheme) to send it to + * @param payload the Voucher Request in cbor format + * @param masaURI the MASA URI (without URI path, without coaps:// scheme) to send it to * @return null if a timeout error happens */ public RestfulVoucherResponse requestVoucher( @@ -630,7 +630,9 @@ public RestfulVoucherResponse requestVoucher( payload, requestContentFormat, ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_COSE_CBOR); - if (resp == null) return null; + if (resp == null) { + return null; + } return new RestfulVoucherResponse( resp.getCode(), resp.getPayload(), resp.getOptions().getContentFormat()); } @@ -643,7 +645,9 @@ private void initEndPoint(X509Certificate[] trustAnchors) { } } - /** HTTPS-based MASA connector, acts as client towards MASA. */ + /** + * HTTPS-based MASA connector, acts as client towards MASA. + */ public final class MASAConnectorHttp { protected SSLContext sc; @@ -656,8 +660,8 @@ public final class MASAConnectorHttp { * Send new Voucher Request to MASA. * * @param requestMediaType the media type string of the body - * @param body the Voucher Request in bytes - * @param masaURI the MASA URI (without URI path, without https:// scheme) to send it to + * @param body the Voucher Request in bytes + * @param masaURI the MASA URI (without URI path, without https:// scheme) to send it to * @return null if any error happens */ public RestfulVoucherResponse requestVoucher( @@ -698,11 +702,12 @@ private void initEndPoint(X509Certificate[] trustAnchors) throws Exception { KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(masaClientCredentials.getKeyStore(), CredentialGenerator.PASSWORD.toCharArray()); - sc.init(kmf.getKeyManagers(), new TrustManager[] {new DummyTrustManager()}, null); + sc.init(kmf.getKeyManagers(), new TrustManager[]{new DummyTrustManager()}, null); } } public class EnrollResource extends CoapResource { + public EnrollResource() { this(Constants.SIMPLE_ENROLL); } @@ -746,12 +751,14 @@ public void handlePOST(CoapExchange exchange) { } public final class ReenrollResource extends EnrollResource { + public ReenrollResource() { super(Constants.SIMPLE_REENROLL); } } public final class CrtsResource extends CoapResource { + public CrtsResource() { super(Constants.CA_CERTIFICATES); } @@ -773,6 +780,7 @@ public void handleGET(CoapExchange exchange) { } public final class WellknownCoreResource extends CoapResource { + public WellknownCoreResource() { super(Constants.CORE); } @@ -796,19 +804,20 @@ public Principal[] getKnownClients() { l.addAll(voucherLog.keySet()); l.addAll(voucherStatusLog.keySet()); l.addAll(enrollStatusLog.keySet()); - return l.toArray(new Principal[] {}); + return l.toArray(new Principal[]{}); } /** * get the last voucher-status telemetry that was sent by a specific client. * * @param client the secure client identifier - * @returns If available, the last voucher-status telemetry. If client did not send any - * voucher-status telemetry, it returns null. If client did send voucher-status telemetry, but - * in an unrecognized format, it returns StatusTelemetry.UNDEFINED. + * @returns If available, the last voucher-status telemetry. If client did not send any voucher-status telemetry, it returns null. If client did send voucher-status telemetry, but in an unrecognized + * format, it returns StatusTelemetry.UNDEFINED. */ public StatusTelemetry getVoucherStatusLogEntry(Principal client) { - if (voucherStatusLog.containsKey(client)) return voucherStatusLog.get(client); + if (voucherStatusLog.containsKey(client)) { + return voucherStatusLog.get(client); + } return null; } @@ -816,12 +825,13 @@ public StatusTelemetry getVoucherStatusLogEntry(Principal client) { * get the last enroll-status telemetry that was sent by a specific client. * * @param client the secure client identifier - * @returns If available, the last enroll-status telemetry. If client did not send any - * enroll-status telemetry, it returns null. If client did send enroll-status telemetry, but - * in an unrecognized format, it returns StatusTelemetry.UNDEFINED. + * @returns If available, the last enroll-status telemetry. If client did not send any enroll-status telemetry, it returns null. If client did send enroll-status telemetry, but in an unrecognized + * format, it returns StatusTelemetry.UNDEFINED. */ public StatusTelemetry getEnrollStatusLogEntry(Principal client) { - if (enrollStatusLog.containsKey(client)) return enrollStatusLog.get(client); + if (enrollStatusLog.containsKey(client)) { + return enrollStatusLog.get(client); + } return null; } @@ -901,13 +911,14 @@ private void initEndpoint() { trustAnchors.add(getDomainCertificate()); CertificateVerifier verifier; - if (this.masaTrustAnchors.length == 0) + if (this.masaTrustAnchors.length == 0) { verifier = new RegistrarCertificateVerifier(null); // trust all clients. - else + } else { verifier = new RegistrarCertificateVerifier( trustAnchors.toArray( new X509Certificate[trustAnchors.size()])); // trust only given MASA CAs. + } CoapEndpoint endpoint = SecurityUtils.genCoapServerEndPoint( diff --git a/src/main/java/com/google/openthread/registrar/RegistrarBuilder.java b/src/main/java/com/google/openthread/registrar/RegistrarBuilder.java index 7d96b9d..f27073e 100644 --- a/src/main/java/com/google/openthread/registrar/RegistrarBuilder.java +++ b/src/main/java/com/google/openthread/registrar/RegistrarBuilder.java @@ -48,12 +48,10 @@ public RegistrarBuilder() { } /** - * Supply the credentials to be used for Registrar in its role as MASA-client. By default, no - * separate credentials are used and rather the 'setCredentials()' credentials are used for - * authentication to MASA server as a client. + * Supply the credentials to be used for Registrar in its role as MASA-client. By default, no separate credentials are used and rather the 'setCredentials()' credentials are used for authentication + * to MASA server as a client. * - * @param cred Credentials to use in client role towards MASA server, or null to re-use the - * 'setCredentials()' credentials for this. + * @param cred Credentials to use in client role towards MASA server, or null to re-use the 'setCredentials()' credentials for this. * @return * @throws GeneralSecurityException */ @@ -113,8 +111,7 @@ public RegistrarBuilder setCertificateChain(X509Certificate[] certificateChain) } /** - * Add a MASA certificate of a trusted MASA server. Only needed if 'setTrustAllMasas(true)' is not - * enabled. + * Add a MASA certificate of a trusted MASA server. Only needed if 'setTrustAllMasas(true)' is not enabled. * * @param masaCertificate * @return @@ -125,8 +122,7 @@ public RegistrarBuilder addMasaCertificate(X509Certificate masaCertificate) { } /** - * Sets whether to trust ALL MASAs (true) or only MASAs for which certificates were added (false). - * By default, this is 'false'. + * Sets whether to trust ALL MASAs (true) or only MASAs for which certificates were added (false). By default, this is 'false'. * * @param status */ @@ -141,8 +137,7 @@ public RegistrarBuilder setPort(int port) { } /** - * Sets whether HTTPS is used to communicate with the MASA. This is usually the case (true). Only - * for testing situations HTTPS is set to 'false', in which case CoAP will be used. + * Sets whether HTTPS is used to communicate with the MASA. This is usually the case (true). Only for testing situations HTTPS is set to 'false', in which case CoAP will be used. * * @param isHttp true if HTTPS is to be used, false if COAPS is to be used. * @return @@ -153,8 +148,7 @@ public RegistrarBuilder setHttpToMasa(boolean isHttp) { } /** - * return the number of supported/trusted MASA servers. Use addMasaCertificate() to add more - * trusted MASA servers. + * return the number of supported/trusted MASA servers. Use addMasaCertificate() to add more trusted MASA servers. * * @return the number of MASA certificates that are considered trusted. */ diff --git a/src/test/java/com/google/openthread/registrar/FunctionalTest.java b/src/test/java/com/google/openthread/registrar/FunctionalTest.java index fc54ffe..bb89bae 100644 --- a/src/test/java/com/google/openthread/registrar/FunctionalTest.java +++ b/src/test/java/com/google/openthread/registrar/FunctionalTest.java @@ -51,8 +51,7 @@ public class FunctionalTest { - public static final String REGISTRAR_URI = - "coaps://[::1]:" + Constants.DEFAULT_REGISTRAR_COAPS_PORT; + public static final String REGISTRAR_URI = "coaps://[::1]:" + Constants.DEFAULT_REGISTRAR_COAPS_PORT; public static final String DEFAULT_DOMAIN_NAME = "Thread-Test"; @@ -67,7 +66,8 @@ public class FunctionalTest { private static Logger logger = LoggerFactory.getLogger(FunctionalTest.class); - @Rule public ExpectedException thrown = ExpectedException.none(); + @Rule + public ExpectedException thrown = ExpectedException.none(); @BeforeClass public static void setup() throws Exception { @@ -77,7 +77,8 @@ public static void setup() throws Exception { } @AfterClass - public static void tearDown() {} + public static void tearDown() { + } @Before public void init() throws Exception { @@ -233,8 +234,7 @@ public void testReenroll() throws Exception { } /** - * Test various status telemetry messages, stand-alone (not associated to enrollment/voucher - * request). Current Registrar is implemented to just accept/log these. + * Test various status telemetry messages, stand-alone (not associated to enrollment/voucher request). Current Registrar is implemented to just accept/log these. * * @throws Exception */ @@ -242,17 +242,14 @@ public void testReenroll() throws Exception { public void testStatusTelemetry() throws Exception { Assert.assertEquals( ResponseCode.CHANGED, - pledge.sendEnrollStatusTelemetry( - true, - "this message should not be here, but may be accepted by Registrar nevertheless.")); + pledge.sendEnrollStatusTelemetry(true, "this message should not be here, but may be accepted by Registrar nevertheless.")); Assert.assertEquals( ResponseCode.CHANGED, pledge.sendVoucherStatusTelemetry( true, "this message should not be here, but may be accepted by Registrar nevertheless.")); - byte[] wrongFormatTelemetry = - Hex.decode( - "a46776657273696f6e6131665374617475730166526561736f6e7822496e666f726d61746976652068756d616e207265616461626c65206d6573736167656e726561736f6e2d636f6e74657874764164646974696f6e616c20696e666f726d6174696f6e"); + byte[] wrongFormatTelemetry = Hex.decode( + "a46776657273696f6e6131665374617475730166526561736f6e7822496e666f726d61746976652068756d616e207265616461626c65206d6573736167656e726561736f6e2d636f6e74657874764164646974696f6e616c20696e666f726d6174696f6e"); Assert.assertEquals( ResponseCode.BAD_REQUEST, pledge.sendStatusTelemetry( @@ -271,9 +268,7 @@ public void testStatusTelemetry() throws Exception { Constants.VOUCHER_STATUS, wrongFormatTelemetry, ExtendedMediaTypeRegistry.APPLICATION_COSE_SIGN1)); - wrongFormatTelemetry = - Hex.decode( - "a36776657273696f6e0166737461747573f467726561736f6e787174686973206b65792069732077726f6e67"); + wrongFormatTelemetry = Hex.decode("a36776657273696f6e0166737461747573f467726561736f6e787174686973206b65792069732077726f6e67"); Assert.assertEquals( ResponseCode.BAD_REQUEST, pledge.sendStatusTelemetry( @@ -337,8 +332,7 @@ public void testMultiPledges() throws Exception { } /** - * In a thread, create a new Pledge and let it do voucher request and enrollment operations. Any - * error state is logged internally. + * In a thread, create a new Pledge and let it do voucher request and enrollment operations. Any error state is logged internally. */ private class PledgeThread extends Thread { @@ -365,7 +359,9 @@ public void run() { } catch (Throwable e) { errorState = e; } finally { - if (pledge != null) pledge.shutdown(); + if (pledge != null) { + pledge.shutdown(); + } } } } @@ -384,7 +380,7 @@ public void testRegistrarWithoutCmcRa() throws Exception { registrar = registrarBuilder .setCredentials(cg.getCredentials(CredentialGenerator.REGISTRAR_ALIAS)) - .setCertificateChain(new X509Certificate[] {cert, domainCaCert}) + .setCertificateChain(new X509Certificate[]{cert, domainCaCert}) .setTrustAllMasas(true) .build(); registrar.setDomainCA(domainCA); @@ -395,7 +391,8 @@ public void testRegistrarWithoutCmcRa() throws Exception { try { response = pledge.sayHello(); Assert.fail("Pledge mistakenly accepted Registrar without cmcRA"); - } catch (IOException ex) {; + } catch (IOException ex) { + ; } // try again without checking strictly for cmcRA @@ -423,11 +420,9 @@ public void testRegistrarUsingCmsJsonVoucherRequest() throws Exception { // create new Registrar that uses only CMS-signed JSON voucher requests towards MASA RegistrarBuilder registrarBuilder = new RegistrarBuilder(); - registrar = - registrarBuilder - .setCredentials(cg.getCredentials(CredentialGenerator.REGISTRAR_ALIAS)) - .setTrustAllMasas(true) - .build(); + registrar = registrarBuilder.setCredentials(cg.getCredentials(CredentialGenerator.REGISTRAR_ALIAS)) + .setTrustAllMasas(true) + .build(); registrar.setDomainCA(domainCA); registrar.setForcedRequestFormat(Constants.HTTP_APPLICATION_VOUCHER_CMS_JSON); registrar.start(); From 96562f9cab11cbf360c9c2c5fc83a8f573af25c2 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Wed, 26 Jun 2024 16:18:58 +0200 Subject: [PATCH 05/25] [registrar] enable -registrar option to run the registrar function. --- .../openthread/main/OtRegistrarMain.java | 10 +- .../openthread/registrar/RegistrarMain.java | 104 ++---------------- 2 files changed, 16 insertions(+), 98 deletions(-) diff --git a/src/main/java/com/google/openthread/main/OtRegistrarMain.java b/src/main/java/com/google/openthread/main/OtRegistrarMain.java index b169655..7fffa5a 100644 --- a/src/main/java/com/google/openthread/main/OtRegistrarMain.java +++ b/src/main/java/com/google/openthread/main/OtRegistrarMain.java @@ -33,6 +33,7 @@ import com.google.openthread.domainca.DomainCA; import com.google.openthread.registrar.Registrar; import com.google.openthread.registrar.RegistrarBuilder; +import com.google.openthread.registrar.RegistrarMain; import com.google.openthread.tools.CredentialGenerator; import java.security.KeyStoreException; import org.apache.commons.cli.CommandLine; @@ -123,6 +124,7 @@ public static void main(String args[]) { .addOption(helpOpt); try { + String forcedMasaUri = null; CommandLineParser parser = new DefaultParser(); CommandLine cmd = parser.parse(options, args); @@ -149,11 +151,17 @@ public static void main(String args[]) { } if (cmd.hasOption('m')) { - // FIXME registrar.setForcedMasaUri(cmd.getOptionValue('m')); + forcedMasaUri = cmd.getOptionValue('m'); } logger.info("using keystore: {}", keyStoreFile); + if (cmd.hasOption("registrar")) { + RegistrarMain.main(keyStoreFile, Integer.parseInt(port), domainName, forcedMasaUri); + }else{ + throw new Exception("not yet impl"); + } + } catch (Exception e) { logger.error(e.getMessage(), e); helper.printHelp(HELP_FORMAT, options); diff --git a/src/main/java/com/google/openthread/registrar/RegistrarMain.java b/src/main/java/com/google/openthread/registrar/RegistrarMain.java index fbea6b6..a64beed 100644 --- a/src/main/java/com/google/openthread/registrar/RegistrarMain.java +++ b/src/main/java/com/google/openthread/registrar/RegistrarMain.java @@ -46,102 +46,13 @@ public final class RegistrarMain { private static Logger logger = LoggerFactory.getLogger(RegistrarMain.class); - public static void main(String args[]) { - - final String HELP_FORMAT = "registrar [-h] [-v] -d -f -p "; - - HelpFormatter helper = new HelpFormatter(); - Options options = new Options(); - - Option domainNameOpt = - Option.builder("d") - .longOpt("domainname") - .hasArg() - .argName("domain-name") - .desc("the domain name") - .build(); - - Option fileOpt = - Option.builder("f") - .longOpt("file") - .hasArg() - .argName("keystore-file") - .desc("the keystore file in PKCS#12 format") - .build(); - - Option optPort = - Option.builder("p") - .longOpt("port") - .hasArg() - .argName("port") - .desc("the port to listen on") - .build(); - - Option optVerbose = - Option.builder("v") - .longOpt("verbose") - .hasArg(false) - .desc("verbose mode with many logs") - .build(); - - Option optForceMasaUri = - Option.builder("m") - .longOpt("masa") - .hasArg(true) - .desc("force the given MASA URI instead of the default one") - .build(); - - Option helpOpt = - Option.builder("h").longOpt("help").hasArg(false).desc("print this message").build(); - - options - .addOption(domainNameOpt) - .addOption(fileOpt) - .addOption(optPort) - .addOption(optVerbose) - .addOption(optForceMasaUri) - .addOption(helpOpt); - + public static void main(String keyStoreFile, int port, String domainName, String forcedMasaUri) { Registrar registrar; try { - CommandLineParser parser = new DefaultParser(); - CommandLine cmd = parser.parse(options, args); - - LoggerInitializer.Init(cmd.hasOption('v')); - - if (cmd.hasOption('h')) { - helper.printHelp(HELP_FORMAT, options); - return; - } - - String keyStoreFile = cmd.getOptionValue('f'); - if (keyStoreFile == null) { - throw new IllegalArgumentException("need keystore file!"); - } - - String port = cmd.getOptionValue('p'); - if (port == null) { - throw new IllegalArgumentException("need port!"); - } - - String domainName = cmd.getOptionValue('d'); - if (domainName == null) { - throw new IllegalArgumentException("need domain name!"); - } - - logger.info("using keystore: " + keyStoreFile); - RegistrarBuilder builder = new RegistrarBuilder(); - Credentials cred = - new Credentials( - keyStoreFile, CredentialGenerator.REGISTRAR_ALIAS, CredentialGenerator.PASSWORD); - Credentials domainCred = - new Credentials( - keyStoreFile, CredentialGenerator.DOMAINCA_ALIAS, CredentialGenerator.PASSWORD); - // Credentials masaCred = - // new Credentials( - // keyStoreFile, CredentialGenerator.MASA_ALIAS, CredentialGenerator.PASSWORD); + Credentials cred = new Credentials(keyStoreFile, CredentialGenerator.REGISTRAR_ALIAS, CredentialGenerator.PASSWORD); + Credentials domainCred = new Credentials(keyStoreFile, CredentialGenerator.DOMAINCA_ALIAS, CredentialGenerator.PASSWORD); if (cred.getPrivateKey() == null || cred.getCertificateChain() == null) { throw new KeyStoreException("can't find registrar key or certificate in keystore"); @@ -153,7 +64,7 @@ public static void main(String args[]) { // re-use the same creds for Pledge-facing identity and MASA-facing identity. builder.setCredentials(cred); - builder.setPort(Integer.parseInt(port)); + builder.setPort(port); // if (true) { // trust all MASAs by default @@ -166,19 +77,18 @@ public static void main(String args[]) { registrar = builder.build(); - if (cmd.hasOption('m')) { - registrar.setForcedMasaUri(cmd.getOptionValue('m')); + if (forcedMasaUri != null) { + registrar.setForcedMasaUri(forcedMasaUri); } DomainCA ca = new DomainCA(domainName, domainCred); registrar.setDomainCA(ca); } catch (Exception e) { logger.error(e.getMessage(), e); - helper.printHelp(HELP_FORMAT, options); return; } registrar.start(); - logger.info("Registrar listening at port: " + registrar.getListenPort()); + logger.info("Registrar listening at port: {}", registrar.getListenPort()); } } From 466194ca1bc267b4454ebad674ea996a46778f5e Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Wed, 26 Jun 2024 22:14:54 +0200 Subject: [PATCH 06/25] restructuring code for main and option parsing. --- credentials/default.p12 | Bin 0 -> 6834 bytes pom.xml | 2 +- .../google/openthread/LoggerInitializer.java | 2 +- .../openthread/main/OtRegistrarConfig.java | 63 ++++++++++++ .../openthread/main/OtRegistrarMain.java | 74 +++++++++----- .../java/com/google/openthread/main/Role.java | 5 + .../com/google/openthread/pledge/Pledge.java | 74 +++++++------- .../google/openthread/pledge/PledgeMain.java | 93 ++++-------------- .../openthread/registrar/RegistrarMain.java | 17 ++-- 9 files changed, 183 insertions(+), 147 deletions(-) create mode 100644 credentials/default.p12 create mode 100644 src/main/java/com/google/openthread/main/OtRegistrarConfig.java create mode 100644 src/main/java/com/google/openthread/main/Role.java diff --git a/credentials/default.p12 b/credentials/default.p12 new file mode 100644 index 0000000000000000000000000000000000000000..42c1feb0b55dcf7894c1a2262a7141b9172301e0 GIT binary patch literal 6834 zcma*qbxd8&x(8s~p~%KIT3pM<-JRl4+#QPR#$n^S3&q{tokDRa#oY?Ui@Oyla5*RU zJCfYwe*dgBdEYgY%#+_tvOo}E4IC^y2m-W5LS+h<3%|pJMTX6T0Cf-`K+V^(DhPr& z@Lw&&W&{Xg{cE`z1c4<)LjT`c7-+C?dBNX7!9yTMB(%SZuS=640PZ#CY3sbDSo(16 z+3mQhc^hFO*x}$|`c)Bv(`bUV49RV16`g9o?WbVgX3eynnK>>C&BP>zm1O7eyVq&O zaaQJNqgc&zJvdDoe{-a@54}{>NEr}HE+<<5DI)h7>qNnt%kVp-0-%@`lJ{GEaMHx;J z0>&D~^8e%EKk>3sT(wtcF#1|?1h-`iIk$m25&cIgv* zX}s8gN;w$wbO$ULllI!*!Y%l7PzGd~mAx#s8Q!!Nv!3L$OMxiMSH6j*Bi=~&x28si9`^H#O4k7*pruI^}wgy#E_G<140M|CwFpKSKgw2aw~!xW4Ac8pihZ zfVsbpO<`RB^OOJUnDKM6zar89EhNS?_9^5BJwc{{y&;K`N>DKd<@R4l#f(gt((?wK zyrC%ld}LqswYIlg1w1n|c6`QjOz4`N=rk`+QPIs2dDkHIe$xc-oO8t-;ySeE3g_z^ z2=wJkO{_g1CO;IFxE|6a$FUpz`KoT>Z^iONF)@TdC*HL%Jd8t%tF!-rr5BTIH_Of| zojunMz||SrPNpps4w_#cG3l^7G*Y~C0 zw%rnHtw#y@V6P}!wmfcBXUjkFf*=6UWY?G4FT~NPd>bx#Yvk$=OKEU*7d9Qi%$f~; z`EAwr4(p(q>`J+G0gQ=36Row9{EBn8q{4&7$JYGXw-ep$MCoLs@#PGbV2aVycHibI zf3@SBl;L^3_I=tTnKH|u3eM5f0;oohe3HyrLP)Cq6W$NAM}HUjDfB#|rgHhVao}y= z=bEEHg$1|t7ACTn%sLC&+gdiy5R7Z;F_+mAP+tDUxcb z4z9f2;P0!`TdQc!dQJZ1_XnJ?4?_iZhfjhw{w_fQ<$@QDoXSyZQR;r_c5Jj2G$#YS zOadhjV@4;|?59w<5@PHUO96LcGW=S0OhvC3tsz7jx9UBq`#s@9<+xlGIAyx{~ZQ?aN_>E*Jg73hVy;ki4IQO`C6TAXdPjFrDnwMbYN zZkJk;NhKV9F3o>K@X%&z}TmmA~PPW|LW-UZfc|dEbCY-!jfA#_w3tq3jCk-(h8KEHC4H82a zs5IJR2!qE9>Mcdl?3~1^Db}5Al!u?66wBFx)0U~SYcFFyWMnP$q9UtQ9xWv`>W!r9 zs5h6F8`#gtEnZ1=UpcuyGq)<_VbAxD>$1^e+z`hbsd=mkSMCw@B4K8_5WoD`RDX85 zO`#uAS=yLVxQeiN*tu?W5HeB9|Ze(R!Ni zIrszp^SJBVP9Og`7LUi&0U>v*giTm$t4U?*;Z&g?VMv@}OVYUv__Fs?ljpL{S&qp! zow!1ra7G%t4Qy;`YZj+X*eE6K`H6nA2KM2)tBDn8;F)0`DHj)0)V>zu z6rYl(K#Pg*x?iphH&g3-J$0xh`+N_v!O~MEH9``)iNjt27jmT|IB?vxtUa|ef6#rr z=Tg*pGW|C^wOh#&E`HW~r}G6OSA_Wu!-rXrBGvmZyA!mEm>A8!kwzR&YJk12DtlS3 zKBmM#uP6+Vm;+ux_G<2eoZ>*I7jxh(^yXocZ*NO`cFsdCQ(|}u`?V<@ z)0Dg|n=^cERE=t5$N9j=rKp8jOHYp^M&YlL#;v6dL)Vs56XPAD(2kT~Rhb!;K}Lk3 z(oGJe=8V8Zv<_P=MBfb|oqer5f9pr4g0WgK)!dm2?pzVRi{~!4sJ4reAlSUu=L;9y zu7q^nl_SE;8$Be?^<{Hr^0Olc3BgoBad_1QvA&vl7d3KYlbnlD1uzxy;QVvc_=dk|~g=dWqS8B*cgENT7^iYi!b~66mSQ$_oanlVPQPv1go+Y&)YB~A%0!r9rNS}f;ss82h`c^HObRVtc9>sC^JcBei^1r zGk=Pix4hghG}VMl8|~G5uXB8eT1|>}CPnvC!NY5q0;zaRabVnagWR{i^TTYDR<+xY zkozZZA*t!kNuP>eeg54ZlEo8VAbrjq9D6K^cI}xm24-$4Il)XOfkCIXWg>{J_7PjB z6!D+uv_MU$uD~pB{7kt3F#^q#PuqqrH{t4pzEd>OVk{?7 z4axZw4nX4%(#Ooi50wNDH!+OecvB4xUn9$1BdA?&DR36#&F-W|+x&endrNnx+{pP| zTk5Og8?i#mwz#Jwy7wIf1^hFi!LXG~>rs>X?OpY5l^zFv;t>U(xSrSPAZCHs;>wON zj)e}2=wf?|jE^f7#j=%y{$Y}Jz=?7^74e1vq25`(Dvy{Ht}+WuTz zHPw{hF26%eeeHK7S@9I}I_bDn97BRJW`e@c_}iZRdF- zrh|bnj-y94!ouzBQqnq1NYgA>?3M;0`7YH_&qs!r(&CHM!tSv3L_$85&us4mj>+=m z;d#I;(kUpx3S1@6=89l5qfA`yoP}7(>}_vAUrd^`}Q}~6ioCM z^TThcq6BBn5W^nD&~S#kX>J;r>&(Rnef7Xo*(t|mDD5CWf^p!KpUF2)mvG?1qFy>Q zV`$L)O;KS!$;U=_INAd53srX~@oPctA%WxH?JGTPYHW;+A;+%r{d5tqD)LJLs`W8| zOR{BQjI|>a-#(`1kr>Q{G8gA#wAjA%rOc@-7gW8r0zm34`n%a2(b?@G`3?Y6fcY7e zWzH%9n8AV)jR+~`(i8vH@2{455%hCq%~tpK;7Pe4++MfJLuDu`@_?QAX>MRraQJ`{ znanV)GD4G;zmw`+)peHboo*t%j%@H$s9nSa+93Q!`oT2+c4k={R)++xb8-6#0j*K0 zt@eAmoNfHkH3T+7TvY1F$%brmmKO~QbH?ow8Y_c+%@Ofpd>C?E6k8mqFtyb8B-qNs zQjC{*AW(D5U>fIl0ZKiUkv;5_4kZHW%3CjI^Vp!pu@aF&-nlG>;}ACt)9T(I>3nPD zP@IwahV1b9#szi~3KRyVv*_!ODjCkI#YYck)0Ws_$+m~pk7?&ROYe9MR3^Edc6aU? z?Bs~sBM!aJNr7P=m@MiqIjUx}sgw%M;Zrtb>I7qe5PbZ-N4%=*Aj0?4zJ zR<*OOq{Qn=Q6g6Xp}{85`%7+B>}zUTcNcOn@HkR}0kHf|1j@}-)JK$# zg0osY2*GIAcMn4W=OVr7pK#34u$wlg%tUW)XImFx15&M#!A8|H{xgwW0A% zYL5QqVI?FWdNpyr}y<2aASzZsK2EwBX z4hS-%<6)`84E-AQtM_^ozFqG=L|y*5Z6Z#ra`z@Hb}&qTWLE7~)Xqjsw+uj8aET=( z$)O&0eufUQ<>~J;@1pfuVe-%vJkf0yzkgOWSdcqO-xaHF1Jj`SGMx7cD0337K5~~G zdWwVs@3TGf4AM2CFdA)Gx<9`C$(CfW+c4mUHDbwJdl#4+WL2Kh`)7R0!Fhm|TGA|c zKKq-qT7;H(&>$&)o9nZkE}>{|Af9gOI8s=a`UmS_*|n1mXnR@8c?p2jLC1&eg4ODHA0k0`Y+i}R=jw#TQJXpgHJzKW+WZMW%h=H~ZV zD#=%1-5(hrap>yvy92hAHR$k$vvpRCayC8@xMrgH==e_XAB$&D6Ez#PT%~BT8%>i~ zo4}4(FubqPy~y3G3TwJSesKI!MaUS9xV1~1oIbkVP(yvJfBr4gp>5y6(K#-Zn(@05 znBx!tFFi(Q2ytcz!JIloOI()i1FB=*Z^X!KaJ~MYLW`R9;XS}KS(4Z?;s5>MRQa816UmDr+5+=pjcXgGT`DWs;6=TipER=N0F|%COKl2i( z;N2lEdv$1`7%W}7wghvVebItjbhJHnA9Xx|R%JB(V5Aq6c$e^=qC!PI1@H;qnF4$I zr-*rp^r|v`ViIt!XSXo8)H9 zW)Ck#2eEv$&k$?xk*P1c8VmiU2mhdM5^BvZqW3~pTXkBAR#h?&Vj9T68uT6!8S!T& z#?8QqUo01QT!L%QihOa9+L&e0jY&+B)vIdnqW$A~m7DK?d3`(97B5CS*Zcn9LNer` zZQ8s#%tCy8`172s=2=d(+&fuMEZZMO@H0jsN>g&hEBTw9zX0D#6gC4$Fv0Ra z1UVJ2g1OH1$=}nY)^Mkvo_t*h{=raWky1i&U!o!OYwuXt2IqnSy4R2@#Qq*@-#k`% zWucZZr79972?VRae*RWk+>*YW&%Q^#dPBrXv8sbRydhxH!4$y@ zDzrL;p(6Zb}e{x zlY7(I_t-gt&LH)2JH5jiYjp<2GOki#tRu>I8AL=_McqsLz~%}@QJEVERc8FG{Pl3W z13lulL-C{`pp1yfI%birYpmF&mW`JQYd1GxD=2+PoB|J4ArJZqvq#`P)1PY6pS1^& zUvjMMxisG&eJvUL&bo_!4p@k@&yl)yBzbpnA+tteT?yigAj3coLdnG%)q8h{PKsrf zPg(65E)jvWJLg5En?gnuN!I1-d$Dg=c*W}m>VnkI#bp=g%zF_oqMCoQHFAvV=~ze+ zF196b<*iOw=O@T$#I~*MUh1aIU&s~+Fdr+lj84WK*%}qLHI>m_F)~>{_Tdo6iOG#S z_EZMbS(hA$(rfE;h>i=C-iS@cJb(OLrfO`?$6`#sKjAFd6yQ~Il{2?B)2LY9k9vvG(#>V~v$s0Lo?#+AA>7iN&8>0s=i;W|Pl=CyVKovGv zUGOWs$Lx-uhy2q{1%&+wA8EiC9;?Dk+7C}7hZ2DgHz(zOazMa465@S}0d$rvCHLb% z*Q0Vb0sq-gy5swYCRCQ7)hMm-T=KB9&F9s1+jG zgv6;i-~i4a=ONM8dL#z36T~~VKsw=1GqxZR z&|45H5+XAeJRA@a1_97t_z)7qU&;F^G)^y(v=;|u#W@fG;JV&DFDj2f>MhJE^WBOD Pm8X>)6Am6WJnw%1N@I~P literal 0 HcmV?d00001 diff --git a/pom.xml b/pom.xml index 8f32277..a07da18 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ 1.8 1.8 2.9.7 - 1.2.3 + 1.2.13 4.13.2 diff --git a/src/main/java/com/google/openthread/LoggerInitializer.java b/src/main/java/com/google/openthread/LoggerInitializer.java index e22ea7d..b9bdf1c 100644 --- a/src/main/java/com/google/openthread/LoggerInitializer.java +++ b/src/main/java/com/google/openthread/LoggerInitializer.java @@ -43,7 +43,7 @@ public static void Init(boolean verbose) { ((Logger) LoggerFactory.getLogger(CALIFORNIUM)).setLevel(Level.DEBUG); Configurator.setLevel(OPENTHREAD, org.apache.logging.log4j.Level.DEBUG); } else { - ((Logger) LoggerFactory.getLogger(CALIFORNIUM)).setLevel(Level.INFO); + ((Logger) LoggerFactory.getLogger(CALIFORNIUM)).setLevel(Level.WARN); Configurator.setLevel(OPENTHREAD, org.apache.logging.log4j.Level.INFO); } } diff --git a/src/main/java/com/google/openthread/main/OtRegistrarConfig.java b/src/main/java/com/google/openthread/main/OtRegistrarConfig.java new file mode 100644 index 0000000..6e20139 --- /dev/null +++ b/src/main/java/com/google/openthread/main/OtRegistrarConfig.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package com.google.openthread.main; + +public class OtRegistrarConfig { + + public Role role; + public int serverPortCoaps; + public String domainName; + public String keyStoreFile; + public String masaUri; + public String registrarUri; + public boolean logVerbose; + + static OtRegistrarConfig Default() { + OtRegistrarConfig config = new OtRegistrarConfig(); + config.role = Role.None; + config.serverPortCoaps = 5684; + config.domainName = "DefaultDomain"; + config.keyStoreFile = "./credentials/default.p12"; + config.masaUri = null; + config.registrarUri = "localhost:5684"; + config.logVerbose = false; + return config; + } + + public String ToString() { + return + "Role : " + role.toString() + "\n" + + "Server port (CoapS) : " + this.serverPortCoaps + "\n" + + "Domain Name : " + this.domainName + "\n" + + "Keystore file : " + this.keyStoreFile + "\n" + + "MASA URI : " + (this.masaUri == null ? "(read from IDevID cert)" : this.masaUri + " (forced)") + "\n" + + "Registrar URI : " + this.registrarUri + "\n" + + "Log verbose : " + (this.logVerbose ? "yes" : "no" ) + "\n"; + } +} diff --git a/src/main/java/com/google/openthread/main/OtRegistrarMain.java b/src/main/java/com/google/openthread/main/OtRegistrarMain.java index 7fffa5a..6f31d66 100644 --- a/src/main/java/com/google/openthread/main/OtRegistrarMain.java +++ b/src/main/java/com/google/openthread/main/OtRegistrarMain.java @@ -28,14 +28,9 @@ package com.google.openthread.main; -import com.google.openthread.Credentials; import com.google.openthread.LoggerInitializer; -import com.google.openthread.domainca.DomainCA; -import com.google.openthread.registrar.Registrar; -import com.google.openthread.registrar.RegistrarBuilder; import com.google.openthread.registrar.RegistrarMain; -import com.google.openthread.tools.CredentialGenerator; -import java.security.KeyStoreException; +import com.google.openthread.pledge.PledgeMain; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; @@ -45,6 +40,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +/** + * Main entry point of the OT Registrar JAR. Based on arguments, it will decide what entity to start: a Registrar, a MASA or a Pledge. + */ public final class OtRegistrarMain { private static Logger logger = LoggerFactory.getLogger(OtRegistrarMain.class); @@ -109,6 +107,14 @@ public static void main(String args[]) { .desc("force the given MASA URI instead of the default one") .build(); + Option optRegistrarUri = + Option.builder("r") + .longOpt("registrar") + .hasArg() + .argName("registrar-uri") + .desc("for a Pledge, the Registrar to connect to") + .build(); + Option helpOpt = Option.builder("h").longOpt("help").hasArg(false).desc("print this message").build(); @@ -121,45 +127,45 @@ public static void main(String args[]) { .addOption(optPort) .addOption(optVerbose) .addOption(optForceMasaUri) + .addOption(optRegistrarUri) .addOption(helpOpt); + OtRegistrarConfig config = OtRegistrarConfig.Default(); + try { - String forcedMasaUri = null; CommandLineParser parser = new DefaultParser(); CommandLine cmd = parser.parse(options, args); - LoggerInitializer.Init(cmd.hasOption('v')); - if (cmd.hasOption('h')) { helper.printHelp(HELP_FORMAT, options); return; } - String keyStoreFile = cmd.getOptionValue('f'); - if (keyStoreFile == null) { - keyStoreFile = "credentials/default.p12"; - } + config.logVerbose = cmd.hasOption("v"); + LoggerInitializer.Init(config.logVerbose); - String port = cmd.getOptionValue('p'); - if (port == null) { - port = "5683"; + if (cmd.hasOption('f')) { + config.keyStoreFile = cmd.getOptionValue('f'); } - - String domainName = cmd.getOptionValue('d'); - if (domainName == null) { - domainName = "DefaultDomain"; + if (cmd.hasOption('p')) { + config.serverPortCoaps = Integer.parseInt(cmd.getOptionValue('p')); + } + if (cmd.hasOption('d')) { + config.domainName = cmd.getOptionValue('d'); } - if (cmd.hasOption('m')) { - forcedMasaUri = cmd.getOptionValue('m'); + config.masaUri = cmd.getOptionValue('m'); } - logger.info("using keystore: {}", keyStoreFile); - if (cmd.hasOption("registrar")) { - RegistrarMain.main(keyStoreFile, Integer.parseInt(port), domainName, forcedMasaUri); - }else{ - throw new Exception("not yet impl"); + config.role = Role.Registrar; + } else if (cmd.hasOption("masa")) { + config.role = Role.Masa; + } else if (cmd.hasOption("pledge")) { + config.role = Role.Pledge; + } else { + helper.printHelp(HELP_FORMAT, options); + return; } } catch (Exception e) { @@ -168,5 +174,19 @@ public static void main(String args[]) { return; } + logger.info("Configuration:\n{}", config.ToString()); + + switch (config.role) { + case Registrar: + RegistrarMain.main(config); + break; + case Masa: + break; + case Pledge: + PledgeMain.main(config); + break; + case None: + break; + } } } diff --git a/src/main/java/com/google/openthread/main/Role.java b/src/main/java/com/google/openthread/main/Role.java new file mode 100644 index 0000000..32ced6c --- /dev/null +++ b/src/main/java/com/google/openthread/main/Role.java @@ -0,0 +1,5 @@ +package com.google.openthread.main; + +public enum Role { + None, Registrar, Masa, Pledge +} diff --git a/src/main/java/com/google/openthread/pledge/Pledge.java b/src/main/java/com/google/openthread/pledge/Pledge.java index 9dc9d73..8322738 100644 --- a/src/main/java/com/google/openthread/pledge/Pledge.java +++ b/src/main/java/com/google/openthread/pledge/Pledge.java @@ -98,8 +98,7 @@ import org.slf4j.LoggerFactory; /** - * The Pledge (i.e., CCM Joiner) is the new device which is to securely bootstrap into the network - * domain using the Constrained BRSKI protocol. + * The Pledge (i.e., CCM Joiner) is the new device which is to securely bootstrap into the network domain using the Constrained BRSKI protocol. */ public class Pledge extends CoapClient { @@ -119,10 +118,9 @@ public enum CertState { /** * Constructing pledge with credentials and uri of the registrar * - * @param privateKey the manufacturer private key - * @param certificateChain the manufacturer certificate chain leading to the masa and including - * masa certificate - * @param hostURI uri of host (registrar) + * @param privateKey the manufacturer private key + * @param certificateChain the manufacturer certificate chain leading to the masa and including masa certificate + * @param hostURI uri of host (registrar) * @throws PledgeException */ public Pledge(Credentials creds, String hostURI) throws PledgeException { @@ -165,16 +163,19 @@ public X509Certificate getOperationalCert() { /** * Get the Thread Domain Name as encoded in the operational certificate of the Pledge. * - * @return the Thread Domain Name, encoded in the SubjectAltName/Othername field as per Thread - * spec. Or "DefaultDomain" if not encoded in there. Null if no operational cert present or if - * it couldn't be parsed. + * @return the Thread Domain Name, encoded in the SubjectAltName/Othername field as per Thread spec. Or "DefaultDomain" if not encoded in there. Null if no operational cert present or if it couldn't + * be parsed. */ public String getDomainName() { - if (operationalCertificate == null) return null; + if (operationalCertificate == null) { + return null; + } try { Collection> cSubjAltNames = operationalCertificate.getSubjectAlternativeNames(); - if (cSubjAltNames == null) return Constants.THREAD_DOMAIN_NAME_DEFAULT; + if (cSubjAltNames == null) { + return Constants.THREAD_DOMAIN_NAME_DEFAULT; + } // loop all subject-alt-names to find a matching 'otherName' item. for (List l : cSubjAltNames) { if (l.size() == 2 && l.get(0).equals(Constants.ASN1_TAG_GENERALNAME_OTHERNAME)) { @@ -184,8 +185,9 @@ public String getDomainName() { ASN1TaggedObject ato = ASN1TaggedObject.getInstance(ds.getObjectAt(1)); if (ato.getTagNo() == 0) { // get to the deepest embedded tagged object. - while (ato.getObject() instanceof ASN1TaggedObject) + while (ato.getObject() instanceof ASN1TaggedObject) { ato = (ASN1TaggedObject) ato.getObject(); + } // must be stored as IA5String return DERIA5String.getInstance(ato.getObject()).toString(); } @@ -288,9 +290,9 @@ public Voucher requestVoucher(VoucherRequest req) if (!voucher.serialNumber.equals(req.serialNumber) || (voucher.idevidIssuer != null - && !Arrays.equals( - voucher.idevidIssuer, - SecurityUtils.getAuthorityKeyIdentifier(getIdevidCertificate())))) { + && !Arrays.equals( + voucher.idevidIssuer, + SecurityUtils.getAuthorityKeyIdentifier(getIdevidCertificate())))) { throw new PledgeException("serial number or idevid-issuer not matched"); } if (req.nonce != null @@ -339,10 +341,8 @@ public void requestCACertificate() { /** * Send Voucher Status telemetry message * - * @param isSuccess true if success voucher-status is to be reported, false if error is to be - * reported. - * @param failureReason human-readable failure reason string to be reported, usually only if - * isSuccess==false. + * @param isSuccess true if success voucher-status is to be reported, false if error is to be reported. + * @param failureReason human-readable failure reason string to be reported, usually only if isSuccess==false. * @throws Exception */ public ResponseCode sendVoucherStatusTelemetry(boolean isSuccess, String failureReason) @@ -357,10 +357,8 @@ public ResponseCode sendVoucherStatusTelemetry(boolean isSuccess, String failure /** * Send Enroll Status telemetry message * - * @param isSuccess true if success enroll-status is to be reported, false if error is to be - * reported. - * @param failureReason human-readable failure reason string to be reported, usually only if - * isSuccess==false. + * @param isSuccess true if success enroll-status is to be reported, false if error is to be reported. + * @param failureReason human-readable failure reason string to be reported, usually only if isSuccess==false. * @throws Exception */ public ResponseCode sendEnrollStatusTelemetry(boolean isSuccess, String failureReason) @@ -497,8 +495,7 @@ public X509Certificate getMASACaCertificate() { } /** - * Set the checking of the CMC-RA (Registration Authority) flag in the Registrar's certificate to - * on (true) or off (false). + * Set the checking of the CMC-RA (Registration Authority) flag in the Registrar's certificate to on (true) or off (false). * * @param doCheckCmcRa */ @@ -507,11 +504,9 @@ public void setCmcRaCheck(boolean doCheckCmcRa) { } /** - * Set the use of 'lightweight' client certificates in the DTLS handshake for this Pledge. If - * 'lightweight', then the MASA CA root certificate will be omitted from the client's Certificate - * message in the DTLS handshake to reduce network load. The Registrar will anyhow have means to - * obtain MASA CA certificates (e.g. by contacting the MASA via the MASA URI, or a sales - * integration process, etc. + * Set the use of 'lightweight' client certificates in the DTLS handshake for this Pledge. If 'lightweight', then the MASA CA root certificate will be omitted from the client's Certificate message + * in the DTLS handshake to reduce network load. The Registrar will anyhow have means to obtain MASA CA certificates (e.g. by contacting the MASA via the MASA URI, or a sales integration process, + * etc. * * @param isSetLightweight whether to use 'lightweight' (true) client certificates or not (false) * @throws PledgeException in case reconfiguration of the Pledge failed for some reason @@ -551,7 +546,9 @@ private void init(Credentials creds, String hostURI, boolean isLightweightClient // remove trailing slash from hostURI - avoid host//path situations leading to a leading, empty // CoAP Uri-Path Option. (=bug) - while (hostURI.endsWith("/")) hostURI = hostURI.substring(0, hostURI.length() - 1); + while (hostURI.endsWith("/")) { + hostURI = hostURI.substring(0, hostURI.length() - 1); + } this.hostURI = hostURI; try { @@ -578,8 +575,9 @@ private void init(Credentials creds, String hostURI, boolean isLightweightClient certState = CertState.NO_CONTACT; X509Certificate[] clientCertChain = this.certificateChain; - if (isLightweightClientCerts) - clientCertChain = new X509Certificate[] {this.certificateChain[0]}; + if (isLightweightClientCerts) { + clientCertChain = new X509Certificate[]{this.certificateChain[0]}; + } initEndpoint(this.privateKey, clientCertChain, this.certVerifier); } @@ -589,9 +587,7 @@ private CoapResponse sendRequestVoucher(VoucherRequest voucherRequest) byte[] vrEncoded = new CBORSerializer().serialize(voucherRequest); // COSE_Sign1 signing of the CBOR - byte[] payload = - SecurityUtils.genCoseSign1Message( - privateKey, SecurityUtils.COSE_SIGNATURE_ALGORITHM, vrEncoded); + byte[] payload = SecurityUtils.genCoseSign1Message(privateKey, SecurityUtils.COSE_SIGNATURE_ALGORITHM, vrEncoded); // store the transmitted PVR this.lastPvr = voucherRequest; this.lastPvrCoseSigned = payload; @@ -664,7 +660,7 @@ private void initEndpoint( PrivateKey privateKey, X509Certificate[] certificateChain, CertificateVerifier verifier) { CoapEndpoint endpoint = SecurityUtils.genCoapClientEndPoint( - new X509Certificate[] {}, privateKey, certificateChain, verifier, false); + new X509Certificate[]{}, privateKey, certificateChain, verifier, false); setEndpoint(endpoint); } @@ -722,7 +718,9 @@ private String getBRSKIPath() { private CertPath registrarCertPath; - /** the Content Format to use for a CSR request */ + /** + * the Content Format to use for a CSR request + */ public int csrContentFormat = ExtendedMediaTypeRegistry.APPLICATION_PKCS10; private PublicKey domainPublicKey; diff --git a/src/main/java/com/google/openthread/pledge/PledgeMain.java b/src/main/java/com/google/openthread/pledge/PledgeMain.java index 1a81b8e..a1602c3 100644 --- a/src/main/java/com/google/openthread/pledge/PledgeMain.java +++ b/src/main/java/com/google/openthread/pledge/PledgeMain.java @@ -29,105 +29,53 @@ package com.google.openthread.pledge; import com.google.openthread.Credentials; +import com.google.openthread.main.OtRegistrarConfig; import com.google.openthread.tools.CredentialGenerator; import java.security.KeyStoreException; import java.util.Scanner; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class PledgeMain { - private PledgeMain() {} - - public static void main(String args[]) { - final String HELP_FORMAT = "pledge [-h] -f -r "; - - HelpFormatter helper = new HelpFormatter(); - Options options = new Options(); - - Option fileOpt = - Option.builder("f") - .longOpt("file") - .hasArg() - .argName("keystore-file") - .desc("the keystore file in PKCS#12 format") - .build(); - - Option optRegistrar = - Option.builder("r") - .longOpt("registrar") - .hasArg() - .argName("registrar-uri") - .desc("the registrar connecting to") - .build(); - - Option helpOpt = - Option.builder("h").longOpt("help").hasArg(false).desc("print this message").build(); + private PledgeMain() { + } - options.addOption(fileOpt).addOption(optRegistrar).addOption(helpOpt); + private static final Logger logger = LoggerFactory.getLogger(PledgeMain.class); + public static void main(OtRegistrarConfig config) { try { - CommandLineParser parser = new DefaultParser(); - CommandLine cmd = parser.parse(options, args); - - if (cmd.hasOption('h')) { - helper.printHelp(HELP_FORMAT, options); - return; - } - - String keyStoreFile = cmd.getOptionValue('f'); - if (keyStoreFile == null) { - throw new IllegalArgumentException("need keystore file!"); - } - - String registrarUri = cmd.getOptionValue('r'); - if (registrarUri == null) { - throw new IllegalArgumentException("need to specify registrar!"); - } - - System.out.println("using keystore: " + keyStoreFile); - String password = CredentialGenerator.PASSWORD; - Credentials cred = new Credentials(keyStoreFile, CredentialGenerator.PLEDGE_ALIAS, password); + Credentials cred = new Credentials(config.keyStoreFile, CredentialGenerator.PLEDGE_ALIAS, password); if (cred == null || cred.getPrivateKey() == null || cred.getCertificateChain() == null) { - throw new KeyStoreException( - String.format( - "can't find pledge key or certificate: %s", CredentialGenerator.PLEDGE_ALIAS)); + throw new KeyStoreException(String.format("can't find pledge key or certificate: %s", CredentialGenerator.PLEDGE_ALIAS)); } - Pledge pledge = new Pledge(cred, registrarUri); - + Pledge pledge = new Pledge(cred, config.registrarUri); run(pledge); - pledge.shutdown(); - } catch (IllegalArgumentException e) { - System.err.println("error: " + e.getMessage()); - helper.printHelp(HELP_FORMAT, options); } catch (Exception e) { - System.err.println("error: " + e.getMessage()); + logger.error("error: {}", e.getMessage(), e); return; } } private static void run(Pledge pledge) { - final String DOMAIN_NAME = "TestDomainTCE"; final String help = - "rv - request voucher\n" - + "enroll - simple enrollment\n" - + "reenroll - simple reenrollment\n" - + "reset - reset to initial state\n" + "rv - request voucher to Registrar (cBRSKI)\n" + + "enroll - simple enrollment with Registrar (EST)\n" + + "reenroll - simple reenrollment with Registrar (EST)\n" + + "reset - reset Pledge to initial state\n" + "exit - exit pledge CLI\n" + "help - print this help message\n"; + System.out.println("Pledge CLI commands:\n" + help); try (Scanner scanner = new Scanner(System.in)) { while (true) { try { System.out.print("> "); - switch (scanner.nextLine().trim()) { + String cmd = scanner.nextLine().trim(); + switch (cmd) { case "rv": pledge.requestVoucher(); break; @@ -146,12 +94,13 @@ private static void run(Pledge pledge) { System.out.println(help); break; default: + logger.error("unknown CLI command: {}", cmd); System.out.println(help); } - System.out.println("done"); + System.out.println("Done"); } catch (Exception e) { - e.printStackTrace(); + logger.error("error: {}", e.getMessage(), e); } } } diff --git a/src/main/java/com/google/openthread/registrar/RegistrarMain.java b/src/main/java/com/google/openthread/registrar/RegistrarMain.java index a64beed..2d43c2a 100644 --- a/src/main/java/com/google/openthread/registrar/RegistrarMain.java +++ b/src/main/java/com/google/openthread/registrar/RegistrarMain.java @@ -31,6 +31,7 @@ import com.google.openthread.Credentials; import com.google.openthread.LoggerInitializer; import com.google.openthread.domainca.DomainCA; +import com.google.openthread.main.OtRegistrarConfig; import com.google.openthread.tools.CredentialGenerator; import java.security.KeyStoreException; import org.apache.commons.cli.CommandLine; @@ -44,15 +45,15 @@ public final class RegistrarMain { - private static Logger logger = LoggerFactory.getLogger(RegistrarMain.class); + private static final Logger logger = LoggerFactory.getLogger(RegistrarMain.class); - public static void main(String keyStoreFile, int port, String domainName, String forcedMasaUri) { + public static void main(OtRegistrarConfig config) { Registrar registrar; try { RegistrarBuilder builder = new RegistrarBuilder(); - Credentials cred = new Credentials(keyStoreFile, CredentialGenerator.REGISTRAR_ALIAS, CredentialGenerator.PASSWORD); - Credentials domainCred = new Credentials(keyStoreFile, CredentialGenerator.DOMAINCA_ALIAS, CredentialGenerator.PASSWORD); + Credentials cred = new Credentials(config.keyStoreFile, CredentialGenerator.REGISTRAR_ALIAS, CredentialGenerator.PASSWORD); + Credentials domainCred = new Credentials(config.keyStoreFile, CredentialGenerator.DOMAINCA_ALIAS, CredentialGenerator.PASSWORD); if (cred.getPrivateKey() == null || cred.getCertificateChain() == null) { throw new KeyStoreException("can't find registrar key or certificate in keystore"); @@ -64,7 +65,7 @@ public static void main(String keyStoreFile, int port, String domainName, String // re-use the same creds for Pledge-facing identity and MASA-facing identity. builder.setCredentials(cred); - builder.setPort(port); + builder.setPort(config.serverPortCoaps); // if (true) { // trust all MASAs by default @@ -77,11 +78,11 @@ public static void main(String keyStoreFile, int port, String domainName, String registrar = builder.build(); - if (forcedMasaUri != null) { - registrar.setForcedMasaUri(forcedMasaUri); + if (config.masaUri != null) { + registrar.setForcedMasaUri(config.masaUri); } - DomainCA ca = new DomainCA(domainName, domainCred); + DomainCA ca = new DomainCA(config.domainName, domainCred); registrar.setDomainCA(ca); } catch (Exception e) { logger.error(e.getMessage(), e); From b4e21862c2a495edf1c1f3a2a5878739de26b793 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 27 Jun 2024 09:46:46 +0200 Subject: [PATCH 07/25] [all] use dedicated configs for each role; fix logging init to right levels. --- CONTRIBUTING.md | 3 +- credentials/default_masa.p12 | Bin 0 -> 8481 bytes ...dge_credentials.p12 => default_pledge.p12} | Bin .../{default.p12 => default_registrar.p12} | Bin .../google/openthread/LoggerInitializer.java | 23 +++-- .../openthread/main/OtRegistrarConfig.java | 63 +++++++++--- .../openthread/main/OtRegistrarMain.java | 75 +++++++------- .../com/google/openthread/masa/MASAMain.java | 88 +++-------------- .../google/openthread/pledge/PledgeMain.java | 11 ++- .../openthread/registrar/RegistrarMain.java | 20 ++-- .../openthread/tools/CredentialGenerator.java | 93 ++++++++---------- 11 files changed, 175 insertions(+), 201 deletions(-) create mode 100644 credentials/default_masa.p12 rename credentials/{pledge_credentials.p12 => default_pledge.p12} (100%) rename credentials/{default.p12 => default_registrar.p12} (100%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52c3046..0a081a8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -99,7 +99,8 @@ This will open up a text editor where you can specify which commits to squash. #### Coding conventions and style -OT Registrar does not use the [Google Java Style](https://google.github.io/styleguide/javaguide.html) at this moment. The reason is that it introduces a very narrow line width, which makes code hard to read on normal-size desktop monitors that can handle long line lengths. +OT Registrar uses most of the [Google Java Style](https://google.github.io/styleguide/javaguide.html) at this moment. The reason for not using the full set of guidelines is that it introduces a very narrow line width (100), which makes code hard to read on normal-size desktop monitors used for coding that can easily handle long line lengths. +For an IDE, the XML file for this style can be [downloaded](https://github.com/google/styleguide) and applied and the line width increased to 200. #### Push and test diff --git a/credentials/default_masa.p12 b/credentials/default_masa.p12 new file mode 100644 index 0000000000000000000000000000000000000000..ecd983398f90c79bf2987088d25b5bcae940412e GIT binary patch literal 8481 zcma)-WlSB)wtzPqcXx;4h2n+cUfiL$ySux)yZgqixE615cPQ>I8|U@jymKXa$vZzr zvewKb^W|GJ%z@;@KnO_YK(YlGc>2(UvSFw|vi?8e9_B!po&QR~%s~ah zO#KOuF$Y2r!XW}DSmI1!aeTVrt;LZWWhw7F z=8TDJA)4rxHH`S8Q9Ac|<_O>1D}P=V)a)EWTqvG5Wbi#D-&zg-q!J=domy~spp97< z^bDScqvGXgT_q&7KTU_eO($o&a1TK+sfn%Y8VfHo?!O6Ou^^DZ{e|cML&L_&{kP4T zQ3up_AFOsU7QTw-pT&1wTt*)Kg$7s^$P0n-b3zvH(32RSVaM>+wO0XjvI#aoEoKhz^ zFvL^fda~+=i|$V&Q$NX-oS>nw@@iM7%MFFiUTDxpGH$R? zBHS^PW%p%_l`4xUGwFYtgF%A!2aMf6?XdvZ{+;6D_-ApE|1Cs@$waMTS6aIVCkQ{S z{N4Fu5f^g*LiA$K4lSl?h2N$<%Mm^Q@?wSSngL&OY)QEqb{Ha62gKe;0weitD>Woi zM2KznWO`oZ3jdhn%~>BFQ+b4{eQ~C-B#TKZOx&N?`VwD*C@2JEunqru((jfYkd5y@ z2l0mD!XJNEsu}4kDFsDYsllDkke9dXtsCte@TvJG?7b))ia|K8Z@}|q|0X0H1>$63|KkzO--5K$WuXdk zifa`;k zKM;TLPv{2_0`O;O|91xBzkWBEfBbHiUWx(U=bAcoq+4S{s=zRPJkOGU!t)Qr_qU{z zMsJg&R^ek=0rBftmAbc=vKG$6Wt%yVOziGTEFHmp>`OU29-I@{GC>H>HeSb;NrEZs zXj_VdM2eCAy~S}0P{UJ(!}B>i+I2`h&P^Um!+|)0dZ_7^%SDidlMJf&9hBt@(KF+_ zKxVIHt|5b)G&bQS_)&e`dWp*^hTx%hd)NT0cVPw+gf4(zbmU{O?SoFoH_^ecFHdDp za%1+Ab86Vx`1LvV9OpfOg5PmE0JG^%IC~QmUEJO8z{sdRG}`OM{VjIBry7S2m)Dj- zGn#j&u-xhg6Y|KyOBVbH7mVgypUAvSnUthL{kDxX(%6qcDM}&u=q~XS`3(|_c%LXwv^7J+6SUjF{ti9N4O6Y#JkmJ2HM}&v4_(o`ldnFV z^(1E+=qX1}%lo?X@%^Q%9Yn@hz4qQo@R@pK(XTI%$xl4Z4`tO%gf;Lm74hID4G@IN*qbIy08O z;l36pLo!hAc`p`y-To@47NfG?cgspi@{6r$b(GgBqzLuhlY25SjFcqfz4+%@Oy)Hp z-_lGTa;|wEbq>9t1ipfCpqmG_5$U%}b~ypbXZxBpXDJ&#!$U?{akO1Pe3@N3rneDo zyizkWi4kr9B`A_a3|YgKoFCraTJpdGi(D)eJtJm;f2d`zVJ*xV#jPy-4bcTrQ9oQQ zI=oxn3VDK#12Ep?Ij=(WS;@T-W`o=RLI+e|?w#p(9}cg5-DZr5cvU-|ZE8YAQRLwa zMc(MmW(-c$nASmtWL1aNkFQ)zbv!iDFzaM_)-7RgW!}g*Vq1{@&4tn1Nr&KpA8Np3 zv00oPE<&Ev`c##%Lep!YhgPUbYFmzc#1qAY>wP=-Xf>_I73}O)jOIC%_LPmJnZYWZ-7S=Q%_%kA{7^h=J8{-T zL*26kD&&LwV!|{)_YC}oeNuSb>Kp6w^pW1>2nU*DY{IlNIws4}z+A_rXtA`)pouzG z@5Fq>$%@wB<_HUWh3UpInJ+}f?e4l_w=ZqJgnpy#hlHq{>e=X)4tTCi+B*#Im;l3} z^VhhlgexbR82zrwGmviCIa*s2&m!U#i}jp1?at&Q5=*)<@277pzlw8p=-5!wku)EQ zm91?CoBf#&s)MFB79TkmV!2u$@%xyoP|6-hUA|`Cn zlwmCU0mtE%enE`RKU-O|5OpM(8fD`dd3LBx%o4uJMz4v{6s|84miI+S+(-+dlCGAv zaY>7f#vmPy0FAaI>9H0!Fv0Uz;CZnT+!Z@Q_&U`bwC-lLYv*tVY}xNT^k6h$eZ|rl zhC%Noov+-`(p@oO0nV@v#Bp%|0pT3S@6%bont;n(=uhYbKVm1;Iri~Xqw<=`VHMfu zhx*N2psS@;DE&#NZ&VBkj~qiD+tf7@3Ht<{$TX8Fgv9NNP-9PSZ&sPq2S5d30!SBF zD2sVmeY%Gu+fPt$S_sbYg7#vsH+}$ICOF}-pY6jxHv5lW@9y@XVJ8Oyu3zDPM+)f9 zkuoZBQkOdrw9>Ae>t#UTZaCNf&ZYn9!p;U!{e(Uv7AE@z9OAcaX$990yEqc-Vu&Pq z$+o&@oY?STj%g)CwXonAYz*8xVO#Kj@0}L1pXX1SJ9gwkks!2ksCOdZ9Hf8Y(2LOu z%9(iilqygC-C%=aJ)}lszwDuN{0mkYiePC(^b4?oOAEBovzo395!}Y2E^oaHDB}6* zD;CjwVk<){XqdTJ{UH8w*N@r%dP*WviMrtFh-pH$O9MqQ5NFBN71By7*-LjMP3L+n z{Z>#;NA4&j*3op>i}5kF#?oM&H{=Hf!uA_wI8w(g1Ua9cx=%uja&js)^$DQi9jL~~ zrXDyt1@`IwIf%3fG^k_7{Iz}7*ol5K#aJfb+x``qTLLC!qSucD1IE~L%#rn&aa7!G ze_+4a0&PV*dysY0uisC_z;IRmG6|^5oM}5<>q5v{64EM$g+FjVI`B+)ZHm&l>t`B( zQ)@>_I+(rvR(}6fDYl(zUlv;X@O3HZ3k5_mTv8jq^OsJ)q~>N6ZpS3RUoKBo~e+ z%5oXx%-WZJbMW1UIpY$HUp!mCIZ)ialovzY-~wmdW(TZv4=U~V8$uicEWu_6mm_NC z>qLWjt}kjz6$JY4%s;Ekl@A1cuRPg>G(xEs>>w6;Tr(zQecpciNE} zHhNy;%5eSiR-BjI1flt)0mex6Y>m=d(nN$O(qwxL=2zY;g|0Jx-&U237+`3i;v(VE zSmB(<6RGM`15YXkCq(y5(H4=H4QcGL2_YUBf@T~JMi3+$*cBZU ztQW6(`zcHz^lW)tX0Sl~NYF(h@qvr1uFelP9hNj3^L)sdvHzCu2JwrLBt?nBWg`ro z8s28E;_ov)_(MyX!2OLCJBQ#9i@`BEoV25-23EfrSz*poh`C2~pZnnQ&om!l73?YO zXm^ruKJK(CNCr5Ymr`EmPI2LAd9cwxVQ5)>&4(1M_6lXT=_QN3;JsMz!J$}k>~U73 zomaTgH@Oe(MmbWXzmJrv#Qef`@je$YU94_pbPjaf6;ksfx3SAN=sGw#70&OCk~KROa=AkL$(4;m&qqoIKCqTz5fcjmeQES7=fD z)}Ul=J^y&9hUR>=DPUmvT=OA@Q~Ah(idBsA9n?=4en|?yVrZIyc}AYRC!B6Qg5>@V zmddw6k>Aw`Lwg^-q+F7Cerd(;a9I#;S4=s6_JCu3NC|Mc78<(q?5D|$+%bIfyvPr8 zNr0!-C|dg6K@;7{RLZ$X{Dod{609*zNSOyQf?Hh}FwkVPha=fhxhLxm6T-+2<@h=D zR-7YdIQ&bS%RDHuQ}xp zJ@8hK91Ge7|FDvo2juIZqfakMnuDRjgiY7yN`_TA$MaVCptGXs%_no!L2I}MC-YeT z6OGP5^Tdg*sA2=hoahEN-M;rVwDk$QQq!D{Ed`EfRuGMz(PL|bas$GD4N<5I_mw?Y zA};(sRs&=&|LCI_M>R)wmBk80sX$vRxo@)PobW`Wh8DFUyBS-sn%0^}huxFoTt?c7|0L7h2sQ<$agPw-r-Wak+Sf{?J zu)xdP(0KYOJ;0i1>6+XYyP}^3YwXTLNgLj??~05D&#V2``$QTBD_OlzltB>jI|tcY z{%m6F{LqbV#&y^Xza$(AC3MMoA`hj`?(EmbIP=Mx9X!SomK1wk#N0{pIN{H)dC{ci zH>=&QY)R7vn`)u1y@tFx(V&6cB*a}c^>*Qh2pxcsXXAIl{aTp-!d$5;qbKO(!RmBR zj$Xjpwg$TC|vEuyJ#Y@AZdBxo-`L z5S2KEYqfeKzbS{=I=?Y%79b-eD7^_O+Uh8(1Yse)10>*DFT2v~z&j0z!I(jkFt5fjKI4vWU*o@; ztw-8}LFW1lP43#(v33MJ%_y!O9`Y{vh0H4Vj*~@Y>*2#1*$S+3{uc4x;J!DMNlTs^ zOurJ>v*j?_dgd2&d;e9O*8gM_v`AJ)X=xJ_r-WmUbk2 zLv(IuN#PILYO&zrT`glG+<0(%oY>#?baB8s(Bb1octe5E*O+|4Nn&yik|OX}424R+ z<0nJ^S>FRP&R6!-h6-S#d63^iP#MT_Pvk%CcI&9E|tSVE~`i`g~&vg1} zMHy{Npsmw3&!{E|-XiZXC9zml=2v>LbeWw@&7-G0(HF55u?O3FEVhi86bq6D7}I(k z={&e|l7UL)b}+Gmkj7*kvaP`UcQ^Jk!L(5D4&s*z;BlyVP#rir_&F*x2W>!mZN#g= z_vArlr|4HOD60VnV}PBYRTR}H0q5x1Hl+i~QI4~OijiQCfODr_QgAd70`iP&1_5-} z9wZ^cO>Tnd&?;(}zilfx)He0mKnT1DxSh74!CUd{ye+MRo6ZTM$N+y_*8mTJc!+2u zJMQ*&YFGkzz3zF)mz0aNSLcvrjUkMB7h}x0etqSkch%Gcwtxw3Mc6G_`tO*c>-_4+ z$r!(f1Xmthp9)agVB`_lxQz0?{ZMGKrO-d0q*H}$o;8aU#nk?kCeEcxpGyW04ptCv z4m;eYs@5DGP{LJYNk|V#Xmc@-JHI*iU=(kd?fKlYK8gDas@eE4HAcbIyQ12k3h=7C ziX+Pv9e~JSD$_F1Z=er8vcPhq9pat9-w!V80V+nFehb$UtS#Ce_f7&E47$#UMRsn* zPv=}vH_J)kf0sTdUL{)hZN)$}Fk&)+5r*ne;U$DvEWt05wxGK0B{-~0in`OqhrvY7 zWNeP(4x7A~O%(`poJIao=WwD}kEJo0fuc0mv=nTPC%-zzAlCWpu4|eNzpmxRy{NrQ z0!-ouqS_<{yKW!x3qGnMsCTTjBfYohN!@(rk%E(-B-YAi>3x1y%QOr^voKDYH=^o6 ziV1=mA+p7GZaJHUDq#iBFJ|7vEc zW8ro}Ltl+_5o)%@bJZrb8F&;{TCHu4o?GTolj~KSs9=oGAok&;Bu1(4K8&|mNAijS z^-EU$n4$g&r+A?rDcjn!Q1+>@ms^ca`1R1qft9REK;Xlw@b|1NyZd2JH|PYgB5}Hl z{ySqgjSQu|HaJ}Qqg&()PPaH-XrvnTq-x*#begU-9QkSBOE%^yE1k+}W4Ona6KuYf zL?7Edk%X+xL=hP^!?sjiON@pc63JtY zHJ~nNm|0{fsZ^UpA}`nN87w-DzYmX^j}|Z{V7@gN3pos=PCuu3LC!#^uv(uP>cn?=EzIbnc$dhNP9NVtwS*|Tn|#z}HP%aX zT^cRJBZfUkAhnh>Hc@$$dvWy*t25YfM~Nn^&8LoU)@x3u4LgDC+-XE&w2F5e&Gg%T zN0{@Jtqg?KvV=V3#ZA#_cnBrpWC7Co*n|x#zWEqxvUg9?YwiXc&e3Eb}b9} zB7Zz?c!7MMzlENZR?UMxW*G)8P0^>`QW_)S#*`x0Eg^+5ESu%TIW|ZIj}|aq@G)I$ zDy$$=RA7izy5`Obw}pWNtGm&7}-+iPx0m_JY$*xcftGh031EuEBI zW)O7yQwe#A&pEdreCjosL;svAL0q88K(>Si>F~6wutMXEZKr>VEU90L>9dauXRVv< z7f5%BMlmBfp=a{AOAdBJWbKwAj%hte3N|CXHC-?***=K zWGg5^80F@2oyaHF^#GY)TX`n9080$aexV-ufg2c@mzyNjFymxWs1>LjV|Czl()Awf zgTGvuFaBnL>JR}CRr}Y}?j+*iPpT`gb6N>>j~uC@camYbJZhKofm6w0^crpRRVgi> zK2Lo*dbj2u_PeLvK3dqWzzH!CIGrl}2EmxRXCq_P*N_6z{!y1)`Mvrk0buOo)R=`| zT`&-GRUqKc>8JQBi%2_ZE9kdwz6OGAvF`^h`9UK8s9G0Qu3u=dVbmtnup2u}x1>vqr*`K<<)sqw}mdX zc^IY}$Dv){6v5(Cld)V6=!Uan^SYrzBBW@{{96+-ioW5@YbV0*V8`jk|x5d!4izr} znJCaMqs8$1U96h*;7EB?T@F*;y&6kT#{B^Yxu4~As2Y(xr!Ldz?CRz|`u z8#4Yjiu_}8h_;y1E7Dx}GJ3A#xk#ukrSO+0HNo2jwZn9Z0uQk#DMDc4>Z5>qqsGjEBiD_1liS>Y|!WkfSTm8 z4D`3*MK}`03{P#}Ns@>t7J$&hjSRim8wn0v7WW`Fe8gI&tWZ_213jHsFeVUGQ6%;2 zcfpy!bCy&@b#e4Hbfj_ozT$G3m(y=khMtHzn1qQu&HiL&BCu}qGoG`fKzS(KD2i4* z4|FF2_VaCAmfTD`Ap10DMt(Dl%a^bd{%|D-^8Jpr9*mD#OeqY*q7*P%IN%lehDNql z>_M%{pHOC6ig9%nF3YC2bhe6%VVFhzez)ZH=E}ZIKUQXZuuK+LeKL9^$bO1MpGcw^ z*4DOUVm;ap!`=m@V>Cu@&!J~+77R#^^|~X>^0(4~%20TOxY1}OwcF*MWx#xm)(Vg_ zL+(y#VyMoVnEHN!b^y1S$RG5?a7yY!(JLhi`al^lSavuM<&u}!GM;Bf(IUOaSr_`uB1OwJ4s1I>T}2_%39Kw&9V y&^iQ+S09s2?|YI&hRH;s0C=IW-eLODGqK}UyeemS=(i@e8!ud|fshcP`Tql^#-3vU literal 0 HcmV?d00001 diff --git a/credentials/pledge_credentials.p12 b/credentials/default_pledge.p12 similarity index 100% rename from credentials/pledge_credentials.p12 rename to credentials/default_pledge.p12 diff --git a/credentials/default.p12 b/credentials/default_registrar.p12 similarity index 100% rename from credentials/default.p12 rename to credentials/default_registrar.p12 diff --git a/src/main/java/com/google/openthread/LoggerInitializer.java b/src/main/java/com/google/openthread/LoggerInitializer.java index b9bdf1c..6d50eee 100644 --- a/src/main/java/com/google/openthread/LoggerInitializer.java +++ b/src/main/java/com/google/openthread/LoggerInitializer.java @@ -30,7 +30,8 @@ import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; -import org.apache.logging.log4j.core.config.Configurator; +import ch.qos.logback.classic.LoggerContext; +import java.util.List; import org.slf4j.LoggerFactory; public class LoggerInitializer { @@ -39,12 +40,20 @@ public class LoggerInitializer { private static final String CALIFORNIUM = "org.eclipse.californium"; public static void Init(boolean verbose) { - if (verbose) { - ((Logger) LoggerFactory.getLogger(CALIFORNIUM)).setLevel(Level.DEBUG); - Configurator.setLevel(OPENTHREAD, org.apache.logging.log4j.Level.DEBUG); - } else { - ((Logger) LoggerFactory.getLogger(CALIFORNIUM)).setLevel(Level.WARN); - Configurator.setLevel(OPENTHREAD, org.apache.logging.log4j.Level.INFO); + final Level level = verbose ? Level.DEBUG : Level.INFO; + final Level levelLibrary = verbose ? Level.INFO : Level.WARN; + + LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); + List loggerList = loggerContext.getLoggerList(); + for (Logger logger : loggerList) { + switch (logger.getName()) { + case OPENTHREAD: + logger.setLevel(level); + break; + case CALIFORNIUM: + logger.setLevel(levelLibrary); + break; + } } } } diff --git a/src/main/java/com/google/openthread/main/OtRegistrarConfig.java b/src/main/java/com/google/openthread/main/OtRegistrarConfig.java index 6e20139..386ca70 100644 --- a/src/main/java/com/google/openthread/main/OtRegistrarConfig.java +++ b/src/main/java/com/google/openthread/main/OtRegistrarConfig.java @@ -31,33 +31,68 @@ public class OtRegistrarConfig { public Role role; - public int serverPortCoaps; + public int serverPort; public String domainName; public String keyStoreFile; public String masaUri; public String registrarUri; public boolean logVerbose; - static OtRegistrarConfig Default() { + static OtRegistrarConfig DefaultPledge() { OtRegistrarConfig config = new OtRegistrarConfig(); - config.role = Role.None; - config.serverPortCoaps = 5684; - config.domainName = "DefaultDomain"; - config.keyStoreFile = "./credentials/default.p12"; + config.role = Role.Pledge; + config.serverPort = 0; + config.domainName = null; + config.keyStoreFile = "./credentials/default_pledge.p12"; config.masaUri = null; config.registrarUri = "localhost:5684"; config.logVerbose = false; return config; } + static OtRegistrarConfig DefaultRegistrar() { + OtRegistrarConfig config = new OtRegistrarConfig(); + config.role = Role.Registrar; + config.serverPort = 5684; + config.domainName = "DefaultDomain"; + config.keyStoreFile = "./credentials/default_registrar.p12"; + config.masaUri = null; + config.registrarUri = null; + config.logVerbose = false; + return config; + } + + static OtRegistrarConfig DefaultMasa() { + OtRegistrarConfig config = new OtRegistrarConfig(); + config.role = Role.Masa; + config.serverPort = 9443; // re-using corporate TLS/HTTPS port + config.domainName = null; + config.keyStoreFile = "./credentials/default_masa.p12"; + config.masaUri = null; + config.registrarUri = null; + config.logVerbose = false; + return config; + } + public String ToString() { - return - "Role : " + role.toString() + "\n" + - "Server port (CoapS) : " + this.serverPortCoaps + "\n" + - "Domain Name : " + this.domainName + "\n" + - "Keystore file : " + this.keyStoreFile + "\n" + - "MASA URI : " + (this.masaUri == null ? "(read from IDevID cert)" : this.masaUri + " (forced)") + "\n" + - "Registrar URI : " + this.registrarUri + "\n" + - "Log verbose : " + (this.logVerbose ? "yes" : "no" ) + "\n"; + String s; + s = "Role : " + role.toString() + "\n"; + if (this.serverPort > 0) { + s += "Server port : " + this.serverPort + "\n"; + } + if (this.domainName != null) { + s += "Domain Name : " + this.domainName + "\n"; + } + if (this.keyStoreFile != null) { + s += "Keystore file : " + this.keyStoreFile + "\n"; + } + if (this.masaUri != null) { + s += "MASA URI : " + this.masaUri + " (forced)\n"; + } + if (this.registrarUri != null) { + s += "Registrar URI : " + this.registrarUri + "\n"; + } + s += "Log verbose : " + (this.logVerbose ? "yes" : "no") + "\n"; + return s; } } diff --git a/src/main/java/com/google/openthread/main/OtRegistrarMain.java b/src/main/java/com/google/openthread/main/OtRegistrarMain.java index 6f31d66..b177b08 100644 --- a/src/main/java/com/google/openthread/main/OtRegistrarMain.java +++ b/src/main/java/com/google/openthread/main/OtRegistrarMain.java @@ -29,6 +29,7 @@ package com.google.openthread.main; import com.google.openthread.LoggerInitializer; +import com.google.openthread.masa.MASAMain; import com.google.openthread.registrar.RegistrarMain; import com.google.openthread.pledge.PledgeMain; import org.apache.commons.cli.CommandLine; @@ -45,9 +46,9 @@ */ public final class OtRegistrarMain { - private static Logger logger = LoggerFactory.getLogger(OtRegistrarMain.class); + private static final Logger logger = LoggerFactory.getLogger(OtRegistrarMain.class); - public static void main(String args[]) { + public static void main(String[] args) { final String HELP_FORMAT = "[-registrar | -masa | -pledge] [-h] [-v] [-d ] [-f ] [-p ]"; @@ -79,44 +80,47 @@ public static void main(String args[]) { Option fileOpt = Option.builder("f") - .longOpt("file") + .longOpt("keyfile") .hasArg() .argName("keystore-file") .desc("the keystore file in PKCS#12 format") .build(); - Option optPort = + Option portOpt = Option.builder("p") .longOpt("port") .hasArg() - .argName("udp-port") - .desc("the port to listen on") + .argName("server-port") + .desc("the server CoAPS or HTTPS port to listen on") .build(); - Option optVerbose = + Option verboseOpt = Option.builder("v") .longOpt("verbose") .desc("verbose mode with many logs") .build(); - Option optForceMasaUri = + Option masaUriOpt = Option.builder("m") - .longOpt("masa") + .longOpt("masaUri") .hasArg() - .argName("force-masa-uri") + .argName("forced-masa-uri") .desc("force the given MASA URI instead of the default one") .build(); - Option optRegistrarUri = + Option registrarUriOpt = Option.builder("r") - .longOpt("registrar") + .longOpt("registrarUri") .hasArg() .argName("registrar-uri") .desc("for a Pledge, the Registrar to connect to") .build(); Option helpOpt = - Option.builder("h").longOpt("help").hasArg(false).desc("print this message").build(); + Option.builder("h") + .longOpt("help") + .desc("print this message") + .build(); options .addOption(registrarOpt) @@ -124,13 +128,13 @@ public static void main(String args[]) { .addOption(pledgeOpt) .addOption(domainNameOpt) .addOption(fileOpt) - .addOption(optPort) - .addOption(optVerbose) - .addOption(optForceMasaUri) - .addOption(optRegistrarUri) + .addOption(portOpt) + .addOption(verboseOpt) + .addOption(masaUriOpt) + .addOption(registrarUriOpt) .addOption(helpOpt); - OtRegistrarConfig config = OtRegistrarConfig.Default(); + OtRegistrarConfig config; try { CommandLineParser parser = new DefaultParser(); @@ -141,14 +145,27 @@ public static void main(String args[]) { return; } - config.logVerbose = cmd.hasOption("v"); + if (cmd.hasOption("registrar")) { + config = OtRegistrarConfig.DefaultRegistrar(); + } else if (cmd.hasOption("masa")) { + config = OtRegistrarConfig.DefaultMasa(); + } else if (cmd.hasOption("pledge")) { + config = OtRegistrarConfig.DefaultPledge(); + } else { + helper.printHelp(HELP_FORMAT, options); + return; + } + + if (cmd.hasOption('v')) { + config.logVerbose = true; + } LoggerInitializer.Init(config.logVerbose); if (cmd.hasOption('f')) { config.keyStoreFile = cmd.getOptionValue('f'); } if (cmd.hasOption('p')) { - config.serverPortCoaps = Integer.parseInt(cmd.getOptionValue('p')); + config.serverPort = Integer.parseInt(cmd.getOptionValue('p')); } if (cmd.hasOption('d')) { config.domainName = cmd.getOptionValue('d'); @@ -157,17 +174,6 @@ public static void main(String args[]) { config.masaUri = cmd.getOptionValue('m'); } - if (cmd.hasOption("registrar")) { - config.role = Role.Registrar; - } else if (cmd.hasOption("masa")) { - config.role = Role.Masa; - } else if (cmd.hasOption("pledge")) { - config.role = Role.Pledge; - } else { - helper.printHelp(HELP_FORMAT, options); - return; - } - } catch (Exception e) { logger.error(e.getMessage(), e); helper.printHelp(HELP_FORMAT, options); @@ -178,14 +184,15 @@ public static void main(String args[]) { switch (config.role) { case Registrar: - RegistrarMain.main(config); + RegistrarMain.startRegistrar(config); break; case Masa: + MASAMain.startMasa(config); break; case Pledge: - PledgeMain.main(config); + PledgeMain.startPledge(config); break; - case None: + default: break; } } diff --git a/src/main/java/com/google/openthread/masa/MASAMain.java b/src/main/java/com/google/openthread/masa/MASAMain.java index b842b16..059a34f 100644 --- a/src/main/java/com/google/openthread/masa/MASAMain.java +++ b/src/main/java/com/google/openthread/masa/MASAMain.java @@ -29,99 +29,41 @@ package com.google.openthread.masa; import com.google.openthread.Credentials; -import com.google.openthread.LoggerInitializer; +import com.google.openthread.main.OtRegistrarConfig; import com.google.openthread.tools.CredentialGenerator; import java.security.KeyStoreException; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class MASAMain { - private MASAMain() {} - - public static void main(String args[]) { - final String HELP_FORMAT = "masa [-h] [-v] [-c] -f -p "; - - HelpFormatter helper = new HelpFormatter(); - Options options = new Options(); - - Option fileOpt = - Option.builder("f") - .longOpt("file") - .hasArg() - .argName("keystore-file") - .desc("the keystore file in PKCS#12 format") - .build(); - - Option optPort = - Option.builder("p") - .longOpt("port") - .hasArg() - .argName("port") - .desc("the port to listen on") - .build(); - - Option optVerbose = - Option.builder("v") - .longOpt("verbose") - .hasArg(false) - .desc("verbose mode with many logs") - .build(); - - Option optHelp = - Option.builder("h").longOpt("help").hasArg(false).desc("print this message").build(); + private MASAMain() { + } - options.addOption(fileOpt).addOption(optPort).addOption(optVerbose).addOption(optHelp); + private static final Logger logger = LoggerFactory.getLogger(MASAMain.class); + public static void startMasa(OtRegistrarConfig config) { MASA masa; try { - CommandLineParser parser = new DefaultParser(); - CommandLine cmd = parser.parse(options, args); - - if (cmd.hasOption('h')) { - helper.printHelp(HELP_FORMAT, options); - return; - } - - String keyStoreFile = cmd.getOptionValue('f'); - if (keyStoreFile == null) { - throw new IllegalArgumentException("need keystore file!"); - } - String port = cmd.getOptionValue('p'); - if (port == null) { - throw new IllegalArgumentException("need port!"); - } - - LoggerInitializer.Init(cmd.hasOption('v')); - - System.out.println("using keystore: " + keyStoreFile); - Credentials cred = - new Credentials( - keyStoreFile, CredentialGenerator.MASA_ALIAS, CredentialGenerator.PASSWORD); - Credentials credCa = - new Credentials( - keyStoreFile, CredentialGenerator.MASACA_ALIAS, CredentialGenerator.PASSWORD); + Credentials cred = new Credentials(config.keyStoreFile, CredentialGenerator.MASA_ALIAS, CredentialGenerator.PASSWORD); + Credentials credCa = new Credentials(config.keyStoreFile, CredentialGenerator.MASACA_ALIAS, CredentialGenerator.PASSWORD); if (cred.getPrivateKey() == null || cred.getCertificate() == null) { - throw new KeyStoreException("can't find MASA server key or certificate"); + throw new KeyStoreException("can't find MASA server key or certificate in key store"); } if (credCa.getPrivateKey() == null || credCa.getCertificate() == null) { - throw new KeyStoreException("can't find MASA CA key or certificate"); + throw new KeyStoreException("can't find MASA CA key or CA certificate in key store"); } - masa = new MASA(cred, credCa, Integer.parseInt(port)); + masa = new MASA(cred, credCa, config.serverPort); } catch (Exception e) { - System.err.println("error: " + e.getMessage()); - helper.printHelp(HELP_FORMAT, options); + logger.error(e.getMessage()); + logger.debug("details:", e); return; } masa.start(); - System.out.println("MASA server listening at " + masa.getListenPort()); + logger.info("MASA server listening (HTTPS) at port {}", masa.getListenPort()); } } diff --git a/src/main/java/com/google/openthread/pledge/PledgeMain.java b/src/main/java/com/google/openthread/pledge/PledgeMain.java index a1602c3..980a360 100644 --- a/src/main/java/com/google/openthread/pledge/PledgeMain.java +++ b/src/main/java/com/google/openthread/pledge/PledgeMain.java @@ -43,24 +43,25 @@ private PledgeMain() { private static final Logger logger = LoggerFactory.getLogger(PledgeMain.class); - public static void main(OtRegistrarConfig config) { + public static void startPledge(OtRegistrarConfig config) { try { String password = CredentialGenerator.PASSWORD; Credentials cred = new Credentials(config.keyStoreFile, CredentialGenerator.PLEDGE_ALIAS, password); - if (cred == null || cred.getPrivateKey() == null || cred.getCertificateChain() == null) { + if (cred.getPrivateKey() == null || cred.getCertificateChain() == null) { throw new KeyStoreException(String.format("can't find pledge key or certificate: %s", CredentialGenerator.PLEDGE_ALIAS)); } Pledge pledge = new Pledge(cred, config.registrarUri); - run(pledge); + runCli(pledge); pledge.shutdown(); } catch (Exception e) { - logger.error("error: {}", e.getMessage(), e); + logger.error(e.getMessage()); + logger.debug("details:", e); return; } } - private static void run(Pledge pledge) { + private static void runCli(Pledge pledge) { final String help = "rv - request voucher to Registrar (cBRSKI)\n" + "enroll - simple enrollment with Registrar (EST)\n" diff --git a/src/main/java/com/google/openthread/registrar/RegistrarMain.java b/src/main/java/com/google/openthread/registrar/RegistrarMain.java index 2d43c2a..c20a189 100644 --- a/src/main/java/com/google/openthread/registrar/RegistrarMain.java +++ b/src/main/java/com/google/openthread/registrar/RegistrarMain.java @@ -29,17 +29,10 @@ package com.google.openthread.registrar; import com.google.openthread.Credentials; -import com.google.openthread.LoggerInitializer; import com.google.openthread.domainca.DomainCA; import com.google.openthread.main.OtRegistrarConfig; import com.google.openthread.tools.CredentialGenerator; import java.security.KeyStoreException; -import org.apache.commons.cli.CommandLine; -import org.apache.commons.cli.CommandLineParser; -import org.apache.commons.cli.DefaultParser; -import org.apache.commons.cli.HelpFormatter; -import org.apache.commons.cli.Option; -import org.apache.commons.cli.Options; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -47,7 +40,7 @@ public final class RegistrarMain { private static final Logger logger = LoggerFactory.getLogger(RegistrarMain.class); - public static void main(OtRegistrarConfig config) { + public static void startRegistrar(OtRegistrarConfig config) { Registrar registrar; try { @@ -63,15 +56,15 @@ public static void main(OtRegistrarConfig config) { throw new KeyStoreException("can't find domain CA key or certificate in keystore"); } - // re-use the same creds for Pledge-facing identity and MASA-facing identity. + // re-use the same creds for Pledge-facing identity and MASA-facing identity of Registrar. builder.setCredentials(cred); - builder.setPort(config.serverPortCoaps); + builder.setPort(config.serverPort); // if (true) { // trust all MASAs by default builder.setTrustAllMasas(true); // } else { - // FIXME if one MASA identity defined in credentials file, use that one as trusted MASA. + // FIXME if one MASA identity defined in credentials file, use that one as trusted MASA. Or add config flag. // if (masaCred.getCertificate() != null) // builder.addMasaCertificate(masaCred.getCertificate()); // } @@ -85,11 +78,12 @@ public static void main(OtRegistrarConfig config) { DomainCA ca = new DomainCA(config.domainName, domainCred); registrar.setDomainCA(ca); } catch (Exception e) { - logger.error(e.getMessage(), e); + logger.error(e.getMessage()); + logger.debug("details:", e); return; } registrar.start(); - logger.info("Registrar listening at port: {}", registrar.getListenPort()); + logger.info("Registrar listening (CoAPS) at port: {}", registrar.getListenPort()); } } diff --git a/src/main/java/com/google/openthread/tools/CredentialGenerator.java b/src/main/java/com/google/openthread/tools/CredentialGenerator.java index a796f87..1278a6b 100644 --- a/src/main/java/com/google/openthread/tools/CredentialGenerator.java +++ b/src/main/java/com/google/openthread/tools/CredentialGenerator.java @@ -92,8 +92,7 @@ public class CredentialGenerator extends CredentialsSet { public static final String PLEDGE_SN = "OT-"; public static final String PLEDGE_DNAME = DNAME_PREFIX + PLEDGE_ALIAS + ",SERIALNUMBER="; - public static final String CREDENTIALS_FILE_IOTCONSULTANCY = - "credentials/iotconsultancy-masa/credentials.p12"; + public static final String CREDENTIALS_FILE_IOTCONSULTANCY = "credentials/iotconsultancy-masa/credentials.p12"; public static final String CREDENTIALS_FILE_HONEYDUKES = "credentials/honeydukes/credentials.p12"; private String masaUri = Constants.DEFAULT_MASA_URI; @@ -107,19 +106,16 @@ public CredentialGenerator() throws Exception { } /** - * Set the MASA URI that will be included in a generated Pledge certificate, in the MASA URI - * extension (RFC 8995 2.3.2). + * Set the MASA URI that will be included in a generated Pledge certificate, in the MASA URI extension (RFC 8995 2.3.2). * - * @param masaUri string that is typically only the 'authority' part of a URI. See RFC 8995 for - * exception cases where more elements can be added. + * @param masaUri string that is typically only the 'authority' part of a URI. See RFC 8995 for exception cases where more elements can be added. */ public void setMasaUri(String masaUri) { this.masaUri = masaUri; } /** - * Sets whether the Extended Key Usage (EKU) extensions is included in any generated Registrar - * cert. By default, it is included and must be included to comply to specifications. For testing + * Sets whether the Extended Key Usage (EKU) extensions is included in any generated Registrar cert. By default, it is included and must be included to comply to specifications. For testing * situations it can be excluded. * * @param isIncluded true if EKU is included (should be used by default), false if not. @@ -180,11 +176,9 @@ public X509Certificate genPledgeCertificate( } /** - * generate a Registrar's certificate which has the cmcRA extended key usage (EKU) set by default. - * Due to RFC 5280 4.2.1.12 rules, if the EKU is present also the 'server' EKU must be present or - * else the identity is not allowed to operate as server. Similar for 'client' EKU; as the - * Registrar also must operate as a client towards MASA potentially with same identity (or - * potentially with another.) + * generate a Registrar's certificate which has the cmcRA extended key usage (EKU) set by default. Due to RFC 5280 4.2.1.12 rules, if the EKU is present also the 'server' EKU must be present or else + * the identity is not allowed to operate as server. Similar for 'client' EKU; as the Registrar also must operate as a client towards MASA potentially with same identity (or potentially with + * another.) * * @param subKeyPair * @param subName @@ -202,10 +196,10 @@ public X509Certificate genRegistrarCertificate( Extension.keyUsage, true, new KeyUsage( - KeyUsage.digitalSignature - | KeyUsage.keyEncipherment - | KeyUsage.dataEncipherment - | KeyUsage.keyAgreement) + KeyUsage.digitalSignature + | KeyUsage.keyEncipherment + | KeyUsage.dataEncipherment + | KeyUsage.keyAgreement) .getEncoded(ASN1Encoding.DER)); Extension extKeyUsage = @@ -213,11 +207,11 @@ public X509Certificate genRegistrarCertificate( Extension.extendedKeyUsage, false, new ExtendedKeyUsage( - new KeyPurposeId[] { - KeyPurposeId.id_kp_serverAuth, - KeyPurposeId.id_kp_clientAuth, - isIncludeExtKeyUsage ? Constants.id_kp_cmcRA : KeyPurposeId.id_kp_codeSigning - }) + new KeyPurposeId[]{ + KeyPurposeId.id_kp_serverAuth, + KeyPurposeId.id_kp_clientAuth, + isIncludeExtKeyUsage ? Constants.id_kp_cmcRA : KeyPurposeId.id_kp_codeSigning + }) .getEncoded(ASN1Encoding.DER)); List extensions = new ArrayList<>(); @@ -228,8 +222,7 @@ public X509Certificate genRegistrarCertificate( } /** - * Generate a new Registrar certificate using default Registrar/DomainCA credentials stored in - * this object. + * Generate a new Registrar certificate using default Registrar/DomainCA credentials stored in this object. * * @return */ @@ -254,17 +247,17 @@ public X509Certificate genMasaServerCertificate( Extension.keyUsage, true, new KeyUsage( - KeyUsage.digitalSignature - | KeyUsage.keyEncipherment - | KeyUsage.dataEncipherment - | KeyUsage.keyAgreement) + KeyUsage.digitalSignature + | KeyUsage.keyEncipherment + | KeyUsage.dataEncipherment + | KeyUsage.keyAgreement) .getEncoded(ASN1Encoding.DER)); Extension extKeyUsage = new Extension( Extension.extendedKeyUsage, false, - new ExtendedKeyUsage(new KeyPurposeId[] {KeyPurposeId.id_kp_serverAuth}) + new ExtendedKeyUsage(new KeyPurposeId[]{KeyPurposeId.id_kp_serverAuth}) .getEncoded(ASN1Encoding.DER)); // for MASA certs, include dns name so that Registrar HTTP client can accept it. @@ -285,18 +278,13 @@ public X509Certificate genMasaServerCertificate( /** * Make/generate a complete set of certificates and store locally within this CredentialsSet. * - * @param domaincaCertKeyFiles filenames for CA cert file and private key file, respectively, or - * null to generate this key/cert - * @param masaCaCertKeyFiles filenames for MASA CA cert file and private key file, respectively, - * or null to generate this key/cert, or a single filename to a MASA CA cert file only - * (without private key) - * @param masaCertKeyFiles filenames for MASA server cert file and private key file, respectively, - * or null to generate this key/cert, or a single filename to a MASA server cert file only - * (without private key) - * @param registrarCertKeyFiles filenames for Registrar cert file and private key file, - * respectively, or null to generate this key/cert - * @param pledgeCertKeyFiles filenames for Pledge cert file and private key file, respectively, or - * null to generate this key/cert + * @param domaincaCertKeyFiles filenames for CA cert file and private key file, respectively, or null to generate this key/cert + * @param masaCaCertKeyFiles filenames for MASA CA cert file and private key file, respectively, or null to generate this key/cert, or a single filename to a MASA CA cert file only (without + * private key) + * @param masaCertKeyFiles filenames for MASA server cert file and private key file, respectively, or null to generate this key/cert, or a single filename to a MASA server cert file only + * (without private key) + * @param registrarCertKeyFiles filenames for Registrar cert file and private key file, respectively, or null to generate this key/cert + * @param pledgeCertKeyFiles filenames for Pledge cert file and private key file, respectively, or null to generate this key/cert * @throws Exception various error cases */ public void make( @@ -323,7 +311,7 @@ public void make( masaCaCert = genSelfSignedCert(masaCaKeyPair, MASACA_DNAME); } this.setCredentials( - MASACA_ALIAS, new X509Certificate[] {masaCaCert}, masaCaKeyPair.getPrivate()); + MASACA_ALIAS, new X509Certificate[]{masaCaCert}, masaCaKeyPair.getPrivate()); // MASA server X509Certificate cert; @@ -341,7 +329,7 @@ public void make( genMasaServerCertificate( keyPair, MASA_DNAME, masaCaKeyPair, masaCaCert.getSubjectX500Principal().getName()); } - this.setCredentials(MASA_ALIAS, new X509Certificate[] {cert, masaCaCert}, keyPair.getPrivate()); + this.setCredentials(MASA_ALIAS, new X509Certificate[]{cert, masaCaCert}, keyPair.getPrivate()); // Pledge makePledge(pledgeCertKeyFiles); @@ -357,7 +345,7 @@ public void make( domaincaCert = genSelfSignedCert(domaincaKeyPair, DOMAINCA_DNAME); } this.setCredentials( - DOMAINCA_ALIAS, new X509Certificate[] {domaincaCert}, domaincaKeyPair.getPrivate()); + DOMAINCA_ALIAS, new X509Certificate[]{domaincaCert}, domaincaKeyPair.getPrivate()); // Registrar if (registrarCertKeyFiles != null) { @@ -373,7 +361,7 @@ public void make( domaincaCert.getSubjectX500Principal().getName()); } this.setCredentials( - REGISTRAR_ALIAS, new X509Certificate[] {cert, domaincaCert}, keyPair.getPrivate()); + REGISTRAR_ALIAS, new X509Certificate[]{cert, domaincaCert}, keyPair.getPrivate()); // Commissioner - not yet loading from a file. TODO keyPair = SecurityUtils.genKeyPair(); @@ -386,14 +374,13 @@ public void make( false, null); this.setCredentials( - COMMISSIONER_ALIAS, new X509Certificate[] {cert, domaincaCert}, keyPair.getPrivate()); + COMMISSIONER_ALIAS, new X509Certificate[]{cert, domaincaCert}, keyPair.getPrivate()); } /** * Make a new Pledge certificate. * - * @param pledgeCertKeyFiles filenames for Pledge cert file and private key file, respectively, or - * null to generate + * @param pledgeCertKeyFiles filenames for Pledge cert file and private key file, respectively, or null to generate */ public void makePledge(String[] pledgeCertKeyFiles) throws Exception { X509Certificate pledgeCert; @@ -419,7 +406,7 @@ public void makePledge(String[] pledgeCertKeyFiles) throws Exception { } this.setCredentials( PLEDGE_ALIAS, - new X509Certificate[] {pledgeCert, masaCaCreds.getCertificate()}, + new X509Certificate[]{pledgeCert, masaCaCreds.getCertificate()}, pledgeKeyPair.getPrivate()); } @@ -433,8 +420,7 @@ public String getPledgeSerialNumber() { } /** - * load a certificate PEM from file and log any load/parse errors to the log. Any exception is - * thrown to caller. + * load a certificate PEM from file and log any load/parse errors to the log. Any exception is thrown to caller. * * @param fn * @return @@ -457,8 +443,7 @@ protected X509Certificate loadCertAndLogErrors(String fn) } /** - * load the private key PEM file in 'fn' and combine this with the public key in 'cert', to return - * the combined KeyPair. Any errors in load/parse are logged and any exceptions are thrown up. + * load the private key PEM file in 'fn' and combine this with the public key in 'cert', to return the combined KeyPair. Any errors in load/parse are logged and any exceptions are thrown up. * * @param cert * @param fn @@ -518,7 +503,7 @@ public void store(String filename) throws Exception { public void dumpSeparateFiles() throws Exception { String[] files = { - MASACA_ALIAS, MASA_ALIAS, PLEDGE_ALIAS, DOMAINCA_ALIAS, REGISTRAR_ALIAS, COMMISSIONER_ALIAS + MASACA_ALIAS, MASA_ALIAS, PLEDGE_ALIAS, DOMAINCA_ALIAS, REGISTRAR_ALIAS, COMMISSIONER_ALIAS }; for (int i = 0; i < files.length; ++i) { From 2fcbe42bde804af531f958b291e45033391565b8 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 27 Jun 2024 10:23:28 +0200 Subject: [PATCH 08/25] [all] moved code to right packages; split Constants into 3 separate files; source style formatting. --- .../java/com/google/openthread/Constants.java | 75 ++---------------- .../com/google/openthread/Credentials.java | 2 + .../com/google/openthread/CredentialsSet.java | 2 + .../com/google/openthread/SecurityUtils.java | 10 ++- .../openthread/brski/ConstantsBrski.java | 79 +++++++++++++++++++ .../ExtendedMediaTypeRegistry.java | 2 +- .../{ => brski}/HardwareModuleName.java | 2 +- .../brski/RestfulVoucherResponse.java | 4 +- .../google/openthread/domainca/DomainCA.java | 30 +++---- .../java/com/google/openthread/masa/MASA.java | 22 +++--- .../com/google/openthread/pledge/Pledge.java | 28 ++++--- .../pledge/PledgeCertificateVerifier.java | 6 +- .../openthread/pledge/PledgeHardware.java | 2 +- .../openthread/registrar/Registrar.java | 44 +++++------ .../registrar/RegistrarBuilder.java | 3 +- .../openthread/thread/ConstantsThread.java | 42 ++++++++++ .../{ => thread}/OpenThreadUtils.java | 2 +- .../openthread/tools/CredentialGenerator.java | 11 +-- .../tools/HardwarePledgeTestSuite.java | 78 +++++++++++------- .../google/openthread/CredentialsTest.java | 58 +++++--------- .../google/openthread/SecurityUtilsTest.java | 4 +- .../openthread/registrar/FunctionalTest.java | 27 +++---- .../registrar/IETFConstrainedBrskiTest.java | 7 +- 23 files changed, 301 insertions(+), 239 deletions(-) create mode 100644 src/main/java/com/google/openthread/brski/ConstantsBrski.java rename src/main/java/com/google/openthread/{ => brski}/ExtendedMediaTypeRegistry.java (99%) rename src/main/java/com/google/openthread/{ => brski}/HardwareModuleName.java (99%) create mode 100644 src/main/java/com/google/openthread/thread/ConstantsThread.java rename src/main/java/com/google/openthread/{ => thread}/OpenThreadUtils.java (98%) diff --git a/src/main/java/com/google/openthread/Constants.java b/src/main/java/com/google/openthread/Constants.java index 853e07e..a22556e 100644 --- a/src/main/java/com/google/openthread/Constants.java +++ b/src/main/java/com/google/openthread/Constants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, The OpenThread Registrar Authors. + * Copyright (c) 2024, The OpenThread Registrar Authors. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -28,79 +28,16 @@ package com.google.openthread; -import com.upokecenter.cbor.CBORObject; -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x509.KeyPurposeId; - +/** + * OT Registrar specific constants are defined here. + */ public class Constants { - // --- BRSKI - EST resources and paths - public static final String WELL_KNOWN = ".well-known"; - public static final String EST = "est"; - public static final String BRSKI = "brski"; - public static final String CORE = "core"; - public static final String EST_PATH = "/" + String.join("/", WELL_KNOWN, EST); - public static final String BRSKI_PATH = "/" + String.join("/", WELL_KNOWN, BRSKI); - public static final String CORE_PATH = "/" + String.join("/", WELL_KNOWN, CORE); - public static final String REQUEST_VOUCHER = "rv"; - public static final String REQUEST_VOUCHER_HTTP = "requestvoucher"; - public static final String VOUCHER_STATUS = "vs"; - public static final String ENROLL_STATUS = "es"; - public static final String CSR_ATTRIBUTES = "att"; - public static final String CA_CERTIFICATES = "crts"; - public static final String SIMPLE_ENROLL = "sen"; - public static final String SIMPLE_REENROLL = "sren"; - - // --- Other resources and paths + // --- URIs, resources and paths + public static final String DEFAULT_MASA_URI = "localhost:9443"; public static final String HELLO = "hello"; - public static final String COMM_PET_REQ_PATH = "/c/cp"; - - // --- HTTP Media Types - public static final String HTTP_APPLICATION_VOUCHER_CMS_JSON = "application/voucher-cms+json"; - public static final String HTTP_APPLICATION_VOUCHER_CMS_CBOR = "application/voucher-cms+cbor"; - public static final String HTTP_APPLICATION_COSE_SIGN1 = - "application/cose; cose-type=\"cose-sign1\""; - public static final String HTTP_APPLICATION_COSE = "application/cose"; - public static final String HTTP_APPLICATION_VOUCHER_COSE_CBOR = "application/voucher-cose+cbor"; - public static final String HTTP_APPLICATION_VOUCHER_COSE_JSON = "application/voucher-cose+json"; - - // --- COSE items - // see https://www.iana.org/assignments/cose/cose.xhtml#header-parameters - public static final CBORObject COSE_X5BAG_HEADER_KEY = CBORObject.FromObject(32); - - // --- COM_TOK items - // This is not defined in Thread specs and we currently use "/.well-known/ccm". - // FIXME should use Thread Group's namespace for this: "/.well-known/thread/ccm". - public static final String COM_TOK = "ccm"; - public static final String CCM_PATH = "/" + String.join("/", WELL_KNOWN, COM_TOK); - // Commissioner token validity in days - public static final int COM_TOK_VALIDITY = 365; - - // --- OID items - public static final String MASA_URI_OID = "1.3.6.1.5.5.7.1.32"; // RFC 8995 - public static final String HARDWARE_MODULE_NAME_OID = "1.3.6.1.5.5.7.8.4"; - public static final String PRIVATE_HARDWARE_TYPE_OID = "1.3.6.1.4.1.21335"; - public static final String THREAD_DOMAIN_NAME_OID = "1.3.6.1.4.1.44970.1"; // per Thread 1.2 spec - public static final String CMC_RA_PKIX_KEY_PURPOSE_OID = "1.3.6.1.5.5.7.3.28"; // RFC 6402 2.10 - public static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37"; - public static final KeyPurposeId id_kp_cmcRA = - KeyPurposeId.getInstance(new ASN1ObjectIdentifier(CMC_RA_PKIX_KEY_PURPOSE_OID)); - public static final ASN1ObjectIdentifier eku = new ASN1ObjectIdentifier(EXTENDED_KEY_USAGE_OID); - public static final Integer ASN1_TAG_GENERALNAME_OTHERNAME = - Integer.valueOf(0); // RFC 5280 Section 4.2.1.6 - - // --- URIs, ports and hostnames - public static final int DEFAULT_REGISTRAR_COAPS_PORT = 5684; - public static final int DEFAULT_MASA_HTTPS_PORT = 9443; - public static final String DEFAULT_MASA_URI_HOST = "localhost"; - - // In case the MASA URI is not specified, this default value will be used. - public static final String DEFAULT_MASA_URI = - DEFAULT_MASA_URI_HOST + ":" + DEFAULT_MASA_HTTPS_PORT; // -- Other items - // Default Thread Domain Name per Thread 1.2 spec. Must not be changed, unless spec changes. - public static final String THREAD_DOMAIN_NAME_DEFAULT = "DefaultDomain"; public static final String KEY_STORE_FORMAT = "PKCS12"; public static final long CERT_VALIDITY = 5 * 365; // LDevID validity in Days. } diff --git a/src/main/java/com/google/openthread/Credentials.java b/src/main/java/com/google/openthread/Credentials.java index 22b8073..e685d0f 100644 --- a/src/main/java/com/google/openthread/Credentials.java +++ b/src/main/java/com/google/openthread/Credentials.java @@ -28,6 +28,8 @@ package com.google.openthread; +import com.google.openthread.brski.ConstantsBrski; +import com.google.openthread.thread.ConstantsThread; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; diff --git a/src/main/java/com/google/openthread/CredentialsSet.java b/src/main/java/com/google/openthread/CredentialsSet.java index beefd08..393a085 100644 --- a/src/main/java/com/google/openthread/CredentialsSet.java +++ b/src/main/java/com/google/openthread/CredentialsSet.java @@ -28,6 +28,8 @@ package com.google.openthread; +import com.google.openthread.brski.ConstantsBrski; + import java.io.FileInputStream; import java.io.InputStream; import java.security.KeyStore; diff --git a/src/main/java/com/google/openthread/SecurityUtils.java b/src/main/java/com/google/openthread/SecurityUtils.java index ae0ad9b..a72a578 100644 --- a/src/main/java/com/google/openthread/SecurityUtils.java +++ b/src/main/java/com/google/openthread/SecurityUtils.java @@ -34,6 +34,8 @@ import COSE.HeaderKeys; import COSE.OneKey; import COSE.Sign1Message; +import com.google.openthread.brski.ConstantsBrski; +import com.google.openthread.brski.HardwareModuleName; import com.upokecenter.cbor.CBORObject; import com.upokecenter.cbor.CBORType; import java.io.ByteArrayInputStream; @@ -182,7 +184,7 @@ public static HardwareModuleName getHWModuleName(X509Certificate cert) GeneralName name = GeneralName.getInstance(obj); if (name.getTagNo() == GeneralName.otherName) { OtherName otherName = OtherName.getInstance(name.getName()); - if (otherName.getTypeID().getId().equals(Constants.HARDWARE_MODULE_NAME_OID)) { + if (otherName.getTypeID().getId().equals(ConstantsBrski.HARDWARE_MODULE_NAME_OID)) { return HardwareModuleName.getInstance(otherName.getValue()); } } @@ -211,7 +213,7 @@ public static String getDNSName(X509Certificate cert) throws CertificateEncoding public static String getMasaUri(X509Certificate cert) { try { X509CertificateHolder holder = new JcaX509CertificateHolder(cert); - Extension masaUri = holder.getExtension(new ASN1ObjectIdentifier(Constants.MASA_URI_OID)); + Extension masaUri = holder.getExtension(new ASN1ObjectIdentifier(ConstantsBrski.MASA_URI_OID)); // TODO check if the below can also handle UTF-8 String types. (Not all use IA5String) String sUri = DERIA5String.fromByteArray(masaUri.getExtnValue().getOctets()).toString(); // remove trailing slashes, if any, from MASA URI. @@ -350,7 +352,7 @@ public static byte[] genCoseSign1Message( msg.sign(new OneKey(null, signingKey)); if (certs != null) { CBORObject x5bag = SecurityUtils.createX5BagCertificates(certs); - msg.addAttribute(Constants.COSE_X5BAG_HEADER_KEY, x5bag, Attribute.UNPROTECTED); + msg.addAttribute(ConstantsBrski.COSE_X5BAG_HEADER_KEY, x5bag, Attribute.UNPROTECTED); } return msg.EncodeToBytes(); } @@ -622,7 +624,7 @@ public static List getX5BagCertificates(Sign1Message sign1Msg) throws CertificateException { List certs = new ArrayList<>(); // look for header parameter - CBORObject x5bag = sign1Msg.findAttribute(Constants.COSE_X5BAG_HEADER_KEY); + CBORObject x5bag = sign1Msg.findAttribute(ConstantsBrski.COSE_X5BAG_HEADER_KEY); if (x5bag == null) return null; // if it is an array of certs if (x5bag.getType().equals(CBORType.Array) && x5bag.size() > 0) { diff --git a/src/main/java/com/google/openthread/brski/ConstantsBrski.java b/src/main/java/com/google/openthread/brski/ConstantsBrski.java new file mode 100644 index 0000000..68de203 --- /dev/null +++ b/src/main/java/com/google/openthread/brski/ConstantsBrski.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2019, 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. + */ + +package com.google.openthread.brski; + +import com.upokecenter.cbor.CBORObject; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x509.KeyPurposeId; + +public class ConstantsBrski { + + // --- BRSKI - EST resources and paths + public static final String WELL_KNOWN = ".well-known"; + public static final String EST = "est"; + public static final String BRSKI = "brski"; + public static final String CORE = "core"; + public static final String EST_PATH = "/" + String.join("/", WELL_KNOWN, EST); + public static final String BRSKI_PATH = "/" + String.join("/", WELL_KNOWN, BRSKI); + public static final String CORE_PATH = "/" + String.join("/", WELL_KNOWN, CORE); + public static final String REQUEST_VOUCHER = "rv"; + public static final String REQUEST_VOUCHER_HTTP = "requestvoucher"; + public static final String VOUCHER_STATUS = "vs"; + public static final String ENROLL_STATUS = "es"; + public static final String CSR_ATTRIBUTES = "att"; + public static final String CA_CERTIFICATES = "crts"; + public static final String SIMPLE_ENROLL = "sen"; + public static final String SIMPLE_REENROLL = "sren"; + + // --- HTTP Media Types + public static final String HTTP_APPLICATION_VOUCHER_CMS_JSON = "application/voucher-cms+json"; + public static final String HTTP_APPLICATION_VOUCHER_CMS_CBOR = "application/voucher-cms+cbor"; + public static final String HTTP_APPLICATION_COSE_SIGN1 = "application/cose; cose-type=\"cose-sign1\""; + public static final String HTTP_APPLICATION_COSE = "application/cose"; + public static final String HTTP_APPLICATION_VOUCHER_COSE_CBOR = "application/voucher-cose+cbor"; + public static final String HTTP_APPLICATION_VOUCHER_COSE_JSON = "application/voucher-cose+json"; + + // --- COSE items + // see https://www.iana.org/assignments/cose/cose.xhtml#header-parameters + public static final CBORObject COSE_X5BAG_HEADER_KEY = CBORObject.FromObject(32); + + // --- OID items + public static final String MASA_URI_OID = "1.3.6.1.5.5.7.1.32"; // RFC 8995 + public static final String HARDWARE_MODULE_NAME_OID = "1.3.6.1.5.5.7.8.4"; + public static final String PRIVATE_HARDWARE_TYPE_OID = "1.3.6.1.4.1.21335"; + public static final String CMC_RA_PKIX_KEY_PURPOSE_OID = "1.3.6.1.5.5.7.3.28"; // RFC 6402 2.10 + public static final String EXTENDED_KEY_USAGE_OID = "2.5.29.37"; + public static final KeyPurposeId id_kp_cmcRA = KeyPurposeId.getInstance(new ASN1ObjectIdentifier(CMC_RA_PKIX_KEY_PURPOSE_OID)); + public static final ASN1ObjectIdentifier eku = new ASN1ObjectIdentifier(EXTENDED_KEY_USAGE_OID); + public static final Integer ASN1_TAG_GENERALNAME_OTHERNAME = 0; // RFC 5280 Section 4.2.1.6 + + // --- URIs, ports and hostnames + public static final int DEFAULT_REGISTRAR_COAPS_PORT = 5684; + public static final int DEFAULT_MASA_HTTPS_PORT = 9443; +} diff --git a/src/main/java/com/google/openthread/ExtendedMediaTypeRegistry.java b/src/main/java/com/google/openthread/brski/ExtendedMediaTypeRegistry.java similarity index 99% rename from src/main/java/com/google/openthread/ExtendedMediaTypeRegistry.java rename to src/main/java/com/google/openthread/brski/ExtendedMediaTypeRegistry.java index 7a69748..81c436d 100644 --- a/src/main/java/com/google/openthread/ExtendedMediaTypeRegistry.java +++ b/src/main/java/com/google/openthread/brski/ExtendedMediaTypeRegistry.java @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -package com.google.openthread; +package com.google.openthread.brski; import java.util.HashMap; import java.util.Set; diff --git a/src/main/java/com/google/openthread/HardwareModuleName.java b/src/main/java/com/google/openthread/brski/HardwareModuleName.java similarity index 99% rename from src/main/java/com/google/openthread/HardwareModuleName.java rename to src/main/java/com/google/openthread/brski/HardwareModuleName.java index 21ea38e..a0e4649 100644 --- a/src/main/java/com/google/openthread/HardwareModuleName.java +++ b/src/main/java/com/google/openthread/brski/HardwareModuleName.java @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -package com.google.openthread; +package com.google.openthread.brski; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1Object; diff --git a/src/main/java/com/google/openthread/brski/RestfulVoucherResponse.java b/src/main/java/com/google/openthread/brski/RestfulVoucherResponse.java index 9a33e5c..8967ea9 100644 --- a/src/main/java/com/google/openthread/brski/RestfulVoucherResponse.java +++ b/src/main/java/com/google/openthread/brski/RestfulVoucherResponse.java @@ -1,7 +1,5 @@ package com.google.openthread.brski; -import com.google.openthread.Constants; -import com.google.openthread.ExtendedMediaTypeRegistry; import org.eclipse.californium.core.coap.CoAP.ResponseCode; /** @@ -68,7 +66,7 @@ public RestfulVoucherResponse(int httpStatus, byte[] payload, String contentType this.code = codeFromHttpStatus(httpStatus); this.payload = payload; if (contentType != null - && !contentType.toLowerCase().equals(Constants.HTTP_APPLICATION_VOUCHER_COSE_CBOR)) + && !contentType.toLowerCase().equals(ConstantsBrski.HTTP_APPLICATION_VOUCHER_COSE_CBOR)) throw new IllegalArgumentException("Unsupported Content-Type " + contentType); this.contentFormat = ExtendedMediaTypeRegistry.parse(contentType); } diff --git a/src/main/java/com/google/openthread/domainca/DomainCA.java b/src/main/java/com/google/openthread/domainca/DomainCA.java index f063c59..a7bc2b1 100644 --- a/src/main/java/com/google/openthread/domainca/DomainCA.java +++ b/src/main/java/com/google/openthread/domainca/DomainCA.java @@ -28,12 +28,11 @@ package com.google.openthread.domainca; -import COSE.OneKey; import com.google.openthread.BouncyCastleInitializer; import com.google.openthread.Constants; import com.google.openthread.Credentials; import com.google.openthread.SecurityUtils; -import com.upokecenter.cbor.CBORObject; +import com.google.openthread.thread.ConstantsThread; import java.math.BigInteger; import java.security.GeneralSecurityException; import java.security.PrivateKey; @@ -46,10 +45,8 @@ import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.logging.Logger; import org.bouncycastle.asn1.ASN1Encodable; @@ -77,7 +74,7 @@ public class DomainCA { protected static final ASN1ObjectIdentifier THREAD_DOMAIN_NAME_OID_ASN1 = - new ASN1ObjectIdentifier(Constants.THREAD_DOMAIN_NAME_OID); // per Thread 1.2 spec + new ASN1ObjectIdentifier(ConstantsThread.THREAD_DOMAIN_NAME_OID); // per Thread 1.2 spec static { BouncyCastleInitializer.init(); @@ -98,9 +95,8 @@ public X509Certificate getCertificate() { } /** - * Get the Thread Domain Name currently used by this Domain CA. Note that a Domain CA may use any - * number of Thread Domains within its own Enterprise Domain, with arbitrary string identifiers. - * In the present implementation only one Thread Domain is used. + * Get the Thread Domain Name currently used by this Domain CA. Note that a Domain CA may use any number of Thread Domains within its own Enterprise Domain, with arbitrary string identifiers. In the + * present implementation only one Thread Domain is used. * * @return the currently used Thread Domain Name for signing LDevID certificates. */ @@ -112,8 +108,7 @@ public X509Certificate signCertificate(PKCS10CertificationRequest csr) throws Ex // 0. POP (proof-of-possession) verification // Ref: RFC-7030 [3.4] - if (!csr.isSignatureValid( - new JcaContentVerifierProviderBuilder().build(csr.getSubjectPublicKeyInfo()))) { + if (!csr.isSignatureValid(new JcaContentVerifierProviderBuilder().build(csr.getSubjectPublicKeyInfo()))) { throw new GeneralSecurityException("POP verification failed"); } @@ -123,11 +118,8 @@ public X509Certificate signCertificate(PKCS10CertificationRequest csr) throws Ex X500Name issuer = getSubjectName(); BigInteger serial = allocateSerialNumber(); Date notBefore = new Date(); - Date notAfter = - new Date(System.currentTimeMillis() + Constants.CERT_VALIDITY * 3600 * 24 * 1000); - X509v3CertificateBuilder builder = - new X509v3CertificateBuilder( - issuer, serial, notBefore, notAfter, csr.getSubject(), csr.getSubjectPublicKeyInfo()); + Date notAfter = new Date(System.currentTimeMillis() + Constants.CERT_VALIDITY * 3600 * 24 * 1000); + X509v3CertificateBuilder builder = new X509v3CertificateBuilder(issuer, serial, notBefore, notAfter, csr.getSubject(), csr.getSubjectPublicKeyInfo()); logger.info("operational certificate not-before: " + notBefore.toString()); logger.info("operational certificate not-after: " + notAfter.toString()); @@ -160,8 +152,8 @@ public X509Certificate signCertificate(PKCS10CertificationRequest csr) throws Ex // to look the same as OpenSSL commandline output. DERSequence otherName = new DERSequence( - new ASN1Encodable[] { - THREAD_DOMAIN_NAME_OID_ASN1, new DERTaggedObject(0, new DERIA5String(domainName)) + new ASN1Encodable[]{ + THREAD_DOMAIN_NAME_OID_ASN1, new DERTaggedObject(0, new DERIA5String(domainName)) }); GeneralNames subjectAltNames = new GeneralNames(new GeneralName(GeneralName.otherName, otherName)); @@ -201,7 +193,7 @@ public X500Name getSubjectName() { private static BigInteger serialNumber = new BigInteger("1"); - private static final synchronized BigInteger allocateSerialNumber() { + private static synchronized BigInteger allocateSerialNumber() { serialNumber = serialNumber.add(BigInteger.ONE); logger.info("allocate serial number: " + serialNumber); return serialNumber; @@ -213,5 +205,5 @@ private static final synchronized BigInteger allocateSerialNumber() { private X509Certificate certificate; - private static Logger logger = Logger.getLogger(DomainCA.class.getCanonicalName()); + private final static Logger logger = Logger.getLogger(DomainCA.class.getCanonicalName()); } diff --git a/src/main/java/com/google/openthread/masa/MASA.java b/src/main/java/com/google/openthread/masa/MASA.java index 66791aa..4766f23 100644 --- a/src/main/java/com/google/openthread/masa/MASA.java +++ b/src/main/java/com/google/openthread/masa/MASA.java @@ -34,7 +34,7 @@ import COSE.OneKey; import COSE.Sign1Message; import com.google.openthread.BouncyCastleInitializer; -import com.google.openthread.Constants; +import com.google.openthread.brski.ConstantsBrski; import com.google.openthread.Credentials; import com.google.openthread.DummyTrustManager; import com.google.openthread.NetworkUtils; @@ -144,7 +144,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { Sign1Message sign1Msg = null; switch (contentType) { - case Constants.HTTP_APPLICATION_VOUCHER_CMS_JSON: + case ConstantsBrski.HTTP_APPLICATION_VOUCHER_CMS_JSON: try { reqContent = SecurityUtils.decodeCMSSignedMessage( @@ -158,9 +158,9 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { } break; - case Constants.HTTP_APPLICATION_VOUCHER_COSE_CBOR: - case Constants.HTTP_APPLICATION_COSE_SIGN1: - case Constants.HTTP_APPLICATION_COSE: + case ConstantsBrski.HTTP_APPLICATION_VOUCHER_COSE_CBOR: + case ConstantsBrski.HTTP_APPLICATION_COSE_SIGN1: + case ConstantsBrski.HTTP_APPLICATION_COSE: try { // Verify signature sign1Msg = (Sign1Message) Message.DecodeFromBytes(body, MessageTag.Sign1); @@ -190,7 +190,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { } switch (contentType) { - case Constants.HTTP_APPLICATION_VOUCHER_CMS_JSON: + case ConstantsBrski.HTTP_APPLICATION_VOUCHER_CMS_JSON: try { req = (VoucherRequest) new JSONSerializer().deserialize(reqContent); } catch (Exception e) { @@ -200,9 +200,9 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { } break; - case Constants.HTTP_APPLICATION_VOUCHER_COSE_CBOR: - case Constants.HTTP_APPLICATION_COSE_SIGN1: - case Constants.HTTP_APPLICATION_COSE: + case ConstantsBrski.HTTP_APPLICATION_VOUCHER_COSE_CBOR: + case ConstantsBrski.HTTP_APPLICATION_COSE_SIGN1: + case ConstantsBrski.HTTP_APPLICATION_COSE: try { req = (VoucherRequest) new CBORSerializer().deserialize(sign1Msg.GetContent()); } catch (Exception e) { @@ -227,7 +227,7 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { .getResponseHeaders() .put( HttpString.tryFromString("Content-Type"), - Constants.HTTP_APPLICATION_VOUCHER_COSE_CBOR); + ConstantsBrski.HTTP_APPLICATION_VOUCHER_COSE_CBOR); byte[] content = new CBORSerializer().serialize(resp.getVoucher()); byte[] payload = SecurityUtils.genCoseSign1Message( @@ -280,7 +280,7 @@ protected RestfulVoucherResponse processVoucherRequest( X509Certificate registrarCert = reqCerts.get(0); if (registrarCert.getExtendedKeyUsage() != null) { for (String eku : registrarCert.getExtendedKeyUsage()) { - if (eku.equals(Constants.CMC_RA_PKIX_KEY_PURPOSE_OID)) { + if (eku.equals(ConstantsBrski.CMC_RA_PKIX_KEY_PURPOSE_OID)) { isRA = true; break; } diff --git a/src/main/java/com/google/openthread/pledge/Pledge.java b/src/main/java/com/google/openthread/pledge/Pledge.java index 8322738..344eea4 100644 --- a/src/main/java/com/google/openthread/pledge/Pledge.java +++ b/src/main/java/com/google/openthread/pledge/Pledge.java @@ -35,13 +35,15 @@ import COSE.Sign1Message; import com.google.openthread.BouncyCastleInitializer; import com.google.openthread.Constants; +import com.google.openthread.brski.ConstantsBrski; import com.google.openthread.Credentials; -import com.google.openthread.ExtendedMediaTypeRegistry; +import com.google.openthread.brski.ExtendedMediaTypeRegistry; import com.google.openthread.SecurityUtils; import com.google.openthread.brski.CBORSerializer; import com.google.openthread.brski.StatusTelemetry; import com.google.openthread.brski.Voucher; import com.google.openthread.brski.VoucherRequest; +import com.google.openthread.thread.ConstantsThread; import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.GeneralSecurityException; @@ -103,7 +105,7 @@ public class Pledge extends CoapClient { protected static final ASN1ObjectIdentifier THREAD_DOMAIN_NAME_OID_ASN1 = - new ASN1ObjectIdentifier(Constants.THREAD_DOMAIN_NAME_OID); // per Thread 1.2 spec + new ASN1ObjectIdentifier(ConstantsThread.THREAD_DOMAIN_NAME_OID); // per Thread 1.2 spec static { BouncyCastleInitializer.init(); @@ -174,11 +176,11 @@ public String getDomainName() { try { Collection> cSubjAltNames = operationalCertificate.getSubjectAlternativeNames(); if (cSubjAltNames == null) { - return Constants.THREAD_DOMAIN_NAME_DEFAULT; + return ConstantsThread.THREAD_DOMAIN_NAME_DEFAULT; } // loop all subject-alt-names to find a matching 'otherName' item. for (List l : cSubjAltNames) { - if (l.size() == 2 && l.get(0).equals(Constants.ASN1_TAG_GENERALNAME_OTHERNAME)) { + if (l.size() == 2 && l.get(0).equals(ConstantsBrski.ASN1_TAG_GENERALNAME_OTHERNAME)) { ASN1Sequence ds = DERSequence.getInstance(DLSequence.fromByteArray((byte[]) l.get(1))); // check that the otherName item has the Thread domain OID if (ds.size() == 2 && ds.getObjectAt(0).equals(THREAD_DOMAIN_NAME_OID_ASN1)) { @@ -199,7 +201,7 @@ public String getDomainName() { return null; } // if cert correct but not encoded in there, use default name. - return Constants.THREAD_DOMAIN_NAME_DEFAULT; + return ConstantsThread.THREAD_DOMAIN_NAME_DEFAULT; } // BRSKI protocol @@ -349,7 +351,7 @@ public ResponseCode sendVoucherStatusTelemetry(boolean isSuccess, String failure throws Exception { // create CBOR data structure StatusTelemetry st = StatusTelemetry.create(isSuccess, failureReason); - setURI(getBRSKIPath() + "/" + Constants.VOUCHER_STATUS); + setURI(getBRSKIPath() + "/" + ConstantsBrski.VOUCHER_STATUS); CoapResponse resp = post(st.serializeToBytes(), ExtendedMediaTypeRegistry.APPLICATION_CBOR); return resp.getCode(); } @@ -365,7 +367,7 @@ public ResponseCode sendEnrollStatusTelemetry(boolean isSuccess, String failureR throws Exception { // create CBOR data structure StatusTelemetry st = StatusTelemetry.create(isSuccess, failureReason); - setURI(getBRSKIPath() + "/" + Constants.ENROLL_STATUS); + setURI(getBRSKIPath() + "/" + ConstantsBrski.ENROLL_STATUS); CoapResponse resp = post(st.serializeToBytes(), ExtendedMediaTypeRegistry.APPLICATION_CBOR); return resp.getCode(); } @@ -410,7 +412,7 @@ public void enroll() throws Exception { SecurityUtils.SIGNATURE_ALGORITHM, operationalKeyPair.getPrivate()); - X509Certificate cert = requestSigning(csr, Constants.SIMPLE_ENROLL); + X509Certificate cert = requestSigning(csr, ConstantsBrski.SIMPLE_ENROLL); if (cert == null) { throw new PledgeException("CSR response includes no certificate"); } @@ -454,7 +456,7 @@ public void reenroll() throws Exception { SecurityUtils.SIGNATURE_ALGORITHM, operationalKeyPair.getPrivate()); - X509Certificate cert = requestSigning(csr, Constants.SIMPLE_REENROLL); + X509Certificate cert = requestSigning(csr, ConstantsBrski.SIMPLE_REENROLL); if (cert == null) { throw new PledgeException("CSR response includes no certificate"); } @@ -473,7 +475,7 @@ public CoapResponse sayHello() throws IOException, ConnectorException { } public CoapResponse discoverResources() throws IOException, ConnectorException { - setURI(hostURI + Constants.CORE_PATH); + setURI(hostURI + ConstantsBrski.CORE_PATH); return get(); } @@ -583,7 +585,7 @@ private void init(Credentials creds, String hostURI, boolean isLightweightClient private CoapResponse sendRequestVoucher(VoucherRequest voucherRequest) throws IOException, ConnectorException, CoseException { - setURI(getBRSKIPath() + "/" + Constants.REQUEST_VOUCHER); + setURI(getBRSKIPath() + "/" + ConstantsBrski.REQUEST_VOUCHER); byte[] vrEncoded = new CBORSerializer().serialize(voucherRequest); // COSE_Sign1 signing of the CBOR @@ -700,11 +702,11 @@ private X509Certificate getRegistrarCertificate() { } private String getESTPath() { - return hostURI + Constants.EST_PATH; + return hostURI + ConstantsBrski.EST_PATH; } private String getBRSKIPath() { - return hostURI + Constants.BRSKI_PATH; + return hostURI + ConstantsBrski.BRSKI_PATH; } private String hostURI; diff --git a/src/main/java/com/google/openthread/pledge/PledgeCertificateVerifier.java b/src/main/java/com/google/openthread/pledge/PledgeCertificateVerifier.java index 5ebed5a..1e63b18 100644 --- a/src/main/java/com/google/openthread/pledge/PledgeCertificateVerifier.java +++ b/src/main/java/com/google/openthread/pledge/PledgeCertificateVerifier.java @@ -28,7 +28,7 @@ package com.google.openthread.pledge; -import com.google.openthread.Constants; +import com.google.openthread.brski.ConstantsBrski; import java.security.cert.CertPath; import java.security.cert.CertPathValidator; import java.security.cert.CertificateException; @@ -94,7 +94,7 @@ public void verifyCertificate(CertificateMessage message, DTLSSession session) new X509CertificateHolder(peerCert.getEncoded()); // BouncyCastle equivalent // Check that it is at least an RA cert - Extension ext = peerCertBC.getExtension(Constants.eku); + Extension ext = peerCertBC.getExtension(ConstantsBrski.eku); // byte[] ekuBytes = peerCert.getExtensionValue(Constants.EXTENDED_KEY_USAGE_OID); if (ext == null) throw new CertificateException("EKU not present in Registrar cert"); ASN1InputStream is = new ASN1InputStream(ext.getExtnValue().getOctets()); @@ -107,7 +107,7 @@ public void verifyCertificate(CertificateMessage message, DTLSSession session) } for (ASN1Encodable eku : ekus) { if (eku.equals(KeyPurposeId.id_kp_serverAuth.toOID())) isServerAuth = true; - if (eku.equals(Constants.id_kp_cmcRA.toOID())) isCmcRa = true; + if (eku.equals(ConstantsBrski.id_kp_cmcRA.toOID())) isCmcRa = true; } is.close(); if (!isServerAuth) throw new CertificateException("EKU tlsServerAuth not present"); diff --git a/src/main/java/com/google/openthread/pledge/PledgeHardware.java b/src/main/java/com/google/openthread/pledge/PledgeHardware.java index 2466f6c..b10e7d1 100644 --- a/src/main/java/com/google/openthread/pledge/PledgeHardware.java +++ b/src/main/java/com/google/openthread/pledge/PledgeHardware.java @@ -29,7 +29,7 @@ package com.google.openthread.pledge; import com.fazecast.jSerialComm.*; -import com.google.openthread.OpenThreadUtils; +import com.google.openthread.thread.OpenThreadUtils; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; diff --git a/src/main/java/com/google/openthread/registrar/Registrar.java b/src/main/java/com/google/openthread/registrar/Registrar.java index e8e2220..7df140a 100644 --- a/src/main/java/com/google/openthread/registrar/Registrar.java +++ b/src/main/java/com/google/openthread/registrar/Registrar.java @@ -33,11 +33,12 @@ import COSE.OneKey; import COSE.Sign1Message; import com.google.openthread.BouncyCastleInitializer; -import com.google.openthread.Constants; +import com.google.openthread.brski.ConstantsBrski; import com.google.openthread.Credentials; +import com.google.openthread.Constants; import com.google.openthread.DummyHostnameVerifier; import com.google.openthread.DummyTrustManager; -import com.google.openthread.ExtendedMediaTypeRegistry; +import com.google.openthread.brski.ExtendedMediaTypeRegistry; import com.google.openthread.RequestDumper; import com.google.openthread.SecurityUtils; import com.google.openthread.brski.CBORSerializer; @@ -49,7 +50,6 @@ import com.google.openthread.domainca.DomainCA; import com.google.openthread.pledge.Pledge; import com.google.openthread.tools.CredentialGenerator; -import com.upokecenter.cbor.CBORObject; import java.io.DataOutputStream; import java.io.IOException; import java.net.URL; @@ -176,10 +176,10 @@ public void setForcedRequestFormat(String mediaType) { switch (mediaType) { case "": this.forcedVoucherRequestFormat = -1; - case Constants.HTTP_APPLICATION_VOUCHER_CMS_JSON: + case ConstantsBrski.HTTP_APPLICATION_VOUCHER_CMS_JSON: this.forcedVoucherRequestFormat = ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_CMS_JSON; break; - case Constants.HTTP_APPLICATION_VOUCHER_COSE_CBOR: + case ConstantsBrski.HTTP_APPLICATION_VOUCHER_COSE_CBOR: this.forcedVoucherRequestFormat = ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_COSE_CBOR; break; default: @@ -215,7 +215,7 @@ public String getDomainName() { public final class VoucherStatusResource extends CoapResource { public VoucherStatusResource() { - super(Constants.VOUCHER_STATUS); + super(ConstantsBrski.VOUCHER_STATUS); } @Override @@ -280,7 +280,7 @@ public void handlePOST(CoapExchange exchange) { public final class EnrollStatusResource extends CoapResource { public EnrollStatusResource() { - super(Constants.ENROLL_STATUS); + super(ConstantsBrski.ENROLL_STATUS); } @Override @@ -341,7 +341,7 @@ public void handlePOST(CoapExchange exchange) { public final class VoucherRequestResource extends CoapResource { public VoucherRequestResource() { - super(Constants.REQUEST_VOUCHER); + super(ConstantsBrski.REQUEST_VOUCHER); } @Override @@ -491,8 +491,8 @@ pledgeReq.proximityRegistrarSPKI, getCertificate().getPublicKey().getEncoded())) if (isCms) { // CMS signing. requestMediaType = isJsonRVR - ? Constants.HTTP_APPLICATION_VOUCHER_CMS_JSON - : Constants.HTTP_APPLICATION_VOUCHER_CMS_CBOR; + ? ConstantsBrski.HTTP_APPLICATION_VOUCHER_CMS_JSON + : ConstantsBrski.HTTP_APPLICATION_VOUCHER_CMS_CBOR; requestContentFormat = isJsonRVR ? ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_CMS_JSON : ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_CMS_CBOR; @@ -511,7 +511,7 @@ pledgeReq.proximityRegistrarSPKI, getCertificate().getPublicKey().getEncoded())) } } else { // COSE signing. - requestMediaType = Constants.HTTP_APPLICATION_VOUCHER_COSE_CBOR; + requestMediaType = ConstantsBrski.HTTP_APPLICATION_VOUCHER_COSE_CBOR; requestContentFormat = ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_COSE_CBOR; try { payload = @@ -623,7 +623,7 @@ public final class MASAConnector extends CoapClient { public RestfulVoucherResponse requestVoucher( int requestContentFormat, byte[] payload, String masaURI) throws IOException, ConnectorException { - setURI("coaps://" + masaURI + Constants.BRSKI_PATH + "/" + Constants.REQUEST_VOUCHER); + setURI("coaps://" + masaURI + ConstantsBrski.BRSKI_PATH + "/" + ConstantsBrski.REQUEST_VOUCHER); // send request as CMS signed CBOR, accept only COSE-signed CBOR back. CoapResponse resp = post( @@ -669,7 +669,7 @@ public RestfulVoucherResponse requestVoucher( throws IOException, ConnectorException, NoSuchAlgorithmException, KeyManagementException { URL url = new URL( - "https://" + masaURI + Constants.BRSKI_PATH + "/" + Constants.REQUEST_VOUCHER_HTTP); + "https://" + masaURI + ConstantsBrski.BRSKI_PATH + "/" + ConstantsBrski.REQUEST_VOUCHER_HTTP); // send request as CMS signed JSON, accept only COSE-signed CBOR back. HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); con.setUseCaches(false); @@ -678,7 +678,7 @@ public RestfulVoucherResponse requestVoucher( con.setRequestMethod("POST"); con.setDoOutput(true); con.setRequestProperty("Content-Type", requestMediaType); - con.setRequestProperty("Accept", Constants.HTTP_APPLICATION_VOUCHER_COSE_CBOR); + con.setRequestProperty("Accept", ConstantsBrski.HTTP_APPLICATION_VOUCHER_COSE_CBOR); con.setInstanceFollowRedirects(true); con.connect(); DataOutputStream out = new DataOutputStream(con.getOutputStream()); @@ -694,7 +694,7 @@ public RestfulVoucherResponse requestVoucher( // TODO below assumes the Content-Type of the response, because Accept header was used. May // need to be checked though. return new RestfulVoucherResponse( - con.getResponseCode(), respPayload, Constants.HTTP_APPLICATION_VOUCHER_COSE_CBOR); + con.getResponseCode(), respPayload, ConstantsBrski.HTTP_APPLICATION_VOUCHER_COSE_CBOR); } private void initEndPoint(X509Certificate[] trustAnchors) throws Exception { @@ -709,7 +709,7 @@ private void initEndPoint(X509Certificate[] trustAnchors) throws Exception { public class EnrollResource extends CoapResource { public EnrollResource() { - this(Constants.SIMPLE_ENROLL); + this(ConstantsBrski.SIMPLE_ENROLL); } protected EnrollResource(String name) { @@ -753,14 +753,14 @@ public void handlePOST(CoapExchange exchange) { public final class ReenrollResource extends EnrollResource { public ReenrollResource() { - super(Constants.SIMPLE_REENROLL); + super(ConstantsBrski.SIMPLE_REENROLL); } } public final class CrtsResource extends CoapResource { public CrtsResource() { - super(Constants.CA_CERTIFICATES); + super(ConstantsBrski.CA_CERTIFICATES); } @Override @@ -782,7 +782,7 @@ public void handleGET(CoapExchange exchange) { public final class WellknownCoreResource extends CoapResource { public WellknownCoreResource() { - super(Constants.CORE); + super(ConstantsBrski.CORE); } @Override @@ -872,9 +872,9 @@ X509Certificate getDomainCertificate() { } private void initResources() { - CoapResource wellKnown = new CoapResource(Constants.WELL_KNOWN); - CoapResource est = new CoapResource(Constants.EST); - CoapResource brski = new CoapResource(Constants.BRSKI); + CoapResource wellKnown = new CoapResource(ConstantsBrski.WELL_KNOWN); + CoapResource est = new CoapResource(ConstantsBrski.EST); + CoapResource brski = new CoapResource(ConstantsBrski.BRSKI); VoucherRequestResource rv = new VoucherRequestResource(); VoucherStatusResource vs = new VoucherStatusResource(); diff --git a/src/main/java/com/google/openthread/registrar/RegistrarBuilder.java b/src/main/java/com/google/openthread/registrar/RegistrarBuilder.java index f27073e..dd1ca64 100644 --- a/src/main/java/com/google/openthread/registrar/RegistrarBuilder.java +++ b/src/main/java/com/google/openthread/registrar/RegistrarBuilder.java @@ -29,6 +29,7 @@ package com.google.openthread.registrar; import com.google.openthread.*; +import com.google.openthread.brski.ConstantsBrski; import java.io.IOException; import java.security.GeneralSecurityException; import java.security.PrivateKey; @@ -180,7 +181,7 @@ private X509Certificate[] getMasaCertificates() { private X509Certificate[] certificateChain; private List masaCertificates; private Credentials credentials, masaClientCredentials; - private int port = Constants.DEFAULT_REGISTRAR_COAPS_PORT; + private int port = ConstantsBrski.DEFAULT_REGISTRAR_COAPS_PORT; private boolean isHttpToMasa = true; private boolean isTrustAllMasas = false; } diff --git a/src/main/java/com/google/openthread/thread/ConstantsThread.java b/src/main/java/com/google/openthread/thread/ConstantsThread.java new file mode 100644 index 0000000..7daceca --- /dev/null +++ b/src/main/java/com/google/openthread/thread/ConstantsThread.java @@ -0,0 +1,42 @@ +/* + * 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. + */ + +package com.google.openthread.thread; + +/** + * Thread or OpenThread specific constants are defined here. + */ +public class ConstantsThread { + + // --- OID items + public static final String THREAD_DOMAIN_NAME_OID = "1.3.6.1.4.1.44970.1"; // per Thread 1.2 spec + + // -- Other items + // Default Thread Domain Name per Thread 1.2 spec. Must not be changed, unless spec changes. + public static final String THREAD_DOMAIN_NAME_DEFAULT = "DefaultDomain"; +} diff --git a/src/main/java/com/google/openthread/OpenThreadUtils.java b/src/main/java/com/google/openthread/thread/OpenThreadUtils.java similarity index 98% rename from src/main/java/com/google/openthread/OpenThreadUtils.java rename to src/main/java/com/google/openthread/thread/OpenThreadUtils.java index f26b0c9..80cff10 100644 --- a/src/main/java/com/google/openthread/OpenThreadUtils.java +++ b/src/main/java/com/google/openthread/thread/OpenThreadUtils.java @@ -26,7 +26,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ -package com.google.openthread; +package com.google.openthread.thread; /** * Utilities for dealing with an OpenThread CLI dongle/device. Used when testing an OpenThread CLI diff --git a/src/main/java/com/google/openthread/tools/CredentialGenerator.java b/src/main/java/com/google/openthread/tools/CredentialGenerator.java index 1278a6b..22d2e26 100644 --- a/src/main/java/com/google/openthread/tools/CredentialGenerator.java +++ b/src/main/java/com/google/openthread/tools/CredentialGenerator.java @@ -29,9 +29,10 @@ package com.google.openthread.tools; import com.google.openthread.Constants; +import com.google.openthread.brski.ConstantsBrski; import com.google.openthread.Credentials; import com.google.openthread.CredentialsSet; -import com.google.openthread.HardwareModuleName; +import com.google.openthread.brski.HardwareModuleName; import com.google.openthread.SecurityUtils; import java.io.File; import java.io.FileInputStream; @@ -153,7 +154,7 @@ public X509Certificate genPledgeCertificate( .getEncoded(ASN1Encoding.DER)); OtherName otherName = - new OtherName(new ASN1ObjectIdentifier(Constants.HARDWARE_MODULE_NAME_OID), moduleName); + new OtherName(new ASN1ObjectIdentifier(ConstantsBrski.HARDWARE_MODULE_NAME_OID), moduleName); Extension subjectAltName = new Extension( Extension.subjectAlternativeName, @@ -163,7 +164,7 @@ public X509Certificate genPledgeCertificate( Extension masaUriExt = new Extension( - new ASN1ObjectIdentifier(Constants.MASA_URI_OID).intern(), + new ASN1ObjectIdentifier(ConstantsBrski.MASA_URI_OID).intern(), false, new DERIA5String(masaUri).getEncoded()); @@ -210,7 +211,7 @@ public X509Certificate genRegistrarCertificate( new KeyPurposeId[]{ KeyPurposeId.id_kp_serverAuth, KeyPurposeId.id_kp_clientAuth, - isIncludeExtKeyUsage ? Constants.id_kp_cmcRA : KeyPurposeId.id_kp_codeSigning + isIncludeExtKeyUsage ? ConstantsBrski.id_kp_cmcRA : KeyPurposeId.id_kp_codeSigning }) .getEncoded(ASN1Encoding.DER)); @@ -388,7 +389,7 @@ public void makePledge(String[] pledgeCertKeyFiles) throws Exception { Credentials masaCaCreds = getCredentials(MASACA_ALIAS); String sn = createNewPledgeSerialNumber(); HardwareModuleName hwModuleName = - new HardwareModuleName(Constants.PRIVATE_HARDWARE_TYPE_OID, sn.getBytes()); + new HardwareModuleName(ConstantsBrski.PRIVATE_HARDWARE_TYPE_OID, sn.getBytes()); if (pledgeCertKeyFiles != null) { pledgeCert = loadCertAndLogErrors(pledgeCertKeyFiles[0]); diff --git a/src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java b/src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java index e0a5cfe..09908f9 100644 --- a/src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java +++ b/src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java @@ -36,16 +36,15 @@ import com.google.openthread.masa.*; import com.google.openthread.pledge.*; import com.google.openthread.registrar.*; +import com.google.openthread.thread.OpenThreadUtils; import java.security.Principal; import org.junit.*; import org.junit.runners.*; import org.slf4j.*; /** - * A tool to test a Hardware Pledge DUT (OpenThread CLI device) against the Registrar/MASA. The - * specific network setup so that the Pledge can reach the Registrar, is to be done by the user and - * out of scope of this tool. It uses JUnit framework for easy GUI usage e.g. in Eclipse; consider - * these as integration tests of the hardware Pledge. + * A tool to test a Hardware Pledge DUT (OpenThread CLI device) against the Registrar/MASA. The specific network setup so that the Pledge can reach the Registrar, is to be done by the user and out of + * scope of this tool. It uses JUnit framework for easy GUI usage e.g. in Eclipse; consider these as integration tests of the hardware Pledge. * *

Using Maven, this test suite is NOT executed during Maven test phase unit testing. So, it * needs to be explicitly invoked. @@ -60,33 +59,32 @@ public class HardwarePledgeTestSuite { public static final String THREAD_DOMAIN_NAME = "TestDomainTCE"; public static final int IEEE_802154_CHANNEL = 19; public static final String[] MASA_CREDENTIAL_FILES = - new String[] { - "./credentials/local-masa/masa_cert.pem", "./credentials/local-masa/masa_private.pem" + new String[]{ + "./credentials/local-masa/masa_cert.pem", "./credentials/local-masa/masa_private.pem" }; public static final String[] MASACA_CREDENTIAL_FILES = - new String[] { - "./credentials/local-masa/masaca_cert.pem", "./credentials/local-masa/masaca_private.pem" + new String[]{ + "./credentials/local-masa/masaca_cert.pem", "./credentials/local-masa/masaca_private.pem" }; public static final String[] DOMAIN_CREDENTIAL_FILES = - new String[] { - "./credentials/local-masa/domainca_cert.pem", - "./credentials/local-masa/domainca_private.pem" + new String[]{ + "./credentials/local-masa/domainca_cert.pem", + "./credentials/local-masa/domainca_private.pem" }; public static final String BORDER_ROUTER_AUTHORITY = "[fd00:910b::3285:1958:d0c9:d06]:49191"; - private static final String REGISTRAR_URI = "[::1]:" + Constants.DEFAULT_REGISTRAR_COAPS_PORT; + private static final String REGISTRAR_URI = "[::1]:" + ConstantsBrski.DEFAULT_REGISTRAR_COAPS_PORT; private DomainCA domainCA; private Registrar registrar; private MASA masa; private static PledgeHardware pledge; private static CredentialGenerator credGen; - private static Logger logger = LoggerFactory.getLogger(HardwarePledgeTestSuite.class); + private final static Logger logger = LoggerFactory.getLogger(HardwarePledgeTestSuite.class); @BeforeClass public static void setup() throws Exception { credGen = new CredentialGenerator(); - credGen.make( - DOMAIN_CREDENTIAL_FILES, MASACA_CREDENTIAL_FILES, MASA_CREDENTIAL_FILES, null, null); + credGen.make(DOMAIN_CREDENTIAL_FILES, MASACA_CREDENTIAL_FILES, MASA_CREDENTIAL_FILES, null, null); pledge = new PledgeHardware(); assertTrue(pledge.factoryReset()); assertTrue(pledge.execCommandDone("channel " + IEEE_802154_CHANNEL)); @@ -106,7 +104,7 @@ public void init() throws Exception { new MASA( credGen.getCredentials(CredentialGenerator.MASA_ALIAS), credGen.getCredentials(CredentialGenerator.MASACA_ALIAS), - Constants.DEFAULT_MASA_HTTPS_PORT); + ConstantsBrski.DEFAULT_MASA_HTTPS_PORT); domainCA = new DomainCA( @@ -133,7 +131,9 @@ public void finalize() throws Exception { masa.stop(); } - /** Basic test for DUT Pledge response */ + /** + * Basic test for DUT Pledge response + */ @Test public void testDUT_responds() throws Exception { assertEquals(PledgeHardware.THREAD_VERSION_PLEDGE, pledge.execCommand("thread version")); @@ -143,10 +143,14 @@ public void testDUT_responds() throws Exception { assertTrue(nkey.length() == 32); } - /** DISC-TC-01: */ + /** + * DISC-TC-01: + */ @Test public void test_5_02_DISC_TC_01() throws Exception { - if (pledge.isEnrolled()) pledge.factoryReset(); + if (pledge.isEnrolled()) { + pledge.factoryReset(); + } assertFalse(pledge.isEnrolled()); assertTrue(pledge.execCommandDone("joiner startae")); String res = pledge.waitForMessage(20000); @@ -155,10 +159,14 @@ public void test_5_02_DISC_TC_01() throws Exception { assertFalse(OpenThreadUtils.detectEnrollFailure(res)); } - /** DISC-TC-02: */ + /** + * DISC-TC-02: + */ @Test public void test_5_02_DISC_TC_02() throws Exception { - if (!pledge.isEnrolled()) pledge.enroll(); + if (!pledge.isEnrolled()) { + pledge.enroll(); + } assertTrue(pledge.isEnrolled()); assertTrue(pledge.execCommandDone("joiner startae")); String res = pledge.waitForMessage(20000); @@ -167,11 +175,15 @@ public void test_5_02_DISC_TC_02() throws Exception { // assertTrue(OpenThreadUtils.detectNkpSuccess(res)); } - /** AE-TC-01: Regular BRSKI + EST enrollment */ + /** + * AE-TC-01: Regular BRSKI + EST enrollment + */ @Test public void test_5_05_AE_TC_01() throws Exception { - if (pledge.isEnrolled()) pledge.factoryReset(); + if (pledge.isEnrolled()) { + pledge.factoryReset(); + } assertFalse(pledge.isEnrolled()); assertTrue(pledge.execCommandDone("joiner startae")); @@ -199,29 +211,39 @@ public void test_5_05_AE_TC_01() throws Exception { assertTrue(pledge.isEnrolled()); } - /** NKP-TC-01: */ + /** + * NKP-TC-01: + */ @Test public void test_5_06_NKP_TC_01() throws Exception { assertTrue(false); } - /** NKP-TC-01a: */ + /** + * NKP-TC-01a: + */ @Test public void test_5_06_NKP_TC_01a() throws Exception { // Need to be enrolled to do NKP. - if (!pledge.isEnrolled()) pledge.enroll(); + if (!pledge.isEnrolled()) { + pledge.enroll(); + } assertTrue(pledge.isEnrolled()); assertTrue(pledge.execCommandDone("joiner startnmkp")); String resp = pledge.waitForMessage(15000); assertTrue(false); // TODO } - /** NKP-TC-02: Network Key Provisioning (NKP) after enrollment. */ + /** + * NKP-TC-02: Network Key Provisioning (NKP) after enrollment. + */ @Test public void test_5_06_NKP_TC_02() throws Exception { // Need to be enrolled to do NKP. - if (!pledge.isEnrolled()) pledge.enroll(); + if (!pledge.isEnrolled()) { + pledge.enroll(); + } assertTrue(pledge.execCommandDone("masterkey 33112233445566118899aabbccddeeff")); String oldkey = pledge.execCommand("masterkey"); diff --git a/src/test/java/com/google/openthread/CredentialsTest.java b/src/test/java/com/google/openthread/CredentialsTest.java index 1b85890..9f7c2fa 100644 --- a/src/test/java/com/google/openthread/CredentialsTest.java +++ b/src/test/java/com/google/openthread/CredentialsTest.java @@ -28,6 +28,8 @@ package com.google.openthread; +import com.google.openthread.brski.ConstantsBrski; +import com.google.openthread.brski.HardwareModuleName; import com.google.openthread.tools.CredentialGenerator; import java.io.File; import java.io.Reader; @@ -41,7 +43,6 @@ import java.security.cert.TrustAnchor; import java.security.cert.X509Certificate; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -67,7 +68,8 @@ public class CredentialsTest { public static final String KEY_STORE_FILE = "test-credentials.temp.p12"; private static String pledgeSn; - @Rule public ExpectedException thrown = ExpectedException.none(); + @Rule + public ExpectedException thrown = ExpectedException.none(); @BeforeClass public static void createCredentialFile() throws Exception { @@ -87,61 +89,43 @@ public static void cleanCredentialFile() { public void testASN1() throws Exception { byte[] hardwareModuleName = "OT-9527".getBytes(); ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new ASN1ObjectIdentifier(Constants.HARDWARE_MODULE_NAME_OID)); + v.add(new ASN1ObjectIdentifier(ConstantsBrski.HARDWARE_MODULE_NAME_OID)); v.add(new DEROctetString(hardwareModuleName)); byte[] encoded = new GeneralNames(new GeneralName(GeneralName.otherName, new DERSequence(v))) .getEncoded(ASN1Encoding.DER); GeneralNames names = GeneralNames.getInstance(encoded); for (GeneralName name : names.getNames()) { - Assert.assertTrue(name.getTagNo() == GeneralName.otherName); + Assert.assertEquals(GeneralName.otherName, name.getTagNo()); ASN1Sequence seq = DERSequence.getInstance(name.getName()); - Assert.assertTrue( - ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)) - .getId() - .equals(Constants.HARDWARE_MODULE_NAME_OID)); + Assert.assertEquals(ConstantsBrski.HARDWARE_MODULE_NAME_OID, ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)).getId()); ASN1OctetString sn = DEROctetString.getInstance(seq.getObjectAt(1)); - Assert.assertTrue(Arrays.equals(sn.getOctets(), hardwareModuleName)); + Assert.assertArrayEquals(sn.getOctets(), hardwareModuleName); } } @Test public void testDomainCredentials() throws Exception { - Credentials domainCred = - new Credentials( - KEY_STORE_FILE, CredentialGenerator.DOMAINCA_ALIAS, CredentialGenerator.PASSWORD); + Credentials domainCred = new Credentials(KEY_STORE_FILE, CredentialGenerator.DOMAINCA_ALIAS, CredentialGenerator.PASSWORD); + Credentials registrarCred = new Credentials(KEY_STORE_FILE, CredentialGenerator.REGISTRAR_ALIAS, CredentialGenerator.PASSWORD); - Credentials registrarCred = - new Credentials( - KEY_STORE_FILE, CredentialGenerator.REGISTRAR_ALIAS, CredentialGenerator.PASSWORD); - - Assert.assertTrue(domainCred.getCertificate().getVersion() == 3); - Assert.assertTrue(registrarCred.getCertificate().getVersion() == 3); + Assert.assertEquals(3, domainCred.getCertificate().getVersion()); + Assert.assertEquals(3, registrarCred.getCertificate().getVersion()); Assert.assertTrue(registrarCred.getCertificate().getEncoded().length < 1024); Assert.assertTrue(registrarCred.getCertificate().getPublicKey().getEncoded().length < 1024); - Assert.assertTrue(registrarCred.getCertificateChain().length == 2); + Assert.assertEquals(2, registrarCred.getCertificateChain().length); - Assert.assertTrue( - registrarCred - .getCertificate() - .getIssuerX500Principal() - .equals(domainCred.getCertificate().getSubjectX500Principal())); + Assert.assertEquals(registrarCred.getCertificate().getIssuerX500Principal(), domainCred.getCertificate().getSubjectX500Principal()); registrarCred.getCertificate().verify(domainCred.getCertificate().getPublicKey()); } @Test public void testMASACredentials() throws Exception { - Credentials masaCred = - new Credentials( - KEY_STORE_FILE, CredentialGenerator.MASACA_ALIAS, CredentialGenerator.PASSWORD); - - Credentials pledgeCred = - new Credentials( - KEY_STORE_FILE, CredentialGenerator.PLEDGE_ALIAS, CredentialGenerator.PASSWORD); + Credentials masaCred = new Credentials(KEY_STORE_FILE, CredentialGenerator.MASACA_ALIAS, CredentialGenerator.PASSWORD); + Credentials pledgeCred = new Credentials(KEY_STORE_FILE, CredentialGenerator.PLEDGE_ALIAS, CredentialGenerator.PASSWORD); - Assert.assertEquals( - SecurityUtils.getMasaUri(pledgeCred.getCertificate()), Constants.DEFAULT_MASA_URI); + Assert.assertEquals(SecurityUtils.getMasaUri(pledgeCred.getCertificate()), Constants.DEFAULT_MASA_URI); Assert.assertTrue(pledgeCred.getCertificateChain().length == 2); pledgeCred.getCertificate().verify(masaCred.getCertificate().getPublicKey()); @@ -181,18 +165,16 @@ public void testHWSerialNumber() throws Exception { } HardwareModuleName hwmn = SecurityUtils.getHWModuleName(cert); - Assert.assertTrue(hwmn != null); + Assert.assertNotNull(hwmn); - Assert.assertTrue(Arrays.equals(SERIAL_NUMBER, hwmn.getSerialNumber().getOctets())); + Assert.assertArrayEquals(SERIAL_NUMBER, hwmn.getSerialNumber().getOctets()); } @Test public void testRegistrarCertChainValidationWithSelfFails() throws Exception { thrown.expect(CertPathValidatorException.class); - Credentials registrarCred = - new Credentials( - KEY_STORE_FILE, CredentialGenerator.REGISTRAR_ALIAS, CredentialGenerator.PASSWORD); + Credentials registrarCred = new Credentials(KEY_STORE_FILE, CredentialGenerator.REGISTRAR_ALIAS, CredentialGenerator.PASSWORD); X509Certificate cert = registrarCred.getCertificate(); Set trustAnchors = new HashSet<>(); diff --git a/src/test/java/com/google/openthread/SecurityUtilsTest.java b/src/test/java/com/google/openthread/SecurityUtilsTest.java index 2bfc627..30f513e 100644 --- a/src/test/java/com/google/openthread/SecurityUtilsTest.java +++ b/src/test/java/com/google/openthread/SecurityUtilsTest.java @@ -30,6 +30,8 @@ import COSE.OneKey; import COSE.Sign1Message; +import com.google.openthread.brski.ConstantsBrski; +import com.google.openthread.brski.HardwareModuleName; import com.google.openthread.tools.CredentialGenerator; import com.upokecenter.cbor.CBORObject; import java.security.*; @@ -85,7 +87,7 @@ public void testSignatureVerification() throws Exception { @Test public void testHWModuleName() throws Exception { HardwareModuleName name0 = - new HardwareModuleName(Constants.PRIVATE_HARDWARE_TYPE_OID, new byte[] {0x01, 0x02, 0x03}); + new HardwareModuleName(ConstantsBrski.PRIVATE_HARDWARE_TYPE_OID, new byte[] {0x01, 0x02, 0x03}); HardwareModuleName name1 = HardwareModuleName.getInstance(name0.getEncoded()); Assert.assertTrue(name0.equals(name1)); } diff --git a/src/test/java/com/google/openthread/registrar/FunctionalTest.java b/src/test/java/com/google/openthread/registrar/FunctionalTest.java index bb89bae..bfcde52 100644 --- a/src/test/java/com/google/openthread/registrar/FunctionalTest.java +++ b/src/test/java/com/google/openthread/registrar/FunctionalTest.java @@ -30,7 +30,7 @@ import static org.junit.Assert.assertSame; -import com.google.openthread.*; +import com.google.openthread.Constants; import com.google.openthread.brski.*; import com.google.openthread.domainca.*; import com.google.openthread.masa.*; @@ -51,7 +51,7 @@ public class FunctionalTest { - public static final String REGISTRAR_URI = "coaps://[::1]:" + Constants.DEFAULT_REGISTRAR_COAPS_PORT; + public static final String REGISTRAR_URI = "coaps://[::1]:" + ConstantsBrski.DEFAULT_REGISTRAR_COAPS_PORT; public static final String DEFAULT_DOMAIN_NAME = "Thread-Test"; @@ -64,7 +64,7 @@ public class FunctionalTest { // credentials used private static CredentialGenerator cg; - private static Logger logger = LoggerFactory.getLogger(FunctionalTest.class); + private final static Logger logger = LoggerFactory.getLogger(FunctionalTest.class); @Rule public ExpectedException thrown = ExpectedException.none(); @@ -90,7 +90,7 @@ protected void initEntities(CredentialGenerator credGen) throws Exception { new MASA( credGen.getCredentials(CredentialGenerator.MASA_ALIAS), credGen.getCredentials(CredentialGenerator.MASACA_ALIAS), - Constants.DEFAULT_MASA_HTTPS_PORT); + ConstantsBrski.DEFAULT_MASA_HTTPS_PORT); pledge = new Pledge(credGen.getCredentials(CredentialGenerator.PLEDGE_ALIAS), REGISTRAR_URI); pledge.setLightweightClientCertificates(true); @@ -124,13 +124,12 @@ protected void stopEntities() { private void VerifyEnroll(Pledge pledge) throws Exception { X509Certificate cert = pledge.getOperationalCert(); - Assert.assertTrue(cert != null); + Assert.assertNotNull(cert); String domainName = pledge.getDomainName(); - Assert.assertTrue(domainName.equals(registrar.getDomainName())); + Assert.assertEquals(domainName, registrar.getDomainName()); - // we expect the LDevID to NOT contain subject key id, per 802.1AR-2018 spec section 8.10.2 for - // LDevID. + // we expect the LDevID to NOT contain subject key id, per 802.1AR-2018 spec section 8.10.2 for LDevID. byte[] subjKeyId = cert.getExtensionValue("2.5.29.14"); Assert.assertNull(subjKeyId); } @@ -253,32 +252,32 @@ public void testStatusTelemetry() throws Exception { Assert.assertEquals( ResponseCode.BAD_REQUEST, pledge.sendStatusTelemetry( - Constants.ENROLL_STATUS, + ConstantsBrski.ENROLL_STATUS, wrongFormatTelemetry, ExtendedMediaTypeRegistry.APPLICATION_CBOR)); Assert.assertEquals( ResponseCode.UNSUPPORTED_CONTENT_FORMAT, pledge.sendStatusTelemetry( - Constants.ENROLL_STATUS, + ConstantsBrski.ENROLL_STATUS, StatusTelemetry.create(true, null).serializeToBytes(), ExtendedMediaTypeRegistry.APPLICATION_COSE_SIGN1)); Assert.assertEquals( ResponseCode.UNSUPPORTED_CONTENT_FORMAT, pledge.sendStatusTelemetry( - Constants.VOUCHER_STATUS, + ConstantsBrski.VOUCHER_STATUS, wrongFormatTelemetry, ExtendedMediaTypeRegistry.APPLICATION_COSE_SIGN1)); wrongFormatTelemetry = Hex.decode("a36776657273696f6e0166737461747573f467726561736f6e787174686973206b65792069732077726f6e67"); Assert.assertEquals( ResponseCode.BAD_REQUEST, pledge.sendStatusTelemetry( - Constants.VOUCHER_STATUS, + ConstantsBrski.VOUCHER_STATUS, wrongFormatTelemetry, ExtendedMediaTypeRegistry.APPLICATION_CBOR)); Assert.assertEquals( ResponseCode.CHANGED, pledge.sendStatusTelemetry( - Constants.ENROLL_STATUS, + ConstantsBrski.ENROLL_STATUS, StatusTelemetry.create(true, "this msg is not needed").serializeToBytes(), ExtendedMediaTypeRegistry.APPLICATION_CBOR)); } @@ -424,7 +423,7 @@ public void testRegistrarUsingCmsJsonVoucherRequest() throws Exception { .setTrustAllMasas(true) .build(); registrar.setDomainCA(domainCA); - registrar.setForcedRequestFormat(Constants.HTTP_APPLICATION_VOUCHER_CMS_JSON); + registrar.setForcedRequestFormat(ConstantsBrski.HTTP_APPLICATION_VOUCHER_CMS_JSON); registrar.start(); Voucher voucher = pledge.requestVoucher(); diff --git a/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java b/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java index 0d85194..fd3fbc6 100644 --- a/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java +++ b/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java @@ -28,7 +28,6 @@ package com.google.openthread.registrar; -import com.google.openthread.*; import com.google.openthread.brski.*; import com.google.openthread.domainca.*; import com.google.openthread.masa.*; @@ -49,7 +48,7 @@ public class IETFConstrainedBrskiTest { public static final String REGISTRAR_URI = - "coaps://[::1]:" + Constants.DEFAULT_REGISTRAR_COAPS_PORT; + "coaps://[::1]:" + ConstantsBrski.DEFAULT_REGISTRAR_COAPS_PORT; public static final String DEFAULT_DOMAIN_NAME = "Thread-Test"; public static final String CREDENTIALS_KEYSTORE_FILE = @@ -92,7 +91,7 @@ protected void initEntities(CredentialGenerator credGen) throws Exception { new MASA( credGen.getCredentials(CredentialGenerator.MASA_ALIAS), credGen.getCredentials(CredentialGenerator.MASACA_ALIAS), - Constants.DEFAULT_MASA_HTTPS_PORT); + ConstantsBrski.DEFAULT_MASA_HTTPS_PORT); pledge = new Pledge(credGen.getCredentials(CredentialGenerator.PLEDGE_ALIAS), REGISTRAR_URI); pledge.setLightweightClientCertificates(true); @@ -110,7 +109,7 @@ protected void initEntities(CredentialGenerator credGen) throws Exception { registrar.setDomainCA(domainCA); registrar.setForcedMasaUri( "localhost:" - + Constants + + ConstantsBrski .DEFAULT_MASA_HTTPS_PORT); // force to localhost, don't heed example MASA URI in // Pledge cert. From 53a3788da54bb10c6d94d4e32c7e4cf0d4885c14 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 27 Jun 2024 11:57:55 +0200 Subject: [PATCH 09/25] [all][tests] remove HW related code from repo; code and test updates to remove code warnings/deprecation warnings. --- pom.xml | 3 +- .../com/google/openthread/SecurityUtils.java | 116 +++---- .../com/google/openthread/pledge/Pledge.java | 8 +- .../openthread/pledge/PledgeHardware.java | 283 ------------------ .../tools/HardwarePledgeTestSuite.java | 263 ---------------- .../google/openthread/CredentialsTest.java | 21 +- .../google/openthread/SecurityUtilsTest.java | 60 ++-- .../google/openthread/SerialPortsTest.java | 46 --- .../google/openthread/brski/VoucherTest.java | 61 ++-- .../openthread/registrar/FunctionalTest.java | 57 ++-- .../registrar/IETFConstrainedBrskiTest.java | 38 +-- 11 files changed, 162 insertions(+), 794 deletions(-) delete mode 100644 src/main/java/com/google/openthread/pledge/PledgeHardware.java delete mode 100644 src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java delete mode 100644 src/test/java/com/google/openthread/SerialPortsTest.java diff --git a/pom.xml b/pom.xml index a07da18..9254a5a 100644 --- a/pom.xml +++ b/pom.xml @@ -13,8 +13,7 @@ UTF-8 - 1.8 - 1.8 + 9 2.9.7 1.2.13 4.13.2 diff --git a/src/main/java/com/google/openthread/SecurityUtils.java b/src/main/java/com/google/openthread/SecurityUtils.java index a72a578..63aa1aa 100644 --- a/src/main/java/com/google/openthread/SecurityUtils.java +++ b/src/main/java/com/google/openthread/SecurityUtils.java @@ -96,6 +96,7 @@ import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.CMSSignedDataGenerator; import org.bouncycastle.cms.CMSTypedData; +import org.bouncycastle.cms.SignerId; import org.bouncycastle.cms.SignerInfoGenerator; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.cms.SignerInformationStore; @@ -110,6 +111,7 @@ import org.bouncycastle.operator.OperatorException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; +import org.bouncycastle.util.Selector; import org.bouncycastle.util.Store; import org.eclipse.californium.core.network.CoapEndpoint; import org.eclipse.californium.scandium.DTLSConnector; @@ -120,7 +122,9 @@ import org.eclipse.californium.scandium.dtls.cipher.CipherSuite; import org.eclipse.californium.scandium.dtls.x509.CertificateVerifier; -/** Provides common security-related definitions and functionalities. */ +/** + * Provides common security-related definitions and functionalities. + */ public class SecurityUtils { public static final String KEY_ALGORITHM = "EC"; @@ -137,7 +141,7 @@ public class SecurityUtils { BouncyCastleInitializer.init(); try { certFactory = CertificateFactory.getInstance("X.509"); - } catch (CertificateException ex) {; + } catch (CertificateException ex) { ex.printStackTrace(); } } @@ -210,21 +214,18 @@ public static String getDNSName(X509Certificate cert) throws CertificateEncoding return null; } - public static String getMasaUri(X509Certificate cert) { + public static String getMasaUri(X509Certificate cert) throws IOException { try { X509CertificateHolder holder = new JcaX509CertificateHolder(cert); Extension masaUri = holder.getExtension(new ASN1ObjectIdentifier(ConstantsBrski.MASA_URI_OID)); // TODO check if the below can also handle UTF-8 String types. (Not all use IA5String) String sUri = DERIA5String.fromByteArray(masaUri.getExtnValue().getOctets()).toString(); // remove trailing slashes, if any, from MASA URI. - while (sUri.endsWith("/")) sUri = sUri.substring(0, sUri.length() - 1); + while (sUri.endsWith("/")) { + sUri = sUri.substring(0, sUri.length() - 1); + } return sUri; - } catch (IOException e) { - // TODO throw exception from this method, remove the prints. - e.printStackTrace(); - return null; } catch (CertificateEncodingException e) { - e.printStackTrace(); return null; } } @@ -252,8 +253,7 @@ public static String toPEMFormat(Object csr) throws IOException { public static X509Certificate parseCertFromPem(Reader reader) throws CertificateException, IOException { PEMParser parser = new PEMParser(reader); - return new JcaX509CertificateConverter() - .getCertificate((X509CertificateHolder) parser.readObject()); + return new JcaX509CertificateConverter().getCertificate((X509CertificateHolder) parser.readObject()); } public static PrivateKey parsePrivateKeyFromPem(Reader reader) throws IOException { @@ -270,11 +270,12 @@ public static PrivateKey parsePrivateKeyFromPem(Reader reader) throws IOExceptio return new JcaPEMKeyConverter().getPrivateKey(pkInfo); } - /** get the content of subject-key-identifier extension without any encoding. */ + /** + * get the content of subject-key-identifier extension without any encoding. + */ public static byte[] getSubjectKeyId(X509Certificate cert) throws IOException { // TODO(wgtdkp): use bouncycastle ? - ASN1OctetString octets = - DEROctetString.getInstance(cert.getExtensionValue(Extension.subjectKeyIdentifier.getId())); + ASN1OctetString octets = DEROctetString.getInstance(cert.getExtensionValue(Extension.subjectKeyIdentifier.getId())); if (octets == null) { // Create subject key identifier if the certificate doesn't include it. return SecurityUtils.createSubjectKeyId(cert.getPublicKey()).getEncoded(); @@ -285,9 +286,7 @@ public static byte[] getSubjectKeyId(X509Certificate cert) throws IOException { } /** - * get the entire Authority Key Identifier OCTET STRING from the certificate. This is an octet - * string that contains an embedded SEQUENCE that defines the AKI extension structure. See RFC - * 5280. + * get the entire Authority Key Identifier OCTET STRING from the certificate. This is an octet string that contains an embedded SEQUENCE that defines the AKI extension structure. See RFC 5280. * * @param cert * @return the entire Authority Key Identifier ASN.1 SEQUENCE, or null if not present. @@ -297,18 +296,16 @@ public static byte[] getAuthorityKeyIdentifier(X509Certificate cert) { } /** - * get only the KeyIdentifier sub-field (OCTET STRING) from the Authority Key Identifier of the - * certificate. See RFC 5280. + * get only the KeyIdentifier sub-field (OCTET STRING) from the Authority Key Identifier of the certificate. See RFC 5280. * * @param cert - * @return only the KeyIdentifier OCTET STRING bytes part of the AKI of the certificate, or null - * if not found. + * @return only the KeyIdentifier OCTET STRING bytes part of the AKI of the certificate, or null if not found. */ public static byte[] getAuthorityKeyIdentifierKeyId(X509Certificate cert) { - ASN1OctetString octets = - DEROctetString.getInstance( - cert.getExtensionValue(Extension.authorityKeyIdentifier.getId())); - if (octets == null) return null; + ASN1OctetString octets = DEROctetString.getInstance(cert.getExtensionValue(Extension.authorityKeyIdentifier.getId())); + if (octets == null) { + return null; + } AuthorityKeyIdentifier aki = AuthorityKeyIdentifier.getInstance(octets.getOctets()); return aki.getKeyIdentifier(); } @@ -332,14 +329,12 @@ public static byte[] genCoseSign1Message( } /** - * Cose-sign1 with optionally X509 certs included in an x5bag structure per - * draft-ietf-anima-constrained-voucher. See draft-ietf-cose-x509-08 for x5bag encoding. + * Cose-sign1 with optionally X509 certs included in an x5bag structure per draft-ietf-anima-constrained-voucher. See draft-ietf-cose-x509-08 for x5bag encoding. * * @param signingKey * @param signingAlg * @param content - * @param certs additional certs to package into an x5bag structure into the COSE object, or null - * if none. + * @param certs additional certs to package into an x5bag structure into the COSE object, or null if none. * @return * @throws CoseException */ @@ -390,17 +385,24 @@ public static CMSSignedData genCMSCertOnlyMessage(X509Certificate cert) throws E generator.addCertificate(holder); // Empty data - CMSTypedData data = new CMSProcessableByteArray(new byte[] {}); + CMSTypedData data = new CMSProcessableByteArray(new byte[]{}); return generator.generate(data, true); } + @SuppressWarnings("unchecked") public static boolean validateCMSSignedMessage(CMSSignedData signedData) throws Exception { Store certs = signedData.getCertificates(); SignerInformationStore signers = signedData.getSignerInfos(); for (SignerInformation signerInfo : signers.getSigners()) { - X509CertificateHolder holder = - (X509CertificateHolder) certs.getMatches(signerInfo.getSID()).iterator().next(); + Selector signerId; + try { + // FIXME see if a newer BouncyCastle could avoid the 'unchecked' warnings, instead of try/catch/suppress. + signerId = (Selector) signerInfo.getSID(); + } catch (ClassCastException ex) { + continue; + } + X509CertificateHolder holder = certs.getMatches(signerId).iterator().next(); SignerInformationVerifier verifier = new JcaSimpleSignerInfoVerifierBuilder().build(holder); return signerInfo.verify(verifier); @@ -436,14 +438,13 @@ public static KeyPair genKeyPair(String algorithm, int keySize) /** * Generate a certificate with default signature and digest algorithm. * - * @param subKeyPair subject key pair - * @param subName subject distinguished name + * @param subKeyPair subject key pair + * @param subName subject distinguished name * @param issuerKeyPair issuer key pair - * @param issuerName issuer distinguished name - * @param ca is this certificate used as a CA - * @param extensions additional extensions + * @param issuerName issuer distinguished name + * @param ca is this certificate used as a CA + * @param extensions additional extensions * @return generated certificate - * @throws Exception */ public static X509Certificate genCertificate( KeyPair subKeyPair, @@ -530,7 +531,7 @@ public static final CoapEndpoint genCoapClientEndPoint( -1, trustAnchors, privateKey, certificateChain, verifier, false, isSniEnabled); } - public static final CoapEndpoint genCoapServerEndPoint( + public static CoapEndpoint genCoapServerEndPoint( int port, X509Certificate[] trustAnchors, PrivateKey privateKey, @@ -540,7 +541,7 @@ public static final CoapEndpoint genCoapServerEndPoint( return genCoapEndPoint(port, trustAnchors, privateKey, certificateChain, verifier, true, true); } - private static final CoapEndpoint genCoapEndPoint( + private static CoapEndpoint genCoapEndPoint( int port, X509Certificate[] trustAnchors, PrivateKey privateKey, @@ -550,13 +551,15 @@ private static final CoapEndpoint genCoapEndPoint( boolean isSniEnabled) { DtlsConnectorConfig.Builder config = new DtlsConnectorConfig.Builder(); - if (isServerEndPoint) + if (isServerEndPoint) { config.setSupportedCipherSuites( CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CCM); - else config.setSupportedCipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); + } else { + config.setSupportedCipherSuites(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); + } config.setRetransmissionTimeout(10 * 1000); @@ -575,9 +578,13 @@ private static final CoapEndpoint genCoapEndPoint( config.setClientOnly(); } - if (verifier != null) config.setCertificateVerifier(verifier); + if (verifier != null) { + config.setCertificateVerifier(verifier); + } - if (trustAnchors != null) config.setTrustStore(trustAnchors); + if (trustAnchors != null) { + config.setTrustStore(trustAnchors); + } List types = new ArrayList<>(); @@ -613,19 +620,19 @@ public static BigInteger allocateSerialNumber() { } /** - * Get the X509 certificates encoded in a COSE-Sign1 message in an 'x5bag' header attribute, - * either protected (tried first) or unprotected (tried last). Per draft-ietf-cose-x509-08. + * Get the X509 certificates encoded in a COSE-Sign1 message in an 'x5bag' header attribute, either protected (tried first) or unprotected (tried last). Per draft-ietf-cose-x509-08. * * @param sign1Msg - * @return List of X509Certificate, decoded from COSE-sign1 message, or null if nothing found in - * header parameters. + * @return List of X509Certificate, decoded from COSE-sign1 message, or null if nothing found in header parameters. */ public static List getX5BagCertificates(Sign1Message sign1Msg) throws CertificateException { List certs = new ArrayList<>(); // look for header parameter CBORObject x5bag = sign1Msg.findAttribute(ConstantsBrski.COSE_X5BAG_HEADER_KEY); - if (x5bag == null) return null; + if (x5bag == null) { + return null; + } // if it is an array of certs if (x5bag.getType().equals(CBORType.Array) && x5bag.size() > 0) { for (int idx = 0; idx < x5bag.size(); idx++) { @@ -644,21 +651,22 @@ public static List getX5BagCertificates(Sign1Message sign1Msg) } /** - * Create an x5bag structure per draft-ietf-cose-x509-08. If one certificate, it simply encodes - * the cert as CBOR byte array. If multiple, it uses CBOR array of byte-arrays. + * Create an x5bag structure per draft-ietf-cose-x509-08. If one certificate, it simply encodes the cert as CBOR byte array. If multiple, it uses CBOR array of byte-arrays. * * @param certs * @return */ public static CBORObject createX5BagCertificates(X509Certificate[] certs) throws CertificateEncodingException { - if (certs.length == 0) return CBORObject.NewArray(); + if (certs.length == 0) { + return CBORObject.NewArray(); + } if (certs.length == 1) { return CBORObject.FromObject(certs[0].getEncoded()); // create CBOR byte string } else { CBORObject ca = CBORObject.NewArray(); - for (int i = 0; i < certs.length; i++) { - ca.Add(CBORObject.FromObject(certs[i].getEncoded())); + for (X509Certificate cert : certs) { + ca.Add(CBORObject.FromObject(cert.getEncoded())); } return ca; } diff --git a/src/main/java/com/google/openthread/pledge/Pledge.java b/src/main/java/com/google/openthread/pledge/Pledge.java index 344eea4..08f1385 100644 --- a/src/main/java/com/google/openthread/pledge/Pledge.java +++ b/src/main/java/com/google/openthread/pledge/Pledge.java @@ -146,14 +146,14 @@ public static String getSerialNumber(X509Certificate idevid) { return serialNumber; } + // FIXME check in specs which serial nr is required. logger.info("extracting Serial-Number from certificate failed, trying HW-Serial-Number"); // Base64 encoded to convert it to printable string - return Base64.toBase64String( - SecurityUtils.getHWModuleName(idevid).getSerialNumber().getOctets()); + return Base64.toBase64String(SecurityUtils.getHWModuleName(idevid).getSerialNumber().getOctets()); } catch (CertificateEncodingException e) { - logger.error("bad certificate: " + e.getMessage()); - e.printStackTrace(); + logger.warn("bad certificate: {}", e.getMessage()); + logger.debug("details:", e); return null; } } diff --git a/src/main/java/com/google/openthread/pledge/PledgeHardware.java b/src/main/java/com/google/openthread/pledge/PledgeHardware.java deleted file mode 100644 index b10e7d1..0000000 --- a/src/main/java/com/google/openthread/pledge/PledgeHardware.java +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (c) 2021, 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. - */ - -package com.google.openthread.pledge; - -import com.fazecast.jSerialComm.*; -import com.google.openthread.thread.OpenThreadUtils; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * A Java proxy object connecting to a hardware Pledge (CCM OpenThread CLI Joiner) over a serial - * interface on the local computer. - */ -public class PledgeHardware { - - /** default wait time in ms after sending a serial command, to allow time for command execution */ - public static final int DEFAULT_SERIAL_CMD_WAIT_MS = 20; - - /** COM port baud rate */ - public static final int COM_BAUD_RATE = 115200; - - /** Expected Thread version of DUT Pledge */ - public static final String THREAD_VERSION_PLEDGE = "1.2"; - - protected SerialPort serPort = null; - protected PrintWriter serialWriter = null; - protected InputStreamReader serialReader = null; - protected StringBuilder pledgeLog = null; - protected boolean statusIsEnrolled = false; - - private static Logger logger = LoggerFactory.getLogger(PledgeHardware.class); - - public PledgeHardware() throws IOException { - init(); - if (!execCommandDone("ifconfig up")) - throw new IOException("Pledge initialization with 'ifconfig up' failed."); - } - - /** select COM port to Pledge and open it */ - protected void init() throws IOException { - SerialPort[] comPorts = SerialPort.getCommPorts(); - if (comPorts.length == 0) - throw new IOException("No serial ports found to connect to hardware Pledge"); - for (int i = 0; i < comPorts.length; i++) { - SerialPort p = comPorts[i]; - if (p.getPortDescription().contains("OpenThread")) { - serPort = p; - break; - } - } - - if (serPort == null) - throw new IOException( - "Serial ports were found, but no compatible port to connect to hardware Pledge"); - - serPort.setComPortParameters(COM_BAUD_RATE, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY); - serPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED); - serPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 2500, 2500); - - boolean isOpen = serPort.openPort(); - if (!isOpen) throw new IOException("Serial port " + serPort + " couldn't be opened."); - - pledgeLog = new StringBuilder(); - serialWriter = new PrintWriter(serPort.getOutputStream()); - serialReader = new InputStreamReader(serPort.getInputStream()); - readSerialLines(); - // reset the CLI to known state (of receiving input) - serialWriter.write("\n\n"); - serialWriter.flush(); - try { - Thread.sleep(10); - } catch (InterruptedException ex) {; - } - readSerialLines(); - } - - /** shutdown the Pledge, stopping the radio and closing the serial connection. */ - public void shutdown() { - if (serPort == null) return; - try { - execCommand("thread stop"); - execCommand("ifconfig down"); - waitForMessage(10); - } catch (IOException ex) { - logger.warn("shutdown() had an exception", ex); - } finally { - serPort.closePort(); - serPort = null; - } - } - - /** - * execute an OpenThread CLI command and check result for the 'Done' response. - * - * @param consoleCmd command to execute in OpenThread CLI e.g. 'ifconfig up' - * @return true if 'Done' was responsed by the OT CLI, false otherwise. - * @throws IOException - */ - public boolean execCommandDone(String consoleCmd) throws IOException { - if (execCommand(consoleCmd).equals("Done")) return true; - return false; - } - - /** - * execute an OpenThread CLI command and return only a single-line response with result of the - * command. - * - * @param consoleCmd command to execute in OpenThread CLI e.g. 'thread version' - * @return result of command, only first line is used. - * @throws IOException if no response was returned by Pledge, or another IO error occurred. - */ - public String execCommand(String consoleCmd) throws IOException { - String res = execCommand(consoleCmd, DEFAULT_SERIAL_CMD_WAIT_MS, true); - if (res == null || res.length() == 0) throw new IOException("No result returned"); - return res; - } - - /** - * Execute a command (sent over serial to the hw Pledge) and return the response line(s) if any. - * - * @param consoleCmd the command - * @param msWait milliseconds to wait after sending command, to try reading result over serial. - * @param filterOutLogLines if true, filters out any log/empty/prompt lines from result. - * @return result of command as lines, or empty string if nothing was returned after the wait - * time. - * @throws IOException - */ - public String execCommand(String consoleCmd, int msWait, boolean filterOutLogLines) - throws IOException { - if (serPort == null || !serPort.isOpen()) - throw new IOException("error in serial port state: not open"); - if (consoleCmd.length() > 0) serialWriter.print("\n" + consoleCmd); - serialWriter.flush(); - try { - Thread.sleep(1 + consoleCmd.length() * 8 * 1000 / COM_BAUD_RATE); - } catch (InterruptedException ex) {; - } - readSerialLines(); - // send CR to execute the command in CLI - if (consoleCmd.length() > 0) serialWriter.print('\n'); - serialWriter.flush(); - // wait for processing to happen - try { - Thread.sleep(msWait); - } catch (InterruptedException ex) {; - } - - // if nothing outputed, return empty string - if (!serialReader.ready()) return ""; - - // create result string. - StringBuilder s = new StringBuilder(); - while (serialReader.ready()) { - s.append((char) serialReader.read()); - } - String res = s.toString(); - addToPledgeLog(res); - - if (filterOutLogLines && res.length() > 0) { - return OpenThreadUtils.filterOutLogLines(res); - } - return res; - } - - /** - * Factory-reset the Pledge and verify that it responds afterwards. - * - * @return true if factory reset was successfully done and Pledge responds after it. - */ - public boolean factoryReset() throws IOException { - execCommand("factoryreset", 250, false); - pledgeLog.append( - "\n----------------[Factory Reset by HardwarePledgeTestSuite]------------------"); - statusIsEnrolled = false; - String v = execCommand("thread version"); - if (v.equals(THREAD_VERSION_PLEDGE)) return true; - else return false; - } - - /** - * Wait for any (non-Log) message or response from the Pledge. It blocks for at most maxWaitTimeMs - * to get a first message i.e. set of line(s), but does not block to get additional lines. - * - * @param maxWaitTimeMs milliseconds time to wait, at most. - * @return lines of the response message received, or null if nothing received within - * maxWaitTimeMs. - * @throws IOException - */ - public String waitForMessage(int maxWaitTimeMs) throws IOException { - long t0 = System.currentTimeMillis(); - do { - String res = execCommand("", 100, true); - String[] aR = res.split("\n"); - if (res.length() > 0 && aR[0].length() > 0) { - return res; - } - } while (System.currentTimeMillis() < t0 + maxWaitTimeMs); - return null; - } - - /** check whether this Pledge is enrolled (true), or not (false). Based on log analysis. */ - public boolean isEnrolled() { - try { - while (waitForMessage(0) != null) ; - } catch (IOException ex) {; - } - return statusIsEnrolled; - } - - public void enroll() throws IOException { - execCommandDone("joiner startae"); - waitForMessage(20000); - - // verify same on pledge side. - if (!isEnrolled()) throw new IOException("enroll() failed"); - } - - /** - * returns the Pledge log, built during the session of using this Pledge. - * - * @return complete Pledge log output - */ - public String getLog() { - return pledgeLog.toString(); - } - - /** - * helper method to read all available serial input from OT device, and store it in the log - * without further processing. - * - * @throws IOException - */ - protected void readSerialLines() throws IOException { - StringBuilder s = new StringBuilder(); - while (serialReader.ready()) { - s.append((char) serialReader.read()); - } - if (s.length() > 0) { - // add new data to the Pledge log - addToPledgeLog(s.toString()); - } - } - - /** - * helper method to add string 'log' to the Pledge log. It will perform log analysis functions on - * the input. - */ - protected void addToPledgeLog(String log) { - pledgeLog.append(log); - if (!statusIsEnrolled) - statusIsEnrolled = - OpenThreadUtils.detectEnrollSuccess(log) && !OpenThreadUtils.detectEnrollFailure(log); - } -} diff --git a/src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java b/src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java deleted file mode 100644 index 09908f9..0000000 --- a/src/main/java/com/google/openthread/tools/HardwarePledgeTestSuite.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2021, 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. - */ - -package com.google.openthread.tools; - -import static org.junit.Assert.*; - -import com.google.openthread.*; -import com.google.openthread.brski.*; -import com.google.openthread.domainca.*; -import com.google.openthread.masa.*; -import com.google.openthread.pledge.*; -import com.google.openthread.registrar.*; -import com.google.openthread.thread.OpenThreadUtils; -import java.security.Principal; -import org.junit.*; -import org.junit.runners.*; -import org.slf4j.*; - -/** - * A tool to test a Hardware Pledge DUT (OpenThread CLI device) against the Registrar/MASA. The specific network setup so that the Pledge can reach the Registrar, is to be done by the user and out of - * scope of this tool. It uses JUnit framework for easy GUI usage e.g. in Eclipse; consider these as integration tests of the hardware Pledge. - * - *

Using Maven, this test suite is NOT executed during Maven test phase unit testing. So, it - * needs to be explicitly invoked. - */ -// One can enable this line to let Eclipse JUnit ignore this test when running all unit tests from -// the GUI. -// @Ignore("The PledgeHw* tests can only be run with hardware Pledge and network setup, skipping.") -// Below test order is not mandatory, but saves time if executed in order. -@FixMethodOrder(MethodSorters.NAME_ASCENDING) -public class HardwarePledgeTestSuite { - - public static final String THREAD_DOMAIN_NAME = "TestDomainTCE"; - public static final int IEEE_802154_CHANNEL = 19; - public static final String[] MASA_CREDENTIAL_FILES = - new String[]{ - "./credentials/local-masa/masa_cert.pem", "./credentials/local-masa/masa_private.pem" - }; - public static final String[] MASACA_CREDENTIAL_FILES = - new String[]{ - "./credentials/local-masa/masaca_cert.pem", "./credentials/local-masa/masaca_private.pem" - }; - public static final String[] DOMAIN_CREDENTIAL_FILES = - new String[]{ - "./credentials/local-masa/domainca_cert.pem", - "./credentials/local-masa/domainca_private.pem" - }; - public static final String BORDER_ROUTER_AUTHORITY = "[fd00:910b::3285:1958:d0c9:d06]:49191"; - - private static final String REGISTRAR_URI = "[::1]:" + ConstantsBrski.DEFAULT_REGISTRAR_COAPS_PORT; - private DomainCA domainCA; - private Registrar registrar; - private MASA masa; - private static PledgeHardware pledge; - private static CredentialGenerator credGen; - private final static Logger logger = LoggerFactory.getLogger(HardwarePledgeTestSuite.class); - - @BeforeClass - public static void setup() throws Exception { - credGen = new CredentialGenerator(); - credGen.make(DOMAIN_CREDENTIAL_FILES, MASACA_CREDENTIAL_FILES, MASA_CREDENTIAL_FILES, null, null); - pledge = new PledgeHardware(); - assertTrue(pledge.factoryReset()); - assertTrue(pledge.execCommandDone("channel " + IEEE_802154_CHANNEL)); - } - - @AfterClass - public static void tearDown() { - if (pledge != null) { - pledge.shutdown(); - logger.info(pledge.getLog()); // dump the Pledge's log, to aid troubleshooting. - } - } - - @Before - public void init() throws Exception { - masa = - new MASA( - credGen.getCredentials(CredentialGenerator.MASA_ALIAS), - credGen.getCredentials(CredentialGenerator.MASACA_ALIAS), - ConstantsBrski.DEFAULT_MASA_HTTPS_PORT); - - domainCA = - new DomainCA( - THREAD_DOMAIN_NAME, credGen.getCredentials(CredentialGenerator.DOMAINCA_ALIAS)); - - RegistrarBuilder registrarBuilder = new RegistrarBuilder(); - registrar = - registrarBuilder - .setCredentials(credGen.getCredentials(CredentialGenerator.REGISTRAR_ALIAS)) - .setTrustAllMasas(true) - .build(); - registrar.setDomainCA(domainCA); - // for local testing we force the MASA URI to localhost. - registrar.setForcedMasaUri(Constants.DEFAULT_MASA_URI); - - masa.start(); - registrar.start(); - } - - @After - public void finalize() throws Exception { - assertTrue(pledge.execCommandDone("thread stop")); - registrar.stop(); - masa.stop(); - } - - /** - * Basic test for DUT Pledge response - */ - @Test - public void testDUT_responds() throws Exception { - assertEquals(PledgeHardware.THREAD_VERSION_PLEDGE, pledge.execCommand("thread version")); - assertTrue(pledge.execCommandDone("ifconfig down")); - assertTrue(pledge.execCommandDone("ifconfig up")); - String nkey = pledge.execCommand("masterkey"); - assertTrue(nkey.length() == 32); - } - - /** - * DISC-TC-01: - */ - @Test - public void test_5_02_DISC_TC_01() throws Exception { - if (pledge.isEnrolled()) { - pledge.factoryReset(); - } - assertFalse(pledge.isEnrolled()); - assertTrue(pledge.execCommandDone("joiner startae")); - String res = pledge.waitForMessage(20000); - assertNotNull(res); - // only check that handshake went well. - assertFalse(OpenThreadUtils.detectEnrollFailure(res)); - } - - /** - * DISC-TC-02: - */ - @Test - public void test_5_02_DISC_TC_02() throws Exception { - if (!pledge.isEnrolled()) { - pledge.enroll(); - } - assertTrue(pledge.isEnrolled()); - assertTrue(pledge.execCommandDone("joiner startae")); - String res = pledge.waitForMessage(20000); - assertNotNull(res); - assertFalse(OpenThreadUtils.detectNkpFailure(res)); - // assertTrue(OpenThreadUtils.detectNkpSuccess(res)); - } - - /** - * AE-TC-01: Regular BRSKI + EST enrollment - */ - @Test - public void test_5_05_AE_TC_01() throws Exception { - - if (pledge.isEnrolled()) { - pledge.factoryReset(); - } - - assertFalse(pledge.isEnrolled()); - assertTrue(pledge.execCommandDone("joiner startae")); - pledge.waitForMessage(20000); - - // verify on registrar side that enrollment completed. - Principal[] lClients = registrar.getKnownClients(); - assertEquals(1, lClients.length); - StatusTelemetry voucherStatus = registrar.getVoucherStatusLogEntry(lClients[0]); - StatusTelemetry enrollStatus = registrar.getEnrollStatusLogEntry(lClients[0]); - - // verify voucherStatus aspects - assertNotNull(voucherStatus); - assertNotEquals(StatusTelemetry.UNDEFINED, voucherStatus); - assertEquals(true, voucherStatus.status); - assertEquals(true, voucherStatus.isValidFormat); - - // verify enrollStatus aspects - assertNotNull(enrollStatus); - assertNotEquals(StatusTelemetry.UNDEFINED, enrollStatus); - assertEquals(true, enrollStatus.status); - assertEquals(true, enrollStatus.isValidFormat); - - // verify same on pledge side. - assertTrue(pledge.isEnrolled()); - } - - /** - * NKP-TC-01: - */ - @Test - public void test_5_06_NKP_TC_01() throws Exception { - assertTrue(false); - } - - /** - * NKP-TC-01a: - */ - @Test - public void test_5_06_NKP_TC_01a() throws Exception { - // Need to be enrolled to do NKP. - if (!pledge.isEnrolled()) { - pledge.enroll(); - } - assertTrue(pledge.isEnrolled()); - assertTrue(pledge.execCommandDone("joiner startnmkp")); - String resp = pledge.waitForMessage(15000); - assertTrue(false); // TODO - } - - /** - * NKP-TC-02: Network Key Provisioning (NKP) after enrollment. - */ - @Test - public void test_5_06_NKP_TC_02() throws Exception { - - // Need to be enrolled to do NKP. - if (!pledge.isEnrolled()) { - pledge.enroll(); - } - - assertTrue(pledge.execCommandDone("masterkey 33112233445566118899aabbccddeeff")); - String oldkey = pledge.execCommand("masterkey"); - assertTrue(pledge.isEnrolled()); - assertTrue(pledge.execCommandDone("joiner startnmkp")); - pledge.waitForMessage(15000); - String newkey = pledge.execCommand("masterkey"); - assertNotEquals(oldkey, newkey); - - // join Thread network - assertEquals("disabled", pledge.execCommand("state")); - assertTrue(pledge.execCommandDone("thread start")); - Thread.sleep(3000); - assertNotEquals("disabled", pledge.execCommand("state")); // verify thread is started - assertEquals("false", pledge.execCommand("singleton")); // verify I joined with BR. - } -} diff --git a/src/test/java/com/google/openthread/CredentialsTest.java b/src/test/java/com/google/openthread/CredentialsTest.java index 9f7c2fa..d69787a 100644 --- a/src/test/java/com/google/openthread/CredentialsTest.java +++ b/src/test/java/com/google/openthread/CredentialsTest.java @@ -59,18 +59,13 @@ import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; public class CredentialsTest { public static final String KEY_STORE_FILE = "test-credentials.temp.p12"; private static String pledgeSn; - @Rule - public ExpectedException thrown = ExpectedException.none(); - @BeforeClass public static void createCredentialFile() throws Exception { CredentialGenerator cg = new CredentialGenerator(); @@ -82,7 +77,7 @@ public static void createCredentialFile() throws Exception { @AfterClass public static void cleanCredentialFile() { File f = new File(KEY_STORE_FILE); - f.delete(); + Assert.assertTrue(f.delete()); } @Test @@ -126,17 +121,17 @@ public void testMASACredentials() throws Exception { Credentials pledgeCred = new Credentials(KEY_STORE_FILE, CredentialGenerator.PLEDGE_ALIAS, CredentialGenerator.PASSWORD); Assert.assertEquals(SecurityUtils.getMasaUri(pledgeCred.getCertificate()), Constants.DEFAULT_MASA_URI); - Assert.assertTrue(pledgeCred.getCertificateChain().length == 2); + Assert.assertEquals(2, pledgeCred.getCertificateChain().length); pledgeCred.getCertificate().verify(masaCred.getCertificate().getPublicKey()); String pledgeSN = SecurityUtils.getSerialNumber(pledgeCred.getCertificate()); - Assert.assertTrue(pledgeSN != null); - Assert.assertTrue(pledgeSN.equals(pledgeSn)); + Assert.assertNotNull(pledgeSN); + Assert.assertEquals(pledgeSN, pledgeSn); HardwareModuleName hwsn = SecurityUtils.getHWModuleName(pledgeCred.getCertificate()); - Assert.assertTrue(hwsn != null); - Assert.assertTrue(new String(hwsn.getSerialNumber().getOctets()).equals(pledgeSn)); + Assert.assertNotNull(hwsn); + Assert.assertEquals(new String(hwsn.getSerialNumber().getOctets()), pledgeSn); } @Test @@ -170,10 +165,8 @@ public void testHWSerialNumber() throws Exception { Assert.assertArrayEquals(SERIAL_NUMBER, hwmn.getSerialNumber().getOctets()); } - @Test + @Test(expected = CertPathValidatorException.class) public void testRegistrarCertChainValidationWithSelfFails() throws Exception { - thrown.expect(CertPathValidatorException.class); - Credentials registrarCred = new Credentials(KEY_STORE_FILE, CredentialGenerator.REGISTRAR_ALIAS, CredentialGenerator.PASSWORD); X509Certificate cert = registrarCred.getCertificate(); diff --git a/src/test/java/com/google/openthread/SecurityUtilsTest.java b/src/test/java/com/google/openthread/SecurityUtilsTest.java index 30f513e..3d8b56f 100644 --- a/src/test/java/com/google/openthread/SecurityUtilsTest.java +++ b/src/test/java/com/google/openthread/SecurityUtilsTest.java @@ -46,14 +46,10 @@ import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; import org.bouncycastle.util.encoders.Hex; import org.junit.Assert; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; public class SecurityUtilsTest { - @Rule public ExpectedException thrown = ExpectedException.none(); - @Test public void testSignatureVerification() throws Exception { final String SIG_ALG = "SHA256withECDSA"; @@ -86,10 +82,9 @@ public void testSignatureVerification() throws Exception { @Test public void testHWModuleName() throws Exception { - HardwareModuleName name0 = - new HardwareModuleName(ConstantsBrski.PRIVATE_HARDWARE_TYPE_OID, new byte[] {0x01, 0x02, 0x03}); + HardwareModuleName name0 = new HardwareModuleName(ConstantsBrski.PRIVATE_HARDWARE_TYPE_OID, new byte[]{0x01, 0x02, 0x03}); HardwareModuleName name1 = HardwareModuleName.getInstance(name0.getEncoded()); - Assert.assertTrue(name0.equals(name1)); + Assert.assertEquals(name0, name1); } @Test @@ -110,42 +105,38 @@ public void testSubjectPublicKeyInfo() throws Exception { public void testX5BagEncoding() throws Exception { KeyPair kp = SecurityUtils.genKeyPair(); X509Certificate cert = SecurityUtils.genCertificate(kp, "CN=Root", kp, "CN=Root", true, null); - CBORObject bagSingle = SecurityUtils.createX5BagCertificates(new X509Certificate[] {cert}); + CBORObject bagSingle = SecurityUtils.createX5BagCertificates(new X509Certificate[]{cert}); + Assert.assertNotNull(bagSingle); KeyPair kp2 = SecurityUtils.genKeyPair(); - X509Certificate cert2 = - SecurityUtils.genCertificate( - kp, "CN=AnotherRoot/L=InSpace", kp2, "CN=AnotherRoot/L=InSpace", true, null); - CBORObject bagMultiple = - SecurityUtils.createX5BagCertificates(new X509Certificate[] {cert, cert2}); - byte[] payload = new byte[] {1, 2, 3, 4, 5}; + X509Certificate cert2 = SecurityUtils.genCertificate(kp, "CN=AnotherRoot/L=InSpace", kp2, "CN=AnotherRoot/L=InSpace", true, null); + CBORObject bagMultiple = SecurityUtils.createX5BagCertificates(new X509Certificate[]{cert, cert2}); + Assert.assertNotNull(bagMultiple); + + byte[] payload = new byte[]{1, 2, 3, 4, 5}; // try single bag - byte[] cose = - SecurityUtils.genCoseSign1Message( - kp.getPrivate(), - SecurityUtils.COSE_SIGNATURE_ALGORITHM, - payload, - new X509Certificate[] {cert}); + byte[] cose = SecurityUtils.genCoseSign1Message(kp.getPrivate(), SecurityUtils.COSE_SIGNATURE_ALGORITHM, payload, new X509Certificate[]{cert}); Sign1Message sign1 = (Sign1Message) Sign1Message.DecodeFromBytes(cose); Assert.assertTrue(sign1.validate(new OneKey(kp.getPublic(), kp.getPrivate()))); List certList = SecurityUtils.getX5BagCertificates(sign1); - Assert.assertTrue(certList.size() == 1); - Assert.assertEquals(certList.get(0), cert); + Assert.assertNotNull(certList); + Assert.assertEquals(1, certList.size()); + Assert.assertEquals(cert, certList.get(0)); // try multi bag - cose = - SecurityUtils.genCoseSign1Message( - kp2.getPrivate(), - SecurityUtils.COSE_SIGNATURE_ALGORITHM, - payload, - new X509Certificate[] {cert, cert2}); + cose = SecurityUtils.genCoseSign1Message( + kp2.getPrivate(), + SecurityUtils.COSE_SIGNATURE_ALGORITHM, + payload, + new X509Certificate[]{cert, cert2}); sign1 = (Sign1Message) Sign1Message.DecodeFromBytes(cose); Assert.assertTrue(sign1.validate(new OneKey(kp2.getPublic(), kp2.getPrivate()))); certList = SecurityUtils.getX5BagCertificates(sign1); - Assert.assertTrue(certList.size() == 2); - Assert.assertEquals(certList.get(0), cert); - Assert.assertEquals(certList.get(1), cert2); + Assert.assertNotNull(certList); + Assert.assertEquals(2, certList.size()); + Assert.assertEquals(cert, certList.get(0)); + Assert.assertEquals(cert2, certList.get(1)); } @Test @@ -156,12 +147,13 @@ public void testAuthorityKeyIdentifier() throws Exception { cg.getCredentials(CredentialGenerator.PLEDGE_ALIAS).getCertificate(); byte[] akiOctetString = SecurityUtils.getAuthorityKeyIdentifier(pledgeCert); byte[] keyId = SecurityUtils.getAuthorityKeyIdentifierKeyId(pledgeCert); - Assert.assertTrue(akiOctetString.length == 26); - Assert.assertTrue(keyId.length == 20); + Assert.assertNotNull(keyId); + Assert.assertEquals(26, akiOctetString.length); + Assert.assertEquals(20, keyId.length); // verify that the last part of akiOctetString in fact contains the keyId. byte[] akiOctetStringLastPart = new byte[20]; System.arraycopy(akiOctetString, 6, akiOctetStringLastPart, 0, 20); - Assert.assertTrue(Arrays.equals(keyId, akiOctetStringLastPart)); + Assert.assertArrayEquals(keyId, akiOctetStringLastPart); // TODO check order expected, actual here. } } diff --git a/src/test/java/com/google/openthread/SerialPortsTest.java b/src/test/java/com/google/openthread/SerialPortsTest.java deleted file mode 100644 index 512d868..0000000 --- a/src/test/java/com/google/openthread/SerialPortsTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2021, 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. - */ - -package com.google.openthread; - -import com.fazecast.jSerialComm.*; -import org.junit.*; -import org.slf4j.*; - -public class SerialPortsTest { - - private static Logger logger = LoggerFactory.getLogger(SerialPortsTest.class); - - @Test - public void testSerialPortEnumeration() throws Exception { - SerialPort[] comPorts = SerialPort.getCommPorts(); - for (int i = 0; i < comPorts.length; i++) { - logger.info(comPorts[0].toString()); - } - } -} diff --git a/src/test/java/com/google/openthread/brski/VoucherTest.java b/src/test/java/com/google/openthread/brski/VoucherTest.java index 3973537..f46dfd7 100644 --- a/src/test/java/com/google/openthread/brski/VoucherTest.java +++ b/src/test/java/com/google/openthread/brski/VoucherTest.java @@ -29,26 +29,21 @@ package com.google.openthread.brski; import java.text.ParseException; -import java.util.Arrays; import java.util.Date; import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.junit.Assert; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; public class VoucherTest { - @Rule public ExpectedException thrown = ExpectedException.none(); - @Test public void testYoungDate() throws Exception { Date date = new Date(); String young = Voucher.dateToYoungFormat(date); Date date2 = Voucher.dateFromYoungFormat(young); - Assert.assertTrue(date.getTime() == date2.getTime()); + Assert.assertEquals(date.getTime(), date2.getTime()); } @Test @@ -57,9 +52,8 @@ public void testSimple() { v1.assertion = Voucher.Assertion.PROXIMITY; v1.createdOn = new Date(); v1.expiresOn = new Date(); - v1.serialNumber = "12345"; - v1.pinnedDomainCert = new byte[] {0x01, 0x02, 0x03}; + v1.pinnedDomainCert = new byte[]{0x01, 0x02, 0x03}; Assert.assertTrue(v1.validate()); @@ -67,17 +61,17 @@ public void testSimple() { Voucher v2 = new CBORSerializer().deserialize(data); Assert.assertTrue(v2.validate()); - Assert.assertTrue(v1.assertion.equals(v2.assertion)); - Assert.assertTrue(v1.serialNumber.equals(v2.serialNumber)); - Assert.assertTrue(Arrays.equals(v1.pinnedDomainCert, v2.pinnedDomainCert)); + Assert.assertEquals(v1.assertion, v2.assertion); + Assert.assertEquals(v1.serialNumber, v2.serialNumber); + Assert.assertArrayEquals(v1.pinnedDomainCert, v2.pinnedDomainCert); data = new JSONSerializer().serialize(v1); Voucher v3 = new JSONSerializer().deserialize(data); Assert.assertTrue(v3.validate()); - Assert.assertTrue(v1.assertion.equals(v3.assertion)); - Assert.assertTrue(v1.serialNumber.equals(v3.serialNumber)); - Assert.assertTrue(Arrays.equals(v1.pinnedDomainCert, v3.pinnedDomainCert)); + Assert.assertEquals(v1.assertion, v3.assertion); + Assert.assertEquals(v1.serialNumber, v3.serialNumber); + Assert.assertArrayEquals(v1.pinnedDomainCert, v3.pinnedDomainCert); } @Test @@ -85,7 +79,7 @@ public void testSimpleRequest() { Voucher vr1 = new VoucherRequest(); vr1.assertion = Voucher.Assertion.PROXIMITY; vr1.serialNumber = "12345"; - vr1.proximityRegistrarCert = new byte[] {0x01, 0x02, 0x03}; + vr1.proximityRegistrarCert = new byte[]{0x01, 0x02, 0x03}; Assert.assertTrue(vr1.validate()); @@ -93,17 +87,17 @@ public void testSimpleRequest() { Voucher vr2 = new CBORSerializer().deserialize(data); Assert.assertTrue(vr2.validate()); - Assert.assertTrue(vr1.assertion.equals(vr2.assertion)); - Assert.assertTrue(vr1.serialNumber.equals(vr2.serialNumber)); - Assert.assertTrue(Arrays.equals(vr1.proximityRegistrarCert, vr2.proximityRegistrarCert)); + Assert.assertEquals(vr1.assertion, vr2.assertion); + Assert.assertEquals(vr1.serialNumber, vr2.serialNumber); + Assert.assertArrayEquals(vr1.proximityRegistrarCert, vr2.proximityRegistrarCert); data = new JSONSerializer().serialize(vr1); Voucher vr3 = new JSONSerializer().deserialize(data); Assert.assertTrue(vr3.validate()); - Assert.assertTrue(vr1.assertion.equals(vr3.assertion)); - Assert.assertTrue(vr1.serialNumber.equals(vr3.serialNumber)); - Assert.assertTrue(Arrays.equals(vr1.proximityRegistrarCert, vr3.proximityRegistrarCert)); + Assert.assertEquals(vr1.assertion, vr3.assertion); + Assert.assertEquals(vr1.serialNumber, vr3.serialNumber); + Assert.assertArrayEquals(vr1.proximityRegistrarCert, vr3.proximityRegistrarCert); } @Test @@ -113,7 +107,7 @@ public void testSimpleConstrained() { cv1.serialNumber = "12345"; cv1.createdOn = new Date(); cv1.expiresOn = new Date(); - cv1.pinnedDomainSPKI = new byte[] {0x01, 0x02, 0x03}; + cv1.pinnedDomainSPKI = new byte[]{0x01, 0x02, 0x03}; Assert.assertTrue(cv1.validate()); @@ -121,9 +115,9 @@ public void testSimpleConstrained() { Voucher cv2 = new CBORSerializer().deserialize(data); Assert.assertTrue(cv2.validate()); - Assert.assertTrue(cv1.assertion.equals(cv2.assertion)); - Assert.assertTrue(cv1.serialNumber.equals(cv2.serialNumber)); - Assert.assertTrue(Arrays.equals(cv1.pinnedDomainSPKI, cv2.pinnedDomainSPKI)); + Assert.assertEquals(cv1.assertion, cv2.assertion); + Assert.assertEquals(cv1.serialNumber, cv2.serialNumber); + Assert.assertArrayEquals(cv1.pinnedDomainSPKI, cv2.pinnedDomainSPKI); } @Test @@ -132,8 +126,7 @@ public void testSimpleConstrainedRequest() { cvr1.setConstrained(true); cvr1.assertion = Voucher.Assertion.PROXIMITY; cvr1.serialNumber = "123"; - - cvr1.proximityRegistrarSPKI = new byte[] {0x01, 0x02, 0x03}; + cvr1.proximityRegistrarSPKI = new byte[]{0x01, 0x02, 0x03}; Assert.assertTrue(cvr1.validate()); @@ -142,9 +135,9 @@ public void testSimpleConstrainedRequest() { Assert.assertTrue(cvr2.isConstrained()); Assert.assertTrue(cvr2.validate()); - Assert.assertTrue(cvr1.assertion.equals(cvr2.assertion)); - Assert.assertTrue(cvr1.serialNumber.equals(cvr2.serialNumber)); - Assert.assertTrue(Arrays.equals(cvr1.proximityRegistrarSPKI, cvr2.proximityRegistrarSPKI)); + Assert.assertEquals(cvr1.assertion, cvr2.assertion); + Assert.assertEquals(cvr1.serialNumber, cvr2.serialNumber); + Assert.assertArrayEquals(cvr1.proximityRegistrarSPKI, cvr2.proximityRegistrarSPKI); } @Test @@ -158,10 +151,10 @@ public void testConstrainedRequestMixedDeltaEncoding() throws ParseException { Voucher cvr = new CBORSerializer().deserialize(data); Assert.assertTrue(cvr.validate()); - Assert.assertTrue(cvr.assertion.equals(Voucher.Assertion.PROXIMITY)); - Assert.assertTrue(cvr.serialNumber.equals("JADA123456789")); - Assert.assertTrue(cvr.proximityRegistrarSPKI.length == 633); - Assert.assertTrue(cvr.createdOn.equals(Voucher.dateFromYoungFormat("2016-10-07T19:31:42Z"))); + Assert.assertEquals(Voucher.Assertion.PROXIMITY, cvr.assertion); + Assert.assertEquals("JADA123456789", cvr.serialNumber); + Assert.assertEquals(633, cvr.proximityRegistrarSPKI.length); + Assert.assertEquals(cvr.createdOn, Voucher.dateFromYoungFormat("2016-10-07T19:31:42Z")); } @Test diff --git a/src/test/java/com/google/openthread/registrar/FunctionalTest.java b/src/test/java/com/google/openthread/registrar/FunctionalTest.java index bfcde52..b0a8a31 100644 --- a/src/test/java/com/google/openthread/registrar/FunctionalTest.java +++ b/src/test/java/com/google/openthread/registrar/FunctionalTest.java @@ -45,14 +45,12 @@ import org.eclipse.californium.core.coap.CoAP.ResponseCode; import org.eclipse.californium.core.coap.MediaTypeRegistry; import org.junit.*; -import org.junit.rules.ExpectedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FunctionalTest { public static final String REGISTRAR_URI = "coaps://[::1]:" + ConstantsBrski.DEFAULT_REGISTRAR_COAPS_PORT; - public static final String DEFAULT_DOMAIN_NAME = "Thread-Test"; // the acting entities @@ -66,9 +64,6 @@ public class FunctionalTest { private final static Logger logger = LoggerFactory.getLogger(FunctionalTest.class); - @Rule - public ExpectedException thrown = ExpectedException.none(); - @BeforeClass public static void setup() throws Exception { // generated credentials set @@ -112,17 +107,13 @@ protected void initEntities(CredentialGenerator credGen) throws Exception { } @After - public void finalize() { - stopEntities(); - } - - protected void stopEntities() { + public void shutdown() { pledge.shutdown(); registrar.stop(); masa.stop(); } - private void VerifyEnroll(Pledge pledge) throws Exception { + private void verifyEnroll(Pledge pledge) { X509Certificate cert = pledge.getOperationalCert(); Assert.assertNotNull(cert); @@ -134,7 +125,7 @@ private void VerifyEnroll(Pledge pledge) throws Exception { Assert.assertNull(subjKeyId); } - private void VerifyPledge(Pledge pledge) { + private void verifyPledge(Pledge pledge) { Assert.assertNotEquals(pledge.getState(), CertState.NO_CONTACT); Assert.assertNotEquals(pledge.getState(), CertState.PROVISIONALLY_ACCEPT); // TODO - implement state verification of Pledge after voucher request, while enroll may or may @@ -166,7 +157,7 @@ public void testConnectionToRegistrarWithFullCertChain() throws Exception { public void testVoucherRequest() throws Exception { Voucher voucher = pledge.requestVoucher(); Assert.assertTrue(voucher.validate()); - VerifyPledge(pledge); + verifyPledge(pledge); Assert.assertEquals(ResponseCode.CHANGED, pledge.sendVoucherStatusTelemetry(true, null)); } @@ -177,8 +168,8 @@ public void testEnroll() throws Exception { Assert.assertTrue(voucher.validate()); pledge.enroll(); - VerifyPledge(pledge); - VerifyEnroll(pledge); + verifyPledge(pledge); + verifyEnroll(pledge); Assert.assertEquals(ResponseCode.CHANGED, pledge.sendEnrollStatusTelemetry(true, null)); } @@ -203,7 +194,7 @@ public void testEnrollWithLoadedCredentials() throws Exception { // start a new set of entities, using loaded credentials. CredentialGenerator cred = new CredentialGenerator(); cred.load(CredentialGenerator.CREDENTIALS_FILE_IOTCONSULTANCY); - this.stopEntities(); + this.shutdown(); this.initEntities(cred); registrar.setForcedMasaUri(Constants.DEFAULT_MASA_URI); // force to local. @@ -212,8 +203,8 @@ public void testEnrollWithLoadedCredentials() throws Exception { Assert.assertTrue(voucher.validate()); pledge.enroll(); - VerifyPledge(pledge); - VerifyEnroll(pledge); + verifyPledge(pledge); + verifyEnroll(pledge); Assert.assertEquals(ResponseCode.CHANGED, pledge.sendEnrollStatusTelemetry(true, null)); } @@ -224,18 +215,16 @@ public void testReenroll() throws Exception { pledge.enroll(); Assert.assertTrue(voucher.validate()); - VerifyPledge(pledge); - VerifyEnroll(pledge); + verifyPledge(pledge); + verifyEnroll(pledge); Assert.assertEquals(ResponseCode.CHANGED, pledge.sendEnrollStatusTelemetry(true, null)); pledge.reenroll(); - VerifyEnroll(pledge); + verifyEnroll(pledge); } /** * Test various status telemetry messages, stand-alone (not associated to enrollment/voucher request). Current Registrar is implemented to just accept/log these. - * - * @throws Exception */ @Test public void testStatusTelemetry() throws Exception { @@ -286,17 +275,17 @@ public void testStatusTelemetry() throws Exception { public void testReset() throws Exception { pledge.requestVoucher(); pledge.enroll(); - VerifyEnroll(pledge); + verifyEnroll(pledge); pledge.reenroll(); - VerifyEnroll(pledge); + verifyEnroll(pledge); pledge.reset(); pledge.requestVoucher(); pledge.enroll(); - VerifyEnroll(pledge); + verifyEnroll(pledge); pledge.reenroll(); - VerifyEnroll(pledge); + verifyEnroll(pledge); } @Test @@ -336,7 +325,7 @@ public void testMultiPledges() throws Exception { private class PledgeThread extends Thread { public Throwable errorState = null; - public Pledge pledge = null; + public Pledge pledge; public PledgeThread() throws Exception { cg.makePledge(null); // create a new Pledge identity and serial number @@ -349,11 +338,11 @@ public void run() { pledge.requestVoucher(); Assert.assertEquals(ResponseCode.CHANGED, pledge.sendVoucherStatusTelemetry(true, null)); pledge.enroll(); - VerifyEnroll(pledge); + verifyEnroll(pledge); Assert.assertEquals(ResponseCode.CHANGED, pledge.sendEnrollStatusTelemetry(true, null)); pledge.reenroll(); - VerifyEnroll(pledge); + verifyEnroll(pledge); } catch (Throwable e) { errorState = e; @@ -386,12 +375,12 @@ public void testRegistrarWithoutCmcRa() throws Exception { registrar.start(); // test connection does not work - our Pledge checks for cmcRA in certificate - CoapResponse response = null; + CoapResponse response; try { - response = pledge.sayHello(); + pledge.sayHello(); Assert.fail("Pledge mistakenly accepted Registrar without cmcRA"); } catch (IOException ex) { - ; + // expected IOException here. } // try again without checking strictly for cmcRA @@ -429,7 +418,7 @@ public void testRegistrarUsingCmsJsonVoucherRequest() throws Exception { Voucher voucher = pledge.requestVoucher(); Assert.assertEquals(ResponseCode.CHANGED, pledge.sendVoucherStatusTelemetry(true, null)); pledge.enroll(); - VerifyEnroll(pledge); + verifyEnroll(pledge); voucher.validate(); Assert.assertEquals(ResponseCode.CHANGED, pledge.sendEnrollStatusTelemetry(true, null)); } diff --git a/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java b/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java index fd3fbc6..76906ee 100644 --- a/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java +++ b/src/test/java/com/google/openthread/registrar/IETFConstrainedBrskiTest.java @@ -42,17 +42,13 @@ /** * This test code is to specifically produce the COSE examples in the Appendix of IETF draft - * "Constrained BRSKI" - see - * https://datatracker.ietf.org/doc/html/draft-ietf-anima-constrained-voucher + * "Constrained BRSKI" - see https://datatracker.ietf.org/doc/html/draft-ietf-anima-constrained-voucher */ public class IETFConstrainedBrskiTest { - public static final String REGISTRAR_URI = - "coaps://[::1]:" + ConstantsBrski.DEFAULT_REGISTRAR_COAPS_PORT; - + 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/keystore_ietf-draft-constrained-brski.p12"; // the acting entities private DomainCA domainCA; @@ -74,7 +70,8 @@ public static void setup() throws Exception { } @AfterClass - public static void tearDown() {} + public static void tearDown() { + } @Before public void init() throws Exception { @@ -110,19 +107,15 @@ protected void initEntities(CredentialGenerator credGen) throws Exception { registrar.setForcedMasaUri( "localhost:" + ConstantsBrski - .DEFAULT_MASA_HTTPS_PORT); // force to localhost, don't heed example MASA URI in - // Pledge cert. + .DEFAULT_MASA_HTTPS_PORT); // force to localhost, don't heed example MASA URI in + // Pledge cert. masa.start(); registrar.start(); } @After - public void finalize() { - stopEntities(); - } - - protected void stopEntities() { + public void shutdown() { pledge.shutdown(); registrar.stop(); masa.stop(); @@ -143,19 +136,12 @@ public void testVoucherRequestAndDisplayArtifacts() throws Exception { // display the artifacts. logger.info("Pledge Voucher Request (PVR) sent by Pledge:\n" + pledge.getLastPvr().toString()); - logger.info( - "Pledge Voucher Request (PVR) sent by Pledge as Hex string:\n" - + Hex.toHexString(pledge.getLastPvrCoseSigned())); + logger.info("Pledge Voucher Request (PVR) sent by Pledge as Hex string:\n" + Hex.toHexString(pledge.getLastPvrCoseSigned())); - logger.info( - "Registrar Voucher Request (RVR) sent by Registrar:\n" + registrar.getLastRvr().toString()); - logger.info( - "Registrar Voucher Request (RVR) sent by Registrar as Hex string:\n" - + Hex.toHexString(registrar.getLastRvrCoseSigned())); + logger.info("Registrar Voucher Request (RVR) sent by Registrar:\n" + registrar.getLastRvr().toString()); + logger.info("Registrar Voucher Request (RVR) sent by Registrar as Hex string:\n" + Hex.toHexString(registrar.getLastRvrCoseSigned())); logger.info("Voucher created by MASA:\n" + voucher); - logger.info( - "Voucher created by MASA as Hex string:\n" - + Hex.toHexString(pledge.getLastVoucherCoseSigned())); + logger.info("Voucher created by MASA as Hex string:\n" + Hex.toHexString(pledge.getLastVoucherCoseSigned())); } } From 4c9d1fbb6cd935c07e8dbb7fb7debdf801e9868b Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 27 Jun 2024 12:13:42 +0200 Subject: [PATCH 10/25] [masa] bugfix missing return statements and code warning fixes. --- .../java/com/google/openthread/masa/MASA.java | 115 +++++++++--------- 1 file changed, 58 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/google/openthread/masa/MASA.java b/src/main/java/com/google/openthread/masa/MASA.java index 4766f23..3c5b495 100644 --- a/src/main/java/com/google/openthread/masa/MASA.java +++ b/src/main/java/com/google/openthread/masa/MASA.java @@ -83,11 +83,19 @@ public class MASA { protected Credentials credentials; // MASA server credentials protected Credentials credentialsCa; // MASA CA credentials (for signing) - public MASA(Credentials credentials, Credentials credentialsCa, int port) throws Exception { + private final int listenPort; + private static final Logger logger = LoggerFactory.getLogger(MASA.class); + + public MASA(Credentials credentials, Credentials credentialsCa, int port) throws MASAException { this.credentials = credentials; this.credentialsCa = credentialsCa; this.listenPort = port; - initHttpServer(); + try { + initHttpServer(); + } catch (Exception ex) { + logger.debug("initHttpServer() failed:", ex); + throw new MASAException("MASAException: HTTP server init failed - " + ex.getMessage()); + } } public int getListenPort() { @@ -95,15 +103,21 @@ public int getListenPort() { } public void start() { - if (httpServer != null) httpServer.start(); + if (httpServer != null) { + httpServer.start(); + } } public void stop() { - if (httpServer != null) httpServer.stop(); + if (httpServer != null) { + httpServer.stop(); + } } final class RootResourceHttpHandler implements HttpHandler { - public RootResourceHttpHandler() {} + + public RootResourceHttpHandler() { + } @Override public void handleRequest(HttpServerExchange exchange) throws Exception { @@ -119,7 +133,8 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { final class VoucherRequestHttpHandler implements HttpHandler { - public VoucherRequestHttpHandler() {} + public VoucherRequestHttpHandler() { + } @Override public void handleRequest(HttpServerExchange exchange) throws Exception { @@ -140,20 +155,18 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { final String contentType = exchange.getRequestHeaders().getFirst("Content-Type"); List reqCerts = new ArrayList<>(); byte[] reqContent = null; - Voucher req = null; + VoucherRequest req = null; Sign1Message sign1Msg = null; switch (contentType) { case ConstantsBrski.HTTP_APPLICATION_VOUCHER_CMS_JSON: try { - reqContent = - SecurityUtils.decodeCMSSignedMessage( - body, reqCerts); // decode CMS, get embedded reqCerts back. + reqContent = SecurityUtils.decodeCMSSignedMessage(body, reqCerts); // decode CMS, get embedded reqCerts back. } catch (Exception e) { - logger.error("CMS signed voucher request error: " + e.getMessage(), e); + logger.error("CMS signed voucher request error: {}", e.getMessage()); + logger.debug("details:", e); exchange.setStatusCode(403); - exchange.setReasonPhrase( - "CMS signing/decoding error in voucher request: " + e.getMessage()); + exchange.setReasonPhrase("CMS signing/decoding error in voucher request: " + e.getMessage()); return; } break; @@ -166,19 +179,19 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { sign1Msg = (Sign1Message) Message.DecodeFromBytes(body, MessageTag.Sign1); // look for set of x509 certificates in header parameters, per draft-ietf-cose-x509-08 reqCerts = SecurityUtils.getX5BagCertificates(sign1Msg); - if (reqCerts == null || reqCerts.size() < 1) - throw new CoseException( - "Registrar signing cert chain not found in X5Bag field of voucher request"); + if (reqCerts == null || reqCerts.isEmpty()) { + throw new CoseException("Registrar signing cert chain not found in X5Bag field of voucher request"); + } if (sign1Msg == null || !sign1Msg.validate(new OneKey(reqCerts.get(0).getPublicKey(), null))) { throw new CoseException("COSE-sign1 voucher validation failed"); } } catch (Exception e) { - logger.error("CBOR signed voucher request error: " + e.getMessage(), e); + logger.error("CBOR signed voucher request error: {}", e.getMessage()); + logger.debug("detail:", e); exchange.setStatusCode(403); - exchange.setReasonPhrase( - "COSE signing/decoding error in voucher request: " + e.getMessage()); + exchange.setReasonPhrase("COSE signing/decoding error in voucher request: " + e.getMessage()); return; } break; @@ -194,9 +207,10 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { try { req = (VoucherRequest) new JSONSerializer().deserialize(reqContent); } catch (Exception e) { - logger.error("JSON deserialization error: " + e.getMessage(), e); + logger.error("JSON deserialization error: {}", e.getMessage(), e); exchange.setStatusCode(400); exchange.setReasonPhrase("JSON deserialization error: " + e.getMessage()); + return; } break; @@ -206,14 +220,15 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { try { req = (VoucherRequest) new CBORSerializer().deserialize(sign1Msg.GetContent()); } catch (Exception e) { - logger.error("CBOR deserialization error: " + e.getMessage(), e); + logger.error("CBOR deserialization error: {}", e.getMessage(), e); exchange.setStatusCode(400); exchange.setReasonPhrase("CBOR deserialization error: " + e.getMessage()); + return; } break; default: - throw new RuntimeException("Internal MASA error"); + throw new MASAException("Internal MASA error"); } Voucher voucher = new Voucher(); @@ -225,14 +240,12 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { exchange.setStatusCode(200); exchange .getResponseHeaders() - .put( - HttpString.tryFromString("Content-Type"), + .put(HttpString.tryFromString("Content-Type"), ConstantsBrski.HTTP_APPLICATION_VOUCHER_COSE_CBOR); byte[] content = new CBORSerializer().serialize(resp.getVoucher()); byte[] payload = - SecurityUtils.genCoseSign1Message( - credentialsCa.getPrivateKey(), SecurityUtils.COSE_SIGNATURE_ALGORITHM, content); - logger.info("returning 200 OK with Voucher: " + Hex.toHexString(payload)); + SecurityUtils.genCoseSign1Message(credentialsCa.getPrivateKey(), SecurityUtils.COSE_SIGNATURE_ALGORITHM, content); + logger.info("returning 200 OK with Voucher: {}", Hex.toHexString(payload)); exchange.getOutputStream().write(payload); exchange.getOutputStream().flush(); exchange.getOutputStream().close(); @@ -245,34 +258,30 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { } /** - * Process incoming Voucher Request (and accompanying certificates of Registrar) and evaluate into - * a generic RESTful response. This response can be an error, or success, and can then be served - * by the respective CoAP or HTTP (or other) protocol server back to the client. + * Process incoming Voucher Request (and accompanying certificates of Registrar) and evaluate into a generic RESTful response. This response can be an error, or success, and can then be served by + * the respective CoAP or HTTP (or other) protocol server back to the client. * - * @param req received Voucher Request object - * @param voucher a new Voucher object of the right type, to be returned upon success in - * RestfulResponse. + * @param req received Voucher Request object + * @param voucher a new Voucher object of the right type, to be returned upon success in RestfulResponse. * @param reqCerts accompanying certificates of the Registrar to verify against - * @return a RESTful response that is either error (with diagnostic message) or success (with - * Voucher) + * @return a RESTful response that is either error (with diagnostic message) or success (with Voucher) */ protected RestfulVoucherResponse processVoucherRequest( Voucher req, Voucher voucher, List reqCerts) { if (!req.validate() || reqCerts.isEmpty()) { logger.error("invalid fields in the voucher request"); - return new RestfulVoucherResponse( - ResponseCode.BAD_REQUEST, "invalid fields in the voucher request"); + return new RestfulVoucherResponse(ResponseCode.BAD_REQUEST, "invalid fields in the voucher request"); } - // TODO(wgtdkp): + // TODO: // Section 5.5.1 BRSKI: MASA renewal of expired vouchers - // TODO(wgtdkp): + // TODO: // Section 5.5.2 BRSKI: MASA verification of voucher-request signature // consistency - // TODO(wgtdkp): + // TODO: // Section 5.5.3 BRSKI: MASA authentication of registrar (certificate) // do a first check on RA flag of Registrar cert. BHC-651 boolean isRA = false; @@ -297,10 +306,10 @@ protected RestfulVoucherResponse processVoucherRequest( return new RestfulVoucherResponse(ResponseCode.FORBIDDEN, msg); // per RFC 8995 5.6 } - // TODO(wgtdkp): + // TODO: // Section 5.5.4 BRSKI: MASA revocation checking of registrar (certificate) - // TODO(wgtdkp): + // TODO: // Section 5.5.5 BRSKI: MASA verification of pledge prior-signed-voucher-request if (req.priorSignedVoucherRequest == null) { final String msg = "missing priorSignedVoucherRequest"; @@ -311,17 +320,14 @@ protected RestfulVoucherResponse processVoucherRequest( // recreate it Sign1Message sign1Msg = null; try { - sign1Msg = - (Sign1Message) Message.DecodeFromBytes(req.priorSignedVoucherRequest, MessageTag.Sign1); + sign1Msg = (Sign1Message) Message.DecodeFromBytes(req.priorSignedVoucherRequest, MessageTag.Sign1); // validate it TODO } catch (Exception ex) { final String msg = "Couldn't parse priorSignedVoucherRequest COSE."; logger.error(msg, ex); return new RestfulVoucherResponse(ResponseCode.BAD_REQUEST, msg); } - VoucherRequest pledgeReq = - (VoucherRequest) - new CBORSerializer().fromCBOR(CBORObject.DecodeFromBytes(sign1Msg.GetContent())); + VoucherRequest pledgeReq = (VoucherRequest) new CBORSerializer().fromCBOR(CBORObject.DecodeFromBytes(sign1Msg.GetContent())); if (pledgeReq == null) { final String msg = "invalid priorSignedVoucherRequest contents"; logger.error(msg); @@ -342,10 +348,10 @@ protected RestfulVoucherResponse processVoucherRequest( return new RestfulVoucherResponse(ResponseCode.BAD_REQUEST, msg); } - // TODO(wgtdkp): + // TODO: // Section 5.5.6 BRSKI: MASA pinning of registrar - // TODO(wgtdkp): + // TODO: // Section 5.5.7 BRSKI: MASA nonce handling // Section 5.6 BRSKI: MASA and Registrar Voucher Response @@ -371,8 +377,7 @@ protected RestfulVoucherResponse processVoucherRequest( // logger.error("get encoded subject-public-key-info failed: " + // e.getMessage()); logger.error("get encoded domain-ca-cert failed: " + e.getMessage(), e); - return new RestfulVoucherResponse( - ResponseCode.INTERNAL_SERVER_ERROR, "Get encoded domain-ca-cert failed."); + return new RestfulVoucherResponse(ResponseCode.INTERNAL_SERVER_ERROR, "Get encoded domain-ca-cert failed."); } if (voucher.nonce == null) { @@ -380,7 +385,7 @@ protected RestfulVoucherResponse processVoucherRequest( voucher.expiresOn = new Date(System.currentTimeMillis() + 1000 * 60 * 10); } - // TODO(wgtdkp): update audit log + // TODO: update audit log // Generate and send response return new RestfulVoucherResponse(voucher); @@ -395,7 +400,7 @@ private void initHttpServer() keyManagers = keyManagerFactory.getKeyManagers(); TrustManager[] trustManagers; - trustManagers = new X509TrustManager[] {new DummyTrustManager()}; + trustManagers = new X509TrustManager[]{new DummyTrustManager()}; SSLContext httpSsl = SSLContext.getInstance("TLS"); httpSsl.init(keyManagers, trustManagers, null); @@ -415,8 +420,4 @@ private void initHttpServer() .setHandler(masaPathHandler) .build(); } - - private final int listenPort; - - private static final Logger logger = LoggerFactory.getLogger(MASA.class); } From fb5a04715ecc394be6ea803e58709a22787a8473 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 27 Jun 2024 12:23:20 +0200 Subject: [PATCH 11/25] [pom.xml] set release level at 11 (hopefully that should cover all used std lib functions like readAllBytes()) --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9254a5a..3473622 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ UTF-8 - 9 + 11 2.9.7 1.2.13 4.13.2 From 9d64169ec4c418f1b9bc722a4934a9c4cec8e926 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 27 Jun 2024 12:46:34 +0200 Subject: [PATCH 12/25] [script] added helper script to avoid code duplication; removed unneeded scripts. --- script/build-docker-image.sh | 8 --- script/cose-validator.sh | 2 +- ...e-keystore-ietf-draft-constrained-brski.sh | 31 +++++++++++- ...reate-pledge-credentials-p12-honeydukes.sh | 10 +--- ...e-pledge-credentials-p12-iotconsultancy.sh | 9 +--- script/create-pledge-credentials-p12.sh | 9 +--- ...n-pledge-localhost.sh => helper-cp-run.sh} | 12 ++++- script/recreate-ot-registrar-cert.sh | 28 +++++++++++ script/recreate-test-credentials-p12.sh | 13 ++--- script/run | 2 +- script/run-masa-only.sh | 46 ----------------- script/run-pledge-honeydukes.sh | 3 +- script/run-pledge-iotconsultancy.sh | 2 +- script/run-pledge.sh | 31 ------------ script/run-registrar-only.sh | 47 ----------------- script/run-servers.sh | 50 +++++-------------- script/start-service.sh | 2 + 17 files changed, 95 insertions(+), 210 deletions(-) rename script/{run-pledge-localhost.sh => helper-cp-run.sh} (83%) delete mode 100755 script/run-masa-only.sh delete mode 100755 script/run-pledge.sh delete mode 100755 script/run-registrar-only.sh diff --git a/script/build-docker-image.sh b/script/build-docker-image.sh index 3feb656..944bb54 100755 --- a/script/build-docker-image.sh +++ b/script/build-docker-image.sh @@ -29,16 +29,8 @@ set -e -## This is not a public repository, make sure you have the access! -readonly TRI_REPO=git@bitbucket.org:threadgroup/tce-registrar-java.git - readonly IMAGE_NAME=ot-registrar -if [ ! -d tri ]; then - echo "cloning 'tce-registrar-java' into 'tri'..." - git clone $TRI_REPO tri -fi - # Enable ipv6 if [ ! -f /etc/docker/daemon.json ]; then echo "enabling ipv6 for docker ..." diff --git a/script/cose-validator.sh b/script/cose-validator.sh index 0aa76db..0206874 100755 --- a/script/cose-validator.sh +++ b/script/cose-validator.sh @@ -27,4 +27,4 @@ # POSSIBILITY OF SUCH DAMAGE. # -java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.tools.CoseValidator $1 $2 +./script/helper-cp-run.sh com.google.openthread.tools.CoseValidator $@ diff --git a/script/create-keystore-ietf-draft-constrained-brski.sh b/script/create-keystore-ietf-draft-constrained-brski.sh index ef4c9a8..b0f34c4 100644 --- a/script/create-keystore-ietf-draft-constrained-brski.sh +++ b/script/create-keystore-ietf-draft-constrained-brski.sh @@ -1,9 +1,36 @@ #!/bin/bash +# +# Copyright (c) 2022, 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. +# CREDS=./credentials/ietf-draft-constrained-brski echo "Creating .p12 keystore file for credentials in $CREDS ..." - java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.tools.CredentialGenerator \ + ./script/helper-cp-run.sh com.google.openthread.tools.CredentialGenerator \ -c $CREDS/domain_ca.pem $CREDS/privkey_domain_ca.pem \ -r $CREDS/registrar.pem $CREDS/privkey_registrar.pem \ -m $CREDS/masa_ca.pem $CREDS/privkey_masa_ca.pem \ -p $CREDS/pledge.pem $CREDS/privkey_pledge.pem \ - -o ./credentials/keystore_ietf-draft-constrained-brski.p12 \ No newline at end of file + -o ./credentials/keystore_ietf-draft-constrained-brski.p12 diff --git a/script/create-pledge-credentials-p12-honeydukes.sh b/script/create-pledge-credentials-p12-honeydukes.sh index ef0ffd1..734dc1b 100755 --- a/script/create-pledge-credentials-p12-honeydukes.sh +++ b/script/create-pledge-credentials-p12-honeydukes.sh @@ -29,14 +29,8 @@ # This script is to run the Java Pledge with Honeydukes IDevID. # The Honeydukes test vendor/MASA is located at: https://honeydukes.sandelman.ca/ -readonly JAR_FILE=./target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar + readonly CREDENTIAL=./credentials/honeydukes/credentials.p12 readonly CRED_DIR=./credentials/honeydukes -# test if build JAR exists -if [ ! -f "${JAR_FILE}" ]; then - echo "Please build using 'mvn -DskipTests package' before running; and run this script from base directory of repo." - exit 1 -fi - -java -cp $JAR_FILE com.google.openthread.tools.CredentialGenerator -m $CRED_DIR/vendor.crt -p $CRED_DIR/device.crt $CRED_DIR/key.pem -o $CREDENTIAL +./script/helper-cp-run.sh com.google.openthread.tools.CredentialGenerator -m $CRED_DIR/vendor.crt -p $CRED_DIR/device.crt $CRED_DIR/key.pem -o $CREDENTIAL diff --git a/script/create-pledge-credentials-p12-iotconsultancy.sh b/script/create-pledge-credentials-p12-iotconsultancy.sh index 1e6905a..81ed1c2 100755 --- a/script/create-pledge-credentials-p12-iotconsultancy.sh +++ b/script/create-pledge-credentials-p12-iotconsultancy.sh @@ -28,17 +28,10 @@ # # This script is to run the Java Pledge with IoTconsultancy IDevID. -readonly JAR_FILE=./target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar readonly CRED_DIR=./credentials/iotconsultancy-masa readonly CREDENTIAL=${CRED_DIR}/credentials.p12 -# test if build JAR exists -if [ ! -f "${JAR_FILE}" ]; then - echo "Please build using 'mvn -DskipTests package' before running; and run this script from base directory of repo." - exit 1 -fi - -java -cp $JAR_FILE com.google.openthread.tools.CredentialGenerator \ +./script/helper-cp-run.sh com.google.openthread.tools.CredentialGenerator \ -ms $CRED_DIR/TestVendor_masa.pem $CRED_DIR/privkey_TestVendor_masa.pem \ -m $CRED_DIR/TestVendor_masa_ca.pem $CRED_DIR/privkey_TestVendor_masa_ca.pem \ -p $CRED_DIR/TestVendor_1.pem $CRED_DIR/privkey_TestVendor_1.pem \ diff --git a/script/create-pledge-credentials-p12.sh b/script/create-pledge-credentials-p12.sh index 4808acb..56eb897 100755 --- a/script/create-pledge-credentials-p12.sh +++ b/script/create-pledge-credentials-p12.sh @@ -27,14 +27,7 @@ # POSSIBILITY OF SUCH DAMAGE. # -readonly JAR_FILE=./target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar readonly CREDENTIAL=./credentials/pledge_credentials.p12 readonly CRED_DIR=./credentials/local-masa -# test if build JAR exists -if [ ! -f "${JAR_FILE}" ]; then - echo "Please build using 'mvn -DskipTests package' before running; and run this script from base directory of repo." - exit 1 -fi - -java -cp $JAR_FILE com.google.openthread.tools.CredentialGenerator -m $CRED_DIR/masa_cert.pem $CRED_DIR/masa_private.pem -p $1 $2 -o $CREDENTIAL +./script/helper-cp-run.sh com.google.openthread.tools.CredentialGenerator -m $CRED_DIR/masa_cert.pem $CRED_DIR/masa_private.pem -p $1 $2 -o $CREDENTIAL diff --git a/script/run-pledge-localhost.sh b/script/helper-cp-run.sh similarity index 83% rename from script/run-pledge-localhost.sh rename to script/helper-cp-run.sh index 7c48016..60dd104 100755 --- a/script/run-pledge-localhost.sh +++ b/script/helper-cp-run.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2019, The OpenThread Registrar Authors. +# Copyright (c) 2024, The OpenThread Registrar Authors. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -27,4 +27,12 @@ # POSSIBILITY OF SUCH DAMAGE. # -java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.pledge.PledgeMain -f ./credentials/local-masa/test_credentials.p12 -r coaps://localhost +readonly JAR_FILE=./target/ot-registrar-0.2-jar-with-dependencies.jar + +# test if OT Registrar JAR exists +if [ ! -f "${JAR_FILE}" ]; then + echo "Please build using 'mvn -DskipTests package' before running." + exit 1 +fi + +java -cp $JAR_FILE $@ diff --git a/script/recreate-ot-registrar-cert.sh b/script/recreate-ot-registrar-cert.sh index 8a2f157..5d3b86f 100755 --- a/script/recreate-ot-registrar-cert.sh +++ b/script/recreate-ot-registrar-cert.sh @@ -1,4 +1,32 @@ #!/bin/bash +# +# Copyright (c) 2021, 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. +# + # Recreate the cert for: OT Registrar (RA) # signed by root=domainCA diff --git a/script/recreate-test-credentials-p12.sh b/script/recreate-test-credentials-p12.sh index a7b1667..1111a98 100755 --- a/script/recreate-test-credentials-p12.sh +++ b/script/recreate-test-credentials-p12.sh @@ -27,14 +27,11 @@ # POSSIBILITY OF SUCH DAMAGE. # -readonly JAR_FILE=./target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar readonly CREDENTIAL=./credentials/local-masa/test_credentials.p12 readonly CRED_DIR=./credentials/local-masa -# test if build JAR exists -if [ ! -f "${JAR_FILE}" ]; then - echo "Please build using 'mvn -DskipTests package' before running; and run this script from base directory of repo." - exit 1 -fi - -java -cp $JAR_FILE com.google.openthread.tools.CredentialGenerator -c $CRED_DIR/domainca_cert.pem $CRED_DIR/domainca_private.pem -m $CRED_DIR/masa_cert.pem $CRED_DIR/masa_private.pem -r $CRED_DIR/registrar_cert.pem $CRED_DIR/registrar_private.pem -o $CREDENTIAL \ No newline at end of file +./script/helper-cp-run.sh com.google.openthread.tools.CredentialGenerator \ + -c $CRED_DIR/domainca_cert.pem $CRED_DIR/domainca_private.pem \ + -m $CRED_DIR/masa_cert.pem $CRED_DIR/masa_private.pem \ + -r $CRED_DIR/registrar_cert.pem $CRED_DIR/registrar_private.pem \ + -o $CREDENTIAL diff --git a/script/run b/script/run index b6aa470..5002bec 100755 --- a/script/run +++ b/script/run @@ -29,7 +29,7 @@ readonly JAR_FILE=./target/ot-registrar-0.2-jar-with-dependencies.jar -# test if Registrar JAR exists +# test if OT Registrar JAR exists if [ ! -f "${JAR_FILE}" ]; then echo "Please build using 'mvn -DskipTests package' before running." exit 1 diff --git a/script/run-masa-only.sh b/script/run-masa-only.sh deleted file mode 100755 index 7705cf7..0000000 --- a/script/run-masa-only.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2022, 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. -# - -set -e - -readonly PORT=9443 -readonly JAR_FILE=./target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar -readonly CREDENTIAL=credentials/iotconsultancy-masa/credentials.p12 - -# test if Registrar JAR exists -if [ ! -f "${JAR_FILE}" ]; then - echo "Please build using 'mvn -DskipTests package' before running." - exit 1 -fi - -echo "starting MASA server, port=${PORT} ..." -java -cp $JAR_FILE \ - com.google.openthread.masa.MASAMain \ - -v -p $PORT -f $CREDENTIAL \ - "$@" diff --git a/script/run-pledge-honeydukes.sh b/script/run-pledge-honeydukes.sh index 416cf15..6a81c06 100755 --- a/script/run-pledge-honeydukes.sh +++ b/script/run-pledge-honeydukes.sh @@ -30,4 +30,5 @@ # This runs a Pledge using Honeydukes IDevID, onboarding via cloud Registrar. # The script create-pledge-credentials-p12-honeydukes.sh can be used to create # or recreate the credentials file. -java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.pledge.PledgeMain -f ./credentials/honeydukes/credentials.p12 -r coaps://masa.iotconsultancy.nl + +./script/run -pledge -f ./credentials/honeydukes/credentials.p12 -r coaps://masa.iotconsultancy.nl diff --git a/script/run-pledge-iotconsultancy.sh b/script/run-pledge-iotconsultancy.sh index ec5ff0c..06abdc3 100755 --- a/script/run-pledge-iotconsultancy.sh +++ b/script/run-pledge-iotconsultancy.sh @@ -37,4 +37,4 @@ if [ "$#" -eq 1 ]; then fi echo "Pledge using IoTconsultancy credentials with Registrar: ${REGISTRAR}" -java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.pledge.PledgeMain -f ./credentials/iotconsultancy-masa/credentials.p12 -r ${REGISTRAR} +./script/run -pledge -f ./credentials/iotconsultancy-masa/credentials.p12 -r ${REGISTRAR} diff --git a/script/run-pledge.sh b/script/run-pledge.sh deleted file mode 100755 index 5e23f33..0000000 --- a/script/run-pledge.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2019, 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. -# - -java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.pledge.PledgeMain -f ./credentials/local-masa/test_credentials.p12 -r coaps://masa.iotconsultancy.nl -#java -cp target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar com.google.openthread.pledge.PledgeMain -f ./credentials/local-masa/test_credentials.p12 -r coaps://localhost diff --git a/script/run-registrar-only.sh b/script/run-registrar-only.sh deleted file mode 100755 index e01cd2d..0000000 --- a/script/run-registrar-only.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -# -# Copyright (c) 2022, 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. -# - -set -e - -readonly DOMAIN_NAME=TestDomainTCE -readonly REGISTRAR_PORT=5684 -readonly JAR_FILE=./target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar -readonly CREDENTIAL=credentials/iotconsultancy-masa/credentials.p12 - -# test if Registrar JAR exists -if [ ! -f "${JAR_FILE}" ]; then - echo "Please build using 'mvn -DskipTests package' before running." - exit 1 -fi - -echo "starting registrar server, port=${REGISTRAR_PORT} ..." -java -cp $JAR_FILE \ - com.google.openthread.registrar.RegistrarMain \ - -v -d $DOMAIN_NAME -p $REGISTRAR_PORT -f $CREDENTIAL \ - "$@" diff --git a/script/run-servers.sh b/script/run-servers.sh index 66e67bd..9249f14 100755 --- a/script/run-servers.sh +++ b/script/run-servers.sh @@ -27,59 +27,33 @@ # POSSIBILITY OF SUCH DAMAGE. # +# This script starts an entire set of Registrar and MASA in the background. + set -e +# Select domain name readonly DOMAIN_NAME=TestDomainTCE +# Select credentials +#readonly CREDENTIAL=credentials/threadgroup-5f9d307c.p12 +#readonly CREDENTIAL=credentials/local-masa/test_credentials.p12 +readonly CREDENTIAL=credentials/iotconsultancy-masa/credentials.p12 + readonly TIMESTAMP=$(date "+%Y-%m-%d_%H.%M.%S") readonly LOGS=logs/${TIMESTAMP} -readonly TRI_LOG=${LOGS}/tri.log readonly REGISTRAR_LOG=${LOGS}/registrar.log readonly MASA_LOG=${LOGS}/masa.log -readonly TRI_PORT=5683 -readonly REGISTRAR_PORT=5684 -readonly MASA_PORT=9443 - -readonly JAR_FILE=./target/ot-registrar-0.1-SNAPSHOT-jar-with-dependencies.jar -# prebuilt TRI v1.2 server from the tce-registrar-java BitBucket repo needs to go here -readonly JAR_TRI=./script/TRIserver.jar - -#readonly CREDENTIAL=credentials/threadgroup-5f9d307c.p12 -#readonly CREDENTIAL=credentials/local-masa/test_credentials.p12 -readonly CREDENTIAL=credentials/iotconsultancy-masa/credentials.p12 - echo "Credentials file set to: ${CREDENTIAL}" - -# test if TRI exists -if [ ! -f "${JAR_TRI}" ]; then - echo "Please add TRI server JAR at ./script/TRIserver.jar" - exit 1 -fi - -# test if Registrar JAR exists -if [ ! -f "${JAR_FILE}" ]; then - echo "Please build using 'mvn -DskipTests package' before running." - exit 1 -fi - rm -rf $LOGS mkdir -p $LOGS -echo "starting TRI, port=${TRI_PORT}, log=${TRI_LOG}..." -java -jar $JAR_TRI [::1] $REGISTRAR_PORT -log $TRI_LOG \ - >> /dev/null 2>&1 & - -echo "starting registrar server, port=${REGISTRAR_PORT}, log=${REGISTRAR_LOG}..." -java -cp $JAR_FILE \ - com.google.openthread.registrar.RegistrarMain \ - -v -d $DOMAIN_NAME -p $REGISTRAR_PORT -f $CREDENTIAL \ +echo "starting Registrar server (CoAPS), log=${REGISTRAR_LOG}..." +./script/run -registrar -v -d $DOMAIN_NAME -f $CREDENTIAL \ >> $REGISTRAR_LOG 2>&1 & -echo "starting HTTPS masa server, port=${MASA_PORT}, log=${MASA_LOG}..." -java -cp $JAR_FILE \ - com.google.openthread.masa.MASAMain \ - -p $MASA_PORT -f $CREDENTIAL \ +echo "starting MASA server (HTTPS), log=${MASA_LOG}..." +./script/run -masa -v -f $CREDENTIAL \ >> $MASA_LOG 2>&1 & echo "Done" diff --git a/script/start-service.sh b/script/start-service.sh index eb69871..2a97354 100755 --- a/script/start-service.sh +++ b/script/start-service.sh @@ -27,6 +27,8 @@ # POSSIBILITY OF SUCH DAMAGE. # +# Start the OT Registrar service in a Docker container for testing. + readonly SUBNET=fdaa:bb::/64 readonly IP6_ADDR=fdaa:bb::de6 readonly NETWORK=network-openthread From c9f693f04b17ca7726d6aa975b76adcef6a4c42a Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 27 Jun 2024 12:56:22 +0200 Subject: [PATCH 13/25] [all] coaps URI bugfix; log fix to avoid Californium library logs to show up always; code formatting. --- .../google/openthread/LoggerInitializer.java | 2 ++ .../openthread/main/OtRegistrarConfig.java | 2 +- .../openthread/pledge/PledgeException.java | 23 ++++++++++--------- .../google/openthread/pledge/PledgeMain.java | 3 ++- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/google/openthread/LoggerInitializer.java b/src/main/java/com/google/openthread/LoggerInitializer.java index 6d50eee..f4af99c 100644 --- a/src/main/java/com/google/openthread/LoggerInitializer.java +++ b/src/main/java/com/google/openthread/LoggerInitializer.java @@ -55,5 +55,7 @@ public static void Init(boolean verbose) { break; } } + + ((Logger)LoggerFactory.getLogger(CALIFORNIUM)).setLevel(levelLibrary); } } diff --git a/src/main/java/com/google/openthread/main/OtRegistrarConfig.java b/src/main/java/com/google/openthread/main/OtRegistrarConfig.java index 386ca70..2a59d27 100644 --- a/src/main/java/com/google/openthread/main/OtRegistrarConfig.java +++ b/src/main/java/com/google/openthread/main/OtRegistrarConfig.java @@ -45,7 +45,7 @@ static OtRegistrarConfig DefaultPledge() { config.domainName = null; config.keyStoreFile = "./credentials/default_pledge.p12"; config.masaUri = null; - config.registrarUri = "localhost:5684"; + config.registrarUri = "coaps://localhost:5684"; config.logVerbose = false; return config; } diff --git a/src/main/java/com/google/openthread/pledge/PledgeException.java b/src/main/java/com/google/openthread/pledge/PledgeException.java index 22a2a85..0d8b6c2 100644 --- a/src/main/java/com/google/openthread/pledge/PledgeException.java +++ b/src/main/java/com/google/openthread/pledge/PledgeException.java @@ -34,12 +34,13 @@ public class PledgeException extends Exception { /** - * An optional CoAP response code, from a CoAP response, that was unexpected or related to the - * exception. + * An optional CoAP response code, from a CoAP response, that was unexpected or related to the exception. */ public ResponseCode code = null; - /** An optional CoAP diagnostic message, from a CoAP response, to clarify what went wrong. */ + /** + * An optional CoAP diagnostic message, from a CoAP response, to clarify what went wrong. + */ public String diagMsg = null; public PledgeException(String msg) { @@ -47,18 +48,18 @@ public PledgeException(String msg) { } public PledgeException(String msg, CoapResponse resp) { - super( - msg - + ((resp.getCode() != null) ? (" (" + resp.getCode().toString() + ")") : "") - + ((resp.getCode() != null && resp.getPayload() != null) - ? (" - CoAP diagnostic: '" + new String(resp.getPayload()) + "'") - : "")); + super(msg + ((resp.getCode() != null) ? (" (" + resp.getCode().toString() + ")") : "") + + ((resp.getCode() != null && resp.getPayload() != null) + ? (" - CoAP diagnostic: '" + new String(resp.getPayload()) + "'") : "")); this.code = resp.getCode(); - if (!ResponseCode.isSuccess(this.code) && resp.getPayload() != null) + if (!ResponseCode.isSuccess(this.code) && resp.getPayload() != null) { this.diagMsg = new String(resp.getPayload()); + } } - public PledgeException(String msg, ResponseCode coapCode, String coapDiagnosticMsg) {} + public PledgeException(String msg, ResponseCode coapCode, String coapDiagnosticMsg) { + // FIXME + } private static final long serialVersionUID = -1980574489782019605L; } diff --git a/src/main/java/com/google/openthread/pledge/PledgeMain.java b/src/main/java/com/google/openthread/pledge/PledgeMain.java index 980a360..cec8f85 100644 --- a/src/main/java/com/google/openthread/pledge/PledgeMain.java +++ b/src/main/java/com/google/openthread/pledge/PledgeMain.java @@ -101,7 +101,8 @@ private static void runCli(Pledge pledge) { System.out.println("Done"); } catch (Exception e) { - logger.error("error: {}", e.getMessage(), e); + logger.error("error: {}", e.getMessage()); + logger.debug("details:", e); } } } From 62816a8b2966a6ae3c9503483e9ea7a94a598dc4 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 27 Jun 2024 21:45:31 +0200 Subject: [PATCH 14/25] [script] rename Docker container to ot-registrar:latest and some updates. --- script/Dockerfile | 11 ++++++----- script/build-docker-image.sh | 15 +++++++++------ script/run-servers.sh | 2 +- script/start-service.sh | 4 ++-- .../google/openthread/main/OtRegistrarConfig.java | 4 +++- 5 files changed, 21 insertions(+), 15 deletions(-) diff --git a/script/Dockerfile b/script/Dockerfile index 116b24b..acb86e0 100644 --- a/script/Dockerfile +++ b/script/Dockerfile @@ -25,7 +25,7 @@ # POSSIBILITY OF SUCH DAMAGE. # -FROM ubuntu:18.04 +FROM ubuntu:22.04 RUN apt-get update @@ -37,7 +37,7 @@ RUN apt-get install maven git sudo lsb-core net-tools -y #RUN add-apt-repository ppa:openjdk-r/ppa #RUN apt-get update -RUN apt-get install openjdk-8-jdk -y +RUN apt-get install openjdk-11-jdk -y RUN java -version WORKDIR /home/ot-registrar @@ -46,10 +46,11 @@ COPY . . # RUN mvn clean package +# CMD triggers a warning as per https://docs.docker.com/reference/build-checks/json-args-recommended/ +# FIXME check if it should be CMD or SHELL; and if the 'bash' part should be split off. CMD ./script/run-servers.sh && bash +# TODO: enable ports to let Registrar receive external traffic (5684). #EXPOSE 5683:5683/udp - -#EXPOSE 5684:5684/udp - +EXPOSE 5684:5684/udp #EXPOSE 5685:5685/udp diff --git a/script/build-docker-image.sh b/script/build-docker-image.sh index 944bb54..b6f17ac 100755 --- a/script/build-docker-image.sh +++ b/script/build-docker-image.sh @@ -30,6 +30,7 @@ set -e readonly IMAGE_NAME=ot-registrar +readonly VERSION=latest # Enable ipv6 if [ ! -f /etc/docker/daemon.json ]; then @@ -38,12 +39,14 @@ if [ ! -f /etc/docker/daemon.json ]; then sudo systemctl restart docker fi -# Create docker image if not exist +# Create docker image if not existing yet if ! $(sudo docker image ls | grep -q "${IMAGE_NAME}"); then + # Building package + echo "building OT Registrar package..." + mvn clean -Dmaven.test.skip=true package + echo "building docker image..." - sudo docker build --no-cache -f script/Dockerfile -t ubuntu:${IMAGE_NAME} . + sudo docker build --no-cache -f script/Dockerfile -t ${IMAGE_NAME}:${VERSION} . +else + echo "Docker image '${IMAGE_NAME}' is already present." fi - -# Building package -echo "building OT Registrar package..." -mvn clean -Dmaven.test.skip=true package diff --git a/script/run-servers.sh b/script/run-servers.sh index 9249f14..c4eae56 100755 --- a/script/run-servers.sh +++ b/script/run-servers.sh @@ -49,7 +49,7 @@ rm -rf $LOGS mkdir -p $LOGS echo "starting Registrar server (CoAPS), log=${REGISTRAR_LOG}..." -./script/run -registrar -v -d $DOMAIN_NAME -f $CREDENTIAL \ +./script/run -registrar -v -d $DOMAIN_NAME -f $CREDENTIAL -m localhost:9994 \ >> $REGISTRAR_LOG 2>&1 & echo "starting MASA server (HTTPS), log=${MASA_LOG}..." diff --git a/script/start-service.sh b/script/start-service.sh index 2a97354..3e93fb7 100755 --- a/script/start-service.sh +++ b/script/start-service.sh @@ -41,9 +41,9 @@ echo "creating subnet ${NETWORK}=${SUBNET} ..." sudo docker network rm $NETWORK sudo docker network create --ipv6 --subnet=$SUBNET $NETWORK -echo "starting registrar(ip=${IP6_ADDR}) container..." +echo "starting ot-registrar(ip=${IP6_ADDR}) container..." sudo docker run -dt --privileged \ --network $NETWORK --ip6 $IP6_ADDR \ --sysctl 'net.ipv6.conf.all.disable_ipv6=0 net.ipv4.conf.all.forwarding=1 net.ipv6.conf.all.forwarding=1' \ -v $ROOT_DIR:/home/ot-registrar \ - ubuntu:ot-registrar + ot-registrar:latest diff --git a/src/main/java/com/google/openthread/main/OtRegistrarConfig.java b/src/main/java/com/google/openthread/main/OtRegistrarConfig.java index 2a59d27..f051535 100644 --- a/src/main/java/com/google/openthread/main/OtRegistrarConfig.java +++ b/src/main/java/com/google/openthread/main/OtRegistrarConfig.java @@ -28,6 +28,8 @@ package com.google.openthread.main; +import com.google.openthread.brski.ConstantsBrski; + public class OtRegistrarConfig { public Role role; @@ -65,7 +67,7 @@ static OtRegistrarConfig DefaultRegistrar() { static OtRegistrarConfig DefaultMasa() { OtRegistrarConfig config = new OtRegistrarConfig(); config.role = Role.Masa; - config.serverPort = 9443; // re-using corporate TLS/HTTPS port + config.serverPort = ConstantsBrski.DEFAULT_MASA_HTTPS_PORT; // re-using corporate TLS/HTTPS port config.domainName = null; config.keyStoreFile = "./credentials/default_masa.p12"; config.masaUri = null; From 7c06a598adc43df8222e17e50a8adc6de3da3833 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Wed, 28 Aug 2024 00:18:51 +0200 Subject: [PATCH 15/25] [pom.xml][brski][registrar] added proper telemetry printing in log; telemetry logic fix; minor source format updates; WIP v0.3 --- pom.xml | 2 +- .../openthread/brski/StatusTelemetry.java | 35 ++++++++++++------- .../openthread/registrar/Registrar.java | 27 ++++---------- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/pom.xml b/pom.xml index 3473622..6d015a0 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/ 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. } } } From cffe697f88e0d7174e1f5cff2e59059b9fb840fc Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Wed, 28 Aug 2024 21:49:51 +0200 Subject: [PATCH 16/25] [doc][script] run scripts bumped to run 0.3; documentation added for 0.2 and 0.3 releases --- GUIDE.md | 127 +++++++++++++++++----------- README.md | 1 + releases/ot-registrar-0.2-readme.md | 22 +++++ releases/ot-registrar-0.3-readme.md | 23 +++++ script/run | 4 +- 5 files changed, 124 insertions(+), 53 deletions(-) create mode 100644 releases/ot-registrar-0.2-readme.md create mode 100644 releases/ot-registrar-0.3-readme.md 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/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/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 From c898caa4c5eab499639ad4beafffc5e88e6459d9 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 29 Aug 2024 08:11:07 +0200 Subject: [PATCH 17/25] [credentials] renamed p12 files for uniform structure. --- .../credentials.p12} | Bin .../{test_credentials.p12 => credentials.p12} | Bin .../{test_credentials.p12 => credentials.p12} | Bin 3 files changed, 0 insertions(+), 0 deletions(-) rename credentials/{keystore_ietf-draft-constrained-brski.p12 => ietf-draft-constrained-brski/credentials.p12} (100%) rename credentials/local-masa/{test_credentials.p12 => credentials.p12} (100%) rename credentials/siemens-masa/{test_credentials.p12 => credentials.p12} (100%) 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 From 431481ab15bfd01c0bbbe51fa9bc52b40b57f383 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 29 Aug 2024 08:11:54 +0200 Subject: [PATCH 18/25] [pom] remove unused jSerialComm dependency --- pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pom.xml b/pom.xml index 6d015a0..e5d3662 100644 --- a/pom.xml +++ b/pom.xml @@ -94,12 +94,6 @@ 2.2.8.Final - - com.fazecast - jSerialComm - [2.0.0,3.0.0) - - From 3c30f3788269542e8ec3a4124160d859a6f2982d Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 29 Aug 2024 08:27:03 +0200 Subject: [PATCH 19/25] [script] build script added --- script/build.sh | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100755 script/build.sh 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 From 49a2830af1ab432188aa5b873d59dd0c04f38ec4 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 29 Aug 2024 08:27:39 +0200 Subject: [PATCH 20/25] [test] fix test path; source formatting --- .../registrar/IETFConstrainedBrskiTest.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) 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(); From daf3fe5c3db3bad265580306f814b04c23039268 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Thu, 29 Aug 2024 08:32:34 +0200 Subject: [PATCH 21/25] [script] +x on script; version JAR bugfix --- script/create-keystore-ietf-draft-constrained-brski.sh | 0 script/helper-cp-run.sh | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 script/create-keystore-ietf-draft-constrained-brski.sh 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 From e587819959227500eced579b5ffdddc4fbc1dd44 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Sun, 1 Sep 2024 17:45:12 +0200 Subject: [PATCH 22/25] [masa] fix port binding issue on 'weird' interfaces on test PC. --- src/main/java/com/google/openthread/masa/MASA.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/google/openthread/masa/MASA.java b/src/main/java/com/google/openthread/masa/MASA.java index 3c5b495..f62e5c1 100644 --- a/src/main/java/com/google/openthread/masa/MASA.java +++ b/src/main/java/com/google/openthread/masa/MASA.java @@ -407,16 +407,16 @@ private void initHttpServer() PathHandler masaPathHandler = new PathHandler() .addExactPath("/", new BlockingHandler(new RootResourceHttpHandler())) - .addExactPath( - "/.well-known/brski/requestvoucher", + .addExactPath("/.well-known/brski/requestvoucher", new BlockingHandler(new VoucherRequestHttpHandler())); - // the :: binds to IPv6 addresses only. + // the :: binds to (hopefully) all available IPv4 and IPv6 addresses. + // the specific listeners using NetworkUtils.getIPvXHost() are meant to pick specific addresses only. httpServer = Undertow.builder() - // .addHttpsListener(listenPort, "::", httpSsl) - .addHttpsListener(listenPort, "localhost", httpSsl) - .addHttpsListener(listenPort, NetworkUtils.getIPv4Host(), httpSsl) - .addHttpsListener(listenPort, NetworkUtils.getIPv6Host(), httpSsl) + .addHttpsListener(listenPort, "::", httpSsl) + //.addHttpsListener(listenPort, "localhost", httpSsl) + //.addHttpsListener(listenPort, NetworkUtils.getIPv4Host(), httpSsl) + //.addHttpsListener(listenPort, NetworkUtils.getIPv6Host(), httpSsl) .setHandler(masaPathHandler) .build(); } From 422334d5261f0021fce17f2ba3b9560328dae4c3 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Sun, 1 Sep 2024 17:46:04 +0200 Subject: [PATCH 23/25] [all] minor source fixes and clarifications; pom.xml libraries bumped --- pom.xml | 23 +++++++++---------- .../java/com/google/openthread/Constants.java | 5 ++-- .../com/google/openthread/NetworkUtils.java | 10 +++++--- .../com/google/openthread/SecurityUtils.java | 3 +-- .../openthread/brski/CBORSerializer.java | 4 ++-- .../google/openthread/domainca/DomainCA.java | 2 +- 6 files changed, 25 insertions(+), 22 deletions(-) diff --git a/pom.xml b/pom.xml index e5d3662..0e10df3 100644 --- a/pom.xml +++ b/pom.xml @@ -15,8 +15,8 @@ UTF-8 11 2.9.7 - 1.2.13 - 4.13.2 + 1.5.7 + 4.13.2 @@ -54,7 +54,13 @@ org.bouncycastle bcpkix-jdk15on - 1.69 + 1.70 + + + + org.slf4j + slf4j-api + 2.0.16 @@ -78,20 +84,13 @@ com.google.code.gson gson - 2.8.5 - - - - - org.apache.logging.log4j - log4j-core - 2.23.1 + 2.8.9 io.undertow undertow-core - 2.2.8.Final + 2.3.16.Final diff --git a/src/main/java/com/google/openthread/Constants.java b/src/main/java/com/google/openthread/Constants.java index a22556e..c57257a 100644 --- a/src/main/java/com/google/openthread/Constants.java +++ b/src/main/java/com/google/openthread/Constants.java @@ -29,7 +29,7 @@ package com.google.openthread; /** - * OT Registrar specific constants are defined here. + * OT Registrar project-specific constants are defined here. */ public class Constants { @@ -39,5 +39,6 @@ public class Constants { // -- Other items public static final String KEY_STORE_FORMAT = "PKCS12"; - public static final long CERT_VALIDITY = 5 * 365; // LDevID validity in Days. + public static final long CERT_VALIDITY_DAYS = 5 * 365; // LDevID validity in Days. + public static final long CERT_VALIDITY_MILLISECONDS = CERT_VALIDITY_DAYS * 24 * 3600 * 1000; } diff --git a/src/main/java/com/google/openthread/NetworkUtils.java b/src/main/java/com/google/openthread/NetworkUtils.java index f4c3d04..f25d728 100644 --- a/src/main/java/com/google/openthread/NetworkUtils.java +++ b/src/main/java/com/google/openthread/NetworkUtils.java @@ -39,8 +39,9 @@ public class NetworkUtils { /** * Returns the IPv6-specific host string for a global address of the current host. For example, - * "[2001:db8::3]". If no global IPv6 available it returns "[::1]". It will try to find an address - * over all interfaces. + * "[2a01:7e01::ca98]". If no global IPv6 available it returns "[::1]". It will try to find an address + * over all interfaces. It will avoid the example IPv6 addresses "[2001:db8:...]" which may be used + * by Docker. * * @return IPv6-specific host string or "[::1]" if no global address available. */ @@ -49,6 +50,7 @@ public static String getIPv6Host() throws UnknownHostException, SocketException Enumeration nifs; InetAddress addr; String retVal = "[::1]"; + String addrStr; nifs = NetworkInterface.getNetworkInterfaces(); // look for addresses per NIF @@ -57,10 +59,12 @@ public static String getIPv6Host() throws UnknownHostException, SocketException Enumeration nifAddrs = nif.getInetAddresses(); while (nifAddrs.hasMoreElements()) { addr = nifAddrs.nextElement(); + addrStr = addr.getHostAddress(); if (addr instanceof Inet6Address && !addr.isLinkLocalAddress() && !addr.isLoopbackAddress() - && !addr.isSiteLocalAddress()) { + && !addr.isSiteLocalAddress() + && !addrStr.startsWith("2001:db8")) { // ((Inet6Address) addr).getScopeId() // could check for scope id retVal = "[" + addr.getHostAddress() + "]"; } diff --git a/src/main/java/com/google/openthread/SecurityUtils.java b/src/main/java/com/google/openthread/SecurityUtils.java index 63aa1aa..4102a90 100644 --- a/src/main/java/com/google/openthread/SecurityUtils.java +++ b/src/main/java/com/google/openthread/SecurityUtils.java @@ -96,7 +96,6 @@ import org.bouncycastle.cms.CMSSignedData; import org.bouncycastle.cms.CMSSignedDataGenerator; import org.bouncycastle.cms.CMSTypedData; -import org.bouncycastle.cms.SignerId; import org.bouncycastle.cms.SignerInfoGenerator; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.cms.SignerInformationStore; @@ -463,7 +462,7 @@ public static X509Certificate genCertificate( new X500Name(issuerName), allocateSerialNumber(), new Date(System.currentTimeMillis()), - new Date(System.currentTimeMillis() + (1000L * 3600 * 24 * Constants.CERT_VALIDITY)), + new Date(System.currentTimeMillis() + Constants.CERT_VALIDITY_MILLISECONDS), new X500Name(subName), subPub); diff --git a/src/main/java/com/google/openthread/brski/CBORSerializer.java b/src/main/java/com/google/openthread/brski/CBORSerializer.java index 9edc112..67dfac6 100644 --- a/src/main/java/com/google/openthread/brski/CBORSerializer.java +++ b/src/main/java/com/google/openthread/brski/CBORSerializer.java @@ -40,7 +40,7 @@ public class CBORSerializer implements VoucherSerializer { protected CBORObject container; protected int parentSid = 0; - private static Logger logger = LoggerFactory.getLogger(CBORSerializer.class); + private static final Logger logger = LoggerFactory.getLogger(CBORSerializer.class); Voucher voucher; @Override @@ -191,7 +191,7 @@ public Voucher fromCBOR(CBORObject cbor) { break; } } catch (Exception e) { - logger.error("bad voucher: " + e.getMessage(), e); + logger.error("bad voucher: {}", e.getMessage(), e); return null; } diff --git a/src/main/java/com/google/openthread/domainca/DomainCA.java b/src/main/java/com/google/openthread/domainca/DomainCA.java index a7bc2b1..afa85b4 100644 --- a/src/main/java/com/google/openthread/domainca/DomainCA.java +++ b/src/main/java/com/google/openthread/domainca/DomainCA.java @@ -118,7 +118,7 @@ public X509Certificate signCertificate(PKCS10CertificationRequest csr) throws Ex X500Name issuer = getSubjectName(); BigInteger serial = allocateSerialNumber(); Date notBefore = new Date(); - Date notAfter = new Date(System.currentTimeMillis() + Constants.CERT_VALIDITY * 3600 * 24 * 1000); + Date notAfter = new Date(System.currentTimeMillis() + Constants.CERT_VALIDITY_MILLISECONDS); X509v3CertificateBuilder builder = new X509v3CertificateBuilder(issuer, serial, notBefore, notAfter, csr.getSubject(), csr.getSubjectPublicKeyInfo()); logger.info("operational certificate not-before: " + notBefore.toString()); From 96d79b5265a2b5c06f61e53d37c42383840fc2c1 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Sun, 1 Sep 2024 21:45:56 +0200 Subject: [PATCH 24/25] [all] more log levels, new log format. --- .../google/openthread/LoggerInitializer.java | 45 +++++++++++++++++-- .../openthread/main/OtRegistrarConfig.java | 33 +++++++++++--- .../openthread/main/OtRegistrarMain.java | 39 +++++++++++++--- .../com/google/openthread/pledge/Pledge.java | 2 + .../google/openthread/pledge/PledgeMain.java | 2 +- src/main/resources/logback.xml | 11 +++++ 6 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 src/main/resources/logback.xml diff --git a/src/main/java/com/google/openthread/LoggerInitializer.java b/src/main/java/com/google/openthread/LoggerInitializer.java index f4af99c..eba38de 100644 --- a/src/main/java/com/google/openthread/LoggerInitializer.java +++ b/src/main/java/com/google/openthread/LoggerInitializer.java @@ -38,10 +38,41 @@ public class LoggerInitializer { private static final String OPENTHREAD = "com.google.openthread"; private static final String CALIFORNIUM = "org.eclipse.californium"; + private static final String XNIO = "org.xnio"; + private static final String JBOSS = "org.jboss"; + private static final String UNDERTOW = "io.undertow"; - public static void Init(boolean verbose) { - final Level level = verbose ? Level.DEBUG : Level.INFO; - final Level levelLibrary = verbose ? Level.INFO : Level.WARN; + public static void Init(int verbosity) { + Level level, levelLibrary; + + switch (verbosity) { + case 0: + level = Level.WARN; + levelLibrary = Level.ERROR; + break; + case 1: + level = Level.INFO; + levelLibrary = Level.WARN; + break; + case 2: + level = Level.DEBUG; + levelLibrary = Level.INFO; + break; + case 3: + level = Level.DEBUG; + levelLibrary = Level.DEBUG; + break; + case 4: + level = Level.TRACE; + levelLibrary = Level.DEBUG; + break; + case 5: + level = Level.TRACE; + levelLibrary = Level.TRACE; + break; + default: + throw new IllegalArgumentException("verbosity parameter must be <= 5"); + } LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory(); List loggerList = loggerContext.getLoggerList(); @@ -51,11 +82,19 @@ public static void Init(boolean verbose) { logger.setLevel(level); break; case CALIFORNIUM: + case XNIO: + case JBOSS: + case UNDERTOW: logger.setLevel(levelLibrary); break; } } + ((Logger)LoggerFactory.getLogger(OPENTHREAD)).setLevel(level); + ((Logger)LoggerFactory.getLogger(CALIFORNIUM)).setLevel(levelLibrary); + ((Logger)LoggerFactory.getLogger(XNIO)).setLevel(levelLibrary); + ((Logger)LoggerFactory.getLogger(JBOSS)).setLevel(levelLibrary); + ((Logger)LoggerFactory.getLogger(UNDERTOW)).setLevel(levelLibrary); } } diff --git a/src/main/java/com/google/openthread/main/OtRegistrarConfig.java b/src/main/java/com/google/openthread/main/OtRegistrarConfig.java index f051535..5062433 100644 --- a/src/main/java/com/google/openthread/main/OtRegistrarConfig.java +++ b/src/main/java/com/google/openthread/main/OtRegistrarConfig.java @@ -38,7 +38,7 @@ public class OtRegistrarConfig { public String keyStoreFile; public String masaUri; public String registrarUri; - public boolean logVerbose; + public int logVerbosity; static OtRegistrarConfig DefaultPledge() { OtRegistrarConfig config = new OtRegistrarConfig(); @@ -48,7 +48,7 @@ static OtRegistrarConfig DefaultPledge() { config.keyStoreFile = "./credentials/default_pledge.p12"; config.masaUri = null; config.registrarUri = "coaps://localhost:5684"; - config.logVerbose = false; + config.logVerbosity = 0; return config; } @@ -60,7 +60,7 @@ static OtRegistrarConfig DefaultRegistrar() { config.keyStoreFile = "./credentials/default_registrar.p12"; config.masaUri = null; config.registrarUri = null; - config.logVerbose = false; + config.logVerbosity = 0; return config; } @@ -72,7 +72,7 @@ static OtRegistrarConfig DefaultMasa() { config.keyStoreFile = "./credentials/default_masa.p12"; config.masaUri = null; config.registrarUri = null; - config.logVerbose = false; + config.logVerbosity = 0; return config; } @@ -94,7 +94,28 @@ public String ToString() { if (this.registrarUri != null) { s += "Registrar URI : " + this.registrarUri + "\n"; } - s += "Log verbose : " + (this.logVerbose ? "yes" : "no") + "\n"; + s += "Log verbosity : " + this.logVerbosity + "\n"; return s; } -} + + public String ToStringSingleLine() { + String s; + s = "role=" + role.toString(); + if (this.serverPort > 0) { + s += " port=" + this.serverPort; + } + if (this.domainName != null) { + s += " domain=" + this.domainName; + } + if (this.keyStoreFile != null) { + s += " keyfile=" + this.keyStoreFile; + } + if (this.masaUri != null) { + s += " masaUri=" + this.masaUri; + } + if (this.registrarUri != null) { + s += " registrarUri=" + this.registrarUri; + } + s += " verbosity=" + this.logVerbosity; + return s; + }} diff --git a/src/main/java/com/google/openthread/main/OtRegistrarMain.java b/src/main/java/com/google/openthread/main/OtRegistrarMain.java index b177b08..279bdf7 100644 --- a/src/main/java/com/google/openthread/main/OtRegistrarMain.java +++ b/src/main/java/com/google/openthread/main/OtRegistrarMain.java @@ -50,7 +50,7 @@ public final class OtRegistrarMain { public static void main(String[] args) { - final String HELP_FORMAT = "[-registrar | -masa | -pledge] [-h] [-v] [-d ] [-f ] [-p ]"; + final String HELP_FORMAT = "[-registrar | -masa | -pledge] [-h] [-d ] [-f ] [-p ] [-v] [-vv] [-vvv] [-vvvv]"; HelpFormatter helper = new HelpFormatter(); Options options = new Options(); @@ -97,7 +97,22 @@ public static void main(String[] args) { Option verboseOpt = Option.builder("v") .longOpt("verbose") - .desc("verbose mode with many logs") + .desc("verbose mode for logs") + .build(); + + Option verboseVvOpt = + Option.builder("vv") + .desc("more verbose mode for logs") + .build(); + + Option verboseVvvOpt = + Option.builder("vvv") + .desc("even more verbose mode for logs") + .build(); + + Option verboseVvvvOpt = + Option.builder("vvvv") + .desc("most verbose mode for logs") .build(); Option masaUriOpt = @@ -130,6 +145,9 @@ public static void main(String[] args) { .addOption(fileOpt) .addOption(portOpt) .addOption(verboseOpt) + .addOption(verboseVvOpt) + .addOption(verboseVvvOpt) + .addOption(verboseVvvvOpt) .addOption(masaUriOpt) .addOption(registrarUriOpt) .addOption(helpOpt); @@ -156,10 +174,20 @@ public static void main(String[] args) { return; } + config.logVerbosity = 0; if (cmd.hasOption('v')) { - config.logVerbose = true; + config.logVerbosity = 1; + } + if (cmd.hasOption("vv")) { + config.logVerbosity = 2; + } + if (cmd.hasOption("vvv")) { + config.logVerbosity = 3; + } + if (cmd.hasOption("vvvv")) { + config.logVerbosity = 4; } - LoggerInitializer.Init(config.logVerbose); + LoggerInitializer.Init(config.logVerbosity); if (cmd.hasOption('f')) { config.keyStoreFile = cmd.getOptionValue('f'); @@ -180,7 +208,8 @@ public static void main(String[] args) { return; } - logger.info("Configuration:\n{}", config.ToString()); + logger.info("Configuration: {}", config.ToStringSingleLine()); + System.out.println("Configuration :\n" + config.ToString()); switch (config.role) { case Registrar: diff --git a/src/main/java/com/google/openthread/pledge/Pledge.java b/src/main/java/com/google/openthread/pledge/Pledge.java index 08f1385..f57ec5e 100644 --- a/src/main/java/com/google/openthread/pledge/Pledge.java +++ b/src/main/java/com/google/openthread/pledge/Pledge.java @@ -593,6 +593,7 @@ private CoapResponse sendRequestVoucher(VoucherRequest voucherRequest) // store the transmitted PVR this.lastPvr = voucherRequest; this.lastPvrCoseSigned = payload; + logger.debug("Voucher request: CoAP POST {} ", getURI()); return post(payload, ExtendedMediaTypeRegistry.APPLICATION_VOUCHER_COSE_CBOR); } @@ -672,6 +673,7 @@ private void initEndpoint( // here send a 'CoAP ping' to registrar to have this session built. private void connect() { setURI(getBRSKIPath()); + logger.debug("DTLS session establishment and sending CoAP ping..."); ping(); } diff --git a/src/main/java/com/google/openthread/pledge/PledgeMain.java b/src/main/java/com/google/openthread/pledge/PledgeMain.java index cec8f85..5f9a92e 100644 --- a/src/main/java/com/google/openthread/pledge/PledgeMain.java +++ b/src/main/java/com/google/openthread/pledge/PledgeMain.java @@ -95,7 +95,7 @@ private static void runCli(Pledge pledge) { System.out.println(help); break; default: - logger.error("unknown CLI command: {}", cmd); + logger.error("unknown CLI command: '{}'", cmd); System.out.println(help); } diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..f248160 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,11 @@ + + + + %date %-5level %-38(%logger{36}) -- %-64(%msg) [%thread]%n + + + + + + + \ No newline at end of file From 0be65c5038de6ce9bde53e044084b6e84b88c207 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Sun, 1 Sep 2024 22:19:20 +0200 Subject: [PATCH 25/25] [registrar] add log msg for newly signed LDevID cert. --- .../java/com/google/openthread/pledge/Pledge.java | 8 +++----- .../com/google/openthread/registrar/Registrar.java | 14 ++++++-------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/google/openthread/pledge/Pledge.java b/src/main/java/com/google/openthread/pledge/Pledge.java index f57ec5e..adb7949 100644 --- a/src/main/java/com/google/openthread/pledge/Pledge.java +++ b/src/main/java/com/google/openthread/pledge/Pledge.java @@ -420,14 +420,12 @@ public void enroll() throws Exception { cert.verify(domainPublicKey); subjectName = cert.getSubjectX500Principal().getName(); - logger.info("enrolled with operational certificate, subject: " + subjectName); + logger.info("enrolled with operational certificate, subject: {}", subjectName); operationalCertificate = cert; - logger.info( - "operational certificate (PEM): \n" + SecurityUtils.toPEMFormat(operationalCertificate)); - logger.info( - "operational private key (PEM): \n" + SecurityUtils.toPEMFormat(operationalKeyPair)); + logger.info("operational certificate (PEM): \n{}", SecurityUtils.toPEMFormat(operationalCertificate)); + logger.info("operational private key (PEM): \n{}", SecurityUtils.toPEMFormat(operationalKeyPair)); } /** diff --git a/src/main/java/com/google/openthread/registrar/Registrar.java b/src/main/java/com/google/openthread/registrar/Registrar.java index 7ec926c..4ef90a5 100644 --- a/src/main/java/com/google/openthread/registrar/Registrar.java +++ b/src/main/java/com/google/openthread/registrar/Registrar.java @@ -282,9 +282,7 @@ public void handlePOST(CoapExchange exchange) { // TODO: check latest draft if JSON mandatory here too. if (contentFormat != ExtendedMediaTypeRegistry.APPLICATION_CBOR) { - logger.warn( - "unexpected content format for enroll status report: content-format=" - + contentFormat); + logger.warn("unexpected content format for enroll status report: content-format={}", contentFormat); exchange.respond( ResponseCode.UNSUPPORTED_CONTENT_FORMAT, "Only Content Format " + ExtendedMediaTypeRegistry.APPLICATION_CBOR + " supported."); @@ -293,10 +291,8 @@ public void handlePOST(CoapExchange exchange) { enrollStatus = StatusTelemetry.deserialize(exchange.getRequestPayload()); if (enrollStatus.cbor == null) { - logger.warn( - "status telemetry report message decoding error: " + enrollStatus.parseResultStatus); - exchange.respond( - ResponseCode.BAD_REQUEST, "payload error: " + enrollStatus.parseResultStatus); + logger.warn("status telemetry report message decoding error: {}", enrollStatus.parseResultStatus); + exchange.respond(ResponseCode.BAD_REQUEST, "payload error: " + enrollStatus.parseResultStatus); return; } @@ -724,12 +720,14 @@ public void handlePOST(CoapExchange exchange) { PKCS10CertificationRequest csr = new PKCS10CertificationRequest(payload); X509Certificate cert = domainCA.signCertificate(csr); + logger.info("Signed new LDevID cert: subj=[{}]\n{}", cert.getSubjectX500Principal().toString(), SecurityUtils.toPEMFormat(cert)); + exchange.respond( ResponseCode.CHANGED, cert.getEncoded(), ExtendedMediaTypeRegistry.APPLICATION_PKIX_CERT); } catch (Exception e) { - logger.warn("sign certificate failed: " + e.getMessage(), e); + logger.warn("sign certificate failed: {}", e.getMessage(), e); // TODO(wgtdkp): exchange.respond(ResponseCode.INTERNAL_SERVER_ERROR); return;