201 lines
6.9 KiB
Java
201 lines
6.9 KiB
Java
/* BuildEdDSAKeystores.java
|
|
*
|
|
* Copyright (C) 2006-2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.InputStream;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Paths;
|
|
import java.nio.file.StandardCopyOption;
|
|
import java.security.KeyFactory;
|
|
import java.security.KeyStore;
|
|
import java.security.PrivateKey;
|
|
import java.security.Security;
|
|
import java.security.cert.Certificate;
|
|
import java.security.cert.CertificateFactory;
|
|
import java.security.spec.PKCS8EncodedKeySpec;
|
|
|
|
import com.wolfssl.provider.jce.WolfCryptProvider;
|
|
|
|
/**
|
|
* Build WKS (WolfSSLKeyStore) files containing Ed25519 and Ed448 cert/key
|
|
* pairs from the wolfssl certs/ed25519 and certs/ed448 files copied into
|
|
* examples/certs/ed25519 and examples/certs/ed448.
|
|
*
|
|
* Used by examples/certs/update-jks-wks.sh to generate the EdDSA test
|
|
* keystores used by WolfSSLKeyStoreTest.
|
|
*
|
|
* Compiles and runs on any JDK 8+ with wolfJCE installed. Does not require
|
|
* JDK 15 SunEC EdDSA support, keytool EdDSA awareness, or openssl.
|
|
*
|
|
* Usage: java -cp <wolfcrypt-jni.jar>:. BuildEdDSAKeystores [--check]
|
|
* (run from examples/certs/)
|
|
*
|
|
* With --check, exits 0 when wolfJCE has EdDSA support and 2 otherwise
|
|
* (used by update-jks-wks.sh to decide whether to regenerate). Ed448
|
|
* keystores are built only when Ed448 is compiled into native wolfSSL.
|
|
*/
|
|
public class BuildEdDSAKeystores {
|
|
|
|
private static final String[] CURVES = { "ed25519", "ed448" };
|
|
private static final char[] PASSWORD = "wolfsslpassword".toCharArray();
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
|
|
Security.addProvider(new WolfCryptProvider());
|
|
|
|
if (args.length > 0 && args[0].equals("--check")) {
|
|
try {
|
|
KeyFactory.getInstance("EdDSA", "wolfJCE");
|
|
System.exit(0);
|
|
}
|
|
catch (Exception e) {
|
|
System.exit(2);
|
|
}
|
|
}
|
|
|
|
int built = 0;
|
|
|
|
for (String curve : CURVES) {
|
|
String jcaName = curve.equals("ed25519") ? "Ed25519" : "Ed448";
|
|
KeyFactory kf;
|
|
try {
|
|
kf = KeyFactory.getInstance(jcaName, "wolfJCE");
|
|
}
|
|
catch (Exception e) {
|
|
System.out.println("\tSkipping " + jcaName +
|
|
", not compiled into native wolfSSL");
|
|
continue;
|
|
}
|
|
|
|
/* update-certs.sh skips missing files one by one. Check all inputs
|
|
* before building anything for this curve */
|
|
String[] inputs = {
|
|
curve + "/server-" + curve + ".der",
|
|
curve + "/server-" + curve + "-priv.der",
|
|
curve + "/client-" + curve + ".der",
|
|
curve + "/client-" + curve + "-priv.der",
|
|
curve + "/ca-" + curve + ".der"
|
|
};
|
|
String missing = null;
|
|
for (String in : inputs) {
|
|
if (!Files.exists(Paths.get(in))) {
|
|
missing = in;
|
|
break;
|
|
}
|
|
}
|
|
if (missing != null) {
|
|
System.out.println("\tSkipping " + jcaName + ", " + missing +
|
|
" not present");
|
|
continue;
|
|
}
|
|
|
|
/* server / client entity keystores: cert + private key, built
|
|
* as .tmp so a failure leaves the prebuilt files untouched */
|
|
for (String who : new String[] { "server", "client" }) {
|
|
String name = who + "-" + curve;
|
|
Certificate cert = loadDerCertificate(
|
|
curve + "/" + name + ".der");
|
|
PrivateKey priv = loadDerPkcs8PrivateKey(kf,
|
|
curve + "/" + name + "-priv.der");
|
|
buildWks(name + ".wks.tmp", name, priv,
|
|
new Certificate[] { cert });
|
|
}
|
|
|
|
/* CA truststore: the CA cert as a trusted entry */
|
|
buildWksTrustStore("ca-" + curve + ".wks.tmp", "ca-" + curve,
|
|
loadDerCertificate(curve + "/ca-" + curve + ".der"));
|
|
|
|
for (String who : new String[] { "server", "client", "ca" }) {
|
|
String name = who + "-" + curve + ".wks";
|
|
Files.move(Paths.get(name + ".tmp"), Paths.get(name),
|
|
StandardCopyOption.REPLACE_EXISTING);
|
|
}
|
|
built++;
|
|
}
|
|
|
|
/* a skipped curve is not an error, update-jks-wks.sh keeps its
|
|
* prebuilt keystores */
|
|
if (built == 0) {
|
|
System.out.println("No EdDSA WKS keystores built");
|
|
}
|
|
else {
|
|
System.out.println("Built EdDSA WKS keystores for " + built +
|
|
" curve(s)");
|
|
}
|
|
}
|
|
|
|
private static Certificate loadDerCertificate(String path)
|
|
throws Exception {
|
|
|
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
|
InputStream in = new FileInputStream(path);
|
|
|
|
try {
|
|
return cf.generateCertificate(in);
|
|
}
|
|
finally {
|
|
in.close();
|
|
}
|
|
}
|
|
|
|
private static PrivateKey loadDerPkcs8PrivateKey(KeyFactory kf,
|
|
String path) throws Exception {
|
|
|
|
byte[] der = Files.readAllBytes(Paths.get(path));
|
|
return kf.generatePrivate(new PKCS8EncodedKeySpec(der));
|
|
}
|
|
|
|
private static void buildWks(String fileName, String alias,
|
|
PrivateKey priv, Certificate[] chain) throws Exception {
|
|
|
|
KeyStore ks = KeyStore.getInstance("WKS", "wolfJCE");
|
|
ks.load(null, null);
|
|
ks.setKeyEntry(alias, priv, PASSWORD, chain);
|
|
|
|
FileOutputStream fos = new FileOutputStream(fileName);
|
|
try {
|
|
ks.store(fos, PASSWORD);
|
|
}
|
|
finally {
|
|
fos.close();
|
|
}
|
|
System.out.println("\tCreated " + fileName);
|
|
}
|
|
|
|
private static void buildWksTrustStore(String fileName, String alias,
|
|
Certificate cert) throws Exception {
|
|
|
|
KeyStore ks = KeyStore.getInstance("WKS", "wolfJCE");
|
|
ks.load(null, null);
|
|
ks.setCertificateEntry(alias, cert);
|
|
|
|
FileOutputStream fos = new FileOutputStream(fileName);
|
|
try {
|
|
ks.store(fos, PASSWORD);
|
|
}
|
|
finally {
|
|
fos.close();
|
|
}
|
|
System.out.println("\tCreated " + fileName);
|
|
}
|
|
}
|