Преглед изворни кода

more tests, some refactoring

git-svn-id: https://svn.apache.org/repos/asf/poi/branches/xml_signature@1628107 13f79535-47bb-0310-9956-ffa450edef68
tags/REL_3_11_BETA3
Andreas Beeker пре 9 година
родитељ
комит
9acd59dd9c

+ 14
- 16
src/java/org/apache/poi/poifs/crypt/HashAlgorithm.java Прегледај датотеку

package org.apache.poi.poifs.crypt; package org.apache.poi.poifs.crypt;
import javax.xml.crypto.dsig.DigestMethod;
import org.apache.poi.EncryptedDocumentException; import org.apache.poi.EncryptedDocumentException;
public enum HashAlgorithm { public enum HashAlgorithm {
none ( "", 0x0000, "", 0, "", null, false),
sha1 ( "SHA-1", 0x8004, "SHA1", 20, "HmacSHA1", DigestMethod.SHA1, false),
sha256 ( "SHA-256", 0x800C, "SHA256", 32, "HmacSHA256", DigestMethod.SHA256, false),
sha384 ( "SHA-384", 0x800D, "SHA384", 48, "HmacSHA384", null, false),
sha512 ( "SHA-512", 0x800E, "SHA512", 64, "HmacSHA512", DigestMethod.SHA512, false),
none ( "", 0x0000, "", 0, "", false),
sha1 ( "SHA-1", 0x8004, "SHA1", 20, "HmacSHA1", false),
sha256 ( "SHA-256", 0x800C, "SHA256", 32, "HmacSHA256", false),
sha384 ( "SHA-384", 0x800D, "SHA384", 48, "HmacSHA384", false),
sha512 ( "SHA-512", 0x800E, "SHA512", 64, "HmacSHA512", false),
/* only for agile encryption */ /* only for agile encryption */
md5 ( "MD5", -1, "MD5", 16, "HmacMD5", null, false),
md5 ( "MD5", -1, "MD5", 16, "HmacMD5", false),
// although sunjc2 supports md2, hmac-md2 is only supported by bouncycastle // although sunjc2 supports md2, hmac-md2 is only supported by bouncycastle
md2 ( "MD2", -1, "MD2", 16, "Hmac-MD2", null, true),
md4 ( "MD4", -1, "MD4", 16, "Hmac-MD4", null, true),
ripemd128("RipeMD128", -1, "RIPEMD-128", 16, "HMac-RipeMD128", null, true),
ripemd160("RipeMD160", -1, "RIPEMD-160", 20, "HMac-RipeMD160", DigestMethod.RIPEMD160, true),
whirlpool("Whirlpool", -1, "WHIRLPOOL", 64, "HMac-Whirlpool", null, true),
md2 ( "MD2", -1, "MD2", 16, "Hmac-MD2", true),
md4 ( "MD4", -1, "MD4", 16, "Hmac-MD4", true),
ripemd128("RipeMD128", -1, "RIPEMD-128", 16, "HMac-RipeMD128", true),
ripemd160("RipeMD160", -1, "RIPEMD-160", 20, "HMac-RipeMD160", true),
whirlpool("Whirlpool", -1, "WHIRLPOOL", 64, "HMac-Whirlpool", true),
// only for xml signing
sha224 ( "SHA-224", -1, "SHA224", 28, "HmacSHA224", true);
; ;
public final String jceId; public final String jceId;
public final String ecmaString; public final String ecmaString;
public final int hashSize; public final int hashSize;
public final String jceHmacId; public final String jceHmacId;
public final String xmlSignUri;
public final boolean needsBouncyCastle; public final boolean needsBouncyCastle;
HashAlgorithm(String jceId, int ecmaId, String ecmaString, int hashSize, String jceHmacId, String xmlSignUri, boolean needsBouncyCastle) {
HashAlgorithm(String jceId, int ecmaId, String ecmaString, int hashSize, String jceHmacId, boolean needsBouncyCastle) {
this.jceId = jceId; this.jceId = jceId;
this.ecmaId = ecmaId; this.ecmaId = ecmaId;
this.ecmaString = ecmaString; this.ecmaString = ecmaString;
this.hashSize = hashSize; this.hashSize = hashSize;
this.jceHmacId = jceHmacId; this.jceHmacId = jceHmacId;
this.xmlSignUri = xmlSignUri;
this.needsBouncyCastle = needsBouncyCastle; this.needsBouncyCastle = needsBouncyCastle;
} }

+ 19
- 17
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/KeyInfoKeySelector.java Прегледај датотеку

import java.security.Key; import java.security.Key;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.xml.crypto.AlgorithmMethod; import javax.xml.crypto.AlgorithmMethod;
private static final POILogger LOG = POILogFactory.getLogger(KeyInfoKeySelector.class); private static final POILogger LOG = POILogFactory.getLogger(KeyInfoKeySelector.class);
private X509Certificate certificate;
private List<X509Certificate> certChain = new ArrayList<X509Certificate>();
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
throw new KeySelectorException("no ds:KeyInfo present"); throw new KeySelectorException("no ds:KeyInfo present");
} }
List<XMLStructure> keyInfoContent = keyInfo.getContent(); List<XMLStructure> keyInfoContent = keyInfo.getContent();
this.certificate = null;
certChain.clear();
for (XMLStructure keyInfoStructure : keyInfoContent) { for (XMLStructure keyInfoStructure : keyInfoContent) {
if (false == (keyInfoStructure instanceof X509Data)) {
if (!(keyInfoStructure instanceof X509Data)) {
continue; continue;
} }
X509Data x509Data = (X509Data) keyInfoStructure; X509Data x509Data = (X509Data) keyInfoStructure;
List<Object> x509DataList = x509Data.getContent(); List<Object> x509DataList = x509Data.getContent();
for (Object x509DataObject : x509DataList) { for (Object x509DataObject : x509DataList) {
if (false == (x509DataObject instanceof X509Certificate)) {
if (!(x509DataObject instanceof X509Certificate)) {
continue; continue;
} }
X509Certificate certificate = (X509Certificate) x509DataObject; X509Certificate certificate = (X509Certificate) x509DataObject;
LOG.log(POILogger.DEBUG, "certificate", certificate.getSubjectX500Principal()); LOG.log(POILogger.DEBUG, "certificate", certificate.getSubjectX500Principal());
if (null == this.certificate) {
/*
* The first certificate is presumably the signer.
*/
this.certificate = certificate;
}
}
if (null != this.certificate) {
return this;
certChain.add(certificate);
} }
} }
throw new KeySelectorException("No key found!");
if (certChain.isEmpty()) {
throw new KeySelectorException("No key found!");
}
return this;
} }
public Key getKey() { public Key getKey() {
return this.certificate.getPublicKey();
// The first certificate is presumably the signer.
return certChain.isEmpty() ? null : certChain.get(0).getPublicKey();
} }
/** /**
* *
* @return * @return
*/ */
public X509Certificate getCertificate() {
return this.certificate;
public X509Certificate getSigner() {
// The first certificate is presumably the signer.
return certChain.isEmpty() ? null : certChain.get(0);
}
public List<X509Certificate> getCertChain() {
return certChain;
} }
} }

