poi/src/ooxml/testcases/org/apache/poi/poifs/crypt/PkiTestUtils.java

358 lines
18 KiB
Java

/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.poifs.crypt;
import static org.apache.poi.poifs.crypt.dsig.HorribleProxy.newProxy;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.SignatureException;
import java.security.cert.CRLException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509Certificate;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.Date;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.ASN1InputStreamIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.AuthorityInformationAccessIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.AuthorityKeyIdentifierIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.BasicConstraintsIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.BasicOCSPRespBuilderIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.BasicOCSPRespIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.CRLNumberIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.CRLReasonIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.CertificateIDIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.CertificateStatusIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.ContentSignerIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.DERIA5StringIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.DEROctetStringIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.DERSequenceIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.DigestCalculatorIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.DistributionPointIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.DistributionPointNameIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.ExtensionIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.ExtensionsIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.GeneralNameIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.GeneralNamesIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.JcaContentSignerBuilderIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.JcaDigestCalculatorProviderBuilderIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.KeyUsageIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.OCSPObjectIdentifiersIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.OCSPReqBuilderIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.OCSPReqIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.OCSPRespBuilderIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.OCSPRespIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.ReqIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.RevokedStatusIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.SubjectKeyIdentifierIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.SubjectPublicKeyInfoIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.X509CertificateHolderIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.X509ExtensionsIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.X509ObjectIdentifiersIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.X509PrincipalIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.X509V2CRLGeneratorIf;
import org.apache.poi.poifs.crypt.dsig.HorribleProxies.X509V3CertificateGeneratorIf;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class PkiTestUtils {
private PkiTestUtils() {
super();
}
static KeyPair generateKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
SecureRandom random = new SecureRandom();
keyPairGenerator.initialize(new RSAKeyGenParameterSpec(1024,
RSAKeyGenParameterSpec.F4), random);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
return keyPair;
}
private static SubjectKeyIdentifierIf createSubjectKeyId(PublicKey publicKey)
throws IOException, ClassNotFoundException, NoSuchMethodException, InstantiationException
, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
ByteArrayInputStream bais = new ByteArrayInputStream(publicKey.getEncoded());
ASN1InputStreamIf asnObj = newProxy(ASN1InputStreamIf.class, bais);
SubjectPublicKeyInfoIf info =
newProxy(SubjectPublicKeyInfoIf.class, asnObj.readObject$Sequence());
SubjectKeyIdentifierIf keyId = newProxy(SubjectKeyIdentifierIf.class, info);
return keyId;
}
private static AuthorityKeyIdentifierIf createAuthorityKeyId(PublicKey publicKey)
throws IOException, ClassNotFoundException, NoSuchMethodException, InstantiationException
, IllegalAccessException, InvocationTargetException, NoSuchFieldException {
ByteArrayInputStream bais = new ByteArrayInputStream(publicKey.getEncoded());
ASN1InputStreamIf asnObj = newProxy(ASN1InputStreamIf.class, bais);
SubjectPublicKeyInfoIf info =
newProxy(SubjectPublicKeyInfoIf.class, asnObj.readObject$Sequence());
AuthorityKeyIdentifierIf keyId = newProxy(AuthorityKeyIdentifierIf.class, info);
return keyId;
}
static X509Certificate generateCertificate(PublicKey subjectPublicKey,
String subjectDn, Date notBefore, Date notAfter,
X509Certificate issuerCertificate, PrivateKey issuerPrivateKey,
boolean caFlag, int pathLength, String crlUri, String ocspUri,
KeyUsageIf keyUsage)
throws IOException, InvalidKeyException, IllegalStateException, NoSuchAlgorithmException
, SignatureException, CertificateException, InvocationTargetException, IllegalAccessException
, InstantiationException, NoSuchMethodException, ClassNotFoundException, NoSuchFieldException
{
String signatureAlgorithm = "SHA1withRSA";
X509V3CertificateGeneratorIf certificateGenerator = newProxy(X509V3CertificateGeneratorIf.class);
certificateGenerator.reset();
certificateGenerator.setPublicKey(subjectPublicKey);
certificateGenerator.setSignatureAlgorithm(signatureAlgorithm);
certificateGenerator.setNotBefore(notBefore);
certificateGenerator.setNotAfter(notAfter);
X509PrincipalIf subjectDN = newProxy(X509PrincipalIf.class, subjectDn);
X509PrincipalIf issuerDN;
if (null != issuerCertificate) {
issuerDN = newProxy(X509PrincipalIf.class, issuerCertificate
.getSubjectX500Principal().toString());
} else {
issuerDN = subjectDN;
}
certificateGenerator.setIssuerDN(issuerDN);
certificateGenerator.setSubjectDN(subjectDN);
certificateGenerator.setSerialNumber(new BigInteger(128,
new SecureRandom()));
X509ExtensionsIf X509Extensions = newProxy(X509ExtensionsIf.class);
certificateGenerator.addExtension(X509Extensions.SubjectKeyIdentifier(),
false, createSubjectKeyId(subjectPublicKey));
PublicKey issuerPublicKey;
issuerPublicKey = subjectPublicKey;
certificateGenerator.addExtension(
X509Extensions.AuthorityKeyIdentifier(), false,
createAuthorityKeyId(issuerPublicKey));
if (caFlag) {
BasicConstraintsIf bc;
if (-1 == pathLength) {
bc = newProxy(BasicConstraintsIf.class, true);
} else {
bc = newProxy(BasicConstraintsIf.class, pathLength);
}
certificateGenerator.addExtension(X509Extensions.BasicConstraints(), false, bc);
}
if (null != crlUri) {
GeneralNameIf gn = newProxy(GeneralNameIf.class);
int uri = gn.uniformResourceIdentifier();
DERIA5StringIf crlUriDer = newProxy(DERIA5StringIf.class, crlUri);
gn = newProxy(GeneralNameIf.class, uri, crlUriDer);
DERSequenceIf gnDer = newProxy(DERSequenceIf.class, gn);
GeneralNamesIf gns = newProxy(GeneralNamesIf.class, gnDer);
DistributionPointNameIf dpn = newProxy(DistributionPointNameIf.class, 0, gns);
DistributionPointIf distp = newProxy(DistributionPointIf.class, dpn, null, null);
DERSequenceIf distpDer = newProxy(DERSequenceIf.class, distp);
certificateGenerator.addExtension(X509Extensions.CRLDistributionPoints(), false, distpDer);
}
if (null != ocspUri) {
GeneralNameIf ocspName = newProxy(GeneralNameIf.class);
int uri = ocspName.uniformResourceIdentifier();
ocspName = newProxy(GeneralNameIf.class, uri, ocspUri);
X509ObjectIdentifiersIf X509ObjectIdentifiers = newProxy(X509ObjectIdentifiersIf.class);
AuthorityInformationAccessIf authorityInformationAccess =
newProxy(AuthorityInformationAccessIf.class
, X509ObjectIdentifiers.ocspAccessMethod(), ocspName);
certificateGenerator.addExtension(
X509Extensions.AuthorityInfoAccess(), false,
authorityInformationAccess);
}
if (null != keyUsage) {
certificateGenerator.addExtension(X509Extensions.KeyUsage(), true, keyUsage);
}
X509Certificate certificate;
certificate = certificateGenerator.generate(issuerPrivateKey);
/*
* Next certificate factory trick is needed to make sure that the
* certificate delivered to the caller is provided by the default
* security provider instead of BouncyCastle. If we don't do this trick
* we might run into trouble when trying to use the CertPath validator.
*/
CertificateFactory certificateFactory = CertificateFactory
.getInstance("X.509");
certificate = (X509Certificate) certificateFactory
.generateCertificate(new ByteArrayInputStream(certificate
.getEncoded()));
return certificate;
}
static Document loadDocument(InputStream documentInputStream)
throws ParserConfigurationException, SAXException, IOException {
InputSource inputSource = new InputSource(documentInputStream);
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilderFactory
.newDocumentBuilder();
Document document = documentBuilder.parse(inputSource);
return document;
}
static String toString(Node dom) throws TransformerException {
Source source = new DOMSource(dom);
StringWriter stringWriter = new StringWriter();
Result result = new StreamResult(stringWriter);
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
/*
* We have to omit the ?xml declaration if we want to embed the
* document.
*/
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(source, result);
return stringWriter.getBuffer().toString();
}
public static X509CRL generateCrl(X509Certificate issuer,
PrivateKey issuerPrivateKey) throws InvalidKeyException,
CRLException, IllegalStateException, NoSuchAlgorithmException,
SignatureException, InvocationTargetException, IllegalAccessException,
InstantiationException, NoSuchMethodException, ClassNotFoundException, NoSuchFieldException {
X509V2CRLGeneratorIf crlGenerator = newProxy(X509V2CRLGeneratorIf.class);
crlGenerator.setIssuerDN(issuer.getSubjectX500Principal());
Date now = new Date();
crlGenerator.setThisUpdate(now);
crlGenerator.setNextUpdate(new Date(now.getTime() + 100000));
crlGenerator.setSignatureAlgorithm("SHA1withRSA");
X509ExtensionsIf X509Extensions = newProxy(X509ExtensionsIf.class);
CRLNumberIf crlNumber = newProxy(CRLNumberIf.class, new BigInteger("1234"));
crlGenerator.addExtension(X509Extensions.CRLNumber(), false, crlNumber);
X509CRL x509Crl = crlGenerator.generate(issuerPrivateKey);
return x509Crl;
}
public static OCSPRespIf createOcspResp(X509Certificate certificate,
boolean revoked, X509Certificate issuerCertificate,
X509Certificate ocspResponderCertificate,
PrivateKey ocspResponderPrivateKey, String signatureAlgorithm,
long nonceTimeinMillis)
throws Exception {
CertificateIDIf certId = newProxy(CertificateIDIf.class);
DigestCalculatorIf digestCalc =
newProxy(JcaDigestCalculatorProviderBuilderIf.class)
.setProvider("BC").build().get(certId.HASH_SHA1());
X509CertificateHolderIf issuerHolder = newProxy(X509CertificateHolderIf.class, issuerCertificate.getEncoded());
certId = newProxy(CertificateIDIf.class, digestCalc, issuerHolder, certificate.getSerialNumber());
// request
//create a nonce to avoid replay attack
BigInteger nonce = BigInteger.valueOf(nonceTimeinMillis);
OCSPObjectIdentifiersIf oidIf = newProxy(OCSPObjectIdentifiersIf.class);
DEROctetStringIf nonceDer = newProxy(DEROctetStringIf.class, nonce.toByteArray());
ExtensionIf ext = newProxy(ExtensionIf.class, oidIf.id_pkix_ocsp_nonce(), true, nonceDer);
ExtensionsIf exts = newProxy(ExtensionsIf.class, ext);
OCSPReqBuilderIf ocspReqBuilder = newProxy(OCSPReqBuilderIf.class);
ocspReqBuilder.addRequest(certId);
ocspReqBuilder.setRequestExtensions(exts);
OCSPReqIf ocspReq = ocspReqBuilder.build();
SubjectPublicKeyInfoIf keyInfo = newProxy(SubjectPublicKeyInfoIf.class
, certId.HASH_SHA1(), ocspResponderCertificate.getPublicKey().getEncoded());
BasicOCSPRespBuilderIf basicOCSPRespBuilder =
newProxy(BasicOCSPRespBuilderIf.class, keyInfo, digestCalc);
basicOCSPRespBuilder.setResponseExtensions(exts);
// request processing
ReqIf[] requestList = ocspReq.getRequestList();
for (ReqIf ocspRequest : requestList) {
CertificateIDIf certificateID = ocspRequest.getCertID();
CertificateStatusIf certificateStatus;
if (revoked) {
CRLReasonIf crlr = newProxy(CRLReasonIf.class);
RevokedStatusIf rs = newProxy(RevokedStatusIf.class, new Date(), crlr.privilegeWithdrawn());
certificateStatus = newProxy(CertificateStatusIf.class, rs.getDelegate());
} else {
CertificateStatusIf cs = newProxy(CertificateStatusIf.class);
certificateStatus = cs.GOOD();
}
basicOCSPRespBuilder.addResponse(certificateID, certificateStatus);
}
// basic response generation
X509CertificateHolderIf[] chain = null;
if (!ocspResponderCertificate.equals(issuerCertificate)) {
// TODO: HorribleProxy can't convert array input params yet
chain = new X509CertificateHolderIf[] {
newProxy(X509CertificateHolderIf.class, ocspResponderCertificate),
issuerHolder
};
}
ContentSignerIf contentSigner = newProxy(JcaContentSignerBuilderIf.class, "SHA1withRSA")
.setProvider("BC").build(ocspResponderPrivateKey);
BasicOCSPRespIf basicOCSPResp = basicOCSPRespBuilder.build(contentSigner, chain, new Date(nonceTimeinMillis));
OCSPRespBuilderIf ocspRespBuilder = newProxy(OCSPRespBuilderIf.class);
OCSPRespIf ocspResp = ocspRespBuilder.build(ocspRespBuilder.SUCCESSFUL(), basicOCSPResp);
return ocspResp;
}
}