blob: 9f3f24aac01d4352f77da9a4f2ca6920364cc448 [file] [log] [blame]
/*
* Copyright 1999-2009 The Apache Software Foundation.
*
* Licensed 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.xml.security.test.signature;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.Security;
import java.security.cert.X509Certificate;
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.apache.xml.security.algorithms.SignatureAlgorithm;
import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.keys.KeyInfo;
import org.apache.xml.security.signature.XMLSignature;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.apache.xml.security.utils.XMLUtils;
import org.apache.xpath.XPathAPI;
import org.w3c.dom.Element;
/**
* Tests that creates and verifies ECDSA signatures.
*
* @author Wolfgang Glas
*/
public class ECDSASignatureTest extends TestCase {
/** {@link org.apache.commons.logging} logging facility */
private static org.apache.commons.logging.Log log =
org.apache.commons.logging.LogFactory.getLog(ECDSASignatureTest.class.getName());
private static final String BASEDIR = System.getProperty("basedir");
private static final String SEP = System.getProperty("file.separator");
private static final String ECDSA_JKS =
"data/org/apache/xml/security/samples/input/ecdsa.jks";
private static final String ECDSA_JKS_PASSWORD = "security";
private KeyStore keyStore;
private javax.xml.parsers.DocumentBuilder db;
private File makeDataFile(String relPath) {
if (BASEDIR != null && !"".equals(BASEDIR)) {
return new File(BASEDIR + SEP + relPath);
} else {
return new File(relPath);
}
}
public static Test suite() {
return new TestSuite(ECDSASignatureTest.class);
}
public ECDSASignatureTest(String name) {
super(name);
}
public static void main(String[] args) {
String[] testCaseName = {"-noloading", ECDSASignatureTest.class.getName()};
junit.textui.TestRunner.main(testCaseName);
}
protected void setUp() throws Exception {
//
// If the BouncyCastle provider is not installed, then try to load it
// via reflection. If it is not available, then skip this test as it is
// required for elliptic curves
//
if (Security.getProvider("BC") == null) {
Constructor cons = null;
try {
Class c = Class.forName("org.bouncycastle.jce.provider.BouncyCastleProvider");
cons = c.getConstructor(new Class[] {});
} catch (Exception e) {
//ignore
}
if (cons == null) {
// BouncyCastle is not available so just return
return;
} else {
Security.addProvider((java.security.Provider)cons.newInstance(new Object[]{}));
}
}
javax.xml.parsers.DocumentBuilderFactory dbf =
javax.xml.parsers.DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
log.info("dbf.isIgnoringComments()=" + dbf.isIgnoringComments());
log.info("dbf.isIgnoringElementContentWhitespace()=" + dbf.isIgnoringElementContentWhitespace());
String id = "http://apache.org/xml/properties/dom/document-class-name";
dbf.setAttribute(id, IndexedDocument.class.getName());
db = dbf.newDocumentBuilder();
org.apache.xml.security.Init.init();
}
public void testOne() throws Exception {
if (Security.getProvider("BC") == null) {
return;
}
keyStore = KeyStore.getInstance("JKS");
keyStore.load(
new java.io.FileInputStream(ECDSA_JKS),
ECDSA_JKS_PASSWORD.toCharArray()
);
doVerify(doSign());
doVerify(doSign());
}
public void testTwo() throws Exception {
if (Security.getProvider("BC") == null) {
return;
}
File file =
makeDataFile("data/org/apache/xml/security/samples/input/ecdsaSignature.xml");
InputStream is = new FileInputStream(file);
doVerify(is);
}
public void testThree() throws Exception {
if (Security.getProvider("BC") == null) {
return;
}
File file = makeDataFile("data/at/buergerkarte/testresp.xml");
InputStream is = new FileInputStream(file);
doVerify(is);
}
private byte[] doSign() throws Exception {
PrivateKey privateKey =
(PrivateKey)keyStore.getKey("ECDSA", ECDSA_JKS_PASSWORD.toCharArray());
org.w3c.dom.Document doc = db.newDocument();
doc.appendChild(doc.createComment(" Comment before "));
Element root = doc.createElementNS("", "RootElement");
doc.appendChild(root);
root.appendChild(doc.createTextNode("Some simple text\n"));
Element canonElem = XMLUtils.createElementInSignatureSpace(doc,
Constants._TAG_CANONICALIZATIONMETHOD);
canonElem.setAttributeNS(null, Constants._ATT_ALGORITHM,
Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
SignatureAlgorithm signatureAlgorithm = new SignatureAlgorithm(doc,
XMLSignature.ALGO_ID_SIGNATURE_ECDSA_SHA1);
XMLSignature sig = new XMLSignature(doc, null, signatureAlgorithm
.getElement(), canonElem);
root.appendChild(sig.getElement());
doc.appendChild(doc.createComment(" Comment after "));
Transforms transforms = new Transforms(doc);
transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE);
transforms.addTransform(Transforms.TRANSFORM_C14N_WITH_COMMENTS);
sig.addDocument("", transforms, Constants.ALGO_ID_DIGEST_SHA1);
X509Certificate x509 = (X509Certificate)keyStore.getCertificate("ECDSA");
sig.addKeyInfo(x509);
sig.sign(privateKey);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
XMLUtils.outputDOMc14nWithComments(doc, bos);
return bos.toByteArray();
}
private void doVerify(byte[] signedXml) throws Exception {
doVerify(new ByteArrayInputStream(signedXml));
}
private void doVerify(InputStream is) throws Exception {
org.w3c.dom.Document doc = this.db.parse(is);
Element nscontext = XMLUtils.createDSctx(doc, "ds",Constants.SignatureSpecNS);
Element sigElement = (Element) XPathAPI.selectSingleNode(doc,"//ds:Signature[1]", nscontext);
XMLSignature signature = new XMLSignature(sigElement, "");
signature.addResourceResolver(new XPointerResourceResolver(sigElement));
KeyInfo ki = signature.getKeyInfo();
if (ki == null) {
throw new RuntimeException("No keyinfo");
}
X509Certificate cert = signature.getKeyInfo().getX509Certificate();
if (cert == null) {
throw new RuntimeException("No certificate");
}
assertTrue(signature.checkSignatureValue(cert) );
}
/**
* DO NOT DELETE THIS COMMENTED OUT METHOD!
*
* The reason this method is commented out is to avoid introducing explicit
* BouncyCastle dependencies.
*
* Create an X.509 Certificate and associated private key using the Elliptic Curve
* DSA algorithm, and store in a KeyStore. This method was used to generate the
* keystore used for this test ("data/org/apache/xml/security/samples/input/ecdsa.jks").
*
private static void setUpKeyAndCertificate() throws Exception {
java.security.KeyPairGenerator kpg =
java.security.KeyPairGenerator.getInstance("ECDSA");
java.math.BigInteger mod_p =
new java.math.BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319");
java.math.BigInteger mod_q =
new java.math.BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323");
org.bouncycastle.math.ec.ECCurve.Fp curve =
new org.bouncycastle.math.ec.ECCurve.Fp(
mod_p, // p
new java.math.BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a
new java.math.BigInteger("166")
); // b
java.security.spec.AlgorithmParameterSpec spec =
new org.bouncycastle.jce.spec.ECParameterSpec(
curve,
new org.bouncycastle.math.ec.ECPoint.Fp(curve,
new org.bouncycastle.math.ec.ECFieldElement.Fp(
curve.getQ(), new java.math.BigInteger("1")
), // x
new org.bouncycastle.math.ec.ECFieldElement.Fp(
curve.getQ(), new java.math.BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")
)
), // y
mod_q
);
kpg.initialize(spec);
java.security.KeyPair kp=kpg.genKeyPair();
org.bouncycastle.x509.X509V3CertificateGenerator certGen =
new org.bouncycastle.x509.X509V3CertificateGenerator();
long now = System.currentTimeMillis();
certGen.setSerialNumber(java.math.BigInteger.valueOf(now));
org.bouncycastle.jce.X509Principal subject =
new org.bouncycastle.jce.X509Principal(
"CN=XML ECDSA Signature Test,DC=apache,DC=org"
);
certGen.setIssuerDN(subject);
certGen.setSubjectDN(subject);
java.util.Date from_date = new java.util.Date(now);
certGen.setNotBefore(from_date);
java.util.Calendar cal = new java.util.GregorianCalendar();
cal.setTime(from_date);
cal.add(java.util.Calendar.YEAR, 4);
java.util.Date to_date = cal.getTime();
certGen.setNotAfter(to_date);
certGen.setPublicKey(kp.getPublic());
certGen.setSignatureAlgorithm("SHA1withECDSA");
certGen.addExtension(
org.bouncycastle.asn1.x509.X509Extensions.BasicConstraints,
true,
new org.bouncycastle.asn1.x509.BasicConstraints(false)
);
certGen.addExtension(
org.bouncycastle.asn1.x509.X509Extensions.KeyUsage,
true,
new org.bouncycastle.asn1.x509.KeyUsage(
org.bouncycastle.asn1.x509.KeyUsage.digitalSignature |
org.bouncycastle.asn1.x509.KeyUsage.keyEncipherment |
org.bouncycastle.asn1.x509.KeyUsage.keyCertSign |
org.bouncycastle.asn1.x509.KeyUsage.cRLSign
)
);
X509Certificate x509 = certGen.generateX509Certificate(kp.getPrivate());
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(null, ECDSA_JKS_PASSWORD.toCharArray());
keyStore.setKeyEntry(
"ECDSA", kp.getPrivate(),
ECDSA_JKS_PASSWORD.toCharArray(), new java.security.cert.Certificate[]{x509}
);
keyStore.store(
new java.io.FileOutputStream(ECDSA_JKS), ECDSA_JKS_PASSWORD.toCharArray()
);
}
*/
}