1 package org.eparapher.core.signature;
2
3 import java.io.File;
4 import java.security.InvalidAlgorithmParameterException;
5 import java.security.NoSuchAlgorithmException;
6 import java.security.NoSuchProviderException;
7 import java.security.cert.CertStore;
8 import java.security.cert.CollectionCertStoreParameters;
9 import java.security.cert.X509Certificate;
10 import java.util.ArrayList;
11
12 import org.apache.log4j.Logger;
13 import org.bouncycastle.asn1.cms.ContentInfo;
14 import org.bouncycastle.cms.CMSProcessable;
15 import org.bouncycastle.cms.CMSProcessableByteArray;
16 import org.bouncycastle.cms.CMSSignedData;
17 import org.bouncycastle.cms.CMSSignedDataGenerator;
18 import org.bouncycastle.cms.CMSSignedGenerator;
19 import org.bouncycastle.cms.SignerInformationStore;
20 import org.bouncycastle.x509.X509Store;
21 import org.eparapher.core.EParapherManager;
22 import org.eparapher.core.crypto.EPKeystoreManager;
23 import org.eparapher.core.crypto.keystore.IUserKeystore;
24 import org.eparapher.core.tools.FileUtil;
25
26
27
28
29
30
31
32
33
34
35 public class CMSSigner {
36
37 private static Logger log = Logger.getLogger(CMSSigner.class);
38
39 private IUserKeystore userpkandcert;
40 private boolean addsignature;
41
42 public CMSSigner() {
43 userpkandcert = EPKeystoreManager.getInstance().getUserkeystore();
44 }
45
46 public String sign( String original_file, CMSSignatureParameters cmssignparams ) {
47 try {
48 addsignature = false;
49 String signed_file = manageFileBeforeSignature( original_file, cmssignparams.isDetached() );
50 if (signed_file == null) {
51 log.info("User cancel the CMS signature process");
52 return null;
53 }
54 log.info("Generating " + (cmssignparams.isDetached()?"detached":"embedded") +" CMS signature of " +original_file + " in " + signed_file );
55
56
57 byte[] content_to_sign = FileUtil.readFile(original_file);
58
59
60 CertStore certs = buildCertsAndCRLsListToInsertInCMS(cmssignparams);
61
62
63 CMSSignedDataGenerator signGen = new CMSSignedDataGenerator();
64 signGen.addSigner(userpkandcert.getPrivateKey(), userpkandcert.getX509Certificate(), cmssignparams.getSignatureDigestAlgOID());
65 if (certs!=null)
66 signGen.addCertificatesAndCRLs(certs);
67
68 CMSSignedData signedData = null;
69 CMSProcessable content=null;
70
71
72 if (addsignature) {
73 if (cmssignparams.isDetached())
74 signedData = new CMSSignedData(FileUtil.readFile(signed_file));
75 else
76 signedData = new CMSSignedData(content_to_sign);
77
78 if (signedData!=null){
79 SignerInformationStore signers = signedData.getSignerInfos();
80 ContentInfo ci = signedData.getContentInfo();
81
82 CertStore existingCerts=signedData.getCertificatesAndCRLs("Collection", "BC");
83 X509Store x509Store=signedData.getAttributeCertificates("Collection", "BC");
84
85
86 signGen.addCertificatesAndCRLs(existingCerts);
87
88 signGen.addAttributeCertificates(x509Store);
89
90 signGen.addSigners(signers);
91 }
92 }
93
94 if ( addsignature && !cmssignparams.isDetached() )
95 content = signedData.getSignedContent();
96 else
97 content = new CMSProcessableByteArray(content_to_sign);
98
99
100 if (EPKeystoreManager.isCAPICOMUsed() || EPKeystoreManager.isPKCS11Used()) {
101 String provName = userpkandcert.getProviderName();
102 signedData = signGen.generate(CMSSignedGenerator.DATA, content, !cmssignparams.isDetached(), provName);
103 } else
104 signedData = signGen.generate(CMSSignedGenerator.DATA, content, !cmssignparams.isDetached(), "BC");
105
106
107 FileUtil.writeToFile(signed_file, signedData.getEncoded());
108
109 return signed_file;
110 } catch (Exception e) {
111 log.error(""+e.getLocalizedMessage(),e);
112 }
113
114 return null;
115 }
116
117 private CertStore buildCertsAndCRLsListToInsertInCMS( CMSSignatureParameters cmssignparams) {
118 ArrayList<X509Certificate> certList = new ArrayList<X509Certificate>();
119 certList.add(userpkandcert.getX509Certificate());
120
121
122
123 CertStore certstore = null;
124 try {
125 certstore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList), "BC");
126 } catch (InvalidAlgorithmParameterException e) {
127 log.error(""+e.getLocalizedMessage(),e);
128 } catch (NoSuchAlgorithmException e) {
129 log.error(""+e.getLocalizedMessage(),e);
130 } catch (NoSuchProviderException e) {
131 log.error(""+e.getLocalizedMessage(),e);
132 }
133 return certstore;
134 }
135
136 private String manageFileBeforeSignature(String original_file, boolean detached) {
137
138 String signed_file, p7sFile, p7mFile;
139
140
141 int dotpos = original_file.toLowerCase().lastIndexOf(".");
142 int fileseppos = original_file.lastIndexOf(File.separator);
143 if (dotpos>=0 && dotpos>fileseppos) {
144 p7sFile = original_file.substring(0,dotpos) + ".p7s";
145 p7mFile = original_file.substring(0,dotpos) + ".p7m";
146 } else {
147 p7sFile = original_file + ".p7s";
148 p7mFile = original_file + ".p7m";
149 }
150
151
152
153
154
155 if (detached) {
156 if (FileUtil.fileExists(p7sFile)) {
157
158
159
160 log.warn("Detached signature already exists : adding a new signature");
161 addsignature = true;
162
163
164
165 }
166 signed_file = p7sFile;
167 } else {
168 if (FileUtil.fileExists(p7mFile)) {
169 if (p7mFile.equals(original_file)) {
170
171
172 log.info("The CMS attached signature file already exists : adding a new signature");
173 addsignature = true;
174 } else {
175
176
177
178 String confirmmsg = "We detect that " + p7mFile + " exists.\nDo you want to overwrite it, and loose old sinatures?";
179 if (EParapherManager.getInstance().getUI().askUserYesNo(confirmmsg)) {
180 log.info("The existing p7m will be overwritten...");
181 } else
182 return null;
183 }
184 }
185 signed_file = p7mFile;
186 }
187
188 return signed_file;
189 }
190
191 }