+ 89
- 7
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureConfig.java Прегледај датотеку

import javax.xml.crypto.URIDereferencer; import javax.xml.crypto.URIDereferencer;
import javax.xml.crypto.dsig.CanonicalizationMethod; import javax.xml.crypto.dsig.CanonicalizationMethod;
import javax.xml.crypto.dsig.DigestMethod;
import org.apache.poi.EncryptedDocumentException; import org.apache.poi.EncryptedDocumentException;
import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.OPCPackage;
// timestamp service provider URL // timestamp service provider URL
private String tspUrl; private String tspUrl;
private boolean tspOldProtocol = false; private boolean tspOldProtocol = false;
private HashAlgorithm tspDigestAlgo = HashAlgorithm.sha1;
/**
* if not defined, it's the same as the main digest
*/
private HashAlgorithm tspDigestAlgo = null;
private String tspUser; private String tspUser;
private String tspPass; private String tspPass;
private TimeStampServiceValidator tspValidator; private TimeStampServiceValidator tspValidator;
* When <code>null</code> the signature will be limited to XAdES-T only. * When <code>null</code> the signature will be limited to XAdES-T only.
*/ */
private RevocationDataService revocationDataService; private RevocationDataService revocationDataService;
private HashAlgorithm xadesDigestAlgo = HashAlgorithm.sha1;
/**
* if not defined, it's the same as the main digest
*/
private HashAlgorithm xadesDigestAlgo = null;
private String xadesRole = null; private String xadesRole = null;
private String xadesSignatureId = null; private String xadesSignatureId = null;
private boolean xadesSignaturePolicyImplied = true; private boolean xadesSignaturePolicyImplied = true;
return packageSignatureId; return packageSignatureId;
} }
public void setPackageSignatureId(String packageSignatureId) { public void setPackageSignatureId(String packageSignatureId) {
this.packageSignatureId = (packageSignatureId != null)
? packageSignatureId
: "xmldsig-" + UUID.randomUUID();
this.packageSignatureId = nvl(packageSignatureId,"xmldsig-"+UUID.randomUUID());
} }
public String getTspUrl() { public String getTspUrl() {
return tspUrl; return tspUrl;
this.tspOldProtocol = tspOldProtocol; this.tspOldProtocol = tspOldProtocol;
} }
public HashAlgorithm getTspDigestAlgo() { public HashAlgorithm getTspDigestAlgo() {
return tspDigestAlgo;
return nvl(tspDigestAlgo,digestAlgo);
} }
public void setTspDigestAlgo(HashAlgorithm tspDigestAlgo) { public void setTspDigestAlgo(HashAlgorithm tspDigestAlgo) {
this.tspDigestAlgo = tspDigestAlgo; this.tspDigestAlgo = tspDigestAlgo;
this.revocationDataService = revocationDataService; this.revocationDataService = revocationDataService;
} }
public HashAlgorithm getXadesDigestAlgo() { public HashAlgorithm getXadesDigestAlgo() {
return xadesDigestAlgo;
return nvl(xadesDigestAlgo,digestAlgo);
} }
public void setXadesDigestAlgo(HashAlgorithm xadesDigestAlgo) { public void setXadesDigestAlgo(HashAlgorithm xadesDigestAlgo) {
this.xadesDigestAlgo = xadesDigestAlgo; this.xadesDigestAlgo = xadesDigestAlgo;
public void setNamespacePrefixes(Map<String, String> namespacePrefixes) { public void setNamespacePrefixes(Map<String, String> namespacePrefixes) {
this.namespacePrefixes = namespacePrefixes; this.namespacePrefixes = namespacePrefixes;
} }
protected static <T> T nvl(T value, T defaultValue) {
return value == null ? defaultValue : value;
}
public byte[] getHashMagic() {
// see https://www.ietf.org/rfc/rfc3110.txt
// RSA/SHA1 SIG Resource Records
byte result[];
switch (getDigestAlgo()) {
case sha1: result = new byte[]
{ 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e
, 0x03, 0x02, 0x1a, 0x04, 0x14 };
break;
case sha224: result = new byte[]
{ 0x30, 0x2b, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86
, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x04, 0x1c };
break;
case sha256: result = new byte[]
{ 0x30, 0x2f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86
, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x04, 0x20 };
break;
case sha384: result = new byte[]
{ 0x30, 0x3f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86
, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x04, 0x30 };
break;
case sha512: result = new byte[]
{ 0x30, 0x4f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86
, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x04, 0x40 };
break;
case ripemd128: result = new byte[]
{ 0x30, 0x1b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24
, 0x03, 0x02, 0x02, 0x04, 0x10 };
break;
case ripemd160: result = new byte[]
{ 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24
, 0x03, 0x02, 0x01, 0x04, 0x14 };
break;
// case ripemd256: result = new byte[]
// { 0x30, 0x2b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24
// , 0x03, 0x02, 0x03, 0x04, 0x20 };
// break;
default: throw new EncryptedDocumentException("Hash algorithm "
+getDigestAlgo()+" not supported for signing.");
}
return result;
}
public String getSignatureMethod() {
switch (getDigestAlgo()) {
case sha1: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;
case sha224: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA224;
case sha256: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256;
case sha384: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384;
case sha512: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512;
case ripemd160: return org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_RIPEMD160;
default: throw new EncryptedDocumentException("Hash algorithm "
+getDigestAlgo()+" not supported for signing.");
}
}
public String getDigestMethodUri() {
return getDigestMethodUri(getDigestAlgo());
}
public static String getDigestMethodUri(HashAlgorithm digestAlgo) {
switch (digestAlgo) {
case sha1: return DigestMethod.SHA1;
case sha224: return "http://www.w3.org/2001/04/xmldsig-more#sha224";
case sha256: return DigestMethod.SHA256;
case sha384: return "http://www.w3.org/2001/04/xmldsig-more#sha384";
case sha512: return DigestMethod.SHA512;
case ripemd160: return DigestMethod.RIPEMD160;
default: throw new EncryptedDocumentException("Hash algorithm "
+digestAlgo+" not supported for signing.");
}
}
} }

