Comme il s'agit de la première implémentation de la signature XML, j'ai décidé de continuer en laissant diverses notes.
--Je veux signer XML en Java
L'opération ci-dessus est requise chaque fois que le certificat électronique est remplacé.
Qu'est-ce que la «normalisation» des certificats électroniques? http://www.atmarkit.co.jp/fxml/tanpatsu/16xmlsecurity/xmlsecurity02.html
À propos du format de fichier de clé et de certificat RSA https://qiita.com/kunichiko/items/12cbccaadcbf41c72735
Extraire la clé privée, le certificat et l'autorité de certification intermédiaire du fichier PKCS # 12 https://qiita.com/cs_sonar/items/f2753ffdebb1c67d5302
Comment créer un certificat auto-signé https://qiita.com/akito1986/items/8eb41f5a43bb9421ae79
Signature XML à l'aide de l'API de signature numérique XML de Java http://qiita.com/KevinFQ/items/4e2484a659b618530e72
liste de commandes keytool http://itref.fc2web.com/java/keytool.html
[Java] Ajouter / supprimer des certificats du magasin de clés en Java https://blogs.yahoo.co.jp/dk521123/37097725.html
Convertir du certificat de serveur pem en crt
$ openssl x509 -outform der in server-crt.pem -out server-crt.crt
Conversion du certificat de serveur pem en p12
$ openssl pkcs12 -export -out server-crt.p12 -in server-crt.pem -inkey server-privatekey.pem -passin pass:root -passout pass:root
Certificat serveur p12 ⇒ Convertir en crt
$ openssl pkcs12 -in server-crt.p12 -clcerts -nokeys -out server-crt.crt
Certificat serveur p12 ⇒ Convertir en cer
$ openssl pkcs12 -in server-crt.p12 -des -out server-crt.cer
https://jp.globalsign.com/support/faq/331.html
Référence de la commande: https://docs.oracle.com/javase/jp/6/technotes/tools/windows/keytool.html
Il semble que Java ne pourra pas se mettre à jour automatiquement si cacerts change. Sauvegarde requise. 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
** Ajouté le 16/10/2017 ** Créez un fichier de clés n'importe où (Lorsque le nom commun est test1, l'unité organisationnelle est test2, l'organisation est test3 et le code de pays à deux caractères est JP)
$ keytool -genkey -dname "cn=test1, ou=test2, o=test3, c=JP" -keystore (nom du fichier de keystore).keystore) -alias (nom qui identifie le certificat / la clé dans le KeyStore)-keypass (certificat / mot de passe clé * 6 caractères ou plus)-storepass (mot de passe du magasin de clés)-keyalg RSA -keysize 2048 -validity 10000
Référence (par génération de paire de clés) https://docs.oracle.com/javase/jp/8/docs/technotes/tools/unix/keytool.html
J'ai pensé que ce serait une bonne idée de laisser le certificat exposé en tant que ressource externe, j'ai donc envisagé d'importer le certificat dans le magasin de clés.
Importer le fichier cer dans le keystore
Lorsque j'essaye d'importer le fichier crt avec la commande suivante, j'obtiens une erreur disant "erreur keytool: java.lang.Exception: L'entrée n'est pas un certificat X.509". Importez avec cer.
$ keytool -import -alias testkey -keystore "C:\Program Files\Java\jreX.X.X_XXX\lib\security\cacerts" -file server-crt.cer
Importer le fichier p12 dans le keystore http://blogger.fastriver.net/2014/10/keytool.html
Si vous ne spécifiez pas d'alias (nom distinctif), il sera importé avec le nom "1" par défaut. Si vous souhaitez ajouter un alias, ajoutez une option telle que "-srcalias 1 -destalias (nom d'alias arbitraire)".
$ 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
Vérifiez le certificat importé
$ 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 {
//Créer une instance de document
DocumentBuilder documentBuilder = null;
documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document document = documentBuilder.newDocument();
//Génération DOM du document XML (omis)
//Création de signature XML
//chemin du fichier p12
File certDir = "XXXXXX";
//Liste des fichiers de certificats sous le répertoire des certificats (en supposant qu'un seul fichier existe)
File[] certP12List = certDir.listFiles((FileFilter) new SuffixFileFilter(".p12"));
//Fichier de certificat
File certP12File = null;
//Obtenez le chemin du fichier keystore
String keyStoreFilePath = "/usr/java/jdkX.X.X_XXX/jre/lib/security/testkeystore";
//Obtenir le fichier de keystore
File keyStoreFile = new File(keyStoreFilePath);
//Mot de passe du fichier de clés
String keyStorePass = "root";
//Mot de passe du certificat
String certificatePass = "changeit";
//Erreur si plusieurs fichiers p12 sont placés
if (certP12List.length == 1) {
certP12File = certP12List[0];
} else {
throw new IOException();
}
try {
//Obtenez le keystore
KeyStore keyStore = getKeyStore(keyStoreFile, keyStorePass);
//Nom distinctif: obtenez un certificat correspondant à XXX à partir du magasin de clés
X509Certificate x509cert = getCertificate(keyStore, XXX);
//Drapeau de jugement d'importation de certificat
boolean importFlg = false;
//Pour vérifier la date d'expiration
// 0:Le certificat importé est dans la date d'expiration, 1:Le certificat importé a expiré,
// 2:Le certificat de ressource externe a expiré, 3:Les deux ont expiré, 4:Erreur d'importation
int checkResult = 0;
if (x509cert != null) {
//Contrôle d'expiration des certificats placés dans des ressources externes et des certificats importés
checkResult = checkCertificateExpired(x509cert, XXX, keyStoreFile, certP12File, keyStorePass, certificatePass);
//Le certificat importé a expiré
if (checkResult == 1) {
//Nom distinctif: XXX supprimer le certificat
deleteProcessExec(XXX, keyStoreFile, certificatePass, keyStorePass);
importFlg = true;
}
} else {
importFlg = true;
}
//Si le certificat importé dans le keystore a expiré
//Réimporter un nouveau certificat
if (importFlg) {
//Effectuer l'importation de certificats
importProcessExec(keyStoreFile, XXX, certP12File, certificatePass, keyStorePass);
//Réacquérir le keystore
keyStore = getKeyStore(keyStoreFile, keyStorePass);
//Nom distinctif: obtenez à nouveau un certificat correspondant à XXX à partir du magasin de clés
x509cert = getCertificate(keyStore, XXX);
//Vérification de la date d'expiration
checkResult = checkCertificateExpired(x509cert, keyStoreFile, certP12File, keyStorePass, certificatePass);
}
//Le certificat placé dans la ressource externe et le certificat importé ont expiré
//Erreur d'importation de certificat de ressource externe
if (checkResult >= 3) {
//Nom distinctif: XXX supprimer le certificat
deleteProcessExec(XXX, keyStoreFile, certificatePass, keyStorePass);
throw new CertificateException();
}
//Obtenez la clé privée
RSAPrivateKey privateKey = (RSAPrivateKey) keyStore.getKey(XXX, certificatePassArray);
//Créer un contexte de signature
DOMSignContext dsc = new DOMSignContext(privateKey, document.getDocumentElement());
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
//Créer un élément de référence
Reference ref = fac.newReference
("#XXXXXX", fac.newDigestMethod(DigestMethod.SHA256, null),
Collections.singletonList
(fac.newTransform(Transform.ENVELOPED,
(TransformParameterSpec) null)), null, null);
//Création des informations de signature
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));
//Signe.
XMLSignature signature = fac.newXMLSignature(si, ki);
signature.sign(dsc);
} catch (XMLSignatureException e) {
throw new XMLSignatureException("Erreur lors du processus de génération ou de validation de la signature XML", 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);
}
/**
*Obtenez le keystore
*
* @param keyStoreFile Fichier Keystore
* @param keyStorePass Mot de passe Keystore
* @return keyStore, objet keystore
*/
private KeyStore getKeyStore(File keyStoreFile, String keyStorePass) {
KeyStore keyStore = null;
try (FileInputStream keyStoreStream = new FileInputStream(keyStoreFile)) {
//Type de fichier de clés:JKS(Pour PKCS12, prenez l'argument"PKCS12"Réparer)
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(keyStoreStream, keyStorePass.toCharArray());
} catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
//Bloc de capture généré automatiquement TODO
e.printStackTrace();
}
return keyStore;
}
/**
*Obtenez un certificat qui correspond à votre nom distinctif dans le fichier de clés
*
* @objet keystore param keyStore
* @param alias Nom distinctif
* @certificat de retour objet Certificat
*/
private X509Certificate getCertificate(KeyStore keyStore, String alias){
X509Certificate certificate = null;
try {
certificate = (X509Certificate) keyStore.getCertificate(alias);
} catch (KeyStoreException e) {
//Bloc de capture généré automatiquement TODO
e.printStackTrace();
}
return certificate;
}
/**
*Vérification d'expiration du certificat
*
* @objet de certificat param x509cert X509
* @param keyStoreFile Fichier Keystore
* @param certFile Fichier de certificat
* @param keyStorePass Mot de passe Keystore
* @param certificatePass Mot de passe du certificat
* @param srcAlias Nom distinctif temporaire immédiatement après l'importation
* @return 0:Le certificat importé est dans la date d'expiration, 1:Le certificat importé a expiré,
* 2:Le certificat de ressource externe a expiré, 3:Les deux ont expiré, 4:Erreur d'importation de certificat de ressource externe
*/
private int checkCertificateExpired(X509Certificate x509cert,
File keyStoreFile, File certFile, String keyStorePass, String certificatePass,
String srcAlias) {
//Résultat du traitement
int result = 0;
//Indicateur d'expiration du certificat importé
// true:Expiré, false:Dans la date d'expiration
boolean importExpiredFlg = false;
//Indicateur d'expiration pour les certificats placés sur des ressources externes
boolean extExpiredFlg = false;
//Obtenez la date d'expiration du certificat importé dans le keystore
Date importExpiredDate = x509cert.getNotAfter();
//Date et heure actuelles
Date now = new Date();
/**************************Contrôle d'expiration du certificat importé START**************************/
//Déterminez si le certificat importé a expiré
if (now.compareTo(importExpiredDate) > 0) {
//S'il a expiré
importExpiredFlg = true;
result = 1;
} else {
//Puisqu'il est dans la date d'expiration, aucune autre vérification n'est requise
return 0;
}
/***************************Contrôle d'expiration du certificat importé END***************************/
/***********************Contrôle d'expiration des certificats placés sur des ressources externes START**********************/
try {
//Nom distinctif temporaire
String destAlias = System.currentTimeMillis();
//Exécuter la commande d'importation
importProcessExec(keyStoreFile, destAlias, certFile, certificatePass, keyStorePass);
//Obtenez le keystore
KeyStore tmpKeyStore = getKeyStore(keyStoreFile, keyStorePass);
//Nom distinctif: obtenez un certificat qui correspond à destAlias à partir du fichier de clés
X509Certificate tmpCert = getCertificate(tmpKeyStore, destAlias);
//Obtenez la date d'expiration du certificat importé
Date extExpiredDate = null;
if (tmpCert != null) {
extExpiredDate = tmpCert.getNotAfter();
} else {
//Erreur d'importation
return 4;
}
//Comparez l'heure actuelle avec la date d'expiration du certificat de la ressource externe
if (now.compareTo(extExpiredDate) > 0) {
//S'il a expiré
extExpiredFlg = true;
result = 2;
}
//Exécuter la commande pour supprimer le certificat importé temporairement
deleteProcessExec(destAlias, keyStoreFile, certificatePass, keyStorePass);
} catch(InterruptedException e) {
//Bloc de capture généré automatiquement TODO
e.printStackTrace();
}
/**********************Contrôle d'expiration END pour les certificats placés sur des ressources externes*********************/
//Certificats importés et certificats placés sur des ressources externes
//Si les deux ont expiré, le résultat:3
if (importExpiredFlg && extExpiredFlg) {
result = 3;
}
return result;
}
/**
*Exécutez la commande de suppression de certificat.
*
* @param alias Nom distinctif
* @param keyStoreFile Fichier Keystore
* @param certificatePass Mot de passe du certificat
* @param keyStorePass Mot de passe Keystore
* @return true:Réussite, false:Terminaison anormale
* @throws InterruptedException
*/
private boolean deleteProcessExec(String alias, File keyStoreFile, String certificatePass,
String keyStorePass)
throws InterruptedException {
//Obtenez la commande pour supprimer le certificat importé dans le keystore
List<String> command = getDeleteCommand(alias, keyStoreFile, certificatePass, keyStorePass);
//Supprimer l'exécution de la commande
return processExec(command);
}
/**
*Obtenez la commande de suppression de certificat.
*
* @param alias Nom distinctif
* @param keyStoreFile Fichier Keystore
* @param certificatePass Mot de passe du certificat
* @param keyStorePass Mot de passe Keystore
* @return commande de suppression de resultList
*/
private List<String> getDeleteCommand(String alias, File keyStoreFile, String certificatePass,
String keyStorePass) {
//Commande pour supprimer le certificat importé dans le keystore
String command = "keytool -delete -alias %alias% -keystore %keyStoreFilePath% -keypass %certificatePass% -storepass %keyStorePass%";
//Commande Split en tableau de chaînes
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;
}
/**
*Exécutez la commande d'importation de certificat.
*
* @param fichier de certificat certFilePath
* @param destAlias Nom distinctif
* @param keyStoreFilePath Fichier Keystore
* @param certificatePass Mot de passe du certificat
* @param keyStorePass Mot de passe Keystore
* @return true:Réussite, false:Terminaison anormale
* @throws InterruptedException
*/
private boolean importProcessExec(File keyStoreFile, String destAlias, File certFile,
String certificatePass,
String keyStorePass) throws InterruptedException {
//Commande pour importer le certificat
List<String> command = getImportCommand(keyStoreFile, destAlias, certFile, certificatePass,
keyStorePass);
//Exécuter la commande d'importation
return processExec(command);
}
/**
*Obtenez la commande d'importation de certificat.
*
* @param fichier de certificat certFilePath
* @param destAlias Nom distinctif
* @param keyStoreFilePath Fichier Keystore
* @param certificatePass Mot de passe du certificat
* @param keyStorePass Mot de passe Keystore
* @return commande d'importation resultList
*/
private List<String> getImportCommand(File keyStoreFile, String destAlias, File certFile,
String certificatePass, String keyStorePass) {
//Commande pour importer le certificat
String command = "keytool -importkeystore -keystore %keyStoreFilePath% -srckeystore %certFilePath% -srcstoretype PKCS12 -srcalias 1 -destalias %destalias% -srcstorepass %certificatePass% -deststorepass %keyStorePass%";
//Commande Split en tableau de chaînes
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;
}
/**
*Exécutez un processus externe.
*
* @commande param Contenu de la commande
* @return true:Réussite, false:Terminaison anormale
*/
private boolean processExec(List<String> command) {
//Résultat du traitement
boolean result = false;
try {
ProcessBuilder processBuilder = new ProcessBuilder(command);
Process Process = processBuilder.start();
//Attendez que le processus se termine normalement
if (Process.waitFor() == 0) {
result = true;
log.info("Process Success: " + command.toString());
} else {
log.warn("Process Failed: " + command.toString());
}
//Sortie standard
String strInput;
BufferedReader ipbr = new BufferedReader(new InputStreamReader(Process.getInputStream()));
while((strInput = ipbr.readLine()) != null) {
log.info(strInput);
}
ipbr.close();
//Sortie d'erreur
String strErr;
BufferedReader erbr = new BufferedReader(new InputStreamReader(Process.getErrorStream()));
while((strErr = erbr.readLine()) != null) {
log.info(strErr);
}
erbr.close();
//InputStream en arrière-plan après l'utilisation de ProcessBuilder, OutputStream,ErrorStream est ouvert.
//Fermez tous les flux pour éviter de manquer de ressources.
Process.getInputStream().close();
Process.getOutputStream().close();
Process.getErrorStream().close();
} catch (InterruptedException | IOException e) {
//Bloc de capture généré automatiquement TODO
e.printStackTrace();
}
return result;
}
Recommended Posts