Skip to content

Commit

Permalink
add -cert -truststore option to server-demo (deprecate keystore options)
Browse files Browse the repository at this point in the history
  • Loading branch information
sbernard31 committed May 6, 2020
1 parent 646837c commit f374e34
Showing 1 changed file with 125 additions and 29 deletions.
Expand Up @@ -19,6 +19,7 @@

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.BindException;
import java.net.InetAddress;
Expand Down Expand Up @@ -136,7 +137,7 @@ public class LeshanServerDemo {

private final static String DEFAULT_KEYSTORE_ALIAS = "leshan";

public static void main(String[] args) {
public static void main(String[] args) throws FileNotFoundException {
// Define options for command line tools
Options options = new Options();

Expand All @@ -156,14 +157,29 @@ public static void main(String[] args) {
final StringBuilder X509Chapter = new StringBuilder();
X509Chapter.append("\n .");
X509Chapter.append("\n .");
X509Chapter.append("\n ===============================[ X509 ]=================================");
X509Chapter.append("\n | By default Leshan demo uses an embedded self-signed certificate and |");
X509Chapter.append("\n | trusts any client certificates. |");
X509Chapter.append("\n | If you want to use your own server keys, certificates and truststore,|");
X509Chapter.append("\n | you can provide a keystore using -ks, -ksp, -kst, -ksa, -ksap. |");
X509Chapter.append("\n | To get helps about files format and how to generate it, see : |");
X509Chapter.append("\n | See https://github.com/eclipse/leshan/wiki/Credential-files-format |");
X509Chapter.append("\n ------------------------------------------------------------------------");
X509Chapter.append("\n===============================[ X509 ]=================================");
X509Chapter.append("\n| By default Leshan demo uses an embedded self-signed certificate and |");
X509Chapter.append("\n| trusts any client certificates allowing to use RPK or X509 |");
X509Chapter.append("\n| at client side. |");
X509Chapter.append("\n| To use X509 with your own server key, certificate and truststore : |");
X509Chapter.append("\n| [-cert, -prik], [-truststore] should be used together |");
X509Chapter.append("\n| To get helps about files format and how to generate it, see : |");
X509Chapter.append("\n| See https://github.com/eclipse/leshan/wiki/Credential-files-format |");
X509Chapter.append("\n------------------------------------------------------------------------");

final StringBuilder X509ChapterDeprecated = new StringBuilder();
X509ChapterDeprecated.append("\n .");
X509ChapterDeprecated.append("\n .");
X509ChapterDeprecated.append("\n=======================[ X509 deprecated way]===========================");
X509ChapterDeprecated.append("\n| By default Leshan demo uses an embedded self-signed certificate and |");
X509ChapterDeprecated.append("\n| trusts any client certificates allowing to use RPK or X509 |");
X509ChapterDeprecated.append("\n| at client side. |");
X509ChapterDeprecated.append("\n| If you want to use your own server keys, certificates and truststore,|");
X509ChapterDeprecated.append("\n| you can provide a keystore using : |");
X509ChapterDeprecated.append("\n| -ks, -ksp, [-kst], [-ksa], -ksap should be used together |");
X509ChapterDeprecated.append("\n| To get helps about files format and how to generate it, see : |");
X509ChapterDeprecated.append("\n| See https://github.com/eclipse/leshan/wiki/Credential-files-format |");
X509ChapterDeprecated.append("\n------------------------------------------------------------------------");

options.addOption("h", "help", false, "Display help information.");
options.addOption("lh", "coaphost", true, "Set the local CoAP address.\n Default: any local address.");
Expand All @@ -185,6 +201,13 @@ public static void main(String[] args) {
options.addOption("prik", true,
"The path to your server private key file.\nThe private key should be in PKCS#8 format (DER encoding)."
+ X509Chapter);
options.addOption("cert", true,
"The path to your server certificate file.\n"
+ "The certificate Common Name (CN) should generally be equal to the server hostname.\n"
+ "The certificate should be in X509v3 format (DER encoding).");
options.addOption("truststore", true,
"The path to a root certificate file to trust or a folder containing all the trusted certificates in X509v3 format (DER encoding).\n Default: All certificates are trusted which is only OK for a demo."
+ X509ChapterDeprecated);
options.addOption("ks", "keystore", true,
"Set the key store file.\nIf set, X.509 mode is enabled, otherwise built-in RPK credentials are used.");
options.addOption("ksp", "storepass", true, "Set the key store password.");
Expand Down Expand Up @@ -233,9 +256,22 @@ public static void main(String[] args) {
rpkConfig = true;
}
}
// Abort if prik is used without complete RPK

// Abort if all X509 config is not complete
boolean x509Config = false;
if (cl.hasOption("cert")) {
if (!cl.hasOption("prik")) {
System.err.println("cert, prik should be used together to connect using X509");
formatter.printHelp(USAGE, options);
return;
} else {
x509Config = true;
}
}

// Abort if prik is used without complete RPK or X509 config
if (cl.hasOption("prik")) {
if (!rpkConfig) {
if (!rpkConfig && !x509Config) {
System.err.println("prik should be used with cert for X509 config OR pubk for RPK config");
formatter.printHelp(USAGE, options);
return;
Expand Down Expand Up @@ -287,6 +323,46 @@ public static void main(String[] args) {
}
}

// get X509 info
X509Certificate certificate = null;
if (cl.hasOption("cert")) {
try {
privateKey = SecurityUtil.privateKey.readFromFile(cl.getOptionValue("prik"));
certificate = SecurityUtil.certificate.readFromFile(cl.getOptionValue("cert"));
} catch (Exception e) {
System.err.println("Unable to load X509 files : " + e.getMessage());
e.printStackTrace();
formatter.printHelp(USAGE, options);
return;
}
}

// get X509 info
List<Certificate> trustStore = null;
if (cl.hasOption("truststore")) {
trustStore = new ArrayList<>();
File input = new File(cl.getOptionValue("truststore"));

// check input exists
if (!input.exists())
throw new FileNotFoundException(input.toString());

// get input files.
File[] files;
if (input.isDirectory()) {
files = input.listFiles();
} else {
files = new File[] { input };
}
for (File file : files) {
try {
trustStore.add(SecurityUtil.certificate.readFromFile(file.getAbsolutePath()));
} catch (Exception e) {
LOG.warn("Unable to load X509 files {}:{} ", file.getAbsolutePath(), e.getMessage());
}
}
}

// Get keystore parameters
String keyStorePath = cl.getOptionValue("ks");
String keyStoreType = cl.getOptionValue("kst", KeyStore.getDefaultType());
Expand All @@ -299,8 +375,9 @@ public static void main(String[] args) {

try {
createAndStartServer(webAddress, webPort, localAddress, localPort, secureLocalAddress, secureLocalPort,
modelsFolderPath, redisUrl, publicKey, privateKey, keyStorePath, keyStoreType, keyStorePass,
keyStoreAlias, keyStoreAliasPass, publishDNSSdServices, cl.hasOption("oc"));
modelsFolderPath, redisUrl, publicKey, privateKey, certificate, trustStore, keyStorePath,
keyStoreType, keyStorePass, keyStoreAlias, keyStoreAliasPass, publishDNSSdServices,
cl.hasOption("oc"));
} catch (BindException e) {
System.err.println(
String.format("Web port %s is already used, you could change it using 'webport' option.", webPort));
Expand All @@ -312,9 +389,9 @@ public static void main(String[] args) {

public static void createAndStartServer(String webAddress, int webPort, String localAddress, int localPort,
String secureLocalAddress, int secureLocalPort, String modelsFolderPath, String redisUrl,
PublicKey publicKey, PrivateKey privateKey, String keyStorePath, String keyStoreType, String keyStorePass,
String keyStoreAlias, String keyStoreAliasPass, Boolean publishDNSSdServices,
boolean supportDeprecatedCiphers) throws Exception {
PublicKey publicKey, PrivateKey privateKey, X509Certificate certificate, List<Certificate> trustStore,
String keyStorePath, String keyStoreType, String keyStorePass, String keyStoreAlias,
String keyStoreAliasPass, Boolean publishDNSSdServices, boolean supportDeprecatedCiphers) throws Exception {
// Prepare LWM2M server
LeshanServerBuilder builder = new LeshanServerBuilder();
builder.setLocalAddress(localAddress, localPort);
Expand Down Expand Up @@ -347,8 +424,20 @@ public static void createAndStartServer(String webAddress, int webPort, String l
dtlsConfig.setRecommendedCipherSuitesOnly(!supportDeprecatedCiphers);

X509Certificate serverCertificate = null;
if (keyStorePath != null) {
// Set up X.509 mode (+ RPK)
if (certificate != null) {
// use X.509 mode (+ RPK)
serverCertificate = certificate;
builder.setPrivateKey(privateKey);
builder.setCertificateChain(new X509Certificate[] { serverCertificate });
} else if (publicKey != null) {
// use RPK only
builder.setPublicKey(publicKey);
builder.setPrivateKey(privateKey);
} else if (keyStorePath != null) {
LOG.warn(
"Keystore way [-ks, -ksp, -kst, -ksa, -ksap] is DEPRECATED for leshan demo and will probably be removed soon, please use [-cert, -prik, -truststore] options");

// Deprecated way : Set up X.509 mode (+ RPK)
try {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
try (FileInputStream fis = new FileInputStream(keyStorePath)) {
Expand All @@ -366,12 +455,12 @@ public static void createAndStartServer(String webAddress, int webPort, String l
System.exit(-1);
}

for (Certificate certificate : certificateChain) {
if (!(certificate instanceof X509Certificate)) {
LOG.error("Non-X.509 certificate in alias chain is not supported: {}", certificate);
for (Certificate cert : certificateChain) {
if (!(cert instanceof X509Certificate)) {
LOG.error("Non-X.509 certificate in alias chain is not supported: {}", cert);
System.exit(-1);
}
x509CertificateChain.add((X509Certificate) certificate);
x509CertificateChain.add((X509Certificate) cert);
}

Key key = keyStore.getKey(alias,
Expand All @@ -394,26 +483,33 @@ public static void createAndStartServer(String webAddress, int webPort, String l
LOG.error("Unable to initialize X.509.", e);
System.exit(-1);
}
} else if (publicKey != null) {
// use RPK only
builder.setPublicKey(publicKey);
builder.setPrivateKey(privateKey);
} else {
}

if (publicKey == null && serverCertificate == null) {
// public key or server certificated is not defined
// use default embedded credentials (X.509 + RPK mode)
try {
PrivateKey embeddedPrivateKey = SecurityUtil.privateKey
.readFromResource("credentials/server_privkey.der");
serverCertificate = SecurityUtil.certificate.readFromResource("credentials/server_cert.der");
builder.setPrivateKey(embeddedPrivateKey);
builder.setCertificateChain(new X509Certificate[] { serverCertificate });
/// Trust all certificates.
builder.setTrustedCertificates(new X509Certificate[0]);
} catch (Exception e) {
LOG.error("Unable to load embedded X.509 certificate.", e);
System.exit(-1);
}
}

// Define trust store
if (serverCertificate != null && keyStorePath == null) {
if (trustStore != null && !trustStore.isEmpty()) {
builder.setTrustedCertificates(trustStore.toArray(new Certificate[trustStore.size()]));
} else {
// by default trust all
builder.setTrustedCertificates(new X509Certificate[0]);
}
}

// Set DTLS Config
builder.setDtlsConfig(dtlsConfig);

Expand Down

0 comments on commit f374e34

Please sign in to comment.