| /* |
| * 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() |
| ); |
| |
| } |
| */ |
| |
| } |