Files
yubikey-ca/yubikey-ca-java/src/main/java/me/hatter/tools/yubikeyca/YubikeyCaMain.java

203 lines
7.7 KiB
Java

package me.hatter.tools.yubikeyca;
import me.hatter.tools.commons.collection.Tuple2;
import me.hatter.tools.commons.log.LogConfig;
import me.hatter.tools.commons.log.LogTool;
import me.hatter.tools.commons.log.LogTools;
import me.hatter.tools.commons.security.cert.X509CertUtil;
import me.hatter.tools.commons.security.key.KeyPairTool;
import me.hatter.tools.commons.security.key.KeyUtil;
import me.hatter.tools.commons.security.key.PKType;
import me.hatter.tools.commons.string.StringUtil;
import me.hatter.tools.crypto.ca.CertificateAuthority;
import me.hatter.tools.yubikeyca.cardcli.CardCliPivCustomerSigner;
import me.hatter.tools.yubikeyca.cardcli.CardCliUtil;
import me.hatter.tools.yubikeyca.hatterink.CertificateUtil;
import java.security.KeyPair;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Optional;
public class YubikeyCaMain {
private static final LogTool log;
static {
LogConfig.initMuteInfoMode();
log = LogTools.getLogTool(YubikeyCaMain.class);
}
public static void main(String[] stringArgs) {
final YubikeyCaArgs args = YubikeyCaArgsUtil.parseArgs(stringArgs);
if (args == null) {
return;
}
if (args.generateKeypair) {
generateKeyPair(args);
return;
}
if (args.issueRootCa) {
issueRootCa(args);
return;
}
if (args.issueIntermediateCa) {
issueIntermediateCa(args);
return;
}
if (args.issueServerCa || args.issueClientCa) {
issueServerClientCa(args);
return;
}
log.error("Unknown command, use --help for help");
}
private static void issueServerClientCa(YubikeyCaArgs args) {
if (checkCertificateArgs(args)) return;
if (StringUtil.isEmpty(args.intermediateCaId)) {
log.error("Intermediate CA id is required.");
return;
}
if (StringUtil.isEmpty(args.keypairType)) {
log.error("Keypair type is required.");
return;
}
if (args.issueServerCa && (args.dnsNames == null || args.dnsNames.length == 0)) {
log.error("DNS name is required.");
return;
}
final PKType pkType = getPkTypeFromArgs(args);
if (pkType == null) return;
final X509Certificate intermediateCertificate = CertificateUtil.getCertificate(args.pin, args.intermediateCaId);
final Tuple2<String, PublicKey> signPivPublicKey = CardCliUtil.getPivPublicKey(args.signSlot);
final String signAlgorithm = signPivPublicKey.getVal1();
final KeyPair keyPair = KeyPairTool.instance(pkType).generateKeyPair().getKeyPair();
final String cardCliCmd = CardCliUtil.getCardCliCmd();
final CertificateAuthority ca = CertificateAuthority.instance()
.subject(args.subject)
.signCert(intermediateCertificate)
.certPubKey(keyPair.getPublic())
.validYears(2)
.customerSigner(new CardCliPivCustomerSigner(args.pin, args.signSlot, signAlgorithm, cardCliCmd));
final X509Certificate cert;
if (args.issueServerCa) {
cert = ca.createServerCert(Arrays.asList(args.dnsNames));
} else {
cert = ca.createClientCert();
}
final String certPem = X509CertUtil.serializeX509CertificateToPEM(cert);
final String privateKeyPem = KeyUtil.serializePrivateKeyToPEM(keyPair.getPrivate());
log.info("Issued CA: \n" + certPem);
if (args.addToRemote) {
CertificateUtil.addCertificate(args.pin, args.intermediateCaId, args.memo, certPem, privateKeyPem);
} else {
log.info("Issued CA private Key: \n" + privateKeyPem);
}
}
private static void issueIntermediateCa(YubikeyCaArgs args) {
if (checkCertificateArgs(args)) return;
if (StringUtil.isEmpty(args.rootCaId)) {
log.error("Root CA id is required.");
return;
}
if (StringUtil.isEmpty(args.certSlot)) {
log.error("Cert slot is required.");
return;
}
final X509Certificate rootCertificate = CertificateUtil.getCertificate(args.pin, args.rootCaId);
final Tuple2<String, PublicKey> certPivPublicKey = CardCliUtil.getPivPublicKey(args.certSlot);
final String signAlgorithm = certPivPublicKey.getVal1();
final PublicKey certPublicKey = certPivPublicKey.getVal2();
final String cardCliCmd = CardCliUtil.getCardCliCmd();
final X509Certificate intermediateCa = CertificateAuthority.instance()
.subject(args.subject)
.signCert(rootCertificate)
.certPubKey(certPublicKey)
.validYears(10)
.customerSigner(new CardCliPivCustomerSigner(args.pin, args.signSlot, signAlgorithm, cardCliCmd))
.createIntermediateCert();
final String intermediateCaPem = X509CertUtil.serializeX509CertificateToPEM(intermediateCa);
log.info("Issued intermediate CA: " + intermediateCaPem);
if (args.addToRemote) {
CertificateUtil.addCertificate(args.pin, args.rootCaId, args.memo, intermediateCaPem, null);
}
}
private static void issueRootCa(YubikeyCaArgs args) {
if (checkCertificateArgs(args)) return;
final Tuple2<String, PublicKey> signPivPublicKey = CardCliUtil.getPivPublicKey(args.signSlot);
final String signAlgorithm = signPivPublicKey.getVal1();
final PublicKey certPublicKey = signPivPublicKey.getVal2();
final String cardCliCmd = CardCliUtil.getCardCliCmd();
final X509Certificate rootCa = CertificateAuthority.instance()
.subject(args.subject)
.certPubKey(certPublicKey)
.validYears(40)
.customerSigner(new CardCliPivCustomerSigner(args.pin, args.signSlot, signAlgorithm, cardCliCmd))
.createCA();
final String rootCaPem = X509CertUtil.serializeX509CertificateToPEM(rootCa);
log.info("Issued root CA: " + rootCaPem);
if (args.addToRemote) {
CertificateUtil.addCertificate(args.pin, null, args.memo, rootCaPem, null);
}
}
private static boolean checkCertificateArgs(YubikeyCaArgs args) {
if (StringUtil.isEmpty(args.signSlot)) {
log.error("Sign slot is required.");
return true;
}
if (StringUtil.isEmpty(args.subject)) {
log.error("Certificate subject is required.");
return true;
}
if (StringUtil.isEmpty(args.pin)) {
log.error("PIV PIN is required.");
return true;
}
return false;
}
private static void generateKeyPair(YubikeyCaArgs args) {
final PKType pkType = getPkTypeFromArgs(args);
if (pkType == null) return;
final KeyPair keyPair = KeyPairTool.instance(pkType).generateKeyPair().getKeyPair();
System.out.println("Private key:\n" + KeyUtil.serializePrivateKeyToPEM(keyPair.getPrivate()) + "\n");
System.out.println("Public key: \n" + KeyUtil.serializePublicKeyToPEM(keyPair.getPublic()) + "\n");
}
private static PKType getPkTypeFromArgs(YubikeyCaArgs args) {
if (StringUtil.isEmpty(args.keypairType)) {
log.error("Keypair type is required.");
return null;
}
Optional<PKType> pkTypeOpt = Arrays.stream(PKType.values())
.filter(t -> t.name().equalsIgnoreCase(args.keypairType))
.findFirst();
if (!pkTypeOpt.isPresent()) {
log.error("Invalid keypair type: " + args.keypairType);
return null;
}
return pkTypeOpt.get();
}
}