diff --git a/src/main/java/xades4j/production/DefaultElementIdGeneratorFactory.java b/src/main/java/xades4j/production/DefaultElementIdGeneratorFactory.java new file mode 100644 index 00000000..099eb860 --- /dev/null +++ b/src/main/java/xades4j/production/DefaultElementIdGeneratorFactory.java @@ -0,0 +1,31 @@ +/* + * XAdES4j - A Java library for generation and verification of XAdES signatures. + * Copyright (C) 2024 Luis Goncalves. + * + * XAdES4j is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or any later version. + * + * XAdES4j is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with XAdES4j. If not, see . + */ + +package xades4j.production; + +import java.util.UUID; + +final class DefaultElementIdGeneratorFactory implements ElementIdGeneratorFactory +{ + @Override + public ElementIdGenerator create() + { + return (namespace, name) -> { + return name.toLowerCase() + "-" + UUID.randomUUID(); + }; + } +} diff --git a/src/main/java/xades4j/production/DefaultProductionBindingsModule.java b/src/main/java/xades4j/production/DefaultProductionBindingsModule.java index 06c660b3..5ca3149d 100644 --- a/src/main/java/xades4j/production/DefaultProductionBindingsModule.java +++ b/src/main/java/xades4j/production/DefaultProductionBindingsModule.java @@ -74,6 +74,7 @@ protected void configure() bind(HttpTsaConfiguration.class).toProvider(() -> { throw new IllegalStateException("HttpTsaConfiguration must be configured in the profile in order to use an HTTP-based time-stamp token provider."); }); + bind(ElementIdGeneratorFactory.class).to(DefaultElementIdGeneratorFactory.class); // PropertiesDataObjectsGenerator is not configurable but the individual // generators may have dependencies. diff --git a/src/main/java/xades4j/production/ElementIdGenerator.java b/src/main/java/xades4j/production/ElementIdGenerator.java new file mode 100644 index 00000000..44e804ae --- /dev/null +++ b/src/main/java/xades4j/production/ElementIdGenerator.java @@ -0,0 +1,57 @@ +/* + * XAdES4j - A Java library for generation and verification of XAdES signatures. + * Copyright (C) 2024 Luis Goncalves. + * + * XAdES4j is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or any later version. + * + * XAdES4j is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with XAdES4j. If not, see . + */ + +package xades4j.production; + +import java.util.UUID; + +/** + * Generates IDs for XML elements in a given signing operation. + */ +public interface ElementIdGenerator +{ + /** + * Generate an ID for an XML element. + * + * @param namespace the element namespace + * @param name the element name + * @return the ID + */ + String generateId(String namespace, String name); + + /** + * Gets a {@link ElementIdGenerator} that uses a UUID for each requested ID. + */ + static ElementIdGenerator uuid() + { + return uuid(null, null); + } + + /** + * Gets a {@link ElementIdGenerator} that uses a UUID for each requested ID, optionally using a constant prefix + * and/or suffix. + * + * @param prefix the ID prefix (may be null) + * @param suffix the ID suffix (may be null) + */ + static ElementIdGenerator uuid(String prefix, String suffix) + { + final String p = prefix == null ? "" : prefix; + final String s = suffix == null ? "" : suffix; + return (ns, n) -> p + UUID.randomUUID() + s; + } +} diff --git a/src/main/java/xades4j/production/ElementIdGeneratorFactory.java b/src/main/java/xades4j/production/ElementIdGeneratorFactory.java new file mode 100644 index 00000000..8b253439 --- /dev/null +++ b/src/main/java/xades4j/production/ElementIdGeneratorFactory.java @@ -0,0 +1,55 @@ +/* + * XAdES4j - A Java library for generation and verification of XAdES signatures. + * Copyright (C) 2024 Luis Goncalves. + * + * XAdES4j is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or any later version. + * + * XAdES4j is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with XAdES4j. If not, see . + */ + +package xades4j.production; + +import java.util.UUID; + +/** + * A factory of {@link ElementIdGenerator}. + */ +public interface ElementIdGeneratorFactory +{ + /** + * Create a new {@link ElementIdGenerator}. This method is invoked once for each signing operation and the returned + * instance is used to obtain element IDs during that operation. This allows for scenarios where all the element IDs + * share a common base. + * + * @return the ID generator + */ + ElementIdGenerator create(); + + /** + * Gets a {@link ElementIdGeneratorFactory} that uses a UUID for each requested ID. + */ + static ElementIdGeneratorFactory uuid() + { + return ElementIdGenerator::uuid; + } + + /** + * Gets a {@link ElementIdGeneratorFactory} that uses a UUID for each requested ID, optionally using a constant + * prefix and/or suffix. + * + * @param prefix the ID prefix (may be null) + * @param suffix the ID suffix (may be null) + */ + static ElementIdGeneratorFactory uuid(String prefix, String suffix) + { + return () -> ElementIdGenerator.uuid(prefix, suffix); + } +} diff --git a/src/main/java/xades4j/production/KeyInfoBuilder.java b/src/main/java/xades4j/production/KeyInfoBuilder.java index f544e186..eefbbc6b 100644 --- a/src/main/java/xades4j/production/KeyInfoBuilder.java +++ b/src/main/java/xades4j/production/KeyInfoBuilder.java @@ -32,6 +32,8 @@ import xades4j.utils.TransformUtils; import xades4j.xml.marshalling.algorithms.AlgorithmsParametersMarshallingProvider; +import static xades4j.production.SignerBES.idFor; + /** * Helper class that creates the {@code ds:KeyInfo} element accordingly to some * signature options. The signing certificate validity and key usages are @@ -60,7 +62,8 @@ class KeyInfoBuilder void buildKeyInfo( List signingCertificateChain, - XMLSignature xmlSig) throws KeyingDataException, UnsupportedAlgorithmException + XMLSignature xmlSig, + ElementIdGenerator idGenerator) throws KeyingDataException, UnsupportedAlgorithmException { X509Certificate signingCertificate = getSigningCertificate(signingCertificateChain); @@ -68,7 +71,7 @@ void buildKeyInfo( addPublicKey(signingCertificate, xmlSig); - addKeyInfoReference(xmlSig); + addKeyInfoReference(xmlSig, idGenerator); } private void addSigningCertificateElements(List signingCertificateChain, X509Certificate signingCertificate, XMLSignature xmlSig) throws KeyingDataException @@ -119,13 +122,13 @@ private void addPublicKey(X509Certificate signingCertificate, XMLSignature xmlSi } } - private void addKeyInfoReference(XMLSignature xmlSig) throws UnsupportedAlgorithmException + private void addKeyInfoReference(XMLSignature xmlSig, ElementIdGenerator idGenerator) throws UnsupportedAlgorithmException { if (this.basicSignatureOptions.signKeyInfo()) { try { - String keyInfoId = xmlSig.getId() + "-keyinfo"; + String keyInfoId = idFor(xmlSig.getKeyInfo(), idGenerator); xmlSig.getKeyInfo().setId(keyInfoId); // Use same canonicalization URI as specified in the ds:CanonicalizationMethod for Signature. diff --git a/src/main/java/xades4j/production/SignedDataObjectsProcessor.java b/src/main/java/xades4j/production/SignedDataObjectsProcessor.java index eb0f5834..0268d16b 100644 --- a/src/main/java/xades4j/production/SignedDataObjectsProcessor.java +++ b/src/main/java/xades4j/production/SignedDataObjectsProcessor.java @@ -40,6 +40,8 @@ import java.util.Map; import java.util.Set; +import static xades4j.production.SignerBES.idFor; + /** * Helper class that processes a set of data object descriptions. * @@ -80,7 +82,8 @@ public Result(Map referenceMappings, Set ma */ SignedDataObjectsProcessor.Result process( SignedDataObjects signedDataObjects, - XMLSignature xmlSignature) throws UnsupportedAlgorithmException { + XMLSignature xmlSignature, + ElementIdGenerator idGenerator) throws UnsupportedAlgorithmException { if (xmlSignature.getSignedInfo().getLength() != 0) { throw new IllegalStateException("XMLSignature already contains references"); @@ -89,19 +92,19 @@ SignedDataObjectsProcessor.Result process( return process( signedDataObjects.getDataObjectsDescs(), xmlSignature.getSignedInfo(), - xmlSignature.getId(), signedDataObjects.getResourceResolvers(), xmlSignature, - false); + false, + idGenerator); } private SignedDataObjectsProcessor.Result process( Collection dataObjects, Manifest container, - String idPrefix, List resourceResolvers, XMLSignature xmlSignature, - boolean hasNullURIReference) throws UnsupportedAlgorithmException { + boolean hasNullURIReference, + ElementIdGenerator idGenerator) throws UnsupportedAlgorithmException { Map referenceMappings = new IdentityHashMap<>(dataObjects.size()); Set manifests = new HashSet<>(); @@ -134,9 +137,9 @@ else if (dataObjDesc instanceof EnvelopedXmlObject) // If the data object info is a EnvelopedXmlObject we need to create a ds:Object to embed it. // The Reference uri will refer the new ds:Object's id. EnvelopedXmlObject envXmlObj = (EnvelopedXmlObject) dataObjDesc; - String xmlObjId = String.format("%s-object%d", idPrefix, index); ObjectContainer xmlObj = new ObjectContainer(container.getDocument()); + String xmlObjId = idFor(xmlObj, idGenerator); xmlObj.setId(xmlObjId); xmlObj.appendChild(envXmlObj.getContent()); xmlObj.setMimeType(envXmlObj.getMimeType()); @@ -164,17 +167,18 @@ else if (dataObjDesc instanceof EnvelopedManifest) // If the data object info is a EnvelopedManifest we need to create a ds:Manifest and a ds:Object // to embed it. The Reference uri will refer the manifest's id. EnvelopedManifest envManifest = (EnvelopedManifest) dataObjDesc; - String xmlManifestId = String.format("%s-manifest%d", idPrefix, index); Manifest xmlManifest = new Manifest(container.getDocument()); + String xmlManifestId = idFor(xmlManifest, idGenerator); xmlManifest.setId(xmlManifestId); + SignedDataObjectsProcessor.Result manifestResult = process( envManifest.getDataObjects(), xmlManifest, - xmlManifestId, resourceResolvers, xmlSignature, - hasNullURIReference); + hasNullURIReference, + idGenerator); ObjectContainer xmlObj = new ObjectContainer(container.getDocument()); xmlObj.appendChild(xmlManifest.getElement()); @@ -199,12 +203,13 @@ else if (dataObjDesc instanceof EnvelopedManifest) refUri, transforms, digestMethodUri, - String.format("%s-ref%d", idPrefix, index), // id + null, refType); // SignedDataObjects and EnvelopedManifest don't allow repeated instances, so there's no // need to check for duplicate entries on the map. Reference ref = container.item(index); + ref.setId(idFor(ref, idGenerator)); referenceMappings.put(dataObjDesc, ref); } diff --git a/src/main/java/xades4j/production/SignerBES.java b/src/main/java/xades4j/production/SignerBES.java index 2ccc23cd..c0f106e8 100644 --- a/src/main/java/xades4j/production/SignerBES.java +++ b/src/main/java/xades4j/production/SignerBES.java @@ -85,6 +85,7 @@ class SignerBES implements XadesSigner private final SignedPropertiesMarshaller signedPropsMarshaller; private final UnsignedPropertiesMarshaller unsignedPropsMarshaller; private final AlgorithmsParametersMarshallingProvider algorithmsParametersMarshaller; + private final ElementIdGeneratorFactory idGeneratorFactory; /**/ private final KeyInfoBuilder keyInfoBuilder; private final QualifyingPropertiesProcessor qualifPropsProcessor; @@ -101,13 +102,14 @@ protected SignerBES( SignedPropertiesMarshaller signedPropsMarshaller, UnsignedPropertiesMarshaller unsignedPropsMarshaller, AlgorithmsParametersMarshallingProvider algorithmsParametersMarshaller, - X500NameStyleProvider x500NameStyleProvider) + X500NameStyleProvider x500NameStyleProvider, + ElementIdGeneratorFactory idGeneratorFactory) { if (ObjectUtils.anyNull( keyingProvider, signatureAlgorithms, basicSignatureOptions, signaturePropsProvider, dataObjPropsProvider, propsDataObjectsGenerator, signedPropsMarshaller, unsignedPropsMarshaller, algorithmsParametersMarshaller, - x500NameStyleProvider)) + x500NameStyleProvider, idGeneratorFactory)) { throw new NullPointerException("One or more arguments are null"); } @@ -120,6 +122,7 @@ protected SignerBES( this.unsignedPropsMarshaller = unsignedPropsMarshaller; this.algorithmsParametersMarshaller = algorithmsParametersMarshaller; this.dataObjectDescsProcessor = dataObjectDescsProcessor; + this.idGeneratorFactory = idGeneratorFactory; this.keyInfoBuilder = new KeyInfoBuilder(basicSignatureOptions, signatureAlgorithms, algorithmsParametersMarshaller, x500NameStyleProvider); this.qualifPropsProcessor = new QualifyingPropertiesProcessor(signaturePropsProvider, dataObjPropsProvider); } @@ -154,10 +157,8 @@ public final XadesSignatureResult sign( this.basicSignatureOptions.ensureValid(); Document signatureDocument = DOMHelper.getOwnerDocument(referenceNode); + ElementIdGenerator idGenerator = this.idGeneratorFactory.create(); - // Generate unique identifiers for the Signature and the SignedProperties. - String signatureId = String.format("xmldsig-%s", UUID.randomUUID()); - String signedPropsId = String.format("%s-signedprops", signatureId); // Signing certificate chain (may contain only the signing certificate). List signingCertificateChain = this.keyingProvider.getSigningCertificateChain(); @@ -173,6 +174,7 @@ public final XadesSignatureResult sign( signedDataObjects.getBaseUri(), signingCertificate.getPublicKey().getAlgorithm()); + String signatureId = idFor(signature, idGenerator); signature.setId(signatureId); /* References */ @@ -181,10 +183,11 @@ public final XadesSignatureResult sign( // are added to the signature. SignedDataObjectsProcessor.Result signedDataObjectsResult = this.dataObjectDescsProcessor.process( signedDataObjects, - signature); + signature, + idGenerator); /* ds:KeyInfo */ - this.keyInfoBuilder.buildKeyInfo(signingCertificateChain, signature); + this.keyInfoBuilder.buildKeyInfo(signingCertificateChain, signature, idGenerator); /* QualifyingProperties element */ // Create the QualifyingProperties element @@ -239,6 +242,7 @@ public final XadesSignatureResult sign( // Marshal the signed properties data to the QualifyingProperties node. this.signedPropsMarshaller.marshal(signedPropsData, qualifyingPropsElem); Element signedPropsElem = DOMHelper.getFirstChildElement(qualifyingPropsElem); + String signedPropsId = idFor(signedPropsElem, idGenerator); DOMHelper.setIdAsXmlId(signedPropsElem, signedPropsId); // SignedProperties reference @@ -285,7 +289,7 @@ public final XadesSignatureResult sign( Element sigValueElem = DOMHelper.getFirstDescendant( signature.getElement(), Constants.SignatureSpecNS, Constants._TAG_SIGNATUREVALUE); - DOMHelper.setIdAsXmlId(sigValueElem, String.format("%s-sigvalue", signatureId)); + DOMHelper.setIdAsXmlId(sigValueElem, idFor(sigValueElem, idGenerator)); /* Marshal unsigned properties */ // Generate the unsigned properties data objects. The data objects structure @@ -385,4 +389,14 @@ protected void getFormatSpecificSignatureProperties( formatSpecificSignedSigProps.add(scp); } } + + public static String idFor(ElementProxy elementProxy, ElementIdGenerator idGenerator) + { + return idGenerator.generateId(elementProxy.getBaseNamespace(), elementProxy.getBaseLocalName()); + } + + public static String idFor(Element element, ElementIdGenerator idGenerator) + { + return idGenerator.generateId(element.getNamespaceURI(), element.getLocalName()); + } } diff --git a/src/main/java/xades4j/production/SignerC.java b/src/main/java/xades4j/production/SignerC.java index b3328bef..cc793309 100644 --- a/src/main/java/xades4j/production/SignerC.java +++ b/src/main/java/xades4j/production/SignerC.java @@ -59,9 +59,10 @@ protected SignerC( UnsignedPropertiesMarshaller unsignedPropsMarshaller, AlgorithmsParametersMarshallingProvider algorithmsParametersMarshaller, X500NameStyleProvider x500NameStyleProvider, + ElementIdGeneratorFactory idGeneratorFactory, Optional policyInfoProvider) { - super(keyingProvider, signatureAlgorithms, basicSignatureOptions, dataObjectDescsProcessor, signaturePropsProvider, dataObjPropsProvider, propsDataObjectsGenerator, signedPropsMarshaller, unsignedPropsMarshaller, algorithmsParametersMarshaller, x500NameStyleProvider, policyInfoProvider); + super(keyingProvider, signatureAlgorithms, basicSignatureOptions, dataObjectDescsProcessor, signaturePropsProvider, dataObjPropsProvider, propsDataObjectsGenerator, signedPropsMarshaller, unsignedPropsMarshaller, algorithmsParametersMarshaller, x500NameStyleProvider, idGeneratorFactory, policyInfoProvider); if (null == validationDataProvider) throw new NullPointerException("ValidationDataProvider is null"); diff --git a/src/main/java/xades4j/production/SignerEPES.java b/src/main/java/xades4j/production/SignerEPES.java index 075edbff..ec95267c 100644 --- a/src/main/java/xades4j/production/SignerEPES.java +++ b/src/main/java/xades4j/production/SignerEPES.java @@ -36,6 +36,7 @@ /** * Produces XAdES-EPES signatures. + * * @author Luís */ class SignerEPES extends SignerBES @@ -56,9 +57,10 @@ protected SignerEPES( SignedPropertiesMarshaller signedPropsMarshaller, UnsignedPropertiesMarshaller unsignedPropsMarshaller, AlgorithmsParametersMarshallingProvider algorithmsParametersMarshaller, - X500NameStyleProvider x500NameStyleProvider) + X500NameStyleProvider x500NameStyleProvider, + ElementIdGeneratorFactory idGeneratorFactory) { - super(keyingProvider, signatureAlgorithms, basicSignatureOptions, dataObjectDescsProcessor, signaturePropsProvider, dataObjPropsProvider, propsDataObjectsGenerator, signedPropsMarshaller, unsignedPropsMarshaller, algorithmsParametersMarshaller, x500NameStyleProvider); + super(keyingProvider, signatureAlgorithms, basicSignatureOptions, dataObjectDescsProcessor, signaturePropsProvider, dataObjPropsProvider, propsDataObjectsGenerator, signedPropsMarshaller, unsignedPropsMarshaller, algorithmsParametersMarshaller, x500NameStyleProvider, idGeneratorFactory); this.policyInfoProvider = policyInfoProvider; } @@ -66,7 +68,8 @@ protected SignerEPES( protected void getFormatSpecificSignatureProperties( Collection formatSpecificSignedSigProps, Collection formatSpecificUnsignedSigProps, - List signingCertificateChain) throws ValidationDataException { + List signingCertificateChain) throws ValidationDataException + { super.getFormatSpecificSignatureProperties(formatSpecificSignedSigProps, formatSpecificUnsignedSigProps, signingCertificateChain); PropertiesUtils.addXadesEpesProperties(formatSpecificSignedSigProps, this.policyInfoProvider); diff --git a/src/main/java/xades4j/production/SignerT.java b/src/main/java/xades4j/production/SignerT.java index d32c4583..4a7aea93 100644 --- a/src/main/java/xades4j/production/SignerT.java +++ b/src/main/java/xades4j/production/SignerT.java @@ -57,9 +57,10 @@ protected SignerT( UnsignedPropertiesMarshaller unsignedPropsMarshaller, AlgorithmsParametersMarshallingProvider algorithmsParametersMarshaller, X500NameStyleProvider x500NameStyleProvider, + ElementIdGeneratorFactory idGeneratorFactory, Optional policyInfoProvider) { - super(keyingProvider, signatureAlgorithms, basicSignatureOptions, dataObjectDescsProcessor, signaturePropsProvider, dataObjPropsProvider, propsDataObjectsGenerator, signedPropsMarshaller, unsignedPropsMarshaller, algorithmsParametersMarshaller, x500NameStyleProvider); + super(keyingProvider, signatureAlgorithms, basicSignatureOptions, dataObjectDescsProcessor, signaturePropsProvider, dataObjPropsProvider, propsDataObjectsGenerator, signedPropsMarshaller, unsignedPropsMarshaller, algorithmsParametersMarshaller, x500NameStyleProvider, idGeneratorFactory); this.policyInfoProvider = policyInfoProvider; } diff --git a/src/main/java/xades4j/production/XadesSigningProfile.java b/src/main/java/xades4j/production/XadesSigningProfile.java index 64f574bb..871a44c8 100644 --- a/src/main/java/xades4j/production/XadesSigningProfile.java +++ b/src/main/java/xades4j/production/XadesSigningProfile.java @@ -1,291 +1,306 @@ -/* - * XAdES4j - A Java library for generation and verification of XAdES signatures. - * Copyright (C) 2010 Luis Goncalves. - * - * XAdES4j is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the Free - * Software Foundation; either version 3 of the License, or any later version. - * - * XAdES4j is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more - * details. - * - * You should have received a copy of the GNU Lesser General Public License along - * with XAdES4j. If not, see . - */ -package xades4j.production; - -import com.google.inject.Module; -import xades4j.properties.QualifyingProperty; -import xades4j.providers.DataObjectPropertiesProvider; -import xades4j.providers.KeyingDataProvider; -import xades4j.providers.MessageDigestEngineProvider; -import xades4j.providers.SignaturePropertiesProvider; -import xades4j.providers.TimeStampTokenProvider; -import xades4j.providers.X500NameStyleProvider; -import xades4j.utils.UtilsBindingsModule; -import xades4j.utils.XadesProfileCore; -import xades4j.utils.XadesProfileResolutionException; -import xades4j.xml.marshalling.MarshallingBindingsModule; -import xades4j.xml.marshalling.SignedPropertiesMarshaller; -import xades4j.xml.marshalling.UnsignedPropertiesMarshaller; -import xades4j.xml.marshalling.algorithms.AlgorithmParametersBindingsModule; - -/** - * A profile for signature production. This class and its subclasses are the entry - * point for producing signatures. A profile is a configuration for the signature - * production process. This includes not only characteristics of the signer and the - * signature, such as the signing key/certificate and signature properties, but also - * components for the process itself, such as digest and time-stamp generation. - *

