From b1c8641a63a67e3c64d948f9e8dce5c01e11e2dd Mon Sep 17 00:00:00 2001 From: mcentner Date: Wed, 5 May 2010 15:29:01 +0000 Subject: Merged feature branch mocca-1.2.13-id@r724 back to trunk. git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@725 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4 --- .../src/main/java/at/gv/egiz/mocca/id/IdLink.java | 346 +++++++++++++++++++++ 1 file changed, 346 insertions(+) create mode 100644 BKUOnline/src/main/java/at/gv/egiz/mocca/id/IdLink.java (limited to 'BKUOnline/src/main/java/at/gv/egiz/mocca/id/IdLink.java') diff --git a/BKUOnline/src/main/java/at/gv/egiz/mocca/id/IdLink.java b/BKUOnline/src/main/java/at/gv/egiz/mocca/id/IdLink.java new file mode 100644 index 00000000..fd4ef8e7 --- /dev/null +++ b/BKUOnline/src/main/java/at/gv/egiz/mocca/id/IdLink.java @@ -0,0 +1,346 @@ +/* +* Copyright 2009 Federal Chancellery Austria and +* Graz University of Technology +* +* 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 at.gv.egiz.mocca.id; + +import iaik.xml.crypto.dom.DOMCryptoContext; +import iaik.xml.crypto.dsig.keyinfo.KeyValueType; + +import java.io.IOException; +import java.io.InputStream; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.crypto.MarshalException; +import javax.xml.crypto.dom.DOMStructure; +import javax.xml.crypto.dsig.Manifest; +import javax.xml.crypto.dsig.Reference; +import javax.xml.crypto.dsig.XMLObject; +import javax.xml.crypto.dsig.XMLSignature; +import javax.xml.crypto.dsig.XMLSignatureException; +import javax.xml.crypto.dsig.XMLSignatureFactory; +import javax.xml.crypto.dsig.dom.DOMValidateContext; +import javax.xml.crypto.dsig.keyinfo.KeyInfo; +import javax.xml.crypto.dsig.keyinfo.X509Data; + +import oasis.names.tc.saml._1_0.assertion.AnyType; +import oasis.names.tc.saml._1_0.assertion.AssertionType; +import oasis.names.tc.saml._1_0.assertion.AttributeStatementType; +import oasis.names.tc.saml._1_0.assertion.AttributeType; +import oasis.names.tc.saml._1_0.assertion.StatementAbstractType; +import oasis.names.tc.saml._1_0.assertion.SubjectConfirmationType; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import at.gv.e_government.reference.namespace.persondata._20020228_.PhysicalPersonType; +import at.gv.egiz.bku.utils.StreamUtil; + +public class IdLink { + + protected Logger log = LoggerFactory.getLogger(IdLink.class); + + /** + * The IdLink is backed by a DOM. + */ + protected Node node; + + /** + * The Assertion (root element) of the IdLink. + */ + protected AssertionType assertion; + + /** + * The citizen's asserted public keys. + */ + protected List citizenPublicKeys; + + /** + * The XMLSignature. + */ + protected XMLSignature signature; + + /** + * The assertion's signer certificate. + */ + protected X509Certificate signerCert; + + /** + * Is the assertion's signature manifest valid? + */ + protected Boolean manifestValid; + + /** + * Is the assertion's signature valid? + */ + protected Boolean signatureValid; + + /** + * The personal identifier + */ + protected IdLinkPersonData personData; + + public IdLink(Element node, AssertionType assertion) throws JAXBException { + this.node = node; + this.assertion = assertion; + } + + public PhysicalPersonType getPhysicalPerson() { + + AttributeStatementType attributeStatement = getAttributeStatement(); + if (attributeStatement != null) { + JAXBElement subjectConfirmation = attributeStatement.getSubject().getContent().get(0); + if (subjectConfirmation.getDeclaredType() == SubjectConfirmationType.class) { + Object data = ((SubjectConfirmationType) subjectConfirmation.getValue()) + .getSubjectConfirmationData().getContent().get(0); + if (data instanceof JAXBElement + && ((JAXBElement) data).getValue() instanceof PhysicalPersonType) { + return (PhysicalPersonType) ((JAXBElement) data).getValue(); + } + } + } + + return null; + } + + public AttributeStatementType getAttributeStatement() { + + StatementAbstractType statement = + assertion.getStatementOrSubjectStatementOrAuthenticationStatement().get(0); + + if (statement instanceof AttributeStatementType) { + return (AttributeStatementType) statement; + } + + return null; + + } + + public IdLinkPersonData getPersonData() throws MarshalException { + if (personData == null) { + try { + personData = new IdLinkPersonData(getPhysicalPerson()); + } catch (ParseException e) { + throw new MarshalException(e); + } + } + return personData; + } + + public List getCitizenPublicKeys() throws MarshalException { + if (citizenPublicKeys == null) { + + citizenPublicKeys = new ArrayList(); + + AttributeStatementType attributeStatement = getAttributeStatement(); + if (attributeStatement != null) { + List attributes = attributeStatement.getAttribute(); + for (AttributeType attribute : attributes) { + if ("urn:publicid:gv.at:namespaces:identitylink:1.2".equals(attribute.getAttributeNamespace()) + && "CitizenPublicKey".equals(attribute.getAttributeName())) { + List value = attribute.getAttributeValue(); + if (value.size() == 1 && value.get(0).getContent().size() == 1) { + Object object = value.get(0).getContent().get(0); + if (object instanceof Element) { + Element element = (Element) object; + DOMStructure structure = iaik.xml.crypto.dom.DOMStructure.getInstance(element, new DOMCryptoContext()); + if (structure instanceof KeyValueType) { + citizenPublicKeys.add(((KeyValueType) structure).getPublicKey()); + } + } + } + } + } + } + + } + return citizenPublicKeys; + } + + public XMLSignature getXMLSignature() throws MarshalException { + if (signature == null) { + + Node n = node.getLastChild(); + while (n != null && n.getNodeType() != Node.ELEMENT_NODE) { + n = n.getPreviousSibling(); + } + + if (n != null + && XMLSignature.XMLNS.equals(n.getNamespaceURI()) + && "Signature".equals(n.getLocalName())) { + + XMLSignatureFactory signatureFactory = XMLSignatureFactory.getInstance(); + signature = signatureFactory.unmarshalXMLSignature(new DOMStructure(n)); + } + + + } + return signature; + } + + public X509Certificate getSignerCert() throws MarshalException { + if (signerCert == null) { + + if (getXMLSignature() != null) { + + KeyInfo keyInfo = signature.getKeyInfo(); + if (keyInfo != null) { + List content = keyInfo.getContent(); + for (Object data : content) { + if (data instanceof X509Data) { + List x509Data = ((X509Data) data).getContent(); + for (Object object : x509Data) { + if (object instanceof X509Certificate) { + signerCert = (X509Certificate) object; + return signerCert; + } + } + } + } + } + } + } + return signerCert; + } + + + @SuppressWarnings("unchecked") + public boolean verifySignature() throws MarshalException, XMLSignatureException { + if (signatureValid == null) { + if (getXMLSignature() != null && getSignerCert() != null) { + + DOMValidateContext validateContext = new DOMValidateContext(signerCert.getPublicKey(), node); + validateContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE); + + signatureValid = signature.validate(validateContext); + + // logging + if (!signatureValid && log.isTraceEnabled()) { + List references = signature.getSignedInfo().getReferences(); + for (Reference reference : references) { + if (!Manifest.TYPE.equals(reference.getType())) { + if (!reference.validate(validateContext)) { + InputStream digestInputStream = reference.getDigestInputStream(); + if (digestInputStream != null) { + try { + log.trace("SignedInfo's reference digest input:\n{}", + StreamUtil.asString(digestInputStream, "UTF-8")); + } catch (IOException e) { + log.info("Failed to get SignedInfos's reference digest input", e.toString()); + } + } + } else { + try { + log.trace("Signature canonicalized data:\n{}", StreamUtil.asString(signature + .getSignedInfo().getCanonicalizedData(), "UTF-8")); + } catch (IOException e) { + log.info("Failed to get canonicalized data.", e); + } + } + break; + } + } + } + + } + } + return signatureValid; + } + + @SuppressWarnings("unchecked") + public boolean verifyManifest() throws MarshalException, XMLSignatureException { + if (manifestValid == null) { + if (getXMLSignature() != null && getSignerCert() != null) { + + DOMValidateContext validateContext = new DOMValidateContext(signerCert.getPublicKey(), node); + if (log.isTraceEnabled()) { + // enable reference caching in trace log-level + validateContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE); + } + boolean valid = false; + + // validate manifest + List objects = signature.getObjects(); + for (XMLObject object : objects) { + List content = object.getContent(); + if (content.get(0) instanceof Manifest) { + Manifest manifest = (Manifest) content.get(0); + List references = manifest.getReferences(); + for (Reference reference : references) { + + valid = reference.validate(validateContext); + + // logging + if (!valid && log.isTraceEnabled()) { + InputStream digestInputStream = reference.getDigestInputStream(); + if (digestInputStream != null) { + try { + log.trace("Manifest's reference digest input:\n{}", + StreamUtil.asString(digestInputStream, "UTF-8")); + } catch (IOException e) { + log.info("Failed to get Manifest's reference digest input", e.toString()); + } + } + } + break; + } + } + } + + // validate reference to manifest + if (valid) { + List references = signature.getSignedInfo().getReferences(); + for (Reference reference : references) { + if (Manifest.TYPE.equals(reference.getType())) { + + boolean refValid = reference.validate(validateContext); + + // logging + if (!refValid && log.isTraceEnabled()) { + InputStream digestInputStream = reference.getDigestInputStream(); + if (digestInputStream != null) { + try { + log.trace("SignedInfo's manifest reference digest input:\n{}", + StreamUtil.asString(digestInputStream, "UTF-8")); + } catch (IOException e) { + log.info("Failed to get SignedInfos's manifest reference digest input", e.toString()); + } + } + } + + valid &= refValid; + + } + } + } + + manifestValid = valid; + + } + + } + return manifestValid; + } + +} -- cgit v1.2.3