Da dies die erste Implementierung der XML-Signatur ist, habe ich beschlossen, fortzufahren und verschiedene Notizen zu hinterlassen.
Der obige Vorgang ist jedes Mal erforderlich, wenn das elektronische Zertifikat ersetzt wird.
Was ist "Normalisierung" elektronischer Zertifikate? http://www.atmarkit.co.jp/fxml/tanpatsu/16xmlsecurity/xmlsecurity02.html
Informationen zum RSA-Schlüssel- und Zertifikatdateiformat https://qiita.com/kunichiko/items/12cbccaadcbf41c72735
Extrahieren Sie den privaten Schlüssel, das Zertifikat und die Zwischenzertifizierungsstelle aus der PKCS # 12-Datei https://qiita.com/cs_sonar/items/f2753ffdebb1c67d5302
So erstellen Sie ein selbstsigniertes Zertifikat https://qiita.com/akito1986/items/8eb41f5a43bb9421ae79
XML-Signatur mit der XML-Signatur-API von Java http://qiita.com/KevinFQ/items/4e2484a659b618530e72
Keytool-Befehlsliste http://itref.fc2web.com/java/keytool.html
[Java] Zertifikate zum Schlüsselspeicher in Java hinzufügen / daraus löschen https://blogs.yahoo.co.jp/dk521123/37097725.html
Konvertieren Sie vom Serverzertifikat pem in crt
$ openssl x509 -outform der in server-crt.pem -out server-crt.crt
Konvertieren Sie vom Serverzertifikat pem nach p12
$ openssl pkcs12 -export -out server-crt.p12 -in server-crt.pem -inkey server-privatekey.pem -passin pass:root -passout pass:root
Serverzertifikat p12 ⇒ In CRT konvertieren
$ openssl pkcs12 -in server-crt.p12 -clcerts -nokeys -out server-crt.crt
Serverzertifikat p12 ⇒ In cer konvertieren
$ openssl pkcs12 -in server-crt.p12 -des -out server-crt.cer
https://jp.globalsign.com/support/faq/331.html
Befehlsreferenz: https://docs.oracle.com/javase/jp/6/technotes/tools/windows/keytool.html
Es scheint, dass Java nicht automatisch aktualisiert werden kann, wenn sich die Cacerts ändern. Backup erforderlich. http://d.hatena.ne.jp/uunfo/20110813/1313242092
keytool -genkeypair -keysize 2048 -keyalg RSA -sigalg SHA256withRSA -alias testcrt -keystore "C:\Program Files\Java\jreX.X.X_XXX\lib\security\cacerts" -storepass changeit
** Hinzugefügt am 16.10.2017 ** Erstellen Sie überall eine Keystore-Datei (Wenn der allgemeine Name test1 lautet, lautet die Organisationseinheit test2, die Organisation test3 und der zweistellige Ländercode JP.)
$ keytool -genkey -dname "cn=test1, ou=test2, o=test3, c=JP" -Keystore (Keystore-Dateiname).keystore) -Alias (Name, der das Zertifikat / den Schlüssel im KeyStore identifiziert)-Tastatur (Zertifikat / Schlüsselkennwort * 6 Zeichen oder mehr)-Storepass (Key Store Passwort)-keyalg RSA -keysize 2048 -validity 10000
Referenz (pro Schlüsselpaargenerierung) https://docs.oracle.com/javase/jp/8/docs/technotes/tools/unix/keytool.html
Ich dachte, es wäre eine gute Idee, das Zertifikat als externe Ressource offen zu lassen, und überlegte daher, das Zertifikat in den Schlüsselspeicher zu importieren.
Importieren Sie die Cer-Datei in den Keystore
Wenn ich versuche, eine CRT-Datei mit dem folgenden Befehl zu importieren, wird die Fehlermeldung "Keytool-Fehler: java.lang.Exception: Eingabe ist kein X.509-Zertifikat" angezeigt. Import mit cer.
$ keytool -import -alias testkey -keystore "C:\Program Files\Java\jreX.X.X_XXX\lib\security\cacerts" -file server-crt.cer
Importieren Sie die p12-Datei in den Keystore http://blogger.fastriver.net/2014/10/keytool.html
Wenn Sie keinen Alias (Unterscheidungsnamen) angeben, wird dieser standardmäßig mit dem Namen "1" importiert. Wenn Sie einen Alias hinzufügen möchten, fügen Sie eine Option wie "-srcalias 1 -destalias (beliebiger Aliasname)" hinzu.
$ keytool -importkeystore -keystore "C:\Program Files\Java\jreX.X.X_XXX\lib\security\cacerts" -srckeystore server-crt.p12 -srcstoretype PKCS12 -srcalias 1 -destalias testcrt -srcstorepass root -deststorepass changeit
Überprüfen Sie das importierte Zertifikat
$ keytool -list -v -alias testcrt -keystore "C:\Program Files\Java\jreX.X.X_XXX\lib\security\cacerts" -keypass root -storepass changeit
$ keytool -delete -alias testcrt -keystore "C:\Program Files\Java\jreX.X.X_XXX\lib\security\cacerts" -keypass root -storepass changeit
$ keytool -changealias -srcalias 11111111 -destalias 22222222 -keystore "C:\Program Files\Java\jreX.X.X_XXX\lib\security\cacerts" -keypass root -storepass changeit
$ keytool -selfcert -alias testcrt -validity 2000 -keystore "C:\Program Files\Java\jreX.X.X_XXX\lib\security\cacerts" -keypass root -storepass changeit
createSignedXml.java
public String createSignedXml(String fileName)
throws Exception {
//Dokumentinstanz erstellen
DocumentBuilder documentBuilder = null;
documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document = documentBuilder.newDocument();
//DOM-Generierung eines XML-Dokuments (weggelassen)
//Erstellung der XML-Signatur
//p12 Dateipfad
File certDir = "XXXXXX";
//Liste der Zertifikatdateien unter dem Zertifikatverzeichnis (vorausgesetzt, es ist nur eine Datei vorhanden)
File[] certP12List = certDir.listFiles((FileFilter) new SuffixFileFilter(".p12"));
//Zertifikatdatei
File certP12File = null;
//Rufen Sie den Pfad der Keystore-Datei ab
String keyStoreFilePath = "/usr/java/jdkX.X.X_XXX/jre/lib/security/testkeystore";
//Keystore-Datei abrufen
File keyStoreFile = new File(keyStoreFilePath);
//Keystore-Passwort
String keyStorePass = "root";
//Zertifikat Passwort
String certificatePass = "changeit";
//Fehler, wenn mehrere p12-Dateien abgelegt werden
if (certP12List.length == 1) {
certP12File = certP12List[0];
} else {
throw new IOException();
}
try {
//Holen Sie sich den Keystore
KeyStore keyStore = getKeyStore(keyStoreFile, keyStorePass);
//Distinguished Name: Beziehen Sie ein Zertifikat, das XXX entspricht, aus dem Schlüsselspeicher
X509Certificate x509cert = getCertificate(keyStore, XXX);
//Flag für die Beurteilung des Imports von Zertifikaten
boolean importFlg = false;
//Überprüfen Sie das Ablaufdatum
// 0:Das importierte Zertifikat liegt innerhalb des Ablaufdatums, 1:Das importierte Zertifikat ist abgelaufen,
// 2:Externes Ressourcenzertifikat ist abgelaufen, 3:Beide sind abgelaufen, 4:Importfehler
int checkResult = 0;
if (x509cert != null) {
//Ablaufprüfung von Zertifikaten in externen Ressourcen und importierten Zertifikaten
checkResult = checkCertificateExpired(x509cert, XXX, keyStoreFile, certP12File, keyStorePass, certificatePass);
//Das importierte Zertifikat ist abgelaufen
if (checkResult == 1) {
//Distinguished Name: XXX Zertifikat löschen
deleteProcessExec(XXX, keyStoreFile, certificatePass, keyStorePass);
importFlg = true;
}
} else {
importFlg = true;
}
//Wenn das in den Schlüsselspeicher importierte Zertifikat abgelaufen ist
//Neues Zertifikat erneut importieren
if (importFlg) {
//Führen Sie den Zertifikatimport durch
importProcessExec(keyStoreFile, XXX, certP12File, certificatePass, keyStorePass);
//Besorgen Sie sich den Keystore erneut
keyStore = getKeyStore(keyStoreFile, keyStorePass);
//Distinguished Name: Beziehen Sie ein Zertifikat, das XXX entspricht, erneut aus dem Keystore
x509cert = getCertificate(keyStore, XXX);
//Ablaufdatum prüfen
checkResult = checkCertificateExpired(x509cert, keyStoreFile, certP12File, keyStorePass, certificatePass);
}
//Sowohl das in der externen Ressource platzierte Zertifikat als auch das importierte Zertifikat sind abgelaufen
//Fehler beim Importieren eines externen Ressourcenzertifikats
if (checkResult >= 3) {
//Distinguished Name: XXX Zertifikat löschen
deleteProcessExec(XXX, keyStoreFile, certificatePass, keyStorePass);
throw new CertificateException();
}
//Holen Sie sich den privaten Schlüssel
RSAPrivateKey privateKey = (RSAPrivateKey) keyStore.getKey(XXX, certificatePassArray);
//Signierkontext erstellen
DOMSignContext dsc = new DOMSignContext(privateKey, document.getDocumentElement());
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
//Referenzelement erstellen
Reference ref = fac.newReference
("#XXXXXX", fac.newDigestMethod(DigestMethod.SHA256, null),
Collections.singletonList
(fac.newTransform(Transform.ENVELOPED,
(TransformParameterSpec) null)), null, null);
//Signaturinformationen erstellen
SignedInfo si = fac.newSignedInfo
(fac.newCanonicalizationMethod
(CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
(C14NMethodParameterSpec) null),
fac.newSignatureMethod("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", null),
Collections.singletonList(ref));
KeyInfoFactory kif = fac.getKeyInfoFactory();
X509Data x509Data = kif.newX509Data(Collections.singletonList(x509cert));
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(x509Data));
//Zeichen.
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
} catch (XMLSignatureException e) {
throw new XMLSignatureException("Fehler beim Generieren oder Validieren der XML-Signatur", e);
} catch (MarshalException e) {
throw new MarshalException(e);
} catch (InvalidAlgorithmParameterException e) {
throw new InvalidAlgorithmParameterException(e);
} catch (NoSuchAlgorithmException e) {
throw new NoSuchAlgorithmException(e);
} catch (KeyStoreException e) {
throw new KeyStoreException(e);
} catch (CertificateException e) {
throw new CertificateException(e);
} catch (UnrecoverableKeyException e) {
throw new UnrecoverableKeyException();
}
return this.write(document);
}
/**
*Holen Sie sich den Keystore
*
* @param keyStoreFile Keystore-Datei
* @param keyStorePass Keystore-Passwort
* @Rückgabe des Keystore-Objekts keyStore
*/
private KeyStore getKeyStore(File keyStoreFile, String keyStorePass) {
KeyStore keyStore = null;
try (FileInputStream keyStoreStream = new FileInputStream(keyStoreFile)) {
//Keystore-Typ:JKS(Nehmen Sie für PKCS12 das Argument"PKCS12"Reparieren)
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(keyStoreStream, keyStorePass.toCharArray());
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
//TODO automatisch generierter Fangblock
e.printStackTrace();
}
return keyStore;
}
/**
*Holen Sie sich ein Zertifikat, das Ihrem definierten Namen entspricht, aus dem Keystore
*
* @param keyStore Keystore-Objekt
* @param alias Distinguished name
* @Zertifikat zurückgeben Zertifikatobjekt
*/
private X509Certificate getCertificate(KeyStore keyStore, String alias){
X509Certificate certificate = null;
try {
certificate = (X509Certificate) keyStore.getCertificate(alias);
} catch (KeyStoreException e) {
//TODO automatisch generierter Fangblock
e.printStackTrace();
}
return certificate;
}
/**
*Ablaufprüfung des Zertifikats
*
* @param x509cert X509-Zertifikatobjekt
* @param keyStoreFile Keystore-Datei
* @param certFile Zertifikatdatei
* @param keyStorePass Keystore-Passwort
* @param certificatePass Zertifikat Passwort
* @param srcAlias Temporärer definierter Name unmittelbar nach dem Import
* @return 0:Das importierte Zertifikat liegt innerhalb des Ablaufdatums, 1:Das importierte Zertifikat ist abgelaufen,
* 2:Externes Ressourcenzertifikat ist abgelaufen, 3:Beide sind abgelaufen, 4:Fehler beim Importieren eines externen Ressourcenzertifikats
*/
private int checkCertificateExpired(X509Certificate x509cert,
File keyStoreFile, File certFile, String keyStorePass, String certificatePass,
String srcAlias) {
//Verarbeitungsergebnis
int result = 0;
//Ablaufflag des importierten Zertifikats
// true:Abgelaufen, false:Innerhalb des Ablaufdatums
boolean importExpiredFlg = false;
//Ablaufflag für Zertifikate, die auf externen Ressourcen platziert sind
boolean extExpiredFlg = false;
//Ruft das Ablaufdatum des in den Keystore importierten Zertifikats ab
Date importExpiredDate = x509cert.getNotAfter();
//Aktuelles Datum und Uhrzeit
Date now = new Date();
/**************************Ablaufprüfung des importierten Zertifikats START**************************/
//Stellen Sie fest, ob das importierte Zertifikat abgelaufen ist
if (now.compareTo(importExpiredDate) > 0) {
//Wenn es abgelaufen ist
importExpiredFlg = true;
result = 1;
} else {
//Da es innerhalb des Ablaufdatums liegt, sind keine weiteren Überprüfungen erforderlich
return 0;
}
/***************************Ablaufprüfung des importierten Zertifikats END***************************/
/***********************Ablaufprüfung für Zertifikate auf externen Ressourcen START**********************/
try {
//Temporärer Distinguished Name
String destAlias = System.currentTimeMillis();
//Importbefehl ausführen
importProcessExec(keyStoreFile, destAlias, certFile, certificatePass, keyStorePass);
//Holen Sie sich den Keystore
KeyStore tmpKeyStore = getKeyStore(keyStoreFile, keyStorePass);
//Distinguished Name: Holen Sie sich ein Zertifikat, das mit destAlias übereinstimmt, aus dem Keystore
X509Certificate tmpCert = getCertificate(tmpKeyStore, destAlias);
//Rufen Sie das Ablaufdatum des importierten Zertifikats ab
Date extExpiredDate = null;
if (tmpCert != null) {
extExpiredDate = tmpCert.getNotAfter();
} else {
//Importfehler
return 4;
}
//Vergleichen Sie die aktuelle Uhrzeit mit dem Ablaufdatum des Zertifikats der externen Ressource
if (now.compareTo(extExpiredDate) > 0) {
//Wenn es abgelaufen ist
extExpiredFlg = true;
result = 2;
}
//Befehl ausführen, um vorübergehend importiertes Zertifikat zu löschen
deleteProcessExec(destAlias, keyStoreFile, certificatePass, keyStorePass);
} catch(InterruptedException e) {
//TODO automatisch generierter Fangblock
e.printStackTrace();
}
/**********************Ablaufprüfung ENDE für Zertifikate, die auf externen Ressourcen abgelegt sind*********************/
//Importierte Zertifikate und Zertifikate für externe Ressourcen
//Wenn beide abgelaufen sind, Ergebnis:3
if (importExpiredFlg && extExpiredFlg) {
result = 3;
}
return result;
}
/**
*Führen Sie den Befehl zum Löschen des Zertifikats aus.
*
* @param alias Distinguished name
* @param keyStoreFile Keystore-Datei
* @param certificatePass Zertifikat Passwort
* @param keyStorePass Keystore-Passwort
* @return true:Erfolgreiche Fertigstellung, false:Abnormale Beendigung
* @throws InterruptedException
*/
private boolean deleteProcessExec(String alias, File keyStoreFile, String certificatePass,
String keyStorePass)
throws InterruptedException {
//Rufen Sie den Befehl ab, um das in den Keystore importierte Zertifikat zu löschen
List<String> command = getDeleteCommand(alias, keyStoreFile, certificatePass, keyStorePass);
//Befehlsausführung löschen
return processExec(command);
}
/**
*Rufen Sie den Befehl zum Löschen des Zertifikats ab.
*
* @param alias Distinguished name
* @param keyStoreFile Keystore-Datei
* @param certificatePass Zertifikat Passwort
* @param keyStorePass Keystore-Passwort
* @Befehl resultList delete zurückgeben
*/
private List<String> getDeleteCommand(String alias, File keyStoreFile, String certificatePass,
String keyStorePass) {
//Befehl zum Löschen des in den Schlüsselspeicher importierten Zertifikats
String command = "keytool -delete -alias %alias% -keystore %keyStoreFilePath% -keypass %certificatePass% -storepass %keyStorePass%";
//Befehl in String-Array aufteilen
String[] commandList = command.split(" ");
List<String> resultList = new ArrayList<String>();
for (String cmd : commandList) {
switch (cmd) {
case "%alias%":
cmd = cmd.replace("%alias%", alias);
break;
case "%keyStoreFilePath%":
cmd = cmd.replace("%keyStoreFilePath%", keyStoreFile.getPath());
break;
case "%certificatePass%":
cmd = cmd.replace("%certificatePass%", certificatePass);
break;
case "%keyStorePass%":
cmd = cmd.replace("%keyStorePass%", keyStorePass);
break;
}
resultList.add(cmd);
}
return resultList;
}
/**
*Führen Sie den Zertifikatimportbefehl aus.
*
* @param certFilePath Zertifikatdatei
* @param destAlias Distinguished name
* @param keyStoreFilePath Keystore-Datei
* @param certificatePass Zertifikat Passwort
* @param keyStorePass Keystore-Passwort
* @return true:Erfolgreiche Fertigstellung, false:Abnormale Beendigung
* @throws InterruptedException
*/
private boolean importProcessExec(File keyStoreFile, String destAlias, File certFile,
String certificatePass,
String keyStorePass) throws InterruptedException {
//Befehl zum Importieren des Zertifikats
List<String> command = getImportCommand(keyStoreFile, destAlias, certFile, certificatePass,
keyStorePass);
//Importbefehl ausführen
return processExec(command);
}
/**
*Befehl zum Importieren von Zertifikaten abrufen.
*
* @param certFilePath Zertifikatdatei
* @param destAlias Distinguished name
* @param keyStoreFilePath Keystore-Datei
* @param certificatePass Zertifikat Passwort
* @param keyStorePass Keystore-Passwort
* @Befehl resultList import zurückgeben
*/
private List<String> getImportCommand(File keyStoreFile, String destAlias, File certFile,
String certificatePass, String keyStorePass) {
//Befehl zum Importieren des Zertifikats
String command = "keytool -importkeystore -keystore %keyStoreFilePath% -srckeystore %certFilePath% -srcstoretype PKCS12 -srcalias 1 -destalias %destalias% -srcstorepass %certificatePass% -deststorepass %keyStorePass%";
//Befehl in String-Array aufteilen
String[] commandList = command.split(" ");
List<String> resultList = new ArrayList<String>();
for (String cmd : commandList) {
switch (cmd) {
case "%keyStoreFilePath%":
cmd = cmd.replace("%keyStoreFilePath%", keyStoreFile.getPath());
break;
case "%certFilePath%":
cmd = cmd.replace("%certFilePath%", certFile.getPath());
break;
case "%destalias%":
cmd = cmd.replace("%destalias%", destAlias);
break;
case "%certificatePass%":
cmd = cmd.replace("%certificatePass%", certificatePass);
break;
case "%keyStorePass%":
cmd = cmd.replace("%keyStorePass%", keyStorePass);
break;
}
resultList.add(cmd);
}
return resultList;
}
/**
*Führen Sie einen externen Prozess aus.
*
* @Befehl param Befehlsinhalt
* @return true:Erfolgreiche Fertigstellung, false:Abnormale Beendigung
*/
private boolean processExec(List<String> command) {
//Verarbeitungsergebnis
boolean result = false;
try {
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process Process = processBuilder.start();
//Warten Sie, bis der Vorgang normal endet
if (Process.waitFor() == 0) {
result = true;
log.info("Process Success: " + command.toString());
} else {
log.warn("Process Failed: " + command.toString());
}
//Standardausgabe
String strInput;
BufferedReader ipbr = new BufferedReader(new InputStreamReader(Process.getInputStream()));
while((strInput = ipbr.readLine()) != null) {
log.info(strInput);
}
ipbr.close();
//Fehlerausgabe
String strErr;
BufferedReader erbr = new BufferedReader(new InputStreamReader(Process.getErrorStream()));
while((strErr = erbr.readLine()) != null) {
log.info(strErr);
}
erbr.close();
//InputStream im Hintergrund nach Verwendung von ProcessBuilder, OutputStream,ErrorStream wird geöffnet.
//Schließen Sie alle Streams, um zu vermeiden, dass Ihnen die Ressourcen ausgehen.
Process.getInputStream().close();
Process.getOutputStream().close();
Process.getErrorStream().close();
} catch (InterruptedException | IOException e) {
//TODO automatisch generierter Fangblock
e.printStackTrace();
}
return result;
}
Recommended Posts