- * The purpose of this class is to configure a {@link XadesSigner} that will actually - * produce signatures with those characteristics. - *

- * Only a {@link KeyingDataProvider} has to externally be supplied. All the other components - * have default implementations that are used if no other actions are taken. However, - * all of them can be replaced through the corresponding methods, either by an instance - * or a class. When a class is used it may have dependencies on other components, - * which will be handled in order to create the {@code XadesSigner}. The types may - * also depend on external components, as long as that dependency is registered - * with on of the {@code addBinding} methods. To that end, the constructors and/or - * setters should use the {@code Inject} annotation from Guice. - *

- * Custom {@link PropertyDataObjectGenerator}s can also be configured. The principles - * on their dependencies are the same. - *

- * The XAdES form is also part of the profile. Each form has additional requirements, - * hence being defined by a specific subclass. There are profiles up to XAdES-C. - * The extended formats are also supported (with a few limitations) but can only - * be added after verfication ({@link xades4j.verification.XadesVerifier}). - *

- * Repeated dependency bindings will not cause an immediate error. An exception - * will be thrown when an instance of {@code XadesSigner} is requested. - * - * @see XadesBesSigningProfile - * @see XadesEpesSigningProfile - * @see XadesTSigningProfile - * @see XadesCSigningProfile - * @see xades4j.utils.XadesProfileCore - * @author Luís - */ -public abstract class XadesSigningProfile -{ - private final XadesProfileCore profileCore; - - protected XadesSigningProfile(KeyingDataProvider keyingProvider) - { - this.profileCore = new XadesProfileCore(); - withBinding(KeyingDataProvider.class, keyingProvider); - } - - protected XadesSigningProfile( - Class keyingProviderClass) - { - this.profileCore = new XadesProfileCore(); - withBinding(KeyingDataProvider.class, keyingProviderClass); - } - - private static final Module[] overridableModules = - { - new DefaultProductionBindingsModule(), - new MarshallingBindingsModule() - }; - - private static final Module[] sealedModules = - { - new UtilsBindingsModule(), - new AlgorithmParametersBindingsModule() - }; - - /** - * Creates a new {@code XadesSigner} based on the current state of the profile. - * If any changes are made after this call, the previously returned signer will - * not be affected. Other signers can be created, accumulating the profile changes. - * @return a {@code XadesSigner} accordingly to this profile - * @throws XadesProfileResolutionException if the dependencies of the signer (direct and indirect) cannot be resolved - */ - public final XadesSigner newSigner() throws XadesProfileResolutionException - { - return this.profileCore.getInstance(getSignerClass(), overridableModules, sealedModules); - } - - protected abstract Class getSignerClass(); - - protected final XadesSigningProfile withOptionalBinding(Class clazz) - { - this.profileCore.addOptionalBinding(clazz); - return this; - } - - /**/ - - /** - * Adds a type dependency mapping to the profile. This is tipically done from an - * interface to a type that implements that interface. When a dependency to - * {@code from} is found, the {@code to} class is used. The {@code to} class - * may in turn have its own dependencies. - *

- * The other {@code withNNNNNN} methods are convenient shortcuts for this one. - * @param from the dependency - * @param to the type that resolves the dependency - * @return this profile - */ - public final XadesSigningProfile withBinding( - Class from, - Class to) - { - this.profileCore.addBinding(from, to); - return this; - } - - /** - * Adds a instance dependency mapping to the profile. When a dependency to - * {@code from} is found, the {@code to} instance is used. - * The other {@code withNNNNNN} methods are convenient shortcuts for this one. - * @param from the dependency - * @param to the instance that resolves the dependency - * @return this profile - */ - public final XadesSigningProfile withBinding( - Class from, - T to) - { - this.profileCore.addBinding(from, to); - return this; - } - - /** - * Adds an instance dependency mapping to the profile, using the instance type as dependency. - * @param instance the instance that resolves the dependency - * @return this profile - */ - public final XadesSigningProfile with(Object instance) { - this.profileCore.addBinding((Class)instance.getClass(), instance); - return this; - } - - /* - ********************************************************************** - */ - - public XadesSigningProfile withSignatureAlgorithms(SignatureAlgorithms algorithms) - { - return withBinding(SignatureAlgorithms.class, algorithms); - } - - public XadesSigningProfile withDigestEngineProvider( - MessageDigestEngineProvider digestProvider) - { - return withBinding(MessageDigestEngineProvider.class, digestProvider); - } - - public XadesSigningProfile withDigestEngineProvider( - Class digestProviderClass) - { - return withBinding(MessageDigestEngineProvider.class, digestProviderClass); - } - - /** - * Experimental API. It may be changed or removed in future releases. - */ - public XadesSigningProfile withX500NameStyleProvider( - X500NameStyleProvider x500NameStyleProvider) - { - return withBinding(X500NameStyleProvider.class, x500NameStyleProvider); - } - - /** - * Experimental API. It may be changed or removed in future releases. - */ - public XadesSigningProfile withX500NameStyleProvider( - Class x500NameStyleProviderClass) - { - return withBinding(X500NameStyleProvider.class, x500NameStyleProviderClass); - } - - public XadesSigningProfile withBasicSignatureOptions( - BasicSignatureOptions options) - { - return withBinding(BasicSignatureOptions.class, options); - } - - public XadesSigningProfile withSignaturePropertiesProvider( - SignaturePropertiesProvider signaturePropsProv) - { - return withBinding(SignaturePropertiesProvider.class, signaturePropsProv); - } - - public XadesSigningProfile withSignaturePropertiesProvider( - Class signaturePropsProvClass) - { - return withBinding(SignaturePropertiesProvider.class, signaturePropsProvClass); - } - - public XadesSigningProfile withDataObjectPropertiesProvider( - DataObjectPropertiesProvider dataObjPropsProvider) - { - return withBinding(DataObjectPropertiesProvider.class, dataObjPropsProvider); - } - - public XadesSigningProfile withDataObjectPropertiesProvider( - Class dataObjPropsProviderClass) - { - return withBinding(DataObjectPropertiesProvider.class, dataObjPropsProviderClass); - } - - public XadesSigningProfile withTimeStampTokenProvider( - TimeStampTokenProvider tsTokenProvider) - { - return withBinding(TimeStampTokenProvider.class, tsTokenProvider); - } - - public XadesSigningProfile withTimeStampTokenProvider( - Class tsTokenProviderClass) - { - return withBinding(TimeStampTokenProvider.class, tsTokenProviderClass); - } - - public XadesSigningProfile withSignedPropertiesMarshaller( - SignedPropertiesMarshaller sPropsMarshaller) - { - return withBinding(SignedPropertiesMarshaller.class, sPropsMarshaller); - } - - public XadesSigningProfile withSignedPropertiesMarshaller( - Class sPropsMarshallerClass) - { - return withBinding(SignedPropertiesMarshaller.class, sPropsMarshallerClass); - } - - public XadesSigningProfile withUnsignedPropertiesMarshaller( - UnsignedPropertiesMarshaller uPropsMarshaller) - { - return withBinding(UnsignedPropertiesMarshaller.class, uPropsMarshaller); - } - - public XadesSigningProfile withUnsignedPropertiesMarshaller( - Class uPropsMarshallerClass) - { - return withBinding(UnsignedPropertiesMarshaller.class, uPropsMarshallerClass); - } - - /* ***************************************** */ - /* ***** Custom data object generation ***** */ - /* ***************************************** s*/ - public XadesSigningProfile withPropertyDataObjectGenerator( - final Class propClass, - final PropertyDataObjectGenerator propDataGen) - { - this.profileCore.addGenericBinding(PropertyDataObjectGenerator.class, propDataGen, propClass); - return this; - } - - public XadesSigningProfile withPropertyDataObjectGenerator( - final Class propClass, - final Class> propDataGenClass) - { - this.profileCore.addGenericBinding(PropertyDataObjectGenerator.class, propDataGenClass, propClass); - return this; - } -} +/* + * XAdES4j - A Java library for generation and verification of XAdES signatures. + * Copyright (C) 2010 Luis Goncalves. + * + * XAdES4j is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or any later version. + * + * XAdES4j is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. + * + * You should have received a copy of the GNU Lesser General Public License along + * with XAdES4j. If not, see . + */ +package xades4j.production; + +import com.google.inject.Module; +import xades4j.properties.QualifyingProperty; +import xades4j.providers.DataObjectPropertiesProvider; +import xades4j.providers.KeyingDataProvider; +import xades4j.providers.MessageDigestEngineProvider; +import xades4j.providers.SignaturePropertiesProvider; +import xades4j.providers.TimeStampTokenProvider; +import xades4j.providers.X500NameStyleProvider; +import xades4j.utils.UtilsBindingsModule; +import xades4j.utils.XadesProfileCore; +import xades4j.utils.XadesProfileResolutionException; +import xades4j.xml.marshalling.MarshallingBindingsModule; +import xades4j.xml.marshalling.SignedPropertiesMarshaller; +import xades4j.xml.marshalling.UnsignedPropertiesMarshaller; +import xades4j.xml.marshalling.algorithms.AlgorithmParametersBindingsModule; + +/** + * A profile for signature production. This class and its subclasses are the entry + * point for producing signatures. A profile is a configuration for the signature + * production process. This includes not only characteristics of the signer and the + * signature, such as the signing key/certificate and signature properties, but also + * components for the process itself, such as digest and time-stamp generation. + *

+ * The purpose of this class is to configure a {@link XadesSigner} that will actually + * produce signatures with those characteristics. + *

+ * Only a {@link KeyingDataProvider} has to externally be supplied. All the other components + * have default implementations that are used if no other actions are taken. However, + * all of them can be replaced through the corresponding methods, either by an instance + * or a class. When a class is used it may have dependencies on other components, + * which will be handled in order to create the {@code XadesSigner}. The types may + * also depend on external components, as long as that dependency is registered + * with on of the {@code addBinding} methods. To that end, the constructors and/or + * setters should use the {@code Inject} annotation from Guice. + *

+ * Custom {@link PropertyDataObjectGenerator}s can also be configured. The principles + * on their dependencies are the same. + *

+ * The XAdES form is also part of the profile. Each form has additional requirements, + * hence being defined by a specific subclass. There are profiles up to XAdES-C. + * The extended formats are also supported (with a few limitations) but can only + * be added after verfication ({@link xades4j.verification.XadesVerifier}). + *

+ * Repeated dependency bindings will not cause an immediate error. An exception + * will be thrown when an instance of {@code XadesSigner} is requested. + * + * @author Luís + * @see XadesBesSigningProfile + * @see XadesEpesSigningProfile + * @see XadesTSigningProfile + * @see XadesCSigningProfile + * @see xades4j.utils.XadesProfileCore + */ +public abstract class XadesSigningProfile +{ + private final XadesProfileCore profileCore; + + protected XadesSigningProfile(KeyingDataProvider keyingProvider) + { + this.profileCore = new XadesProfileCore(); + withBinding(KeyingDataProvider.class, keyingProvider); + } + + protected XadesSigningProfile( + Class keyingProviderClass) + { + this.profileCore = new XadesProfileCore(); + withBinding(KeyingDataProvider.class, keyingProviderClass); + } + + private static final Module[] overridableModules = + { + new DefaultProductionBindingsModule(), + new MarshallingBindingsModule() + }; + + private static final Module[] sealedModules = + { + new UtilsBindingsModule(), + new AlgorithmParametersBindingsModule() + }; + + /** + * Creates a new {@code XadesSigner} based on the current state of the profile. + * If any changes are made after this call, the previously returned signer will + * not be affected. Other signers can be created, accumulating the profile changes. + * + * @return a {@code XadesSigner} accordingly to this profile + * @throws XadesProfileResolutionException if the dependencies of the signer (direct and indirect) cannot be resolved + */ + public final XadesSigner newSigner() throws XadesProfileResolutionException + { + return this.profileCore.getInstance(getSignerClass(), overridableModules, sealedModules); + } + + protected abstract Class getSignerClass(); + + protected final XadesSigningProfile withOptionalBinding(Class clazz) + { + this.profileCore.addOptionalBinding(clazz); + return this; + } + + /**/ + + /** + * Adds a type dependency mapping to the profile. This is tipically done from an + * interface to a type that implements that interface. When a dependency to + * {@code from} is found, the {@code to} class is used. The {@code to} class + * may in turn have its own dependencies. + *

+ * The other {@code withNNNNNN} methods are convenient shortcuts for this one. + * + * @param from the dependency + * @param to the type that resolves the dependency + * @return this profile + */ + public final XadesSigningProfile withBinding( + Class from, + Class to) + { + this.profileCore.addBinding(from, to); + return this; + } + + /** + * Adds a instance dependency mapping to the profile. When a dependency to + * {@code from} is found, the {@code to} instance is used. + * The other {@code withNNNNNN} methods are convenient shortcuts for this one. + * + * @param from the dependency + * @param to the instance that resolves the dependency + * @return this profile + */ + public final XadesSigningProfile withBinding( + Class from, + T to) + { + this.profileCore.addBinding(from, to); + return this; + } + + /** + * Adds an instance dependency mapping to the profile, using the instance type as dependency. + * + * @param instance the instance that resolves the dependency + * @return this profile + */ + public final XadesSigningProfile with(Object instance) + { + this.profileCore.addBinding((Class) instance.getClass(), instance); + return this; + } + + /* + ********************************************************************** + */ + + public XadesSigningProfile withSignatureAlgorithms(SignatureAlgorithms algorithms) + { + return withBinding(SignatureAlgorithms.class, algorithms); + } + + public XadesSigningProfile withDigestEngineProvider( + MessageDigestEngineProvider digestProvider) + { + return withBinding(MessageDigestEngineProvider.class, digestProvider); + } + + public XadesSigningProfile withDigestEngineProvider( + Class digestProviderClass) + { + return withBinding(MessageDigestEngineProvider.class, digestProviderClass); + } + + /** + * Experimental API. It may be changed or removed in future releases. + */ + public XadesSigningProfile withX500NameStyleProvider( + X500NameStyleProvider x500NameStyleProvider) + { + return withBinding(X500NameStyleProvider.class, x500NameStyleProvider); + } + + /** + * Experimental API. It may be changed or removed in future releases. + */ + public XadesSigningProfile withX500NameStyleProvider( + Class x500NameStyleProviderClass) + { + return withBinding(X500NameStyleProvider.class, x500NameStyleProviderClass); + } + + public XadesSigningProfile withBasicSignatureOptions( + BasicSignatureOptions options) + { + return withBinding(BasicSignatureOptions.class, options); + } + + public XadesSigningProfile withElementIdGenerator(ElementIdGeneratorFactory idGeneratorFactory) + { + return withBinding(ElementIdGeneratorFactory.class, idGeneratorFactory); + } + + public XadesSigningProfile withElementIdGenerator(Class idGeneratorFactoryClass) + { + return withBinding(ElementIdGeneratorFactory.class, idGeneratorFactoryClass); + } + + public XadesSigningProfile withSignaturePropertiesProvider( + SignaturePropertiesProvider signaturePropsProv) + { + return withBinding(SignaturePropertiesProvider.class, signaturePropsProv); + } + + public XadesSigningProfile withSignaturePropertiesProvider( + Class signaturePropsProvClass) + { + return withBinding(SignaturePropertiesProvider.class, signaturePropsProvClass); + } + + public XadesSigningProfile withDataObjectPropertiesProvider( + DataObjectPropertiesProvider dataObjPropsProvider) + { + return withBinding(DataObjectPropertiesProvider.class, dataObjPropsProvider); + } + + public XadesSigningProfile withDataObjectPropertiesProvider( + Class dataObjPropsProviderClass) + { + return withBinding(DataObjectPropertiesProvider.class, dataObjPropsProviderClass); + } + + public XadesSigningProfile withTimeStampTokenProvider( + TimeStampTokenProvider tsTokenProvider) + { + return withBinding(TimeStampTokenProvider.class, tsTokenProvider); + } + + public XadesSigningProfile withTimeStampTokenProvider( + Class tsTokenProviderClass) + { + return withBinding(TimeStampTokenProvider.class, tsTokenProviderClass); + } + + public XadesSigningProfile withSignedPropertiesMarshaller( + SignedPropertiesMarshaller sPropsMarshaller) + { + return withBinding(SignedPropertiesMarshaller.class, sPropsMarshaller); + } + + public XadesSigningProfile withSignedPropertiesMarshaller( + Class sPropsMarshallerClass) + { + return withBinding(SignedPropertiesMarshaller.class, sPropsMarshallerClass); + } + + public XadesSigningProfile withUnsignedPropertiesMarshaller( + UnsignedPropertiesMarshaller uPropsMarshaller) + { + return withBinding(UnsignedPropertiesMarshaller.class, uPropsMarshaller); + } + + public XadesSigningProfile withUnsignedPropertiesMarshaller( + Class uPropsMarshallerClass) + { + return withBinding(UnsignedPropertiesMarshaller.class, uPropsMarshallerClass); + } + + /* ***************************************** */ + /* ***** Custom data object generation ***** */ + /* ***************************************** s*/ + public XadesSigningProfile withPropertyDataObjectGenerator( + final Class propClass, + final PropertyDataObjectGenerator propDataGen) + { + this.profileCore.addGenericBinding(PropertyDataObjectGenerator.class, propDataGen, propClass); + return this; + } + + public XadesSigningProfile withPropertyDataObjectGenerator( + final Class propClass, + final Class> propDataGenClass) + { + this.profileCore.addGenericBinding(PropertyDataObjectGenerator.class, propDataGenClass, propClass); + return this; + } +} diff --git a/src/test/java/xades4j/production/KeyInfoBuilderTest.java b/src/test/java/xades4j/production/KeyInfoBuilderTest.java index ea16072c..13dc8dc4 100644 --- a/src/test/java/xades4j/production/KeyInfoBuilderTest.java +++ b/src/test/java/xades4j/production/KeyInfoBuilderTest.java @@ -45,6 +45,7 @@ public class KeyInfoBuilderTest extends SignatureServicesTestBase private static X509Certificate testCertificate; private static X509Certificate intermCertificate; private static List certificates; + private static ElementIdGenerator idGenerator; @BeforeAll public static void setUpClass() throws Exception @@ -55,6 +56,7 @@ public static void setUpClass() throws Exception testCertificate = (X509Certificate) certificateFactory.generateCertificate(new FileInputStream(toPlatformSpecificCertDirFilePath("my/LG.cer"))); intermCertificate = (X509Certificate) certificateFactory.generateCertificate(new FileInputStream(toPlatformSpecificCertDirFilePath("my/Interm.cer"))); certificates = Arrays.asList(testCertificate, intermCertificate); + idGenerator = ElementIdGenerator.uuid(); } @Test @@ -65,7 +67,7 @@ void testIncludeCertAndKey() throws Exception .includePublicKey(true)); XMLSignature xmlSignature = getTestSignature(); - keyInfoBuilder.buildKeyInfo(certificates, xmlSignature); + keyInfoBuilder.buildKeyInfo(certificates, xmlSignature, idGenerator); assertEquals(0, xmlSignature.getSignedInfo().getLength()); @@ -86,7 +88,7 @@ void testIncludeCertChain() throws Exception .includeSigningCertificate(SigningCertificateMode.FULL_CHAIN)); XMLSignature xmlSignature = getTestSignature(); - keyInfoBuilder.buildKeyInfo(certificates, xmlSignature); + keyInfoBuilder.buildKeyInfo(certificates, xmlSignature, idGenerator); assertEquals(0, xmlSignature.getSignedInfo().getLength()); @@ -107,7 +109,7 @@ void testIncludeIssuerSerial() throws Exception .includeIssuerSerial(true)); XMLSignature xmlSignature = getTestSignature(); - keyInfoBuilder.buildKeyInfo(certificates, xmlSignature); + keyInfoBuilder.buildKeyInfo(certificates, xmlSignature, idGenerator); assertEquals(1, xmlSignature.getKeyInfo().lengthX509Data()); assertEquals(1, xmlSignature.getKeyInfo().itemX509Data(0).lengthIssuerSerial()); @@ -120,7 +122,7 @@ void testIncludeSubjectName() throws Exception .includeSubjectName(true)); XMLSignature xmlSignature = getTestSignature(); - keyInfoBuilder.buildKeyInfo(certificates, xmlSignature); + keyInfoBuilder.buildKeyInfo(certificates, xmlSignature, idGenerator); assertEquals(1, xmlSignature.getKeyInfo().lengthX509Data()); assertEquals(1, xmlSignature.getKeyInfo().itemX509Data(0).lengthSubjectName()); @@ -133,7 +135,7 @@ void testSignKeyInfo() throws Exception .signKeyInfo(true)); XMLSignature xmlSignature = getTestSignature(); - keyInfoBuilder.buildKeyInfo(certificates, xmlSignature); + keyInfoBuilder.buildKeyInfo(certificates, xmlSignature, idGenerator); SignedInfo signedInfo = xmlSignature.getSignedInfo(); assertEquals(1, signedInfo.getLength()); diff --git a/src/test/java/xades4j/production/SignedDataObjectsProcessorTest.java b/src/test/java/xades4j/production/SignedDataObjectsProcessorTest.java index 8fd39a87..8ade6b61 100644 --- a/src/test/java/xades4j/production/SignedDataObjectsProcessorTest.java +++ b/src/test/java/xades4j/production/SignedDataObjectsProcessorTest.java @@ -18,6 +18,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -44,10 +45,13 @@ */ public class SignedDataObjectsProcessorTest extends SignatureServicesTestBase { + private static ElementIdGenerator idGenerator; + @BeforeAll public static void setUpClass() { Init.initXMLSec(); + idGenerator = ElementIdGenerator.uuid(); } @Test @@ -61,12 +65,11 @@ void testProcess() throws Exception .withSignedDataObject(new EnvelopedXmlObject(doc.createElement("test2"), "text/xml", null)); XMLSignature xmlSignature = new XMLSignature(doc, "", XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256); - xmlSignature.setId("sigId"); AllwaysNullAlgsParamsMarshaller algsParamsMarshaller = new AllwaysNullAlgsParamsMarshaller(); SignedDataObjectsProcessor processor = new SignedDataObjectsProcessor(new SignatureAlgorithms(), algsParamsMarshaller); - SignedDataObjectsProcessor.Result result = processor.process(dataObjsDescs, xmlSignature); + SignedDataObjectsProcessor.Result result = processor.process(dataObjsDescs, xmlSignature, idGenerator); assertEquals(3, result.referenceMappings.size()); assertEquals(3, xmlSignature.getSignedInfo().getLength()); @@ -75,29 +78,29 @@ void testProcess() throws Exception assertEquals(1, algsParamsMarshaller.getInvokeCount()); Reference ref = xmlSignature.getSignedInfo().item(0); - assertEquals("sigId-ref0", ref.getId()); + assertNotNull(ref.getId()); assertEquals("uri", ref.getURI()); assertEquals(1, ref.getTransforms().getLength()); + ObjectContainer obj1 = xmlSignature.getObjectItem(0); + assertNotNull(obj1.getId()); + assertTrue(StringUtils.isNullOrEmptyString(obj1.getMimeType())); + assertTrue(StringUtils.isNullOrEmptyString(obj1.getEncoding())); + ref = xmlSignature.getSignedInfo().item(1); - assertEquals("sigId-ref1", ref.getId()); - assertEquals("#sigId-object1", ref.getURI()); + assertNotNull(ref.getId()); + assertEquals("#" + obj1.getId(), ref.getURI()); assertNull(ref.getTransforms()); - ObjectContainer obj = xmlSignature.getObjectItem(0); - assertEquals("sigId-object1", obj.getId()); - assertTrue(StringUtils.isNullOrEmptyString(obj.getMimeType())); - assertTrue(StringUtils.isNullOrEmptyString(obj.getEncoding())); + ObjectContainer obj2 = xmlSignature.getObjectItem(1); + assertNotNull(obj2.getId()); + assertEquals("text/xml", obj2.getMimeType()); + assertTrue(StringUtils.isNullOrEmptyString(obj2.getEncoding())); ref = xmlSignature.getSignedInfo().item(2); - assertEquals("sigId-ref2", ref.getId()); - assertEquals("#sigId-object2", ref.getURI()); + assertNotNull(ref.getId()); + assertEquals("#" + obj2.getId(), ref.getURI()); assertNull(ref.getTransforms()); - - obj = xmlSignature.getObjectItem(1); - assertEquals("sigId-object2", obj.getId()); - assertEquals("text/xml", obj.getMimeType()); - assertTrue(StringUtils.isNullOrEmptyString(obj.getEncoding())); } @Test @@ -129,12 +132,11 @@ public boolean engineCanResolveURI(ResourceResolverContext context) }); XMLSignature xmlSignature = new XMLSignature(doc, "", XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256); - xmlSignature.setId("sigId"); AllwaysNullAlgsParamsMarshaller algsParamsMarshaller = new AllwaysNullAlgsParamsMarshaller(); SignedDataObjectsProcessor processor = new SignedDataObjectsProcessor(new SignatureAlgorithms(), algsParamsMarshaller); - SignedDataObjectsProcessor.Result result = processor.process(signedObjects, xmlSignature); + SignedDataObjectsProcessor.Result result = processor.process(signedObjects, xmlSignature, idGenerator); // Simulate what's done during signature production doc.appendChild(xmlSignature.getElement()); @@ -149,31 +151,34 @@ public boolean engineCanResolveURI(ResourceResolverContext context) assertEquals(1, xmlSignature.getSignedInfo().getLength()); Manifest manifest1 = new Manifest(DOMHelper.getFirstChildElement(xmlSignature.getObjectItem(1).getElement()), ""); - assertEquals("sigId-manifest0", manifest1.getId()); + assertNotNull(manifest1.getId()); assertEquals(3, manifest1.getLength()); + Manifest manifest2 = new Manifest(DOMHelper.getFirstChildElement(xmlSignature.getObjectItem(0).getElement()), ""); + assertNotNull(manifest2.getId()); + assertEquals(1, manifest2.getLength()); + + Reference ref0 = xmlSignature.getSignedInfo().item(0); + assertEquals("#" + manifest1.getId(), ref0.getURI()); + Reference ref11 = manifest1.item(0); assertEquals("xades4j:1", ref11.getURI()); - assertEquals("sigId-manifest0-ref0", ref11.getId()); + assertNotNull(ref11.getId()); assertNotEquals(0, ref11.getDigestValue().length); Reference ref12 = manifest1.item(1); assertEquals("xades4j:2", ref12.getURI()); - assertEquals("sigId-manifest0-ref1", ref12.getId()); + assertNotNull(ref12.getId()); assertNotEquals(0, ref12.getDigestValue().length); Reference ref13 = manifest1.item(2); - assertEquals("#sigId-manifest0-manifest2", ref13.getURI()); - assertEquals("sigId-manifest0-ref2", ref13.getId()); + assertEquals("#" + manifest2.getId(), ref13.getURI()); + assertNotNull(ref13.getId()); assertNotEquals(0, ref13.getDigestValue().length); - Manifest manifest2 = new Manifest(DOMHelper.getFirstChildElement(xmlSignature.getObjectItem(0).getElement()), ""); - assertEquals(1, manifest2.getLength()); - assertEquals("sigId-manifest0-manifest2", manifest2.getId()); - Reference ref21 = manifest2.item(0); assertEquals("xades4j:3", ref21.getURI()); - assertEquals("sigId-manifest0-manifest2-ref0", ref21.getId()); + assertNotNull(ref21.getId()); assertNotEquals(0, ref21.getDigestValue().length); } @@ -186,10 +191,9 @@ void testAddNullReference() throws Exception .withSignedDataObject(new AnonymousDataObjectReference("data".getBytes())); XMLSignature xmlSignature = new XMLSignature(doc, "", XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256); - xmlSignature.setId("sigId"); SignedDataObjectsProcessor processor = new SignedDataObjectsProcessor(new SignatureAlgorithms(), new AllwaysNullAlgsParamsMarshaller()); - SignedDataObjectsProcessor.Result result = processor.process(dataObjsDescs, xmlSignature); + SignedDataObjectsProcessor.Result result = processor.process(dataObjsDescs, xmlSignature, idGenerator); assertEquals(1, result.referenceMappings.size()); assertEquals(0, xmlSignature.getObjectLength()); diff --git a/src/test/xml/document.signed.bes.xml b/src/test/xml/document.signed.bes.xml index c5598a05..cc907d25 100644 --- a/src/test/xml/document.signed.bes.xml +++ b/src/test/xml/document.signed.bes.xml @@ -1,269 +1,266 @@ - - - Questions, unanswered - Steve and the flubberblubs - 1989 - - - What do you know? - Steve and the flubberblubs - 2006-10-17-08:31 - - - Who do you know? - Steve and the flubberblubs - 2006-10-17-08:35 - - - When do you know? - Steve and the flubberblubs - 2006-10-17-08:39 - - - Do you know? - Steve and the flubberblubs - 2006-10-17-08:44 - - - - - - - - - - - - -rD/g8soqKz8EiPUBhEWfcQacS0ta4ULHX3dKMEH6ZoQ= - - - -HEWYEoR1AMt8yYmx/QfnU1wjnixjsBResadDQCodxgE= - - - - - - -a4cZUpKk+SKJQvr2I6Nz2fpGNZC62mAbJGhqe5Ooyxk= - - - -pvkyjtHH3h4ImkqCh9yAvfjZ6pyc0SGI2RUhOv/cGiJ4G3wlrVo5jVVEnfkyJkUUrMWu2QWcA3UN -k9TGNVnG/0bOQwTDZeNYZk2f6OF2JbsWkL/e8PEwO6LFEohIa+nktAgMWks5QFp/aajCBgysxjIY -pzG2rQY2sIjdKoiMPfU= - - - - -MIICbTCCAdqgAwIBAgIQpkK0uals+ItHxBlpJuypOTAJBgUrDgMCHQUAMD8xCzAJBgNVBAYTAlBU -MQ0wCwYDVQQKEwRJU0VMMQswCQYDVQQLEwJDQzEUMBIGA1UEAxMLSXRlcm1lZGlhdGUwHhcNMTAw -NjI1MTc1ODQ5WhcNMzkxMjMxMjM1OTU5WjBCMQswCQYDVQQGEwJQVDENMAsGA1UEChMESVNFTDEL -MAkGA1UECxMCQ0MxFzAVBgNVBAMTDkx1aXMgR29uY2FsdmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GN -ADCBiQKBgQCpP9acMX69Dbg9ciMLFc5dm1tlpTY9OTNZ/EaCYoGVhh/3+DFgyIbEer6SA24hpREm -AhNG9+Ca0AurDPPgb3aKWFY9pj1WcOctis0VsR0YvzqP+2IGFqKDCd7bXFvv2tI0dEvpdc0oO6PF -Q02xvJG0kxQf44XljOCjUBU43jkJawIDAQABo28wbTBrBgNVHQEEZDBigBBdbbL4pDKLT56PpOpA -/56toTwwOjELMAkGA1UEBhMCUFQxDTALBgNVBAoTBElTRUwxCzAJBgNVBAsTAkNDMQ8wDQYDVQQD -EwZUZXN0Q0GCEN00x9qe7SuWQvpLK0/oay8wCQYFKw4DAh0FAAOBgQBSma8g9dQjiQo4WUljRRuG -yMUVRyCqW/9oRz8+0EoLNR/AhrIlGqdNbqQ1BkncgNNdqMAus5VD34v/EhgrkgWN5fZajMpYsmcR -Ahu4PzJ6hggAlWWMy245JwIYuV0s1Oi39GVTxVNOBIX//AONZlGWO4S2Psb1mqdZ99b/MugsaA== - -CN=Luis Goncalves,OU=CC,O=ISEL,C=PT - -CN=Itermediate,OU=CC,O=ISEL,C=PT --119284162484605703133798696662099777223 - - - -11223344556677889900 -2017-11-20T22:05:29.425Z4btVb5gQ5cdcNhGpvDSWQZabPQrR9jf1x8e3YF9Ajss=CN=Itermediate,OU=CC,O=ISEL,C=PT-119284162484605703133798696662099777223vm5QpbblsWV7fCYXotPhNTeCt4nk8cLFuF36L5RJ4Ok=CN=TestCA,OU=CC,O=ISEL,C=PT-46248926895392336918291885380930606289AUaN+IdhKQqxIVmEOrFwq+Dn22ebTkXJqD3BoOP/x8E=CN=TestCA,OU=CC,O=ISEL,C=PT-99704378678639105802976522062798066869Isto é uma descrição do elemento raizhttp://elem.roothttp://doc1.txthttp://doc2.txttext/xmlMyEncodingIsto é uma descrição do elemento dentro do objecthttp://elem.in.objecthttp://doc3.txthttp://doc4.txttext/xmlMyEncodinghttp://uri.etsi.org/01903/v1.2.2#ProofOfCreationIndicates that the signer has created the signed data object (but not necessarily approved, nor sent it)#xmldsig-cf3b2e5e-0cb0-44fc-af55-db58089207a1-ref0#xmldsig-cf3b2e5e-0cb0-44fc-af55-db58089207a1-ref1MyQualifierhttp://uri.etsi.org/01903/v1.2.2#ProofOfApprovalIndicates that the signer has approved the content of the signed data objectMyQualifierMIAGCSqGSIb3DQEHAqCAMIIVAgIBAzELMAkGBSsOAwIaBQAwggE3BgsqhkiG9w0BCRABBKCCASYE -ggEiMIIBHgIBAQYLKwYBBAG/VQNkAgAwITAJBgUrDgMCGgUABBRLZrSkS81gEzyefV7judeV3hCJ -PgIELnRUdxgPMjAxNzExMjAyMjA1MjdaAQH/AgYBX9t2/eGggaqkgacwgaQxFzAVBgNVBAMMDlRT -QTEgQUNDViAyMDE2MRAwDgYDVQQLDAdQS0lBQ0NWMUQwQgYDVQQKDDtBZ2VuY2lhIGRlIFRlY25v -bG9nw61hIHkgQ2VydGlmaWNhY2nDs24gRWxlY3Ryw7NuaWNhIC0gQUNDVjERMA8GA1UEBwwIVmFs -ZW5jaWExETAPBgNVBAgMCFZhbGVuY2lhMQswCQYDVQQGEwJFU6EaMBgGCCsGAQUFBwEDBAwwCjAI -BgYEAIGXXgGgghA7MIIIYDCCBkigAwIBAgIIDXSvZku1aQ0wDQYJKoZIhvcNAQELBQAwQjESMBAG -A1UEAwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQG -EwJFUzAeFw0xNjAyMjkxNjM3NTBaFw0yOTAyMjUxNjM3NTBaMIGkMRcwFQYDVQQDDA5UU0ExIEFD -Q1YgMjAxNjEQMA4GA1UECwwHUEtJQUNDVjFEMEIGA1UECgw7QWdlbmNpYSBkZSBUZWNub2xvZ8Ot -YSB5IENlcnRpZmljYWNpw7NuIEVsZWN0csOzbmljYSAtIEFDQ1YxETAPBgNVBAcMCFZhbGVuY2lh -MREwDwYDVQQIDAhWYWxlbmNpYTELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQC5E8SzuMnjbK3DwMMCEQmnW839Mm0yQEMphf0qCw91YXRO4668e/AX4PnLMZEoTGAg -MoAUZfdexXgRnQOxHJt94Ujz88J1A/6QmOjWLNDHXS6HLFDIqWxDEPWb3vb2Qeeu3CjxLW0pgw5V -tDenuXbg8pk4QVYmS96H1ZXV/eYmgXHuK0QE0o/EjyVOOY6aV6sxfX2hGhzkGpU4b5na4cD4e9vH -W9spQYbKBpRygGUrMiH1odj60XObD1fhZx/CAcWfVp1jkqiregiWzu5X2TvUHw0xIMTpCGMQ1KgK -zvxLMw6sD2MA+4rnTQTWzEaFaTT5l4aGwFqT4Q4O4Ap5xbc612DwA8wI1FZffJENNTlq5LYGqQ27 -DP3+AfrdZWXiCLRMemOYZ6qSChOcM3aFARiGJadTp1F/S483xIj+HpCq0UsoHaQXCdUVK/YWY5av -+4uiC7x3WFIdAJCofAu0Eg7Ftm/myspBGrqpDgzEJZ5p3M/+zjqJxP/flS0LOVQQLsjZ04QtBwPS -HsR+UNTD55Vec4vqTGsT6mutve+8zcfRkgeyK0pC3XfWCHxOqGI2aYrgGyuXMJH0axa1Ug1JmKbm -iy0SmCcxOhMr16GOhL2b96jRkXKPoPb1GY/EoB9sik3H85L0vCnGKSTswPd6pu1Ng/auKQDW0q12 -Sq1EQoK9CQIDAQABo4IC9TCCAvEwZgYIKwYBBQUHAQEEWjBYMDUGCCsGAQUFBzAChilodHRwOi8v -d3d3LmFjY3YuZXMvZ2VzdGNlcnQvQUNDVlJBSVoxLmNydDAfBggrBgEFBQcwAYYTaHR0cDovL29j -c3AuYWNjdi5lczAdBgNVHQ4EFgQUxsTYQMhIlJ2dS1HD+k7VDlRilZQwHwYDVR0jBBgwFoAU0oe0 -4983J5NV9lbqgeU2zIweP70wggHGBgNVHSAEggG9MIIBuTCCAbUGCysGAQQBv1UDZAIAMIIBpDCC -AW4GCCsGAQUFBwICMIIBYB6CAVwAUwBlAHIAdgBpAGQAbwByACAAZABlACAAUwBlAGwAbABhAGQA -bwAgAGQAZQAgAFQAaQBlAG0AcABvACAAZABlACAAbABhACAAQQBnAGUAbgBjAGkAYQAgAGQAZQAg -AFQAZQBjAG4AbwBsAG8AZwDtAGEAIAB5ACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAEUA -bABlAGMAdAByAPMAbgBpAGMAYQAgAEkAVgBGACAAKABQAGwALgAgAGQAZQAgAE4AYQBwAG8AbABl -AHMAIAB5ACAAUwBpAGMAaQBsAGkAYQAgADYALAAgAEMAUAAgADQANgAwADAAMwAgAEMASQBGACAA -UQA5ADYANQAwADAAMQAwAEMAKQAuACAAQwBQAFMAIAB5ACAAQwBQACAAZQBuACAAaAB0AHQAcAA6 -AC8ALwB3AHcAdwAuAGEAYwBjAHYALgBlAHMwMAYIKwYBBQUHAgEWJGh0dHA6Ly93d3cuYWNjdi5l -cy9sZWdpc2xhY2lvbl9jLmh0bTBVBgNVHR8ETjBMMEqgSKBGhkRodHRwOi8vd3d3LmFjY3YuZXMv -ZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjFfZGVyLmNybDAOBgNVHQ8B -Af8EBAMCBsAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggIBAAjWDDA6 -ddmDPJ1t09dU/0/7VbuCwqQhMONkk8Phn+NtIoUAxWsDk8OYa1CuOSGHvyKys0vgL3MNJlFxnr+U -E0PnYhZ7wz8ziTsI9p5G3bB/7Euvw1s55/+4kxypGoJeJYY8+Jax9pT+x1VuZF5Uvv2ic7gQCYwa -5X0gSGXAdVgzKLYLuvzovitpkuIgbDmVmhGw36GvLQ6FAtxQJb2Mmgfubo7RBlirxgMlkyBwxZRe -b7VWN6dTACm933SjCY/pSgjo11iGpNRcRlTKRIU58yosdZa239gZU+3TxsfNifwulMSTg58lYiHE -ufHKKgtlhACdKm8JwaX1F0afogn06ZwzBKxUgXb9sxUFdHlIzu0leYzULg11DD6/CkqiuygnVNQh -Aa8dNBsMwbQ50rOSbMq1azIZNuoF6Oo9clH5Cz7jEKt+1xMYk/Lmq4ZUdE0IuQ2tezadOXn/B6rq -Dc4xFhKKcTUt2VprTUKGWCXTX49FwhDdmyP3/BlL62NkvlALorjD2GiW4WqaOicefE2yVmqv4H9g -h4F70eEa8CPqxYY75MImIoQGtzk49veDe63Yji1ZsTY7Ju4k8z9YKeDjjo7DZ1c1NoQOeadfoEbA -CBeb2NScosghLACz+Pj0O2eOo1LIu2e49OnEeSVSzVZz82q2Bm7BmUjTpgZyvVhlhglAMIIH0zCC -BbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJBSVoxMRAw -DgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3 -MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUND -VjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoYHtiP -2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0RGy9ocLL -A76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdDaaxXbXmQ -eOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4 -e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9w -rqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 -4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR5LpSLhl+ -0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J9Y0fkIky -F/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMAp -cQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3 -LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8G -CCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2VuqB5TbM -jB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyMHj+9MIIB -cwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAAQQB1AHQA -bwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAg -AGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8A -bABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQAcgDz -AG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMAIABlAG4A -IABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYkaHR0cDov -L3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93 -d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIu -Y3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF -BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70ER9m+27Up -2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxNYEAZSUNU -Y9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9 -ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsn -dQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT -2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5hI6zppSSM -EYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1XgNce4hL60 -Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew -+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tV -NEYqi4Y7MYIDdDCCA3ACAQEwTjBCMRIwEAYDVQQDDAlBQ0NWUkFJWjExEDAOBgNVBAsMB1BLSUFD -Q1YxDTALBgNVBAoMBEFDQ1YxCzAJBgNVBAYTAkVTAggNdK9mS7VpDTAJBgUrDgMCGgUAoIH8MBoG -CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMTcxMTIwMjIwNTI3WjAj -BgkqhkiG9w0BCQQxFgQU7RM79gbOP2fJfu5GZGwrJK755ZMwgZoGCyqGSIb3DQEJEAIMMYGKMIGH -MIGEMBYEFEd+bHvRVM1kdTOD4YwdkxzxqQ34MGoEFJMFeogVxk/OiC/6kRZSKHi8U2QXMFIwRqRE -MEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUNDVjEL -MAkGA1UEBhMCRVMCCF7Dt6ZDf6TgMA0GCSqGSIb3DQEBAQUABIICAFI19wPCTa/IXLxP5RSVVkIF -BcqSxjBGkeRxyx8MCji4bo6ODR2zD4NCIMm+Z/8IeC10A6UPootwpxVcKAA26C7rxvoRxA5NfSkr -knt2pRoQWjsYWyVkzLGp/k4F7CCEsoEpHgoQiRR8af9VwsxV7kaG3A8Jz7Ktz7EepU0yzBSYFKY3 -FZBDh86uaCL8Jtz5SYY54Byj8LFUeOy2vmGyHBhqWLnMGKgN0CRlC4B98a4sikXMMT4+1M0IGOK4 -dID228mKJr4m20hAKrEN/R3y6BtO5Caih3HY819f3ittWFFavQCzk2sMGzMpuQzScTbvWHUxrnKR -ksS7bvVCgOppHUg8YeNGW3eaXacu9zZDf83Shpn7eLwvzVXxlhd359mzZNzNsj7cuV8dWB+xHi7M -0fkT2WgeqUA+4hLZB0SoV+G6TC4YVQGrcUdNbeF+w3vNeoJvvMS+rirC25Se0dVk0sUI3PCrgENt -3c3TvdMThn9lOte9qhTagxoXc2WVQYFUfjRcb+SMKM9y/Mqo5rJEu89zJoyGW0XkcXdFOLNwYn+K -IulxBBaY3NndZsb69xhb85hNVfh9tUNrts6HQ+FyK+roEU92OwUlUjLsWe+G2pe5cAjgfL21ViAX -9f/j8mLqWYHXErOiKuVu274XZ37qZXA7Pqctg9YOSuRxaJoo1OEBAAAAAA==MIAGCSqGSIb3DQEHAqCAMIIVAgIBAzELMAkGBSsOAwIaBQAwggE3BgsqhkiG9w0BCRABBKCCASYE -ggEiMIIBHgIBAQYLKwYBBAG/VQNkAgAwITAJBgUrDgMCGgUABBRLZrSkS81gEzyefV7judeV3hCJ -PgIELnRUehgPMjAxNzExMjAyMjA1MjdaAQH/AgYBX9t2/6aggaqkgacwgaQxFzAVBgNVBAMMDlRT -QTEgQUNDViAyMDE2MRAwDgYDVQQLDAdQS0lBQ0NWMUQwQgYDVQQKDDtBZ2VuY2lhIGRlIFRlY25v -bG9nw61hIHkgQ2VydGlmaWNhY2nDs24gRWxlY3Ryw7NuaWNhIC0gQUNDVjERMA8GA1UEBwwIVmFs -ZW5jaWExETAPBgNVBAgMCFZhbGVuY2lhMQswCQYDVQQGEwJFU6EaMBgGCCsGAQUFBwEDBAwwCjAI -BgYEAIGXXgGgghA7MIIIYDCCBkigAwIBAgIIDXSvZku1aQ0wDQYJKoZIhvcNAQELBQAwQjESMBAG -A1UEAwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQG -EwJFUzAeFw0xNjAyMjkxNjM3NTBaFw0yOTAyMjUxNjM3NTBaMIGkMRcwFQYDVQQDDA5UU0ExIEFD -Q1YgMjAxNjEQMA4GA1UECwwHUEtJQUNDVjFEMEIGA1UECgw7QWdlbmNpYSBkZSBUZWNub2xvZ8Ot -YSB5IENlcnRpZmljYWNpw7NuIEVsZWN0csOzbmljYSAtIEFDQ1YxETAPBgNVBAcMCFZhbGVuY2lh -MREwDwYDVQQIDAhWYWxlbmNpYTELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQC5E8SzuMnjbK3DwMMCEQmnW839Mm0yQEMphf0qCw91YXRO4668e/AX4PnLMZEoTGAg -MoAUZfdexXgRnQOxHJt94Ujz88J1A/6QmOjWLNDHXS6HLFDIqWxDEPWb3vb2Qeeu3CjxLW0pgw5V -tDenuXbg8pk4QVYmS96H1ZXV/eYmgXHuK0QE0o/EjyVOOY6aV6sxfX2hGhzkGpU4b5na4cD4e9vH -W9spQYbKBpRygGUrMiH1odj60XObD1fhZx/CAcWfVp1jkqiregiWzu5X2TvUHw0xIMTpCGMQ1KgK -zvxLMw6sD2MA+4rnTQTWzEaFaTT5l4aGwFqT4Q4O4Ap5xbc612DwA8wI1FZffJENNTlq5LYGqQ27 -DP3+AfrdZWXiCLRMemOYZ6qSChOcM3aFARiGJadTp1F/S483xIj+HpCq0UsoHaQXCdUVK/YWY5av -+4uiC7x3WFIdAJCofAu0Eg7Ftm/myspBGrqpDgzEJZ5p3M/+zjqJxP/flS0LOVQQLsjZ04QtBwPS -HsR+UNTD55Vec4vqTGsT6mutve+8zcfRkgeyK0pC3XfWCHxOqGI2aYrgGyuXMJH0axa1Ug1JmKbm -iy0SmCcxOhMr16GOhL2b96jRkXKPoPb1GY/EoB9sik3H85L0vCnGKSTswPd6pu1Ng/auKQDW0q12 -Sq1EQoK9CQIDAQABo4IC9TCCAvEwZgYIKwYBBQUHAQEEWjBYMDUGCCsGAQUFBzAChilodHRwOi8v -d3d3LmFjY3YuZXMvZ2VzdGNlcnQvQUNDVlJBSVoxLmNydDAfBggrBgEFBQcwAYYTaHR0cDovL29j -c3AuYWNjdi5lczAdBgNVHQ4EFgQUxsTYQMhIlJ2dS1HD+k7VDlRilZQwHwYDVR0jBBgwFoAU0oe0 -4983J5NV9lbqgeU2zIweP70wggHGBgNVHSAEggG9MIIBuTCCAbUGCysGAQQBv1UDZAIAMIIBpDCC -AW4GCCsGAQUFBwICMIIBYB6CAVwAUwBlAHIAdgBpAGQAbwByACAAZABlACAAUwBlAGwAbABhAGQA -bwAgAGQAZQAgAFQAaQBlAG0AcABvACAAZABlACAAbABhACAAQQBnAGUAbgBjAGkAYQAgAGQAZQAg -AFQAZQBjAG4AbwBsAG8AZwDtAGEAIAB5ACAAQwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAEUA -bABlAGMAdAByAPMAbgBpAGMAYQAgAEkAVgBGACAAKABQAGwALgAgAGQAZQAgAE4AYQBwAG8AbABl -AHMAIAB5ACAAUwBpAGMAaQBsAGkAYQAgADYALAAgAEMAUAAgADQANgAwADAAMwAgAEMASQBGACAA -UQA5ADYANQAwADAAMQAwAEMAKQAuACAAQwBQAFMAIAB5ACAAQwBQACAAZQBuACAAaAB0AHQAcAA6 -AC8ALwB3AHcAdwAuAGEAYwBjAHYALgBlAHMwMAYIKwYBBQUHAgEWJGh0dHA6Ly93d3cuYWNjdi5l -cy9sZWdpc2xhY2lvbl9jLmh0bTBVBgNVHR8ETjBMMEqgSKBGhkRodHRwOi8vd3d3LmFjY3YuZXMv -ZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjFfZGVyLmNybDAOBgNVHQ8B -Af8EBAMCBsAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwDQYJKoZIhvcNAQELBQADggIBAAjWDDA6 -ddmDPJ1t09dU/0/7VbuCwqQhMONkk8Phn+NtIoUAxWsDk8OYa1CuOSGHvyKys0vgL3MNJlFxnr+U -E0PnYhZ7wz8ziTsI9p5G3bB/7Euvw1s55/+4kxypGoJeJYY8+Jax9pT+x1VuZF5Uvv2ic7gQCYwa -5X0gSGXAdVgzKLYLuvzovitpkuIgbDmVmhGw36GvLQ6FAtxQJb2Mmgfubo7RBlirxgMlkyBwxZRe -b7VWN6dTACm933SjCY/pSgjo11iGpNRcRlTKRIU58yosdZa239gZU+3TxsfNifwulMSTg58lYiHE -ufHKKgtlhACdKm8JwaX1F0afogn06ZwzBKxUgXb9sxUFdHlIzu0leYzULg11DD6/CkqiuygnVNQh -Aa8dNBsMwbQ50rOSbMq1azIZNuoF6Oo9clH5Cz7jEKt+1xMYk/Lmq4ZUdE0IuQ2tezadOXn/B6rq -Dc4xFhKKcTUt2VprTUKGWCXTX49FwhDdmyP3/BlL62NkvlALorjD2GiW4WqaOicefE2yVmqv4H9g -h4F70eEa8CPqxYY75MImIoQGtzk49veDe63Yji1ZsTY7Ju4k8z9YKeDjjo7DZ1c1NoQOeadfoEbA -CBeb2NScosghLACz+Pj0O2eOo1LIu2e49OnEeSVSzVZz82q2Bm7BmUjTpgZyvVhlhglAMIIH0zCC -BbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJBSVoxMRAw -DgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3 -MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUND -VjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoYHtiP -2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0RGy9ocLL -A76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdDaaxXbXmQ -eOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4 -e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9w -rqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 -4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR5LpSLhl+ -0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J9Y0fkIky -F/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMAp -cQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3 -LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8G -CCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2VuqB5TbM -jB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyMHj+9MIIB -cwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAAQQB1AHQA -bwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAg -AGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8A -bABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQAcgDz -AG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMAIABlAG4A -IABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYkaHR0cDov -L3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93 -d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIu -Y3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF -BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70ER9m+27Up -2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxNYEAZSUNU -Y9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9 -ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsn -dQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT -2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5hI6zppSSM -EYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1XgNce4hL60 -Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew -+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tV -NEYqi4Y7MYIDdDCCA3ACAQEwTjBCMRIwEAYDVQQDDAlBQ0NWUkFJWjExEDAOBgNVBAsMB1BLSUFD -Q1YxDTALBgNVBAoMBEFDQ1YxCzAJBgNVBAYTAkVTAggNdK9mS7VpDTAJBgUrDgMCGgUAoIH8MBoG -CSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMTcxMTIwMjIwNTI3WjAj -BgkqhkiG9w0BCQQxFgQUmBt5xg7f42PUNiKvlkAlHewcmcowgZoGCyqGSIb3DQEJEAIMMYGKMIGH -MIGEMBYEFEd+bHvRVM1kdTOD4YwdkxzxqQ34MGoEFJMFeogVxk/OiC/6kRZSKHi8U2QXMFIwRqRE -MEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUNDVjEL -MAkGA1UEBhMCRVMCCF7Dt6ZDf6TgMA0GCSqGSIb3DQEBAQUABIICAFvOSPWEXPG1uHflhPt7/L/Q -24LDGpqqjgAYihAgb2gZkB14SIrTtEu3r5Kdn5H9EDRIDeVGNwrTHEQDBmIMdUXP9rkio/2nlZf4 -Fzth/WeO8uxTlRk3GhLiXcp3yy69uVyqi1lCHU1bfLfh5wRUZ2cnLNuf6z+kzsIuzEezgRUU/tKY -vK9FJDuwOfxZVA8fk6Ve+ZUtqZEVqmWu6FJOyubA4BC6oM2Lj0JX1oIzPCwD4lT7gpAHuFZvoJNO -x/ekyJJ17FPv4mpYkUPrhI6nsuwJNL0vvz+cQlZKCI47ksSpl75AagZy5s49rcCpNVYXQe86nKsa -TxHjIV/x2UHUnKkE81yreJhPK1ZEBJ/sLhB47uUxrXEISdWpQc9Ge/1Afno6Y7b+JlHsLIh58HtR -TbiMMqnA8rXLG4CMf45zyMjmCiXDk7T0WWwWHqlzXvddUGLg2Qydqz7YQOkohZguMbFJnTwHour+ -IvZ9bRr9oFUeuwNN2C3EPCouTieT0f9hkz8EsB/kv94j+mxLcKXb3MZJX0DpZK+ChU20icLzvPM6 -bx8mchtEa2titwwnA1EMR6avzDd6wueEccQUBJC9FFoGwN4VE8wDUpouiYrhPGeeNcK9MGhwO81/ -9OUidEzJa7+x0aeXwRQls8+VuwgfyBa7KD9Cl0Vt3C1MQu8Edgv5AAAAAA== + + + Questions, unanswered + Steve and the flubberblubs + 1989 + + + What do you know? + Steve and the flubberblubs + 2006-10-17-08:31 + + + Who do you know? + Steve and the flubberblubs + 2006-10-17-08:35 + + + When do you know? + Steve and the flubberblubs + 2006-10-17-08:39 + + + Do you know? + Steve and the flubberblubs + 2006-10-17-08:44 + + + + + + + + + + + + +rD/g8soqKz8EiPUBhEWfcQacS0ta4ULHX3dKMEH6ZoQ= + + + +hsd3PFTaWKcYpIppePtI4+mpSzO5tNF+DbL5vwHXoY8= + + + + + + +IyvKL5Ex+GHmudpzbKVhOQAftIG19U5phgT9jc+rZa8= + + + +fukzf/UTEdcGkUc3ODV5Izs4AILesFDCKVw3To7QxbMSMbaXIsfd5EB5AlXrqUn6hHKv1pKc1+yq +QvlpnRtZc0E/A2yfmy0x2UYD7h+6uC+7EKeEY2R+uzn+C80PeNSmveGyZLwgHaYxRFlNUuMl8XKS +bXap9yOOmrmc3XUSSWE= + + + + +MIICbTCCAdqgAwIBAgIQpkK0uals+ItHxBlpJuypOTAJBgUrDgMCHQUAMD8xCzAJBgNVBAYTAlBU +MQ0wCwYDVQQKEwRJU0VMMQswCQYDVQQLEwJDQzEUMBIGA1UEAxMLSXRlcm1lZGlhdGUwHhcNMTAw +NjI1MTc1ODQ5WhcNMzkxMjMxMjM1OTU5WjBCMQswCQYDVQQGEwJQVDENMAsGA1UEChMESVNFTDEL +MAkGA1UECxMCQ0MxFzAVBgNVBAMTDkx1aXMgR29uY2FsdmVzMIGfMA0GCSqGSIb3DQEBAQUAA4GN +ADCBiQKBgQCpP9acMX69Dbg9ciMLFc5dm1tlpTY9OTNZ/EaCYoGVhh/3+DFgyIbEer6SA24hpREm +AhNG9+Ca0AurDPPgb3aKWFY9pj1WcOctis0VsR0YvzqP+2IGFqKDCd7bXFvv2tI0dEvpdc0oO6PF +Q02xvJG0kxQf44XljOCjUBU43jkJawIDAQABo28wbTBrBgNVHQEEZDBigBBdbbL4pDKLT56PpOpA +/56toTwwOjELMAkGA1UEBhMCUFQxDTALBgNVBAoTBElTRUwxCzAJBgNVBAsTAkNDMQ8wDQYDVQQD +EwZUZXN0Q0GCEN00x9qe7SuWQvpLK0/oay8wCQYFKw4DAh0FAAOBgQBSma8g9dQjiQo4WUljRRuG +yMUVRyCqW/9oRz8+0EoLNR/AhrIlGqdNbqQ1BkncgNNdqMAus5VD34v/EhgrkgWN5fZajMpYsmcR +Ahu4PzJ6hggAlWWMy245JwIYuV0s1Oi39GVTxVNOBIX//AONZlGWO4S2Psb1mqdZ99b/MugsaA== + + + +11223344556677889900 +2024-09-12T12:49:22.772+01:004btVb5gQ5cdcNhGpvDSWQZabPQrR9jf1x8e3YF9Ajss=cn=Itermediate,ou=CC,o=ISEL,c=PT-119284162484605703133798696662099777223vm5QpbblsWV7fCYXotPhNTeCt4nk8cLFuF36L5RJ4Ok=cn=TestCA,ou=CC,o=ISEL,c=PT-46248926895392336918291885380930606289AUaN+IdhKQqxIVmEOrFwq+Dn22ebTkXJqD3BoOP/x8E=cn=TestCA,ou=CC,o=ISEL,c=PT-99704378678639105802976522062798066869Isto é uma descrição do elemento raizhttp://elem.roothttp://doc1.txthttp://doc2.txttext/xmlMyEncodingIsto é uma descrição do elemento dentro do objecthttp://elem.in.objecthttp://doc3.txthttp://doc4.txttext/xmlMyEncodinghttp://uri.etsi.org/01903/v1.2.2#ProofOfApprovalIndicates that the signer has approved the content of the signed data objecthttp://uri.etsi.org/01903/v1.2.2#ProofOfCreationIndicates that the signer has created the signed data object (but not necessarily approved, nor sent it)#reference-142945b4-28e1-42df-bf15-4311f2ef682e#reference-7738a46a-425f-43bb-becb-014fe45d146cMyQualifierMIIVRwYJKoZIhvcNAQcCoIIVODCCFTQCAQMxDzANBglghkgBZQMEAgEFADCCAVQGCyqGSIb3DQEJ +EAEEoIIBQwSCAT8wggE7AgEBBgsrBgEEAb9VA2QCADAxMA0GCWCGSAFlAwQCAQUABCBnwxKHlpXD +Js7FA0olRjYhBg82qQLK9CVNT39EcbwIiwIEXHpsVBgPMjAyNDA5MTIxMTQ5MjNaMAoCAQCAAgH0 +gQEBAQH/AgYBkeYRDQyggaqkgacwgaQxFzAVBgNVBAMMDlRTQTEgQUNDViAyMDE2MRAwDgYDVQQL +DAdQS0lBQ0NWMUQwQgYDVQQKDDtBZ2VuY2lhIGRlIFRlY25vbG9nw61hIHkgQ2VydGlmaWNhY2nD +s24gRWxlY3Ryw7NuaWNhIC0gQUNDVjERMA8GA1UEBwwIVmFsZW5jaWExETAPBgNVBAgMCFZhbGVu +Y2lhMQswCQYDVQQGEwJFU6EbMBkGCCsGAQUFBwEDBA0wCzAJBgcEAIGXXgEBoIIQOzCCCGAwggZI +oAMCAQICCA10r2ZLtWkNMA0GCSqGSIb3DQEBCwUAMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4G +A1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwHhcNMTYwMjI5MTYzNzUw +WhcNMjkwMjI1MTYzNzUwWjCBpDEXMBUGA1UEAwwOVFNBMSBBQ0NWIDIwMTYxEDAOBgNVBAsMB1BL +SUFDQ1YxRDBCBgNVBAoMO0FnZW5jaWEgZGUgVGVjbm9sb2fDrWEgeSBDZXJ0aWZpY2FjacOzbiBF +bGVjdHLDs25pY2EgLSBBQ0NWMREwDwYDVQQHDAhWYWxlbmNpYTERMA8GA1UECAwIVmFsZW5jaWEx +CzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuRPEs7jJ42ytw8DD +AhEJp1vN/TJtMkBDKYX9KgsPdWF0TuOuvHvwF+D5yzGRKExgIDKAFGX3XsV4EZ0DsRybfeFI8/PC +dQP+kJjo1izQx10uhyxQyKlsQxD1m9729kHnrtwo8S1tKYMOVbQ3p7l24PKZOEFWJkveh9WV1f3m +JoFx7itEBNKPxI8lTjmOmlerMX19oRoc5BqVOG+Z2uHA+Hvbx1vbKUGGygaUcoBlKzIh9aHY+tFz +mw9X4WcfwgHFn1adY5Koq3oIls7uV9k71B8NMSDE6QhjENSoCs78SzMOrA9jAPuK500E1sxGhWk0 ++ZeGhsBak+EODuAKecW3Otdg8APMCNRWX3yRDTU5auS2BqkNuwz9/gH63WVl4gi0THpjmGeqkgoT +nDN2hQEYhiWnU6dRf0uPN8SI/h6QqtFLKB2kFwnVFSv2FmOWr/uLogu8d1hSHQCQqHwLtBIOxbZv +5srKQRq6qQ4MxCWeadzP/s46icT/35UtCzlUEC7I2dOELQcD0h7EflDUw+eVXnOL6kxrE+prrb3v +vM3H0ZIHsitKQt131gh8TqhiNmmK4BsrlzCR9GsWtVINSZim5ostEpgnMToTK9ehjoS9m/eo0ZFy +j6D29RmPxKAfbIpNx/OS9Lwpxikk7MD3eqbtTYP2rikA1tKtdkqtREKCvQkCAwEAAaOCAvUwggLx +MGYGCCsGAQUFBwEBBFowWDA1BggrBgEFBQcwAoYpaHR0cDovL3d3dy5hY2N2LmVzL2dlc3RjZXJ0 +L0FDQ1ZSQUlaMS5jcnQwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmFjY3YuZXMwHQYDVR0OBBYE +FMbE2EDISJSdnUtRw/pO1Q5UYpWUMB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyMHj+9MIIB +xgYDVR0gBIIBvTCCAbkwggG1BgsrBgEEAb9VA2QCADCCAaQwggFuBggrBgEFBQcCAjCCAWAeggFc +AFMAZQByAHYAaQBkAG8AcgAgAGQAZQAgAFMAZQBsAGwAYQBkAG8AIABkAGUAIABUAGkAZQBtAHAA +bwAgAGQAZQAgAGwAYQAgAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA7QBh +ACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQAcgDzAG4AaQBjAGEA +IABJAFYARgAgACgAUABsAC4AIABkAGUAIABOAGEAcABvAGwAZQBzACAAeQAgAFMAaQBjAGkAbABp +AGEAIAA2ACwAIABDAFAAIAA0ADYAMAAwADMAIABDAEkARgAgAFEAOQA2ADUAMAAwADEAMABDACkA +LgAgAEMAUABTACAAeQAgAEMAUAAgAGUAbgAgAGgAdAB0AHAAOgAvAC8AdwB3AHcALgBhAGMAYwB2 +AC4AZQBzMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LmFjY3YuZXMvbGVnaXNsYWNpb25fYy5odG0w +VQYDVR0fBE4wTDBKoEigRoZEaHR0cDovL3d3dy5hY2N2LmVzL2ZpbGVhZG1pbi9BcmNoaXZvcy9j +ZXJ0aWZpY2Fkb3MvcmFpemFjY3YxX2Rlci5jcmwwDgYDVR0PAQH/BAQDAgbAMBYGA1UdJQEB/wQM +MAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEBCwUAA4ICAQAI1gwwOnXZgzydbdPXVP9P+1W7gsKkITDj +ZJPD4Z/jbSKFAMVrA5PDmGtQrjkhh78isrNL4C9zDSZRcZ6/lBND52IWe8M/M4k7CPaeRt2wf+xL +r8NbOef/uJMcqRqCXiWGPPiWsfaU/sdVbmReVL79onO4EAmMGuV9IEhlwHVYMyi2C7r86L4raZLi +IGw5lZoRsN+hry0OhQLcUCW9jJoH7m6O0QZYq8YDJZMgcMWUXm+1VjenUwApvd90owmP6UoI6NdY +hqTUXEZUykSFOfMqLHWWtt/YGVPt08bHzYn8LpTEk4OfJWIhxLnxyioLZYQAnSpvCcGl9RdGn6IJ +9OmcMwSsVIF2/bMVBXR5SM7tJXmM1C4NdQw+vwpKorsoJ1TUIQGvHTQbDMG0OdKzkmzKtWsyGTbq +BejqPXJR+Qs+4xCrftcTGJPy5quGVHRNCLkNrXs2nTl5/weq6g3OMRYSinE1Ldlaa01Chlgl01+P +RcIQ3Zsj9/wZS+tjZL5QC6K4w9holuFqmjonHnxNslZqr+B/YIeBe9HhGvAj6sWGO+TCJiKEBrc5 +OPb3g3ut2I4tWbE2OybuJPM/WCng446Ow2dXNTaEDnmnX6BGwAgXm9jUnKLIISwAs/j49DtnjqNS +yLtnuPTpxHklUs1Wc/NqtgZuwZlI06YGcr1YZYYJQDCCB9MwggW7oAMCAQICCF7Dt6ZDf6TgMA0G +CSqGSIb3DQEBBQUAMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsG +A1UECgwEQUNDVjELMAkGA1UEBhMCRVMwHhcNMTEwNTA1MDkzNzM3WhcNMzAxMjMxMDkzNzM3WjBC +MRIwEAYDVQQDDAlBQ0NWUkFJWjExEDAOBgNVBAsMB1BLSUFDQ1YxDTALBgNVBAoMBEFDQ1YxCzAJ +BgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAm6mrv2FKl68vl2aadF/Q +2Zb9z+LkZu8fH0czwkSj35reH7VU3RV8aTURb7vIDI5qGB7Yj9kWvBBINlzwY7OQWlwkN9ej1ssJ +cbnxAXKEsH3bTYDN/NNvyfjatg6C0kWFqBtoqD3o9ERsvaHCywO+jD4TAITfSkjA4yIK6Ok3pxhM +sQkNI1Z/BE3ZF4QYpcjaQJRz684OVzwDgTqdCqFXQ2msV215kHjltbQ72LxMjSihp6OnugJOJdEq +ru2uAyK4ayAPMChUlX/g7s4KZp3RQC1uIq+dGsEFGdJvwPKf+HuzAkL7UKkdLZMPI6vGwQ+S/9Ci +FfVTCXEc/0UThOYmXvjgiBwK/Ba2qHMGuPBjhAKgxlrs53TfcK6jgyXq1seXh5OnxoqKM5dgNxA+ +lz5uKRXWoQ/RiCwSn2+qpMZC60Gi45VD0wGFbY67O/MjNsf+O+ChJQdIq8mJdP8Ij4C/wJZl8+7s +S2i9nYjDMbNA8ejP9ji7nOTRf9TlWJt8+tTzDpt1keS6Ui4ZftH1zVoZ/LoG9vtSqEuZBN34+bSL +UKNOYonwhyT6g0LBh/rVLSkqWnF6ZGrXJ2BjDdvOSfWNH5CJMhf4c0O40lqThmHW4XUK6nlmdohP +cesEJdYKWnqT5blLF0APsba59d5P3OCzrDsRcGCESkNumSDAKXEKwGUCAwEAAaOCAsswggLHMH0G +CCsGAQUFBwEBBHEwbzBMBggrBgEFBQcwAoZAaHR0cDovL3d3dy5hY2N2LmVzL2ZpbGVhZG1pbi9B +cmNoaXZvcy9jZXJ0aWZpY2Fkb3MvcmFpemFjY3YxLmNydDAfBggrBgEFBQcwAYYTaHR0cDovL29j +c3AuYWNjdi5lczAdBgNVHQ4EFgQU0oe04983J5NV9lbqgeU2zIweP70wDwYDVR0TAQH/BAUwAwEB +/zAfBgNVHSMEGDAWgBTSh7Tj3zcnk1X2VuqB5TbMjB4/vTCCAXMGA1UdIASCAWowggFmMIIBYgYE +VR0gADCCAVgwggEiBggrBgEFBQcCAjCCARQeggEQAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAA +QwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABBAEMAQwBW +ACAAKABBAGcAZQBuAGMAaQBhACAAZABlACAAVABlAGMAbgBvAGwAbwBnAO0AYQAgAHkAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAARQBsAGUAYwB0AHIA8wBuAGkAYwBhACwAIABDAEkARgAg +AFEANAA2ADAAMQAxADUANgBFACkALgAgAEMAUABTACAAZQBuACAAaAB0AHQAcAA6AC8ALwB3AHcA +dwAuAGEAYwBjAHYALgBlAHMwMAYIKwYBBQUHAgEWJGh0dHA6Ly93d3cuYWNjdi5lcy9sZWdpc2xh +Y2lvbl9jLmh0bTBVBgNVHR8ETjBMMEqgSKBGhkRodHRwOi8vd3d3LmFjY3YuZXMvZmlsZWFkbWlu +L0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjFfZGVyLmNybDAOBgNVHQ8BAf8EBAMCAQYw +FwYDVR0RBBAwDoEMYWNjdkBhY2N2LmVzMA0GCSqGSIb3DQEBBQUAA4ICAQCXMQKf5/1DZ0hEFOQp +h+1MKGbQjzXaTWG3SpdNtduQ4AUuDsZ50PKXaQ+9BEfZvtu1Kdqb2a6pmdXTPDCT9Y2hqPwGjUT0 +yhaVfDPcYouoN/gn2AktG+/IFCcgqWRE/y7WdapsTWBAGUlDVGPa4sy6ZuVPRHpb2WqBK0DVf/kB +J1gsyO1IkXw/pgDPxClzETbehhk+ne4ZihvVsO2OPZwqwA3YPWbjPA291ZRc4uKnNRsEAPY/Wo3q +Q71fiR2pwbDMmeJNAAraySdb5xOQXOT1M6JVbdzgCU0vsSZbJ3UACcRidykIX55ZrLZ+rZ9UMCID +wR5xZP75OAqWGN0CFKwjywYcHqR9jQ3eJ0HordoVt7Aj3Suo09olh+3oVURNiPQ2foSaeKz3DlZJ +DtYzJdaEUEJsIBIdKtW+vPJwgaRwYL4FtZueBES+YSOs6aUkjBGAlFqiorlJ0sHc0aftMREsnhmm +7uFV4cDqzw2E5Be3onyl3lUlBu7MwIdcQNrMlT9V4DXHuIS+tF3NeoMBcu6H5l8drrWFxibf5sGa +6R4CR58qqG2pW8/sRXd/mCeaMl0q44TuxZhmL5YgHd3YwyfXsPn+2X3N0J+PCxRYUZ8vi8M4Ld7o +j9aNh6T1VkMWmSz0pFa0NLhhN8nCWIAboJeh/FmN6RH20Q9LVTRGKouGOzGCA4UwggOBAgEBME4w +QjESMBAGA1UEAwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUwIIDXSvZku1aQ0wDQYJYIZIAWUDBAIBBQCgggEIMBoGCSqGSIb3DQEJAzENBgsq +hkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjQwOTEyMTE0OTIzWjAvBgkqhkiG9w0BCQQxIgQg +dyV2mc05tAEniqdi3hmO7QT+x1ADZPcSsiU1mcOFQcAwgZoGCyqGSIb3DQEJEAIMMYGKMIGHMIGE +MBYEFEd+bHvRVM1kdTOD4YwdkxzxqQ34MGoEFJMFeogVxk/OiC/6kRZSKHi8U2QXMFIwRqREMEIx +EjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkG +A1UEBhMCRVMCCF7Dt6ZDf6TgMA0GCSqGSIb3DQEBAQUABIICAKlAdh9XrnLOlbu5phwVvqAXSmIt +e9Ty0jjS1sIiEE+Z8wApYrw8UWuvh94hJt3Dfn8sj960mvxgF70Ugnc3E8UwYOgVU1nQJ7CsloE1 +gACYFPVZkCNlfIUNsicP6UwKFaVEz6wXXmcNT5Dy6TW0yMVc5QN3DWhbSdQw8hHD5HSGuZugQjKD +cnrsqnCQ5+tBvUSpt3mAD9kvGy4QxJHzGyggd3k4QAFIpeabTdlK7v4Z4GyH5bQuKec9cOMAKo0L +zqbF8c+9eAzmLslAOHUlMS5RhwTQDKFpMgmNCkodnZ+rI1rszHSjWfUkCxiKiz8yBUmjK5xZ0X2k +Gbtr/67z0nU0E9XVaI9oSK4U2q+MaeRA27NnEf6J2LR+Rp+plpj3OrP0TJixQrVvYerR1kHYwuJv +CfLPqqZ+AE5LZGb3NajvMM/lcBYUdIamLzqBmuGOfJDkVYI8M2ynksQtI4N2AlkhEUa+sES4DmPL +lPD19g4x32icypJDmeClbbArODL/I1qihpeuZuqUa4Gx594/FuiE2dCt81SvL6OdIxEDxgJWvR/0 +yH0EHoiKYvhiob/u8P3oQnDnjeI3nrWWARwGdKo8bhYodEW3/Aa17vgBw0dpNjG9SjCpsI/jz+hu +uqIuFm/MhU4eK9kYayAlT8kTgziga/MbBrfDkMY4CSTok7U1MIIVRwYJKoZIhvcNAQcCoIIVODCCFTQCAQMxDzANBglghkgBZQMEAgEFADCCAVQGCyqGSIb3DQEJ +EAEEoIIBQwSCAT8wggE7AgEBBgsrBgEEAb9VA2QCADAxMA0GCWCGSAFlAwQCAQUABCBnwxKHlpXD +Js7FA0olRjYhBg82qQLK9CVNT39EcbwIiwIEXHpsWhgPMjAyNDA5MTIxMTQ5MjNaMAoCAQCAAgH0 +gQEBAQH/AgYBkeYRDf+ggaqkgacwgaQxFzAVBgNVBAMMDlRTQTEgQUNDViAyMDE2MRAwDgYDVQQL +DAdQS0lBQ0NWMUQwQgYDVQQKDDtBZ2VuY2lhIGRlIFRlY25vbG9nw61hIHkgQ2VydGlmaWNhY2nD +s24gRWxlY3Ryw7NuaWNhIC0gQUNDVjERMA8GA1UEBwwIVmFsZW5jaWExETAPBgNVBAgMCFZhbGVu +Y2lhMQswCQYDVQQGEwJFU6EbMBkGCCsGAQUFBwEDBA0wCzAJBgcEAIGXXgEBoIIQOzCCCGAwggZI +oAMCAQICCA10r2ZLtWkNMA0GCSqGSIb3DQEBCwUAMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4G +A1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwHhcNMTYwMjI5MTYzNzUw +WhcNMjkwMjI1MTYzNzUwWjCBpDEXMBUGA1UEAwwOVFNBMSBBQ0NWIDIwMTYxEDAOBgNVBAsMB1BL +SUFDQ1YxRDBCBgNVBAoMO0FnZW5jaWEgZGUgVGVjbm9sb2fDrWEgeSBDZXJ0aWZpY2FjacOzbiBF +bGVjdHLDs25pY2EgLSBBQ0NWMREwDwYDVQQHDAhWYWxlbmNpYTERMA8GA1UECAwIVmFsZW5jaWEx +CzAJBgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAuRPEs7jJ42ytw8DD +AhEJp1vN/TJtMkBDKYX9KgsPdWF0TuOuvHvwF+D5yzGRKExgIDKAFGX3XsV4EZ0DsRybfeFI8/PC +dQP+kJjo1izQx10uhyxQyKlsQxD1m9729kHnrtwo8S1tKYMOVbQ3p7l24PKZOEFWJkveh9WV1f3m +JoFx7itEBNKPxI8lTjmOmlerMX19oRoc5BqVOG+Z2uHA+Hvbx1vbKUGGygaUcoBlKzIh9aHY+tFz +mw9X4WcfwgHFn1adY5Koq3oIls7uV9k71B8NMSDE6QhjENSoCs78SzMOrA9jAPuK500E1sxGhWk0 ++ZeGhsBak+EODuAKecW3Otdg8APMCNRWX3yRDTU5auS2BqkNuwz9/gH63WVl4gi0THpjmGeqkgoT +nDN2hQEYhiWnU6dRf0uPN8SI/h6QqtFLKB2kFwnVFSv2FmOWr/uLogu8d1hSHQCQqHwLtBIOxbZv +5srKQRq6qQ4MxCWeadzP/s46icT/35UtCzlUEC7I2dOELQcD0h7EflDUw+eVXnOL6kxrE+prrb3v +vM3H0ZIHsitKQt131gh8TqhiNmmK4BsrlzCR9GsWtVINSZim5ostEpgnMToTK9ehjoS9m/eo0ZFy +j6D29RmPxKAfbIpNx/OS9Lwpxikk7MD3eqbtTYP2rikA1tKtdkqtREKCvQkCAwEAAaOCAvUwggLx +MGYGCCsGAQUFBwEBBFowWDA1BggrBgEFBQcwAoYpaHR0cDovL3d3dy5hY2N2LmVzL2dlc3RjZXJ0 +L0FDQ1ZSQUlaMS5jcnQwHwYIKwYBBQUHMAGGE2h0dHA6Ly9vY3NwLmFjY3YuZXMwHQYDVR0OBBYE +FMbE2EDISJSdnUtRw/pO1Q5UYpWUMB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyMHj+9MIIB +xgYDVR0gBIIBvTCCAbkwggG1BgsrBgEEAb9VA2QCADCCAaQwggFuBggrBgEFBQcCAjCCAWAeggFc +AFMAZQByAHYAaQBkAG8AcgAgAGQAZQAgAFMAZQBsAGwAYQBkAG8AIABkAGUAIABUAGkAZQBtAHAA +bwAgAGQAZQAgAGwAYQAgAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA7QBh +ACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQAcgDzAG4AaQBjAGEA +IABJAFYARgAgACgAUABsAC4AIABkAGUAIABOAGEAcABvAGwAZQBzACAAeQAgAFMAaQBjAGkAbABp +AGEAIAA2ACwAIABDAFAAIAA0ADYAMAAwADMAIABDAEkARgAgAFEAOQA2ADUAMAAwADEAMABDACkA +LgAgAEMAUABTACAAeQAgAEMAUAAgAGUAbgAgAGgAdAB0AHAAOgAvAC8AdwB3AHcALgBhAGMAYwB2 +AC4AZQBzMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LmFjY3YuZXMvbGVnaXNsYWNpb25fYy5odG0w +VQYDVR0fBE4wTDBKoEigRoZEaHR0cDovL3d3dy5hY2N2LmVzL2ZpbGVhZG1pbi9BcmNoaXZvcy9j +ZXJ0aWZpY2Fkb3MvcmFpemFjY3YxX2Rlci5jcmwwDgYDVR0PAQH/BAQDAgbAMBYGA1UdJQEB/wQM +MAoGCCsGAQUFBwMIMA0GCSqGSIb3DQEBCwUAA4ICAQAI1gwwOnXZgzydbdPXVP9P+1W7gsKkITDj +ZJPD4Z/jbSKFAMVrA5PDmGtQrjkhh78isrNL4C9zDSZRcZ6/lBND52IWe8M/M4k7CPaeRt2wf+xL +r8NbOef/uJMcqRqCXiWGPPiWsfaU/sdVbmReVL79onO4EAmMGuV9IEhlwHVYMyi2C7r86L4raZLi +IGw5lZoRsN+hry0OhQLcUCW9jJoH7m6O0QZYq8YDJZMgcMWUXm+1VjenUwApvd90owmP6UoI6NdY +hqTUXEZUykSFOfMqLHWWtt/YGVPt08bHzYn8LpTEk4OfJWIhxLnxyioLZYQAnSpvCcGl9RdGn6IJ +9OmcMwSsVIF2/bMVBXR5SM7tJXmM1C4NdQw+vwpKorsoJ1TUIQGvHTQbDMG0OdKzkmzKtWsyGTbq +BejqPXJR+Qs+4xCrftcTGJPy5quGVHRNCLkNrXs2nTl5/weq6g3OMRYSinE1Ldlaa01Chlgl01+P +RcIQ3Zsj9/wZS+tjZL5QC6K4w9holuFqmjonHnxNslZqr+B/YIeBe9HhGvAj6sWGO+TCJiKEBrc5 +OPb3g3ut2I4tWbE2OybuJPM/WCng446Ow2dXNTaEDnmnX6BGwAgXm9jUnKLIISwAs/j49DtnjqNS +yLtnuPTpxHklUs1Wc/NqtgZuwZlI06YGcr1YZYYJQDCCB9MwggW7oAMCAQICCF7Dt6ZDf6TgMA0G +CSqGSIb3DQEBBQUAMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsG +A1UECgwEQUNDVjELMAkGA1UEBhMCRVMwHhcNMTEwNTA1MDkzNzM3WhcNMzAxMjMxMDkzNzM3WjBC +MRIwEAYDVQQDDAlBQ0NWUkFJWjExEDAOBgNVBAsMB1BLSUFDQ1YxDTALBgNVBAoMBEFDQ1YxCzAJ +BgNVBAYTAkVTMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAm6mrv2FKl68vl2aadF/Q +2Zb9z+LkZu8fH0czwkSj35reH7VU3RV8aTURb7vIDI5qGB7Yj9kWvBBINlzwY7OQWlwkN9ej1ssJ +cbnxAXKEsH3bTYDN/NNvyfjatg6C0kWFqBtoqD3o9ERsvaHCywO+jD4TAITfSkjA4yIK6Ok3pxhM +sQkNI1Z/BE3ZF4QYpcjaQJRz684OVzwDgTqdCqFXQ2msV215kHjltbQ72LxMjSihp6OnugJOJdEq +ru2uAyK4ayAPMChUlX/g7s4KZp3RQC1uIq+dGsEFGdJvwPKf+HuzAkL7UKkdLZMPI6vGwQ+S/9Ci +FfVTCXEc/0UThOYmXvjgiBwK/Ba2qHMGuPBjhAKgxlrs53TfcK6jgyXq1seXh5OnxoqKM5dgNxA+ +lz5uKRXWoQ/RiCwSn2+qpMZC60Gi45VD0wGFbY67O/MjNsf+O+ChJQdIq8mJdP8Ij4C/wJZl8+7s +S2i9nYjDMbNA8ejP9ji7nOTRf9TlWJt8+tTzDpt1keS6Ui4ZftH1zVoZ/LoG9vtSqEuZBN34+bSL +UKNOYonwhyT6g0LBh/rVLSkqWnF6ZGrXJ2BjDdvOSfWNH5CJMhf4c0O40lqThmHW4XUK6nlmdohP +cesEJdYKWnqT5blLF0APsba59d5P3OCzrDsRcGCESkNumSDAKXEKwGUCAwEAAaOCAsswggLHMH0G +CCsGAQUFBwEBBHEwbzBMBggrBgEFBQcwAoZAaHR0cDovL3d3dy5hY2N2LmVzL2ZpbGVhZG1pbi9B +cmNoaXZvcy9jZXJ0aWZpY2Fkb3MvcmFpemFjY3YxLmNydDAfBggrBgEFBQcwAYYTaHR0cDovL29j +c3AuYWNjdi5lczAdBgNVHQ4EFgQU0oe04983J5NV9lbqgeU2zIweP70wDwYDVR0TAQH/BAUwAwEB +/zAfBgNVHSMEGDAWgBTSh7Tj3zcnk1X2VuqB5TbMjB4/vTCCAXMGA1UdIASCAWowggFmMIIBYgYE +VR0gADCCAVgwggEiBggrBgEFBQcCAjCCARQeggEQAEEAdQB0AG8AcgBpAGQAYQBkACAAZABlACAA +QwBlAHIAdABpAGYAaQBjAGEAYwBpAPMAbgAgAFIAYQDtAHoAIABkAGUAIABsAGEAIABBAEMAQwBW +ACAAKABBAGcAZQBuAGMAaQBhACAAZABlACAAVABlAGMAbgBvAGwAbwBnAO0AYQAgAHkAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAARQBsAGUAYwB0AHIA8wBuAGkAYwBhACwAIABDAEkARgAg +AFEANAA2ADAAMQAxADUANgBFACkALgAgAEMAUABTACAAZQBuACAAaAB0AHQAcAA6AC8ALwB3AHcA +dwAuAGEAYwBjAHYALgBlAHMwMAYIKwYBBQUHAgEWJGh0dHA6Ly93d3cuYWNjdi5lcy9sZWdpc2xh +Y2lvbl9jLmh0bTBVBgNVHR8ETjBMMEqgSKBGhkRodHRwOi8vd3d3LmFjY3YuZXMvZmlsZWFkbWlu +L0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjFfZGVyLmNybDAOBgNVHQ8BAf8EBAMCAQYw +FwYDVR0RBBAwDoEMYWNjdkBhY2N2LmVzMA0GCSqGSIb3DQEBBQUAA4ICAQCXMQKf5/1DZ0hEFOQp +h+1MKGbQjzXaTWG3SpdNtduQ4AUuDsZ50PKXaQ+9BEfZvtu1Kdqb2a6pmdXTPDCT9Y2hqPwGjUT0 +yhaVfDPcYouoN/gn2AktG+/IFCcgqWRE/y7WdapsTWBAGUlDVGPa4sy6ZuVPRHpb2WqBK0DVf/kB +J1gsyO1IkXw/pgDPxClzETbehhk+ne4ZihvVsO2OPZwqwA3YPWbjPA291ZRc4uKnNRsEAPY/Wo3q +Q71fiR2pwbDMmeJNAAraySdb5xOQXOT1M6JVbdzgCU0vsSZbJ3UACcRidykIX55ZrLZ+rZ9UMCID +wR5xZP75OAqWGN0CFKwjywYcHqR9jQ3eJ0HordoVt7Aj3Suo09olh+3oVURNiPQ2foSaeKz3DlZJ +DtYzJdaEUEJsIBIdKtW+vPJwgaRwYL4FtZueBES+YSOs6aUkjBGAlFqiorlJ0sHc0aftMREsnhmm +7uFV4cDqzw2E5Be3onyl3lUlBu7MwIdcQNrMlT9V4DXHuIS+tF3NeoMBcu6H5l8drrWFxibf5sGa +6R4CR58qqG2pW8/sRXd/mCeaMl0q44TuxZhmL5YgHd3YwyfXsPn+2X3N0J+PCxRYUZ8vi8M4Ld7o +j9aNh6T1VkMWmSz0pFa0NLhhN8nCWIAboJeh/FmN6RH20Q9LVTRGKouGOzGCA4UwggOBAgEBME4w +QjESMBAGA1UEAwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUwIIDXSvZku1aQ0wDQYJYIZIAWUDBAIBBQCgggEIMBoGCSqGSIb3DQEJAzENBgsq +hkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjQwOTEyMTE0OTIzWjAvBgkqhkiG9w0BCQQxIgQg +kTgiyAuDgO+Q4bdDbmgMIJrRmn4wDg5FuL14z+wb7gowgZoGCyqGSIb3DQEJEAIMMYGKMIGHMIGE +MBYEFEd+bHvRVM1kdTOD4YwdkxzxqQ34MGoEFJMFeogVxk/OiC/6kRZSKHi8U2QXMFIwRqREMEIx +EjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkG +A1UEBhMCRVMCCF7Dt6ZDf6TgMA0GCSqGSIb3DQEBAQUABIICALR5EMuSGWWUEU7UHeL+vxis12fl +RQsArFIxEpKDjWULGg/ZdKyZfOqkIdK7ULCUGnr11UQ9Kc0ytdsZw7MQur4XPF1dS2XNX2cmdyW9 +bVR5OLYeFnamwUN7mah/baMTXZfGf0jsA5sgySt7L/UebreEDHF77vhJ1XEVXKPr1OGT3hHV5cOw +ft0x0p8TKlwWgKEdeCkQxTdscbH1judsEsjpzuK8BxY5Nfk2MKlgrSCvxAolFR4lWik21upTayHN +65B/xIZB2/3jRKfiKoDVo8xKTY0v7XWjLCowsKjK+by5PGZWIaqRClzJsmUA31Dp26p0rTEkGn5d +B9VEQaBjU9j+i+659L7rA8EBaYI0o+PVTSpMnqqZt+kSz4BFLOJrn0OivZ5PHyu3Heukcz5BZygW +9xAcOXkDtnQUkrEd7VPmDE4cK8bOMBqVJs+KgE5aru0isb/Jbjpnuvd63/u6M4opMFcfLhOUqRGU +4YKG+zfROLmiWYFgzIKWiiWOGbPL19rgi/f1WrwvTeL+cZ4G4j7PWHNbQugIl2/RsILYuUQI96ZM +XgVxxUjUURogqv+YV84SaxW678NrZjhUkGGIb0TPumXPyYc7d9K9xCmTK16RLU4R2Bhaw6hGjS81 +LDxdJt27gwtdIY9zXmGmSGCB9X8TwoSeO2hakOAi+ZvQDs3n \ No newline at end of file