\r
package org.apache.poi.poifs.crypt;\r
\r
-import javax.xml.crypto.dsig.DigestMethod;\r
-\r
import org.apache.poi.EncryptedDocumentException;\r
\r
public enum HashAlgorithm {\r
- none ( "", 0x0000, "", 0, "", null, false),\r
- sha1 ( "SHA-1", 0x8004, "SHA1", 20, "HmacSHA1", DigestMethod.SHA1, false),\r
- sha256 ( "SHA-256", 0x800C, "SHA256", 32, "HmacSHA256", DigestMethod.SHA256, false),\r
- sha384 ( "SHA-384", 0x800D, "SHA384", 48, "HmacSHA384", null, false),\r
- sha512 ( "SHA-512", 0x800E, "SHA512", 64, "HmacSHA512", DigestMethod.SHA512, false),\r
+ none ( "", 0x0000, "", 0, "", false),\r
+ sha1 ( "SHA-1", 0x8004, "SHA1", 20, "HmacSHA1", false),\r
+ sha256 ( "SHA-256", 0x800C, "SHA256", 32, "HmacSHA256", false),\r
+ sha384 ( "SHA-384", 0x800D, "SHA384", 48, "HmacSHA384", false),\r
+ sha512 ( "SHA-512", 0x800E, "SHA512", 64, "HmacSHA512", false),\r
/* only for agile encryption */\r
- md5 ( "MD5", -1, "MD5", 16, "HmacMD5", null, false),\r
+ md5 ( "MD5", -1, "MD5", 16, "HmacMD5", false),\r
// although sunjc2 supports md2, hmac-md2 is only supported by bouncycastle\r
- md2 ( "MD2", -1, "MD2", 16, "Hmac-MD2", null, true),\r
- md4 ( "MD4", -1, "MD4", 16, "Hmac-MD4", null, true),\r
- ripemd128("RipeMD128", -1, "RIPEMD-128", 16, "HMac-RipeMD128", null, true),\r
- ripemd160("RipeMD160", -1, "RIPEMD-160", 20, "HMac-RipeMD160", DigestMethod.RIPEMD160, true),\r
- whirlpool("Whirlpool", -1, "WHIRLPOOL", 64, "HMac-Whirlpool", null, true),\r
+ md2 ( "MD2", -1, "MD2", 16, "Hmac-MD2", true),\r
+ md4 ( "MD4", -1, "MD4", 16, "Hmac-MD4", true),\r
+ ripemd128("RipeMD128", -1, "RIPEMD-128", 16, "HMac-RipeMD128", true),\r
+ ripemd160("RipeMD160", -1, "RIPEMD-160", 20, "HMac-RipeMD160", true),\r
+ whirlpool("Whirlpool", -1, "WHIRLPOOL", 64, "HMac-Whirlpool", true),\r
+ // only for xml signing\r
+ sha224 ( "SHA-224", -1, "SHA224", 28, "HmacSHA224", true);\r
;\r
\r
public final String jceId;\r
public final String ecmaString;\r
public final int hashSize;\r
public final String jceHmacId;\r
- public final String xmlSignUri;\r
public final boolean needsBouncyCastle;\r
\r
- HashAlgorithm(String jceId, int ecmaId, String ecmaString, int hashSize, String jceHmacId, String xmlSignUri, boolean needsBouncyCastle) {\r
+ HashAlgorithm(String jceId, int ecmaId, String ecmaString, int hashSize, String jceHmacId, boolean needsBouncyCastle) {\r
this.jceId = jceId;\r
this.ecmaId = ecmaId;\r
this.ecmaString = ecmaString;\r
this.hashSize = hashSize;\r
this.jceHmacId = jceHmacId;\r
- this.xmlSignUri = xmlSignUri;\r
this.needsBouncyCastle = needsBouncyCastle;\r
}\r
\r
\r
import java.security.Key;\r
import java.security.cert.X509Certificate;\r
+import java.util.ArrayList;\r
import java.util.List;\r
\r
import javax.xml.crypto.AlgorithmMethod;\r
\r
private static final POILogger LOG = POILogFactory.getLogger(KeyInfoKeySelector.class);\r
\r
- private X509Certificate certificate;\r
+ private List<X509Certificate> certChain = new ArrayList<X509Certificate>();\r
\r
@SuppressWarnings("unchecked")\r
@Override\r
throw new KeySelectorException("no ds:KeyInfo present");\r
}\r
List<XMLStructure> keyInfoContent = keyInfo.getContent();\r
- this.certificate = null;\r
+ certChain.clear();\r
for (XMLStructure keyInfoStructure : keyInfoContent) {\r
- if (false == (keyInfoStructure instanceof X509Data)) {\r
+ if (!(keyInfoStructure instanceof X509Data)) {\r
continue;\r
}\r
X509Data x509Data = (X509Data) keyInfoStructure;\r
List<Object> x509DataList = x509Data.getContent();\r
for (Object x509DataObject : x509DataList) {\r
- if (false == (x509DataObject instanceof X509Certificate)) {\r
+ if (!(x509DataObject instanceof X509Certificate)) {\r
continue;\r
}\r
X509Certificate certificate = (X509Certificate) x509DataObject;\r
LOG.log(POILogger.DEBUG, "certificate", certificate.getSubjectX500Principal());\r
- if (null == this.certificate) {\r
- /*\r
- * The first certificate is presumably the signer.\r
- */\r
- this.certificate = certificate;\r
- }\r
- }\r
- if (null != this.certificate) {\r
- return this;\r
+ certChain.add(certificate);\r
}\r
}\r
- throw new KeySelectorException("No key found!");\r
+ if (certChain.isEmpty()) {\r
+ throw new KeySelectorException("No key found!");\r
+ }\r
+ return this;\r
}\r
\r
public Key getKey() {\r
- return this.certificate.getPublicKey();\r
+ // The first certificate is presumably the signer.\r
+ return certChain.isEmpty() ? null : certChain.get(0).getPublicKey();\r
}\r
\r
/**\r
* \r
* @return\r
*/\r
- public X509Certificate getCertificate() {\r
- return this.certificate;\r
+ public X509Certificate getSigner() {\r
+ // The first certificate is presumably the signer.\r
+ return certChain.isEmpty() ? null : certChain.get(0);\r
+ }\r
+ \r
+ public List<X509Certificate> getCertChain() {\r
+ return certChain;\r
}\r
}\r
\r
import javax.xml.crypto.URIDereferencer;\r
import javax.xml.crypto.dsig.CanonicalizationMethod;\r
+import javax.xml.crypto.dsig.DigestMethod;\r
\r
import org.apache.poi.EncryptedDocumentException;\r
import org.apache.poi.openxml4j.opc.OPCPackage;\r
// timestamp service provider URL\r
private String tspUrl;\r
private boolean tspOldProtocol = false;\r
- private HashAlgorithm tspDigestAlgo = HashAlgorithm.sha1;\r
+ /**\r
+ * if not defined, it's the same as the main digest\r
+ */\r
+ private HashAlgorithm tspDigestAlgo = null;\r
private String tspUser;\r
private String tspPass;\r
private TimeStampServiceValidator tspValidator;\r
* When <code>null</code> the signature will be limited to XAdES-T only.\r
*/\r
private RevocationDataService revocationDataService;\r
- private HashAlgorithm xadesDigestAlgo = HashAlgorithm.sha1;\r
+ /**\r
+ * if not defined, it's the same as the main digest\r
+ */\r
+ private HashAlgorithm xadesDigestAlgo = null;\r
private String xadesRole = null;\r
private String xadesSignatureId = null;\r
private boolean xadesSignaturePolicyImplied = true;\r
return packageSignatureId;\r
}\r
public void setPackageSignatureId(String packageSignatureId) {\r
- this.packageSignatureId = (packageSignatureId != null)\r
- ? packageSignatureId\r
- : "xmldsig-" + UUID.randomUUID();\r
+ this.packageSignatureId = nvl(packageSignatureId,"xmldsig-"+UUID.randomUUID());\r
}\r
public String getTspUrl() {\r
return tspUrl;\r
this.tspOldProtocol = tspOldProtocol;\r
}\r
public HashAlgorithm getTspDigestAlgo() {\r
- return tspDigestAlgo;\r
+ return nvl(tspDigestAlgo,digestAlgo);\r
}\r
public void setTspDigestAlgo(HashAlgorithm tspDigestAlgo) {\r
this.tspDigestAlgo = tspDigestAlgo;\r
this.revocationDataService = revocationDataService;\r
}\r
public HashAlgorithm getXadesDigestAlgo() {\r
- return xadesDigestAlgo;\r
+ return nvl(xadesDigestAlgo,digestAlgo);\r
}\r
public void setXadesDigestAlgo(HashAlgorithm xadesDigestAlgo) {\r
this.xadesDigestAlgo = xadesDigestAlgo;\r
public void setNamespacePrefixes(Map<String, String> namespacePrefixes) {\r
this.namespacePrefixes = namespacePrefixes;\r
}\r
+ protected static <T> T nvl(T value, T defaultValue) {\r
+ return value == null ? defaultValue : value;\r
+ }\r
+ public byte[] getHashMagic() {\r
+ // see https://www.ietf.org/rfc/rfc3110.txt\r
+ // RSA/SHA1 SIG Resource Records\r
+ byte result[];\r
+ switch (getDigestAlgo()) {\r
+ case sha1: result = new byte[]\r
+ { 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e\r
+ , 0x03, 0x02, 0x1a, 0x04, 0x14 };\r
+ break;\r
+ case sha224: result = new byte[] \r
+ { 0x30, 0x2b, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
+ , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x04, 0x1c };\r
+ break;\r
+ case sha256: result = new byte[]\r
+ { 0x30, 0x2f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
+ , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x04, 0x20 };\r
+ break;\r
+ case sha384: result = new byte[]\r
+ { 0x30, 0x3f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
+ , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x04, 0x30 };\r
+ break;\r
+ case sha512: result = new byte[]\r
+ { 0x30, 0x4f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
+ , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x04, 0x40 };\r
+ break;\r
+ case ripemd128: result = new byte[]\r
+ { 0x30, 0x1b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24\r
+ , 0x03, 0x02, 0x02, 0x04, 0x10 };\r
+ break;\r
+ case ripemd160: result = new byte[]\r
+ { 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24\r
+ , 0x03, 0x02, 0x01, 0x04, 0x14 };\r
+ break;\r
+ // case ripemd256: result = new byte[]\r
+ // { 0x30, 0x2b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24\r
+ // , 0x03, 0x02, 0x03, 0x04, 0x20 };\r
+ // break;\r
+ default: throw new EncryptedDocumentException("Hash algorithm "\r
+ +getDigestAlgo()+" not supported for signing.");\r
+ }\r
+ \r
+ return result;\r
+ }\r
+\r
+ public String getSignatureMethod() {\r
+ switch (getDigestAlgo()) {\r
+ case sha1: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;\r
+ case sha224: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA224;\r
+ case sha256: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256;\r
+ case sha384: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384;\r
+ case sha512: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512;\r
+ case ripemd160: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_RIPEMD160;\r
+ default: throw new EncryptedDocumentException("Hash algorithm "\r
+ +getDigestAlgo()+" not supported for signing.");\r
+ }\r
+ }\r
+ \r
+ public String getDigestMethodUri() {\r
+ return getDigestMethodUri(getDigestAlgo());\r
+ }\r
+ \r
+ public static String getDigestMethodUri(HashAlgorithm digestAlgo) {\r
+ switch (digestAlgo) {\r
+ case sha1: return DigestMethod.SHA1;\r
+ case sha224: return "http://www.w3.org/2001/04/xmldsig-more#sha224";\r
+ case sha256: return DigestMethod.SHA256;\r
+ case sha384: return "http://www.w3.org/2001/04/xmldsig-more#sha384";\r
+ case sha512: return DigestMethod.SHA512;\r
+ case ripemd160: return DigestMethod.RIPEMD160;\r
+ default: throw new EncryptedDocumentException("Hash algorithm "\r
+ +digestAlgo+" not supported for signing.");\r
+ }\r
+ }\r
+ \r
}\r
package org.apache.poi.poifs.crypt.dsig;\r
\r
import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.XML_DIGSIG_NS;\r
-import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_MAC_HMAC_RIPEMD160;\r
-import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;\r
-import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256;\r
-import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384;\r
-import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512;\r
\r
import java.io.ByteArrayOutputStream;\r
import java.io.File;\r
\r
public class SignatureInfo implements SignatureConfigurable {\r
\r
- // see https://www.ietf.org/rfc/rfc3110.txt\r
- // RSA/SHA1 SIG Resource Records\r
- public static final byte[] SHA1_DIGEST_INFO_PREFIX = new byte[]\r
- { 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14 };\r
-\r
- public static final byte[] SHA224_DIGEST_INFO_PREFIX = new byte[] \r
- { 0x30, 0x2b, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
- , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x04, 0x1c };\r
-\r
- public static final byte[] SHA256_DIGEST_INFO_PREFIX = new byte[]\r
- { 0x30, 0x2f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
- , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x04, 0x20 };\r
-\r
- public static final byte[] SHA384_DIGEST_INFO_PREFIX = new byte[]\r
- { 0x30, 0x3f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
- , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x04, 0x30 };\r
-\r
- public static final byte[] SHA512_DIGEST_INFO_PREFIX = new byte[]\r
- { 0x30, 0x4f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86\r
- , 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x04, 0x40 };\r
-\r
- public static final byte[] RIPEMD128_DIGEST_INFO_PREFIX = new byte[]\r
- { 0x30, 0x1b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x02, 0x04, 0x10 };\r
-\r
- public static final byte[] RIPEMD160_DIGEST_INFO_PREFIX = new byte[]\r
- { 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x01, 0x04, 0x14 };\r
-\r
- public static final byte[] RIPEMD256_DIGEST_INFO_PREFIX = new byte[]\r
- { 0x30, 0x2b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x03, 0x04, 0x20 };\r
-\r
private static final POILogger LOG = POILogFactory.getLogger(SignatureInfo.class);\r
private static boolean isInitialized = false;\r
\r
public class SignaturePart {\r
private final PackagePart signaturePart;\r
private X509Certificate signer;\r
+ private List<X509Certificate> certChain;\r
\r
private SignaturePart(PackagePart signaturePart) {\r
this.signaturePart = signaturePart;\r
return signer;\r
}\r
\r
+ public List<X509Certificate> getCertChain() {\r
+ return certChain;\r
+ }\r
+ \r
public SignatureDocument getSignatureDocument() throws IOException, XmlException {\r
// TODO: check for XXE\r
return SignatureDocument.Factory.parse(signaturePart.getInputStream());\r
boolean valid = xmlSignature.validate(domValidateContext);\r
\r
if (valid) {\r
- signer = keySelector.getCertificate();\r
+ signer = keySelector.getSigner();\r
+ certChain = keySelector.getCertChain();\r
}\r
\r
return valid;\r
\r
try {\r
ByteArrayOutputStream digestInfoValueBuf = new ByteArrayOutputStream();\r
- digestInfoValueBuf.write(getHashMagic());\r
+ digestInfoValueBuf.write(signatureConfig.getHashMagic());\r
digestInfoValueBuf.write(digest);\r
byte[] digestInfoValue = digestInfoValueBuf.toByteArray();\r
byte[] signatureValue = cipher.doFinal(digestInfoValue);\r
throw new RuntimeException("JRE doesn't support default xml signature provider - set jsr105Provider system property!");\r
}\r
\r
- protected byte[] getHashMagic() {\r
- switch (signatureConfig.getDigestAlgo()) {\r
- case sha1: return SHA1_DIGEST_INFO_PREFIX;\r
- // sha224: return SHA224_DIGEST_INFO_PREFIX;\r
- case sha256: return SHA256_DIGEST_INFO_PREFIX;\r
- case sha384: return SHA384_DIGEST_INFO_PREFIX;\r
- case sha512: return SHA512_DIGEST_INFO_PREFIX;\r
- case ripemd128: return RIPEMD128_DIGEST_INFO_PREFIX;\r
- case ripemd160: return RIPEMD160_DIGEST_INFO_PREFIX;\r
- // case ripemd256: return RIPEMD256_DIGEST_INFO_PREFIX;\r
- default: throw new EncryptedDocumentException("Hash algorithm "+signatureConfig.getDigestAlgo()+" not supported for signing.");\r
- }\r
- }\r
-\r
- protected String getSignatureMethod() {\r
- switch (signatureConfig.getDigestAlgo()) {\r
- case sha1: return ALGO_ID_SIGNATURE_RSA_SHA1;\r
- case sha256: return ALGO_ID_SIGNATURE_RSA_SHA256;\r
- case sha384: return ALGO_ID_SIGNATURE_RSA_SHA384;\r
- case sha512: return ALGO_ID_SIGNATURE_RSA_SHA512;\r
- case ripemd160: return ALGO_ID_MAC_HMAC_RIPEMD160;\r
- default: throw new EncryptedDocumentException("Hash algorithm "+signatureConfig.getDigestAlgo()+" not supported for signing.");\r
- }\r
- }\r
- \r
protected static synchronized void initXmlProvider() {\r
if (isInitialized) return;\r
isInitialized = true;\r
for (DigestInfo digestInfo : safe(digestInfos)) {\r
byte[] documentDigestValue = digestInfo.digestValue;\r
\r
- DigestMethod digestMethod = signatureFactory.newDigestMethod(\r
- digestInfo.hashAlgo.xmlSignUri, null);\r
+ DigestMethod digestMethod = signatureFactory.newDigestMethod\r
+ (signatureConfig.getDigestMethodUri(), null);\r
\r
String uri = new File(digestInfo.description).getName();\r
\r
/*\r
* ds:SignedInfo\r
*/\r
- SignatureMethod signatureMethod = signatureFactory.newSignatureMethod(getSignatureMethod(), null);\r
+ SignatureMethod signatureMethod = signatureFactory.newSignatureMethod\r
+ (signatureConfig.getSignatureMethod(), null);\r
CanonicalizationMethod canonicalizationMethod = signatureFactory\r
.newCanonicalizationMethod(signatureConfig.getCanonicalizationMethod(),\r
(C14NMethodParameterSpec) null);\r
, List<Reference> references\r
, List<XMLObject> objects)\r
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {\r
- DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);\r
+ DigestMethod digestMethod = signatureFactory.newDigestMethod\r
+ (signatureConfig.getDigestMethodUri(), null);\r
\r
List<Transform> transforms = new ArrayList<Transform>();\r
- Transform envelopedTransform = signatureFactory\r
- .newTransform(CanonicalizationMethod.ENVELOPED,\r
- (TransformParameterSpec) null);\r
+ Transform envelopedTransform = signatureFactory.newTransform\r
+ (CanonicalizationMethod.ENVELOPED, (TransformParameterSpec) null);\r
transforms.add(envelopedTransform);\r
- Transform exclusiveTransform = signatureFactory\r
- .newTransform(CanonicalizationMethod.EXCLUSIVE,\r
- (TransformParameterSpec) null);\r
+ Transform exclusiveTransform = signatureFactory.newTransform\r
+ (CanonicalizationMethod.EXCLUSIVE, (TransformParameterSpec) null);\r
transforms.add(exclusiveTransform);\r
\r
Reference reference = signatureFactory.newReference("", digestMethod,\r
XMLObject xo = signatureFactory.newXMLObject(objectContent, objectId, null, null);\r
objects.add(xo);\r
\r
- DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);\r
+ DigestMethod digestMethod = signatureFactory.newDigestMethod\r
+ (signatureConfig.getDigestMethodUri(), null);\r
Reference reference = signatureFactory.newReference\r
("#" + objectId, digestMethod, null, XML_DIGSIG_NS+"Object", null);\r
references.add(reference);\r
OPCPackage ooxml = signatureConfig.getOpcPackage();\r
List<PackagePart> relsEntryNames = ooxml.getPartsByContentType(ContentTypes.RELATIONSHIPS_PART);\r
\r
- DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);\r
+ DigestMethod digestMethod = signatureFactory.newDigestMethod\r
+ (signatureConfig.getDigestMethodUri(), null);\r
Set<String> digestedPartNames = new HashSet<String>();\r
for (PackagePart pp : relsEntryNames) {\r
String baseUri = pp.getPartName().getName().replaceFirst("(.*)/_rels/.*", "$1");\r
\r
SignatureInfoV1Document sigV1 = SignatureInfoV1Document.Factory.newInstance();\r
CTSignatureInfoV1 ctSigV1 = sigV1.addNewSignatureInfoV1();\r
- ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestAlgo().xmlSignUri);\r
+ ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestMethodUri());\r
Element n = (Element)document.importNode(ctSigV1.getDomNode(), true);\r
n.setAttributeNS(XML_NS, XMLConstants.XMLNS_ATTRIBUTE, MS_DIGSIG_NS);\r
\r
String objectId = "idOfficeObject";\r
objects.add(signatureFactory.newXMLObject(objectContent, objectId, null, null));\r
\r
- DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);\r
+ DigestMethod digestMethod = signatureFactory.newDigestMethod\r
+ (signatureConfig.getDigestMethodUri(), null);\r
Reference reference = signatureFactory.newReference\r
("#" + objectId, digestMethod, null, XML_DIGSIG_NS+"Object", null);\r
references.add(reference);\r
objects.add(xadesObject);\r
\r
// add XAdES ds:Reference\r
- DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);\r
+ DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestMethodUri(), null);\r
List<Transform> transforms = new ArrayList<Transform>();\r
Transform exclusiveTransform = signatureFactory\r
.newTransform(CanonicalizationMethod.INCLUSIVE,\r
protected static void setDigestAlgAndValue(\r
DigestAlgAndValueType digestAlgAndValue,\r
byte[] data,\r
- HashAlgorithm hashAlgo) {\r
+ HashAlgorithm digestAlgo) {\r
DigestMethodType digestMethod = digestAlgAndValue.addNewDigestMethod();\r
- digestMethod.setAlgorithm(hashAlgo.xmlSignUri);\r
+ digestMethod.setAlgorithm(SignatureConfig.getDigestMethodUri(digestAlgo));\r
\r
- MessageDigest messageDigest = CryptoFunctions.getMessageDigest(hashAlgo);\r
+ MessageDigest messageDigest = CryptoFunctions.getMessageDigest(digestAlgo);\r
byte[] digestValue = messageDigest.digest(data);\r
digestAlgAndValue.setDigestValue(digestValue);\r
}\r
package org.apache.poi.poifs.crypt;\r
\r
import static org.junit.Assert.assertEquals;\r
+import static org.junit.Assert.assertFalse;\r
import static org.junit.Assert.assertNotNull;\r
import static org.junit.Assert.assertTrue;\r
\r
import java.io.FileInputStream;\r
import java.io.FileOutputStream;\r
import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.lang.reflect.Method;\r
import java.net.MalformedURLException;\r
import java.net.URL;\r
import java.net.URLClassLoader;\r
import org.apache.poi.util.IOUtils;\r
import org.apache.poi.util.POILogFactory;\r
import org.apache.poi.util.POILogger;\r
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;\r
import org.apache.xmlbeans.XmlObject;\r
import org.bouncycastle.asn1.x509.KeyUsage;\r
import org.bouncycastle.cert.ocsp.OCSPResp;\r
pkg.close();\r
}\r
\r
+ @Test\r
+ public void testManipulation() throws Exception {\r
+ // sign & validate\r
+ String testFile = "hello-world-unsigned.xlsx";\r
+ OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);\r
+ sign(pkg, "Test", "CN=Test", 1);\r
+ \r
+ // manipulate\r
+ XSSFWorkbook wb = new XSSFWorkbook(pkg);\r
+ wb.setSheetName(0, "manipulated");\r
+ // ... I don't know, why commit is protected ...\r
+ Method m = XSSFWorkbook.class.getDeclaredMethod("commit");\r
+ m.setAccessible(true);\r
+ m.invoke(wb);\r
+\r
+ // todo: test a manipulation on a package part, which is not signed\r
+ // ... maybe in combination with #56164 \r
+ \r
+ // validate\r
+ SignatureConfig sic = new SignatureConfig();\r
+ sic.setOpcPackage(pkg);\r
+ SignatureInfo si = new SignatureInfo();\r
+ si.setSignatureConfig(sic);\r
+ boolean b = si.verifySignature();\r
+ assertFalse("signature should be broken", b);\r
+ \r
+ wb.close();\r
+ }\r
+ \r
@Test\r
public void testSignSpreadsheetWithSignatureInfo() throws Exception {\r
initKeyPair("Test", "CN=Test");\r
"$this/ds:Signature/ds:SignedInfo/ds:Reference";\r
for (ReferenceType rt : (ReferenceType[])sigDoc.selectPath(digestValXQuery)) {\r
assertNotNull(rt.getDigestValue());\r
- assertEquals(HashAlgorithm.sha1.xmlSignUri, rt.getDigestMethod().getAlgorithm());\r
+ assertEquals(signatureConfig.getDigestMethodUri(), rt.getDigestMethod().getAlgorithm());\r
}\r
\r
String certDigestXQuery = declareNS +\r
\r
pkg.close();\r
}\r
+\r
+ @Test\r
+ public void testCertChain() throws Exception {\r
+ KeyStore keystore = KeyStore.getInstance("PKCS12");\r
+ String password = "test";\r
+ InputStream is = testdata.openResourceAsStream("chaintest.pfx");\r
+ keystore.load(is, password.toCharArray());\r
+ is.close();\r
+\r
+ Key key = keystore.getKey("poitest", password.toCharArray());\r
+ Certificate chainList[] = keystore.getCertificateChain("poitest");\r
+ List<X509Certificate> certChain = new ArrayList<X509Certificate>();\r
+ for (Certificate c : chainList) {\r
+ certChain.add((X509Certificate)c);\r
+ }\r
+ x509 = certChain.get(0);\r
+ keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);\r
+ \r
+ String testFile = "hello-world-unsigned.xlsx";\r
+ OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);\r
+\r
+ SignatureConfig signatureConfig = new SignatureConfig();\r
+ signatureConfig.setKey(keyPair.getPrivate());\r
+ signatureConfig.setSigningCertificateChain(certChain);\r
+ Calendar cal = Calendar.getInstance();\r
+ cal.set(2007, 7, 1);\r
+ signatureConfig.setExecutionTime(cal.getTime());\r
+ signatureConfig.setDigestAlgo(HashAlgorithm.sha1);\r
+ signatureConfig.setOpcPackage(pkg);\r
+ \r
+ SignatureInfo si = new SignatureInfo();\r
+ si.setSignatureConfig(signatureConfig);\r
+\r
+ si.confirmSignature();\r
+ \r
+ for (SignaturePart sp : si.getSignatureParts()){\r
+ boolean b = sp.validate();\r
+ assertTrue(b);\r
+ X509Certificate signer = sp.getSigner();\r
+ assertNotNull("signer undefined?!", signer);\r
+ List<X509Certificate> certChainRes = sp.getCertChain();\r
+ assertEquals(3, certChainRes.size());\r
+ }\r
+ \r
+ pkg.close();\r
+ }\r
+\r
+ @Test\r
+ public void testNonSha1() throws Exception {\r
+ String testFile = "hello-world-unsigned.xlsx";\r
+ initKeyPair("Test", "CN=Test");\r
+\r
+ SignatureConfig signatureConfig = new SignatureConfig();\r
+ signatureConfig.setKey(keyPair.getPrivate());\r
+ signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));\r
+\r
+ HashAlgorithm testAlgo[] = { HashAlgorithm.sha224, HashAlgorithm.sha256\r
+ , HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.ripemd160 }; \r
+ \r
+ for (HashAlgorithm ha : testAlgo) {\r
+ signatureConfig.setDigestAlgo(ha);\r
+ OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);\r
+ signatureConfig.setOpcPackage(pkg);\r
+ \r
+ SignatureInfo si = new SignatureInfo();\r
+ si.setSignatureConfig(signatureConfig);\r
+ \r
+ si.confirmSignature();\r
+ boolean b = si.verifySignature();\r
+ pkg.close();\r
\r
- private OPCPackage sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception {\r
+ assertTrue(b);\r
+ }\r
+ }\r
+ \r
+ \r
+ private void sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception {\r
initKeyPair(alias, signerDn);\r
\r
SignatureConfig signatureConfig = new SignatureConfig();\r
}\r
}\r
assertEquals(signerCount, result.size());\r
-\r
- return pkgCopy;\r
}\r
\r
private void initKeyPair(String alias, String subjectDN) throws Exception {\r