in jsign-core/src/main/java/net/jsign/SignerHelper.java [271:467]
private AuthenticodeSigner build() throws SignerException {
PrivateKey privateKey;
Certificate[] chain;
// some exciting parameter validation...
if (keystore == null && keyfile == null && certfile == null && !"YUBIKEY".equals(storetype) && !"DIGICERTONE".equals(storetype)) {
throw new SignerException("keystore " + parameterName + ", or keyfile and certfile " + parameterName + "s must be set");
}
if (keystore != null && keyfile != null) {
throw new SignerException("keystore " + parameterName + " can't be mixed with keyfile");
}
if ("AZUREKEYVAULT".equals(storetype)) {
if (keystore == null) {
throw new SignerException("keystore " + parameterName + " must specify the Azure vault name");
}
if (storepass == null) {
throw new SignerException("storepass " + parameterName + " must specify the Azure API access token");
}
} else if ("DIGICERTONE".equals(storetype)) {
if (storepass == null || storepass.split("\\|").length != 3) {
throw new SignerException("storepass " + parameterName + " must specify the DigiCert ONE API key and the client certificate: <apikey>|<keystore>|<password>");
}
} else if ("GOOGLECLOUD".equals(storetype)) {
if (keystore == null) {
throw new SignerException("keystore " + parameterName + " must specify the Goole Cloud keyring");
}
if (storepass == null) {
throw new SignerException("storepass " + parameterName + " must specify the Goole Cloud API access token");
}
if (certfile == null) {
throw new SignerException("certfile " + parameterName + " must be set");
}
}
Provider provider = null;
if ("PKCS11".equals(storetype)) {
// the keystore parameter is either the provider name or the SunPKCS11 configuration file
if (keystore != null && keystore.exists()) {
provider = ProviderUtils.createSunPKCS11Provider(keystore.getPath());
} else if (keystore != null && keystore.getName().startsWith("SunPKCS11-")) {
provider = Security.getProvider(keystore.getName());
if (provider == null) {
throw new SignerException("Security provider " + keystore.getName() + " not found");
}
} else {
throw new SignerException("keystore " + parameterName + " should either refer to the SunPKCS11 configuration file or to the name of the provider configured in jre/lib/security/java.security");
}
} else if ("YUBIKEY".equals(storetype)) {
provider = YubiKey.getProvider();
} else if ("AZUREKEYVAULT".equals(storetype)) {
provider = new SigningServiceJcaProvider(new AzureKeyVaultSigningService(keystore.getName(), storepass));
} else if ("DIGICERTONE".equals(storetype)) {
String[] elements = storepass.split("\\|");
provider = new SigningServiceJcaProvider(new DigiCertOneSigningService(elements[0], new File(elements[1]), elements[2]));
} else if ("GOOGLECLOUD".equals(storetype)) {
provider = new SigningServiceJcaProvider(new GoogleCloudSigningService(keystore.getPath(), storepass, alias -> {
try {
return loadCertificateChain(certfile);
} catch (IOException | CertificateException e) {
throw new RuntimeException("Failed to load the certificate from " + certfile, e);
}
}));
}
if (keystore != null || "YUBIKEY".equals(storetype) || "DIGICERTONE".equals(storetype)) {
KeyStore ks;
try {
ks = KeyStoreUtils.load(keystore, "YUBIKEY".equals(storetype) ? "PKCS11" : storetype, storepass, provider);
} catch (KeyStoreException e) {
throw new SignerException("Failed to load the keystore " + keystore, e);
}
Set<String> aliases = null;
if (alias == null) {
if ("YUBIKEY".equals(storetype)) {
alias = "X.509 Certificate for Digital Signature";
} else {
// guess the alias if there is only one in the keystore
try {
aliases = new LinkedHashSet<>(Collections.list(ks.aliases()));
} catch (KeyStoreException e) {
throw new SignerException(e.getMessage(), e);
}
if (aliases.isEmpty()) {
throw new SignerException("No certificate found in the keystore " + (provider != null ? provider.getName() : keystore));
} else if (aliases.size() == 1) {
alias = aliases.iterator().next();
} else {
throw new SignerException("alias " + parameterName + " must be set to select a certificate (available aliases: " + String.join(", ", aliases) + ")");
}
}
}
try {
chain = ks.getCertificateChain(alias);
} catch (KeyStoreException e) {
throw new SignerException(e.getMessage(), e);
}
if (chain == null) {
String message = "No certificate found under the alias '" + alias + "' in the keystore " + (provider != null ? provider.getName() : keystore);
if (aliases == null) {
try {
aliases = new LinkedHashSet<>(Collections.list(ks.aliases()));
if (aliases.isEmpty()) {
message = "No certificate found in the keystore " + (provider != null ? provider.getName() : keystore);
} else {
message += " (available aliases: " + String.join(", ", aliases) + ")";
}
} catch (KeyStoreException e) {
message += " (couldn't load the list of available aliases: " + e.getMessage() + ")";
}
}
throw new SignerException(message);
}
if (certfile != null && !"GOOGLECLOUD".equals(storetype)) {
if (chain.length != 1) {
throw new SignerException("certfile " + parameterName + " can only be specified if the certificate from the keystore contains only one entry");
}
// replace the certificate chain from the keystore with the complete chain from file
try {
Certificate[] chainFromFile = loadCertificateChain(certfile);
if (chainFromFile[0].equals(chain[0])) {
// replace certificate with complete chain
chain = chainFromFile;
} else {
throw new SignerException("The certificate chain in " + certfile + " does not match the chain from the keystore");
}
} catch (SignerException e) {
throw e;
} catch (Exception e) {
throw new SignerException("Failed to load the certificate from " + certfile, e);
}
}
char[] password = keypass != null ? keypass.toCharArray() : storepass.toCharArray();
try {
privateKey = (PrivateKey) ks.getKey(alias, password);
} catch (Exception e) {
throw new SignerException("Failed to retrieve the private key from the keystore", e);
}
} else {
// separate private key and certificate files (PVK/SPC)
if (keyfile == null) {
throw new SignerException("keyfile " + parameterName + " must be set");
}
if (!keyfile.exists()) {
throw new SignerException("The keyfile " + keyfile + " couldn't be found");
}
if (certfile == null) {
throw new SignerException("certfile " + parameterName + " must be set");
}
if (!certfile.exists()) {
throw new SignerException("The certfile " + certfile + " couldn't be found");
}
// load the certificate chain
try {
chain = loadCertificateChain(certfile);
} catch (Exception e) {
throw new SignerException("Failed to load the certificate from " + certfile, e);
}
// load the private key
try {
privateKey = PrivateKeyUtils.load(keyfile, keypass != null ? keypass : storepass);
} catch (Exception e) {
throw new SignerException("Failed to load the private key from " + keyfile, e);
}
}
if (alg != null && DigestAlgorithm.of(alg) == null) {
throw new SignerException("The digest algorithm " + alg + " is not supported");
}
try {
initializeProxy(proxyUrl, proxyUser, proxyPass);
} catch (Exception e) {
throw new SignerException("Couldn't initialize proxy", e);
}
// configure the signer
return new AuthenticodeSigner(chain, privateKey)
.withProgramName(name)
.withProgramURL(url)
.withDigestAlgorithm(DigestAlgorithm.of(alg))
.withSignatureProvider(provider)
.withSignaturesReplaced(replace)
.withTimestamping(tsaurl != null || tsmode != null)
.withTimestampingMode(tsmode != null ? TimestampingMode.of(tsmode) : TimestampingMode.AUTHENTICODE)
.withTimestampingRetries(tsretries)
.withTimestampingRetryWait(tsretrywait)
.withTimestampingAuthority(tsaurl != null ? tsaurl.split(",") : null);
}