From 3c09f3d47b9c435a0a21705be7d3f2e80a018689 Mon Sep 17 00:00:00 2001 From: Esko Dijk Date: Sun, 1 Sep 2024 22:28:07 +0200 Subject: [PATCH] New features and fixes for v0.3 (#25) * [src] removed CSRAttrs, not used in cBRSKI * [src] remove Commissioner class, tests and related ace-java dependency (was used for CWT-like/token function) * [pom.xml] bump versions to avoid log4j related performance WARNING msg. * removal of ACE, doc updates, src format updates, and new generic-main function WIP. * [registrar] enable -registrar option to run the registrar function. * restructuring code for main and option parsing. * [all] use dedicated configs for each role; fix logging init to right levels. * [all] moved code to right packages; split Constants into 3 separate files; source style formatting. * [all][tests] remove HW related code from repo; code and test updates to remove code warnings/deprecation warnings. * [masa] bugfix missing return statements and code warning fixes. * [pom.xml] set release level at 11 (hopefully that should cover all used std lib functions like readAllBytes()) * [script] added helper script to avoid code duplication; removed unneeded scripts. * [all] coaps URI bugfix; log fix to avoid Californium library logs to show up always; code formatting. * [script] rename Docker container to ot-registrar:latest and some updates. * [pom.xml][brski][registrar] added proper telemetry printing in log; telemetry logic fix; minor source format updates; WIP v0.3 * [doc][script] run scripts bumped to run 0.3; documentation added for 0.2 and 0.3 releases * [credentials] renamed p12 files for uniform structure. * [pom] remove unused jSerialComm dependency * [script] build script added * [test] fix test path; source formatting * [script] +x on script; version JAR bugfix * [masa] fix port binding issue on 'weird' interfaces on test PC. * [all] minor source fixes and clarifications; pom.xml libraries bumped * [all] more log levels, new log format. * [registrar] add log msg for newly signed LDevID cert. --- pom.xml | 23 +++++----- .../java/com/google/openthread/Constants.java | 5 ++- .../google/openthread/LoggerInitializer.java | 45 +++++++++++++++++-- .../com/google/openthread/NetworkUtils.java | 10 +++-- .../com/google/openthread/SecurityUtils.java | 2 +- .../openthread/brski/CBORSerializer.java | 4 +- .../google/openthread/domainca/DomainCA.java | 2 +- .../openthread/main/OtRegistrarConfig.java | 32 ++++++++++--- .../openthread/main/OtRegistrarMain.java | 39 +++++++++++++--- .../java/com/google/openthread/masa/MASA.java | 14 +++--- .../com/google/openthread/pledge/Pledge.java | 10 ++--- .../google/openthread/pledge/PledgeMain.java | 2 +- .../openthread/registrar/Registrar.java | 14 +++--- src/main/resources/logback.xml | 11 +++++ 14 files changed, 158 insertions(+), 55 deletions(-) create mode 100644 src/main/resources/logback.xml 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/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/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..d479eed 100644 --- a/src/main/java/com/google/openthread/SecurityUtils.java +++ b/src/main/java/com/google/openthread/SecurityUtils.java @@ -463,7 +463,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()); diff --git a/src/main/java/com/google/openthread/main/OtRegistrarConfig.java b/src/main/java/com/google/openthread/main/OtRegistrarConfig.java index f051535..eb04837 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,29 @@ 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/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(); } diff --git a/src/main/java/com/google/openthread/pledge/Pledge.java b/src/main/java/com/google/openthread/pledge/Pledge.java index 08f1385..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)); } /** @@ -593,6 +591,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 +671,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/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; 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