+ 12
- 65
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/SignatureInfo.java Прегледај датотеку

package org.apache.poi.poifs.crypt.dsig; package org.apache.poi.poifs.crypt.dsig;
import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.XML_DIGSIG_NS; import static org.apache.poi.poifs.crypt.dsig.facets.SignatureFacet.XML_DIGSIG_NS;
import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_MAC_HMAC_RIPEMD160;
import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1;
import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256;
import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA384;
import static org.apache.xml.security.signature.XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA512;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
public class SignatureInfo implements SignatureConfigurable { public class SignatureInfo implements SignatureConfigurable {
// see https://www.ietf.org/rfc/rfc3110.txt
// RSA/SHA1 SIG Resource Records
public static final byte[] SHA1_DIGEST_INFO_PREFIX = new byte[]
{ 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x04, 0x14 };
public static final byte[] SHA224_DIGEST_INFO_PREFIX = new byte[]
{ 0x30, 0x2b, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86
, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x04, 0x1c };
public static final byte[] SHA256_DIGEST_INFO_PREFIX = new byte[]
{ 0x30, 0x2f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86
, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x04, 0x20 };
public static final byte[] SHA384_DIGEST_INFO_PREFIX = new byte[]
{ 0x30, 0x3f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86
, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x04, 0x30 };
public static final byte[] SHA512_DIGEST_INFO_PREFIX = new byte[]
{ 0x30, 0x4f, 0x30, 0x0b, 0x06, 0x09, 0x60, (byte) 0x86
, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x04, 0x40 };
public static final byte[] RIPEMD128_DIGEST_INFO_PREFIX = new byte[]
{ 0x30, 0x1b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x02, 0x04, 0x10 };
public static final byte[] RIPEMD160_DIGEST_INFO_PREFIX = new byte[]
{ 0x30, 0x1f, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x01, 0x04, 0x14 };
public static final byte[] RIPEMD256_DIGEST_INFO_PREFIX = new byte[]
{ 0x30, 0x2b, 0x30, 0x07, 0x06, 0x05, 0x2b, 0x24, 0x03, 0x02, 0x03, 0x04, 0x20 };
private static final POILogger LOG = POILogFactory.getLogger(SignatureInfo.class); private static final POILogger LOG = POILogFactory.getLogger(SignatureInfo.class);
private static boolean isInitialized = false; private static boolean isInitialized = false;
public class SignaturePart { public class SignaturePart {
private final PackagePart signaturePart; private final PackagePart signaturePart;
private X509Certificate signer; private X509Certificate signer;
private List<X509Certificate> certChain;
private SignaturePart(PackagePart signaturePart) { private SignaturePart(PackagePart signaturePart) {
this.signaturePart = signaturePart; this.signaturePart = signaturePart;
return signer; return signer;
} }
public List<X509Certificate> getCertChain() {
return certChain;
}
public SignatureDocument getSignatureDocument() throws IOException, XmlException { public SignatureDocument getSignatureDocument() throws IOException, XmlException {
// TODO: check for XXE // TODO: check for XXE
return SignatureDocument.Factory.parse(signaturePart.getInputStream()); return SignatureDocument.Factory.parse(signaturePart.getInputStream());
boolean valid = xmlSignature.validate(domValidateContext); boolean valid = xmlSignature.validate(domValidateContext);
if (valid) { if (valid) {
signer = keySelector.getCertificate();
signer = keySelector.getSigner();
certChain = keySelector.getCertChain();
} }
return valid; return valid;
try { try {
ByteArrayOutputStream digestInfoValueBuf = new ByteArrayOutputStream(); ByteArrayOutputStream digestInfoValueBuf = new ByteArrayOutputStream();
digestInfoValueBuf.write(getHashMagic());
digestInfoValueBuf.write(signatureConfig.getHashMagic());
digestInfoValueBuf.write(digest); digestInfoValueBuf.write(digest);
byte[] digestInfoValue = digestInfoValueBuf.toByteArray(); byte[] digestInfoValue = digestInfoValueBuf.toByteArray();
byte[] signatureValue = cipher.doFinal(digestInfoValue); byte[] signatureValue = cipher.doFinal(digestInfoValue);
throw new RuntimeException("JRE doesn't support default xml signature provider - set jsr105Provider system property!"); throw new RuntimeException("JRE doesn't support default xml signature provider - set jsr105Provider system property!");
} }
protected byte[] getHashMagic() {
switch (signatureConfig.getDigestAlgo()) {
case sha1: return SHA1_DIGEST_INFO_PREFIX;
// sha224: return SHA224_DIGEST_INFO_PREFIX;
case sha256: return SHA256_DIGEST_INFO_PREFIX;
case sha384: return SHA384_DIGEST_INFO_PREFIX;
case sha512: return SHA512_DIGEST_INFO_PREFIX;
case ripemd128: return RIPEMD128_DIGEST_INFO_PREFIX;
case ripemd160: return RIPEMD160_DIGEST_INFO_PREFIX;
// case ripemd256: return RIPEMD256_DIGEST_INFO_PREFIX;
default: throw new EncryptedDocumentException("Hash algorithm "+signatureConfig.getDigestAlgo()+" not supported for signing.");
}
}
protected String getSignatureMethod() {
switch (signatureConfig.getDigestAlgo()) {
case sha1: return ALGO_ID_SIGNATURE_RSA_SHA1;
case sha256: return ALGO_ID_SIGNATURE_RSA_SHA256;
case sha384: return ALGO_ID_SIGNATURE_RSA_SHA384;
case sha512: return ALGO_ID_SIGNATURE_RSA_SHA512;
case ripemd160: return ALGO_ID_MAC_HMAC_RIPEMD160;
default: throw new EncryptedDocumentException("Hash algorithm "+signatureConfig.getDigestAlgo()+" not supported for signing.");
}
}
protected static synchronized void initXmlProvider() { protected static synchronized void initXmlProvider() {
if (isInitialized) return; if (isInitialized) return;
isInitialized = true; isInitialized = true;
for (DigestInfo digestInfo : safe(digestInfos)) { for (DigestInfo digestInfo : safe(digestInfos)) {
byte[] documentDigestValue = digestInfo.digestValue; byte[] documentDigestValue = digestInfo.digestValue;
DigestMethod digestMethod = signatureFactory.newDigestMethod(
digestInfo.hashAlgo.xmlSignUri, null);
DigestMethod digestMethod = signatureFactory.newDigestMethod
(signatureConfig.getDigestMethodUri(), null);
String uri = new File(digestInfo.description).getName(); String uri = new File(digestInfo.description).getName();
/* /*
* ds:SignedInfo * ds:SignedInfo
*/ */
SignatureMethod signatureMethod = signatureFactory.newSignatureMethod(getSignatureMethod(), null);
SignatureMethod signatureMethod = signatureFactory.newSignatureMethod
(signatureConfig.getSignatureMethod(), null);
CanonicalizationMethod canonicalizationMethod = signatureFactory CanonicalizationMethod canonicalizationMethod = signatureFactory
.newCanonicalizationMethod(signatureConfig.getCanonicalizationMethod(), .newCanonicalizationMethod(signatureConfig.getCanonicalizationMethod(),
(C14NMethodParameterSpec) null); (C14NMethodParameterSpec) null);

+ 6
- 7
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/EnvelopedSignatureFacet.java Прегледај датотеку

, List<Reference> references , List<Reference> references
, List<XMLObject> objects) , List<XMLObject> objects)
throws NoSuchAlgorithmException, InvalidAlgorithmParameterException { throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);
DigestMethod digestMethod = signatureFactory.newDigestMethod
(signatureConfig.getDigestMethodUri(), null);
List<Transform> transforms = new ArrayList<Transform>(); List<Transform> transforms = new ArrayList<Transform>();
Transform envelopedTransform = signatureFactory
.newTransform(CanonicalizationMethod.ENVELOPED,
(TransformParameterSpec) null);
Transform envelopedTransform = signatureFactory.newTransform
(CanonicalizationMethod.ENVELOPED, (TransformParameterSpec) null);
transforms.add(envelopedTransform); transforms.add(envelopedTransform);
Transform exclusiveTransform = signatureFactory
.newTransform(CanonicalizationMethod.EXCLUSIVE,
(TransformParameterSpec) null);
Transform exclusiveTransform = signatureFactory.newTransform
(CanonicalizationMethod.EXCLUSIVE, (TransformParameterSpec) null);
transforms.add(exclusiveTransform); transforms.add(exclusiveTransform);
Reference reference = signatureFactory.newReference("", digestMethod, Reference reference = signatureFactory.newReference("", digestMethod,

+ 7
- 4
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/OOXMLSignatureFacet.java Прегледај датотеку

XMLObject xo = signatureFactory.newXMLObject(objectContent, objectId, null, null); XMLObject xo = signatureFactory.newXMLObject(objectContent, objectId, null, null);
objects.add(xo); objects.add(xo);
DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);
DigestMethod digestMethod = signatureFactory.newDigestMethod
(signatureConfig.getDigestMethodUri(), null);
Reference reference = signatureFactory.newReference Reference reference = signatureFactory.newReference
("#" + objectId, digestMethod, null, XML_DIGSIG_NS+"Object", null); ("#" + objectId, digestMethod, null, XML_DIGSIG_NS+"Object", null);
references.add(reference); references.add(reference);
OPCPackage ooxml = signatureConfig.getOpcPackage(); OPCPackage ooxml = signatureConfig.getOpcPackage();
List<PackagePart> relsEntryNames = ooxml.getPartsByContentType(ContentTypes.RELATIONSHIPS_PART); List<PackagePart> relsEntryNames = ooxml.getPartsByContentType(ContentTypes.RELATIONSHIPS_PART);
DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);
DigestMethod digestMethod = signatureFactory.newDigestMethod
(signatureConfig.getDigestMethodUri(), null);
Set<String> digestedPartNames = new HashSet<String>(); Set<String> digestedPartNames = new HashSet<String>();
for (PackagePart pp : relsEntryNames) { for (PackagePart pp : relsEntryNames) {
String baseUri = pp.getPartName().getName().replaceFirst("(.*)/_rels/.*", "$1"); String baseUri = pp.getPartName().getName().replaceFirst("(.*)/_rels/.*", "$1");
SignatureInfoV1Document sigV1 = SignatureInfoV1Document.Factory.newInstance(); SignatureInfoV1Document sigV1 = SignatureInfoV1Document.Factory.newInstance();
CTSignatureInfoV1 ctSigV1 = sigV1.addNewSignatureInfoV1(); CTSignatureInfoV1 ctSigV1 = sigV1.addNewSignatureInfoV1();
ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestAlgo().xmlSignUri);
ctSigV1.setManifestHashAlgorithm(signatureConfig.getDigestMethodUri());
Element n = (Element)document.importNode(ctSigV1.getDomNode(), true); Element n = (Element)document.importNode(ctSigV1.getDomNode(), true);
n.setAttributeNS(XML_NS, XMLConstants.XMLNS_ATTRIBUTE, MS_DIGSIG_NS); n.setAttributeNS(XML_NS, XMLConstants.XMLNS_ATTRIBUTE, MS_DIGSIG_NS);
String objectId = "idOfficeObject"; String objectId = "idOfficeObject";
objects.add(signatureFactory.newXMLObject(objectContent, objectId, null, null)); objects.add(signatureFactory.newXMLObject(objectContent, objectId, null, null));
DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);
DigestMethod digestMethod = signatureFactory.newDigestMethod
(signatureConfig.getDigestMethodUri(), null);
Reference reference = signatureFactory.newReference Reference reference = signatureFactory.newReference
("#" + objectId, digestMethod, null, XML_DIGSIG_NS+"Object", null); ("#" + objectId, digestMethod, null, XML_DIGSIG_NS+"Object", null);
references.add(reference); references.add(reference);

+ 4
- 4
src/ooxml/java/org/apache/poi/poifs/crypt/dsig/facets/XAdESSignatureFacet.java Прегледај датотеку

objects.add(xadesObject); objects.add(xadesObject);
// add XAdES ds:Reference // add XAdES ds:Reference
DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestAlgo().xmlSignUri, null);
DigestMethod digestMethod = signatureFactory.newDigestMethod(signatureConfig.getDigestMethodUri(), null);
List<Transform> transforms = new ArrayList<Transform>(); List<Transform> transforms = new ArrayList<Transform>();
Transform exclusiveTransform = signatureFactory Transform exclusiveTransform = signatureFactory
.newTransform(CanonicalizationMethod.INCLUSIVE, .newTransform(CanonicalizationMethod.INCLUSIVE,
protected static void setDigestAlgAndValue( protected static void setDigestAlgAndValue(
DigestAlgAndValueType digestAlgAndValue, DigestAlgAndValueType digestAlgAndValue,
byte[] data, byte[] data,
HashAlgorithm hashAlgo) {
HashAlgorithm digestAlgo) {
DigestMethodType digestMethod = digestAlgAndValue.addNewDigestMethod(); DigestMethodType digestMethod = digestAlgAndValue.addNewDigestMethod();
digestMethod.setAlgorithm(hashAlgo.xmlSignUri);
digestMethod.setAlgorithm(SignatureConfig.getDigestMethodUri(digestAlgo));
MessageDigest messageDigest = CryptoFunctions.getMessageDigest(hashAlgo);
MessageDigest messageDigest = CryptoFunctions.getMessageDigest(digestAlgo);
byte[] digestValue = messageDigest.digest(data); byte[] digestValue = messageDigest.digest(data);
digestAlgAndValue.setDigestValue(digestValue); digestAlgAndValue.setDigestValue(digestValue);
} }

+ 110
- 4
src/ooxml/testcases/org/apache/poi/poifs/crypt/TestSignatureInfo.java Прегледај датотеку

package org.apache.poi.poifs.crypt; package org.apache.poi.poifs.crypt;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import org.apache.poi.util.IOUtils; import org.apache.poi.util.IOUtils;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; import org.apache.poi.util.POILogger;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlObject;
import org.bouncycastle.asn1.x509.KeyUsage; import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.ocsp.OCSPResp; import org.bouncycastle.cert.ocsp.OCSPResp;
pkg.close(); pkg.close();
} }
@Test
public void testManipulation() throws Exception {
// sign & validate
String testFile = "hello-world-unsigned.xlsx";
OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);
sign(pkg, "Test", "CN=Test", 1);
// manipulate
XSSFWorkbook wb = new XSSFWorkbook(pkg);
wb.setSheetName(0, "manipulated");
// ... I don't know, why commit is protected ...
Method m = XSSFWorkbook.class.getDeclaredMethod("commit");
m.setAccessible(true);
m.invoke(wb);
// todo: test a manipulation on a package part, which is not signed
// ... maybe in combination with #56164
// validate
SignatureConfig sic = new SignatureConfig();
sic.setOpcPackage(pkg);
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(sic);
boolean b = si.verifySignature();
assertFalse("signature should be broken", b);
wb.close();
}
@Test @Test
public void testSignSpreadsheetWithSignatureInfo() throws Exception { public void testSignSpreadsheetWithSignatureInfo() throws Exception {
initKeyPair("Test", "CN=Test"); initKeyPair("Test", "CN=Test");
"$this/ds:Signature/ds:SignedInfo/ds:Reference"; "$this/ds:Signature/ds:SignedInfo/ds:Reference";
for (ReferenceType rt : (ReferenceType[])sigDoc.selectPath(digestValXQuery)) { for (ReferenceType rt : (ReferenceType[])sigDoc.selectPath(digestValXQuery)) {
assertNotNull(rt.getDigestValue()); assertNotNull(rt.getDigestValue());
assertEquals(HashAlgorithm.sha1.xmlSignUri, rt.getDigestMethod().getAlgorithm());
assertEquals(signatureConfig.getDigestMethodUri(), rt.getDigestMethod().getAlgorithm());
} }
String certDigestXQuery = declareNS + String certDigestXQuery = declareNS +
pkg.close(); pkg.close();
} }
@Test
public void testCertChain() throws Exception {
KeyStore keystore = KeyStore.getInstance("PKCS12");
String password = "test";
InputStream is = testdata.openResourceAsStream("chaintest.pfx");
keystore.load(is, password.toCharArray());
is.close();
Key key = keystore.getKey("poitest", password.toCharArray());
Certificate chainList[] = keystore.getCertificateChain("poitest");
List<X509Certificate> certChain = new ArrayList<X509Certificate>();
for (Certificate c : chainList) {
certChain.add((X509Certificate)c);
}
x509 = certChain.get(0);
keyPair = new KeyPair(x509.getPublicKey(), (PrivateKey)key);
String testFile = "hello-world-unsigned.xlsx";
OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);
SignatureConfig signatureConfig = new SignatureConfig();
signatureConfig.setKey(keyPair.getPrivate());
signatureConfig.setSigningCertificateChain(certChain);
Calendar cal = Calendar.getInstance();
cal.set(2007, 7, 1);
signatureConfig.setExecutionTime(cal.getTime());
signatureConfig.setDigestAlgo(HashAlgorithm.sha1);
signatureConfig.setOpcPackage(pkg);
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(signatureConfig);
si.confirmSignature();
for (SignaturePart sp : si.getSignatureParts()){
boolean b = sp.validate();
assertTrue(b);
X509Certificate signer = sp.getSigner();
assertNotNull("signer undefined?!", signer);
List<X509Certificate> certChainRes = sp.getCertChain();
assertEquals(3, certChainRes.size());
}
pkg.close();
}
@Test
public void testNonSha1() throws Exception {
String testFile = "hello-world-unsigned.xlsx";
initKeyPair("Test", "CN=Test");
SignatureConfig signatureConfig = new SignatureConfig();
signatureConfig.setKey(keyPair.getPrivate());
signatureConfig.setSigningCertificateChain(Collections.singletonList(x509));
HashAlgorithm testAlgo[] = { HashAlgorithm.sha224, HashAlgorithm.sha256
, HashAlgorithm.sha384, HashAlgorithm.sha512, HashAlgorithm.ripemd160 };
for (HashAlgorithm ha : testAlgo) {
signatureConfig.setDigestAlgo(ha);
OPCPackage pkg = OPCPackage.open(copy(testdata.getFile(testFile)), PackageAccess.READ_WRITE);
signatureConfig.setOpcPackage(pkg);
SignatureInfo si = new SignatureInfo();
si.setSignatureConfig(signatureConfig);
si.confirmSignature();
boolean b = si.verifySignature();
pkg.close();
private OPCPackage sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception {
assertTrue(b);
}
}
private void sign(OPCPackage pkgCopy, String alias, String signerDn, int signerCount) throws Exception {
initKeyPair(alias, signerDn); initKeyPair(alias, signerDn);
SignatureConfig signatureConfig = new SignatureConfig(); SignatureConfig signatureConfig = new SignatureConfig();
} }
} }
assertEquals(signerCount, result.size()); assertEquals(signerCount, result.size());
return pkgCopy;
} }
private void initKeyPair(String alias, String subjectDN) throws Exception { private void initKeyPair(String alias, String subjectDN) throws Exception {

BIN
test-data/xmldsign/chaintest.pfx Прегледај датотеку


Loading…
Откажи
Сачувај