diff options
Diffstat (limited to 'bkucommon/src/main/java/at/gv/egiz/bku/slcommands')
16 files changed, 1306 insertions, 107 deletions
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkCommand.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkCommand.java new file mode 100644 index 00000000..7deb8e22 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkCommand.java @@ -0,0 +1,27 @@ +/* + * Copyright 2015 Datentechnik Innovation and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.bku.slcommands; + + +public interface BulkCommand extends SLCommand { + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkSignatureResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkSignatureResult.java new file mode 100644 index 00000000..8670d635 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/BulkSignatureResult.java @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Datentechnik Innovation and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.bku.slcommands; + +import org.w3c.dom.Element; + +public interface BulkSignatureResult extends SLResult { + + public Element getContent(); + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandFactory.java new file mode 100644 index 00000000..7f7d7f1e --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandFactory.java @@ -0,0 +1,40 @@ +/* + * Copyright 2015 Datentechnik Innovation and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + +package at.gv.egiz.bku.slcommands.impl; + +import javax.xml.bind.JAXBElement; + +import at.gv.egiz.bku.slcommands.AbstractSLCommandFactory; +import at.gv.egiz.bku.slcommands.SLCommand; +import at.gv.egiz.bku.slexceptions.SLCommandException; + +public class BulkCommandFactory extends AbstractSLCommandFactory { + + @Override + public SLCommand createSLCommand(JAXBElement<?> element) throws SLCommandException { + BulkCommandImpl command = new BulkCommandImpl(); + command.init(element); + command.setConfiguration(configuration); + return command; + } +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandImpl.java new file mode 100644 index 00000000..7094e284 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkCommandImpl.java @@ -0,0 +1,439 @@ +/* + * Copyright 2015 Datentechnik Innovation GmbH and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.bku.slcommands.impl; + +import iaik.asn1.DerCoder; +import iaik.asn1.INTEGER; +import iaik.asn1.SEQUENCE; +import iaik.asn1.structures.AlgorithmID; +import iaik.cms.CMSException; +import iaik.cms.CMSSignatureException; +import iaik.utils.Util; + +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.SignatureException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +import org.apache.commons.configuration.Configuration; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.BulkRequestType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.BulkRequestType.CreateSignatureRequest; +import at.buergerkarte.namespaces.securitylayer._1_2_3.CreateCMSSignatureRequestType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; +import at.gv.egiz.bku.conf.MoccaConfigurationFacade; +import at.gv.egiz.bku.slcommands.BulkCommand; +import at.gv.egiz.bku.slcommands.SLCommandContext; +import at.gv.egiz.bku.slcommands.SLResult; +import at.gv.egiz.bku.slcommands.impl.cms.BulkCollectionSecurityProvider; +import at.gv.egiz.bku.slcommands.impl.cms.BulkSignature; +import at.gv.egiz.bku.slcommands.impl.cms.BulkSignatureInfo; +import at.gv.egiz.bku.slcommands.impl.cms.CMSHashDataInput; +import at.gv.egiz.bku.slcommands.impl.xsect.STALSignatureException; +import at.gv.egiz.bku.slexceptions.SLCommandException; +import at.gv.egiz.bku.slexceptions.SLException; +import at.gv.egiz.bku.slexceptions.SLRequestException; +import at.gv.egiz.bku.slexceptions.SLViewerException; +import at.gv.egiz.stal.BulkSignRequest; +import at.gv.egiz.stal.BulkSignResponse; +import at.gv.egiz.stal.ErrorResponse; +import at.gv.egiz.stal.HashDataInput; +import at.gv.egiz.stal.InfoboxReadRequest; +import at.gv.egiz.stal.STALRequest; +import at.gv.egiz.stal.STALResponse; +import at.gv.egiz.stal.SignRequest; +import at.gv.egiz.stal.SignRequest.SignedInfo; + +/** + * This class implements the security layer command <code>BulkRequest</code>. + * + * @author szoescher + */ +public class BulkCommandImpl extends SLCommandImpl<BulkRequestType> implements BulkCommand { + + private final static String ID_ECSIGTYPE = "1.2.840.10045.4"; + + /** + * Logging facility. + */ + private final static Logger log = LoggerFactory.getLogger(BulkCommandImpl.class); + + /** + * The signing certificate. + */ + protected X509Certificate signingCertificate; + + /** + * The keybox identifier of the key used for signing. + */ + protected String keyboxIdentifier; + + /** + * The configuration facade used to access the MOCCA configuration. + */ + private ConfigurationFacade configurationFacade = new ConfigurationFacade(); + + private class ConfigurationFacade implements MoccaConfigurationFacade { + private Configuration configuration; + + public static final String USE_STRONG_HASH = "UseStrongHash"; + + public void setConfiguration(Configuration configuration) { + this.configuration = configuration; + } + + public boolean getUseStrongHash() { + return configuration.getBoolean(USE_STRONG_HASH, true); + } + } + + @Override + public String getName() { + return "BulkRequest"; + } + + public void setConfiguration(Configuration configuration) { + configurationFacade.setConfiguration(configuration); + } + + @Override + public SLResult execute(SLCommandContext commandContext) { + + List<BulkSignature> signatures = new LinkedList<BulkSignature>(); + + try { + + List<CreateSignatureRequest> signatureRequests = getRequestValue().getCreateSignatureRequest(); + + + List<String> requestIds = new LinkedList<String>(); + + if (signatureRequests != null && signatureRequests.size() != 0) { + + BulkCollectionSecurityProvider securityProvider = new BulkCollectionSecurityProvider(); + + log.debug("get keyboxIdentifier from BulkSingatureRequest"); + keyboxIdentifier = setKeyboxIdentifier(signatureRequests); + + log.info("Requesting signing certificate."); + signingCertificate = requestSigningCertificate(keyboxIdentifier, commandContext); + log.debug("Got signing certificate. {}", signingCertificate); + + + for (int i=0; i<signatureRequests.size(); i++) { + + CreateSignatureRequest request = signatureRequests.get(i); + if (request.getCreateCMSSignatureRequest() != null) { + log.info("execute CMSSignature request."); + + requestIds.add(request.getId()); + + BulkSignature signature = prepareCMSSignatureRequests(securityProvider, request.getCreateCMSSignatureRequest(), + commandContext); + + signatures.add(signature); + + for(HashDataInput hashDataInput : securityProvider.getBulkSignatureInfo().get(i).getHashDataInput()){ + + if(hashDataInput instanceof CMSHashDataInput) { + CMSHashDataInput cmsHashDataInput = (CMSHashDataInput) hashDataInput; + log.debug("setting fileName {}", getFileName(request, i+1)); + cmsHashDataInput.setFilename(getFileName(request, i+1)); + cmsHashDataInput.setDigest(signature.getSignerInfo().getDigest()); + } + + + } + } else { + if (request.getCreateXMLSignatureRequest() != null) { + log.error("XML signature requests are currently not supported in bulk signature requests."); + throw new SLCommandException(4124); + } + } + } + + + return new BulkSignatureResultImpl(signBulkRequest(securityProvider.getBulkSignatureInfo(), commandContext, + signatures), requestIds); + + + + } + + } catch (SLException e) { + return new ErrorResultImpl(e, commandContext.getLocale()); + + } catch (CMSException e) { + log.error("Error reading message digest.",e); + } + return null; + } + + private String getFileName(CreateSignatureRequest request, int requestCounter) { + + String referenceURL = null; + + if (request.getCreateCMSSignatureRequest().getDataObject() != null + && request.getCreateCMSSignatureRequest().getDataObject().getContent() != null) { + referenceURL = request.getCreateCMSSignatureRequest().getDataObject().getContent().getReference(); + } + + if (StringUtils.isNotEmpty(referenceURL)) { + return FilenameUtils.getBaseName(referenceURL); + } else { + + StringBuilder fileNameBuilder = new StringBuilder(); + + if (StringUtils.isNotEmpty(request.getDisplayName())) { + fileNameBuilder.append(request.getDisplayName()); + } else { + fileNameBuilder.append(HashDataInput.DEFAULT_FILENAME); + fileNameBuilder.append("_"); + fileNameBuilder.append(requestCounter); + } + + return fileNameBuilder.toString(); + } + } + + private List<byte[]> signBulkRequest(List<BulkSignatureInfo> bulkSignatureInfo, SLCommandContext commandContext, + List<BulkSignature> signatures) throws SLCommandException, SLRequestException { + + try { + + List<byte[]> signatureValues; + + BulkSignRequest signRequest = getSTALSignRequest(bulkSignatureInfo); + + // send BulkStalRequest + List<STALResponse> responses = commandContext.getSTAL().handleRequest( + Collections.singletonList((STALRequest) signRequest)); + + if (responses == null || responses.size() != 1) { + throw new SignatureException("Failed to access STAL."); + } + + STALResponse response = responses.get(0); + + // setSignatureValues from STALResponse + if (response instanceof BulkSignResponse) { + BulkSignResponse bulkSignatureResponse = ((BulkSignResponse) response); + + signatureValues = new LinkedList<byte[]>(); + for (int i = 0; i < bulkSignatureResponse.getSignResponse().size(); i++) { + byte[] sig = ((BulkSignResponse) response).getSignResponse().get(i).getSignatureValue(); + log.debug("Got signature response: " + Util.toBase64String(sig)); + signatures.get(i).getSignerInfo() + .setSignatureValue(wrapSignatureValue(sig, bulkSignatureInfo.get(i).getSignatureAlgorithm())); + signatureValues.add(signatures.get(i).getEncoded()); + } + + return signatureValues; + + } else if (response instanceof ErrorResponse) { + + ErrorResponse err = (ErrorResponse) response; + log.debug("Error signing bulk request. Error response code: " + err.getErrorCode() + " (" + err.getErrorMessage() + ")."); + throw new SLCommandException(err.getErrorCode()); + } + + } catch (SignatureException e) { + log.error("Error creating CMSSignature", e); + throw new SLCommandException(4000); + } catch (CMSException e) { + log.error("Error creating CMSSignature", e); + } + return null; + } + + private String setKeyboxIdentifier(List<CreateSignatureRequest> signatureRequests) throws SLCommandException { + + String keyboxIdentifier = null; + + for (CreateSignatureRequest request : signatureRequests) { + if (request.getCreateCMSSignatureRequest() != null) { + + if (keyboxIdentifier == null) { + keyboxIdentifier = request.getCreateCMSSignatureRequest().getKeyboxIdentifier(); + } else { + if (request.getCreateCMSSignatureRequest().getKeyboxIdentifier() == null) { + log.error("No keyboxIdentifier has been specified for this signature request."); + throw new SLCommandException(3003); + + } else if (!request.getCreateCMSSignatureRequest().getKeyboxIdentifier().equals(keyboxIdentifier)) { + + log.error("Error creating bulk signature. The bulkSignature value has to be the same fo all signature requests."); + throw new SLCommandException(3003); + } + } + } + } + + + return keyboxIdentifier; + } + + private BulkSignature prepareCMSSignatureRequests(BulkCollectionSecurityProvider securityProvieder, + CreateCMSSignatureRequestType request, SLCommandContext commandContext) throws SLCommandException, + SLRequestException, SLViewerException { + + BulkSignature signature; + + // prepare the CMSSignature for signing + log.debug("Preparing CMS signature."); + signature = prepareCMSSignature(request, commandContext); + + try { + + // update securityProvieder with parameters of the given signature + securityProvieder.updateBulkCollectionSecurityProvider(keyboxIdentifier, signature.getHashDataInput(), + signature.getExcludedByteRange()); + + // prepare the CMSSignatures of the Bulk Request + log.debug("Signing CMS signature."); + + + + return prepareStalRequest(securityProvieder, signature, commandContext); + + } catch (Exception e) { + log.error("Error creating CMS Signature.", e); + throw new SLCommandException(4000); + } + + } + + private BulkSignature prepareCMSSignature(CreateCMSSignatureRequestType request, SLCommandContext commandContext) + throws SLCommandException, SLRequestException { + + // DataObject, SigningCertificate, SigningTime + Date signingTime = new Date(); + try { + return new BulkSignature( + request.getDataObject() != null ? request.getDataObject() : request.getReferenceObject(), + request.getStructure(), signingCertificate, signingTime, commandContext.getURLDereferencer(), + configurationFacade.getUseStrongHash()); + } catch (SLCommandException e) { + log.error("Error creating CMS Signature.", e); + throw e; + } catch (InvalidParameterException e) { + log.error("Error creating CMS Signature.", e); + throw new SLCommandException(3004); + } catch (Exception e) { + log.error("Error creating CMS Signature.", e); + throw new SLCommandException(4000); + } + } + + private BulkSignature prepareStalRequest(BulkCollectionSecurityProvider securityProvieder, BulkSignature signature, + SLCommandContext commandContext) throws SLCommandException, SLViewerException { + + try { + + signature.sign(securityProvieder, commandContext.getSTAL(), keyboxIdentifier); + return signature; + } catch (CMSException e) { + log.error("Error creating CMSSignature", e); + throw new SLCommandException(4000); + } catch (CMSSignatureException e) { + log.error("Error creating CMSSignature", e); + throw new SLCommandException(4000); + } + } + + private X509Certificate requestSigningCertificate(String keyboxIdentifier, SLCommandContext commandContext) + throws SLCommandException { + + InfoboxReadRequest stalRequest = new InfoboxReadRequest(); + stalRequest.setInfoboxIdentifier(keyboxIdentifier); + + STALHelper stalHelper = new STALHelper(commandContext.getSTAL()); + + stalHelper.transmitSTALRequest(Collections.singletonList((STALRequest) stalRequest)); + List<X509Certificate> certificates = stalHelper.getCertificatesFromResponses(); + if (certificates == null || certificates.size() != 1) { + log.info("Got an unexpected number of certificates from STAL."); + throw new SLCommandException(4000); + } + return signingCertificate = certificates.get(0); + + } + + private static BulkSignRequest getSTALSignRequest(List<BulkSignatureInfo> bulkSignatureInfo) { + BulkSignRequest bulkSignRequest = new BulkSignRequest(); + + for (int i = 0; i< bulkSignatureInfo.size(); i++) { + + BulkSignatureInfo signatureInfo = bulkSignatureInfo.get(i); + SignRequest signRequest = new SignRequest(); + signRequest.setKeyIdentifier(signatureInfo.getKeyboxIdentifier()); + log.debug("SignedAttributes: " + Util.toBase64String(signatureInfo.getSignedAttributes())); + SignedInfo signedInfo = new SignedInfo(); + signedInfo.setValue(signatureInfo.getSignedAttributes()); + signedInfo.setIsCMSSignedAttributes(true); + signRequest.setSignedInfo(signedInfo); + log.info("set displayName for Request {}", signatureInfo.getHashDataInput().get(0).getFilename()); + signRequest.setDisplayName(signatureInfo.getHashDataInput().get(0).getFilename()); + signRequest.setMimeType(signatureInfo.getHashDataInput().get(0).getMimeType()); + + signRequest.setSignatureMethod(signatureInfo.getSignatureMethod()); + signRequest.setDigestMethod(signatureInfo.getDigestMethod()); + signRequest.setHashDataInput(signatureInfo.getHashDataInput()); + + ExcludedByteRangeType excludedByteRange = signatureInfo.getExcludedByteRange(); + if (excludedByteRange != null) { + SignRequest.ExcludedByteRange ebr = new SignRequest.ExcludedByteRange(); + ebr.setFrom(excludedByteRange.getFrom()); + ebr.setTo(excludedByteRange.getTo()); + signRequest.setExcludedByteRange(ebr); + } + + bulkSignRequest.getSignRequests().add(signRequest); + } + return bulkSignRequest; + } + + private static byte[] wrapSignatureValue(byte[] sig, AlgorithmID sigAlgorithmID) { + String id = sigAlgorithmID.getAlgorithm().getID(); + if (id.startsWith(ID_ECSIGTYPE)) // X9.62 Format ECDSA signatures + { + // Wrap r and s in ASN.1 SEQUENCE + byte[] r = Arrays.copyOfRange(sig, 0, sig.length / 2); + byte[] s = Arrays.copyOfRange(sig, sig.length / 2, sig.length); + SEQUENCE sigS = new SEQUENCE(); + sigS.addComponent(new INTEGER(new BigInteger(1, r))); + sigS.addComponent(new INTEGER(new BigInteger(1, s))); + return DerCoder.encode(sigS); + } else + return sig; + } + +}
\ No newline at end of file diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkSignatureResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkSignatureResultImpl.java new file mode 100644 index 00000000..2a88b6be --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/BulkSignatureResultImpl.java @@ -0,0 +1,138 @@ +/* + * Copyright 2015 Datentechnik Innovation and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.bku.slcommands.impl; + +import java.util.List; + +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.bind.Marshaller; +import javax.xml.transform.Result; +import javax.xml.transform.Templates; +import javax.xml.transform.dom.DOMResult; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.BulkResponseType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.BulkResponseType.CreateSignatureResponse; +import at.buergerkarte.namespaces.securitylayer._1_2_3.CreateCMSSignatureResponseType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.ObjectFactory; +import at.gv.egiz.bku.slcommands.BulkSignatureResult; +import at.gv.egiz.bku.slcommands.SLMarshallerFactory; +import at.gv.egiz.bku.slexceptions.SLRuntimeException; + +/** + * This implements the result of the security layer command + * <code>BulkRequest</code>. + * + * @author szoescher + */ +public class BulkSignatureResultImpl extends SLResultImpl implements BulkSignatureResult { + + /** + * Logging facility. + */ + private final Logger log = LoggerFactory.getLogger(BulkSignatureResultImpl.class); + + /** + * The CMSSignatures data. + */ + protected List<byte[]> signatures; + + + protected List<String> requestIds; + + + /** + * The BulkResponse. + */ + private Element content; + + /** + * Creates a new instance of this BulkSignatureResultImpl with the given + * signatures <code>signatures</code>. + */ + public BulkSignatureResultImpl(List<byte[]> signatures, List<String> requestIds) { + super(); + + if (signatures == null || signatures.size() == 0) + throw new NullPointerException("Argument 'signature' must not be null."); + this.signatures = signatures; + + this.requestIds = requestIds; + + marshallBulkSignatureResponse(); + } + + /** + * Marshalls the <code>BulkResponseType</code>. + */ + private void marshallBulkSignatureResponse() { + + ObjectFactory factory = new ObjectFactory(); + + BulkResponseType bulkResponseType = factory.createBulkResponseType(); + + for (int i=0; i< signatures.size(); i++) { + + byte[] signature = signatures.get(i); + CreateSignatureResponse createSignatureResponse = factory.createBulkResponseTypeCreateSignatureResponse(); + + if (requestIds.get(i) != null) { + createSignatureResponse.setId(requestIds.get(i)); + } + CreateCMSSignatureResponseType createCreateCMSSignatureResponseType = factory + .createCreateCMSSignatureResponseType(); + createCreateCMSSignatureResponseType.setCMSSignature(signature); + createSignatureResponse.setCreateCMSSignatureResponse(createCreateCMSSignatureResponseType); + bulkResponseType.getCreateSignatureResponse().add(createSignatureResponse); + + + } + + JAXBElement<BulkResponseType> createBulkResponse = factory.createBulkResponse(bulkResponseType); + DOMResult res = new DOMResult(); + + Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(false); + + try { + marshaller.marshal(createBulkResponse, res); + } catch (JAXBException e) { + log.error("Failed to marshall 'createBulkResponse'.", e); + throw new SLRuntimeException(e); + } + content = ((Document) res.getNode()).getDocumentElement(); + } + + @Override + public void writeTo(Result result, Templates templates, boolean fragment) { + writeTo(content, result, templates, fragment); + } + + @Override + public Element getContent() { + return content; + } +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImpl.java index eaf3e70a..93e0eee8 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImpl.java @@ -123,8 +123,9 @@ public class CreateCMSSignatureCommandImpl extends // DataObject, SigningCertificate, SigningTime Date signingTime = request.isPAdESCompatibility() ? null : new Date(); - signature = new Signature(request.getDataObject(), request.getStructure(), - signingCertificate, signingTime, commandContext.getURLDereferencer(), + signature = new Signature(request.getDataObject() != null ? request.getDataObject() + : request.getReferenceObject(), request.getStructure(), signingCertificate, signingTime, + commandContext.getURLDereferencer(), configurationFacade.getUseStrongHash()); } } catch (SLCommandException e) { diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java index d0451138..74a0b4da 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/DataObjectHashDataInput.java @@ -76,4 +76,8 @@ public class DataObjectHashDataInput implements HashDataInput { return dataObject.getFilename(); } + @Override + public byte[] getDigest() { + return dataObject.getReference().getDigestValue(); + } } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkCollectionSecurityProvider.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkCollectionSecurityProvider.java new file mode 100644 index 00000000..6bbdc682 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkCollectionSecurityProvider.java @@ -0,0 +1,114 @@ +/* + * Copyright 2015 Datentechnik Innovation GmbH and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + + +package at.gv.egiz.bku.slcommands.impl.cms; + +import iaik.asn1.structures.AlgorithmID; +import iaik.cms.IaikProvider; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.SignatureException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; +import at.gv.egiz.stal.HashDataInput; + + +/** + * This security Provider is used to collect multiple sign Requests to create one Stal BulkRequest. + * The related signature parameters are stored as a List of <code>BulkSignatureInfo</code>. + * @author szoescher + * + */ +public class BulkCollectionSecurityProvider extends IaikProvider { + + private final static Logger log = LoggerFactory.getLogger(BulkCollectionSecurityProvider.class); + + private String keyboxIdentifier; + private List<HashDataInput> hashDataInput; + private ExcludedByteRangeType excludedByteRange; + + private List<BulkSignatureInfo> bulkSignatureInfo; + + + public BulkCollectionSecurityProvider() { + bulkSignatureInfo = new LinkedList<BulkSignatureInfo>(); + } + + public BulkCollectionSecurityProvider(String keyboxIdentifier, HashDataInput hashDataInput, + ExcludedByteRangeType excludedByteRange) { + + bulkSignatureInfo = new LinkedList<BulkSignatureInfo>(); + updateBulkCollectionSecurityProvider(keyboxIdentifier, hashDataInput, excludedByteRange); + + } + + public void updateBulkCollectionSecurityProvider(String keyboxIdentifier, HashDataInput hashDataInput, + ExcludedByteRangeType excludedByteRange) { + + this.keyboxIdentifier = keyboxIdentifier; + this.hashDataInput = new ArrayList<HashDataInput>(); + this.hashDataInput.add(hashDataInput); + this.excludedByteRange = excludedByteRange; + + } + + /* (non-Javadoc) + * @see iaik.cms.IaikProvider#calculateSignatureFromSignedAttributes(iaik.asn1.structures.AlgorithmID, iaik.asn1.structures.AlgorithmID, java.security.PrivateKey, byte[]) + */ + @Override + public byte[] calculateSignatureFromSignedAttributes(AlgorithmID signatureAlgorithm, + AlgorithmID digestAlgorithm, PrivateKey privateKey, + byte[] signedAttributes) + throws SignatureException, InvalidKeyException, NoSuchAlgorithmException { + log.debug("calculateSignatureFromSignedAttributes: " + signatureAlgorithm + ", " + digestAlgorithm); + + + STALPrivateKey spk = (STALPrivateKey) privateKey; + + //Store signature information that is required to create a StalBulkSignatureRequest. + bulkSignatureInfo.add(new BulkSignatureInfo(privateKey, signatureAlgorithm, keyboxIdentifier, signedAttributes, + spk.getAlgorithm(), spk.getDigestAlgorithm(), hashDataInput, excludedByteRange)); + + //Size of placeholder doesn't matter + byte[] signaturePlaceholder = new byte[1]; + return signaturePlaceholder; + } + +public List<BulkSignatureInfo> getBulkSignatureInfo() { + return bulkSignatureInfo; +} + + + + + + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignature.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignature.java new file mode 100644 index 00000000..bf220034 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignature.java @@ -0,0 +1,116 @@ +/* + * Copyright 2015 Datentechnik Innovation GmbH and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + + + +package at.gv.egiz.bku.slcommands.impl.cms; + +import iaik.asn1.CodingException; +import iaik.cms.CMSException; +import iaik.cms.CMSSignatureException; +import iaik.cms.ContentInfo; +import iaik.cms.SecurityProvider; +import iaik.cms.SignedData; +import iaik.cms.SignerInfo; +import iaik.x509.X509ExtensionException; + +import java.io.IOException; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Date; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.CMSDataObjectOptionalMetaType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; +import at.gv.egiz.bku.slexceptions.SLCommandException; +import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; +import at.gv.egiz.stal.STAL; + +/** + * This class represents a CMS-Signature as to be created by the + * security layer command <code>BulkSignatureRequest</code>. + * + * @author szoescher + */ +public class BulkSignature extends Signature { + + public final static String ID_AA_ETS_MIMETYPE = "0.4.0.1733.2.1"; + + public BulkSignature(CMSDataObjectOptionalMetaType dataObject, String structure, + X509Certificate signingCertificate, Date signingTime, URLDereferencer urlDereferencer, + boolean useStrongHash) + throws NoSuchAlgorithmException, CertificateEncodingException, + CertificateException, X509ExtensionException, InvalidParameterException, + CodingException, SLCommandException, IOException, CMSException { + super(dataObject, structure, signingCertificate, signingTime, urlDereferencer, useStrongHash); + } + + /** + * Additionally to the <code>sign()<code> method from the supertype, + * contains a additional parameter to set a custom securityProvider. + * @param securityProvider The Security Provider that handles the sign request. + */ + public byte[] sign(SecurityProvider securityProvider, STAL stal, String keyboxIdentifier) throws CMSException, CMSSignatureException, SLCommandException { + signedData.setSecurityProvider(securityProvider); + try { + signedData.addSignerInfo(signerInfo); + } catch (NoSuchAlgorithmException e) { + throw new CMSSignatureException(e); + } + if (digestValue != null) { + try { + signedData.setMessageDigest(digestAlgorithm, digestValue); + } catch (NoSuchAlgorithmException e) { + throw new CMSSignatureException(e); + } + } + ContentInfo contentInfo = new ContentInfo(signedData); + return contentInfo.getEncoded(); + } + + + public ExcludedByteRangeType getExcludedByteRange() { + return excludedByteRange; + } + + public SignerInfo getSignerInfo() { + return signerInfo; + } + + public void setSignerInfo(SignerInfo signerInfo) { + this.signerInfo = signerInfo; + } + + + public SignedData getSignedData() { + return signedData; + } + + public byte[] getEncoded() throws CMSException{ + ContentInfo contentInfo = new ContentInfo(signedData); + return contentInfo.getEncoded(); + } + + +} + diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignatureInfo.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignatureInfo.java new file mode 100644 index 00000000..1d918f9f --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/BulkSignatureInfo.java @@ -0,0 +1,104 @@ +/* + * Copyright 2015 Datentechnik Innovation GmbH and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.bku.slcommands.impl.cms; + +import iaik.asn1.structures.AlgorithmID; + +import java.security.PrivateKey; +import java.util.List; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; +import at.gv.egiz.stal.HashDataInput; + + +/** + * + * @author szoescher + * + */ +public class BulkSignatureInfo { + + AlgorithmID signatureAlgorithm; + + String keyboxIdentifier; + + byte[] signedAttributes; + + String signatureMethod; + + String digestMethod; + + List<HashDataInput> hashDataInput; + + ExcludedByteRangeType excludedByteRange; + + PrivateKey privateKey; + + public BulkSignatureInfo(PrivateKey privateKey, AlgorithmID signatureAlgorithm, String keyboxIdentifier, + byte[] signedAttributes, String signatureMethod, String digestMethod, List<HashDataInput> hashDataInput, + ExcludedByteRangeType excludedByteRange) { + this.privateKey = privateKey; + this.signatureAlgorithm = signatureAlgorithm; + this.keyboxIdentifier = keyboxIdentifier; + this.signedAttributes = signedAttributes; + this.signatureMethod = signatureMethod; + this.digestMethod = digestMethod; + this.hashDataInput = hashDataInput; + this.excludedByteRange = excludedByteRange; + } + + public String getKeyboxIdentifier() { + return keyboxIdentifier; + } + + public byte[] getSignedAttributes() { + return signedAttributes; + } + + public String getSignatureMethod() { + return signatureMethod; + } + + public String getDigestMethod() { + return digestMethod; + } + + public List<HashDataInput> getHashDataInput() { + return hashDataInput; + } + + public ExcludedByteRangeType getExcludedByteRange() { + return excludedByteRange; + } + + public AlgorithmID getSignatureAlgorithm() { + return signatureAlgorithm; + } + + public PrivateKey getPrivateKey() { + return privateKey; + } + + + + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/CMSHashDataInput.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/CMSHashDataInput.java index e51c5823..25162dc4 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/CMSHashDataInput.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/CMSHashDataInput.java @@ -25,6 +25,7 @@ package at.gv.egiz.bku.slcommands.impl.cms; import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; import at.gv.egiz.bku.gui.viewer.MimeTypes; @@ -32,18 +33,33 @@ import at.gv.egiz.stal.HashDataInput; public class CMSHashDataInput implements HashDataInput { - private final static String DEFAULT_FILENAME = "SignatureData"; + public final static String DEFAULT_FILENAME = "SignatureData"; private byte[] data; - private String mimeType; + private byte[] digest; + protected String mimeType; + private String referenceId; + private String fileName; public CMSHashDataInput(byte[] data, String mimeType) { this.data = data; this.mimeType = mimeType; } + public CMSHashDataInput(byte[] data, String mimeType, byte[] digest) { + this.data = data; + this.mimeType = mimeType; + } + + public CMSHashDataInput() { + } + @Override public String getReferenceId() { + + if (referenceId != null) { + return referenceId; + } return CMS_DEF_REFERENCE_ID; } @@ -59,11 +75,38 @@ public class CMSHashDataInput implements HashDataInput { @Override public String getFilename() { + if (fileName != null) { + return fileName; + } + + if (mimeType != null) { return DEFAULT_FILENAME + MimeTypes.getExtension(mimeType); } + return DEFAULT_FILENAME; + } + @Override - public InputStream getHashDataInput() { + public InputStream getHashDataInput() throws IOException { return new ByteArrayInputStream(data); } + + @Override + public byte[] getDigest() { + return digest; + } + + + public void setFilename(String fileName) { + this.fileName = fileName; + } + + public void setDigest(byte[] digest) { + this.digest = digest; + } + + public void setReferenceId(String referenceId) { + this.referenceId = referenceId; + } + } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/ReferencedHashDataInput.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/ReferencedHashDataInput.java new file mode 100644 index 00000000..96e0e7de --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/ReferencedHashDataInput.java @@ -0,0 +1,81 @@ +/* + * Copyright 2015 Datentechnik Innovation GmbH and Prime Sign GmbH, Austria + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ + +package at.gv.egiz.bku.slcommands.impl.cms; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.ArrayUtils; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; +import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; + +public class ReferencedHashDataInput extends CMSHashDataInput { + + private String urlReference; + private URLDereferencer urlDereferencer; + private ExcludedByteRangeType excludedByteRange; + + public ReferencedHashDataInput(String mimeType, URLDereferencer urlDereferencer, String urlReference, ExcludedByteRangeType excludedByteRange) { + super(null, mimeType); + this.urlDereferencer = urlDereferencer; + this.urlReference = urlReference; + this.excludedByteRange = excludedByteRange; + } + + + public URLDereferencer getUrlDereferencer() { + return urlDereferencer; + } + + + public void setUrlDereferencer(URLDereferencer urlDereferencer) { + this.urlDereferencer = urlDereferencer; + } + + public InputStream getHashDataInput() throws IOException { + + InputStream hashDataInputStream = urlDereferencer.dereference(urlReference).getStream(); + + try { + byte[] content = IOUtils.toByteArray(hashDataInputStream); + + if (excludedByteRange != null) { + + int from = excludedByteRange.getFrom().intValue(); + int to = excludedByteRange.getTo().intValue(); + + byte[] signedContent = ArrayUtils.addAll(ArrayUtils.subarray(content, 0, from), ArrayUtils.subarray(content, to, content.length)); + + return new ByteArrayInputStream(signedContent); + + } else { + return new ByteArrayInputStream(content); + } + + } finally { + hashDataInputStream.close(); + } + } +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALSecurityProvider.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALSecurityProvider.java index 87c00644..1dd6cc9e 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALSecurityProvider.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALSecurityProvider.java @@ -69,8 +69,8 @@ public class STALSecurityProvider extends IaikProvider { private ExcludedByteRangeType excludedByteRange; private STALSignatureException stalSignatureException; - public STALSecurityProvider(STAL stal, String keyboxIdentifier, - HashDataInput hashDataInput, ExcludedByteRangeType excludedByteRange) { + public STALSecurityProvider(STAL stal, String keyboxIdentifier, HashDataInput hashDataInput, + ExcludedByteRangeType excludedByteRange) { this.keyboxIdentifier = keyboxIdentifier; this.stal = stal; this.hashDataInput = new ArrayList<HashDataInput>(); @@ -78,23 +78,27 @@ public class STALSecurityProvider extends IaikProvider { this.excludedByteRange = excludedByteRange; } - /* (non-Javadoc) - * @see iaik.cms.IaikProvider#calculateSignatureFromSignedAttributes(iaik.asn1.structures.AlgorithmID, iaik.asn1.structures.AlgorithmID, java.security.PrivateKey, byte[]) + /* + * (non-Javadoc) + * + * @see + * iaik.cms.IaikProvider#calculateSignatureFromSignedAttributes(iaik.asn1. + * structures.AlgorithmID, iaik.asn1.structures.AlgorithmID, + * java.security.PrivateKey, byte[]) */ @Override - public byte[] calculateSignatureFromSignedAttributes(AlgorithmID signatureAlgorithm, - AlgorithmID digestAlgorithm, PrivateKey privateKey, - byte[] signedAttributes) - throws SignatureException, InvalidKeyException, NoSuchAlgorithmException { + public byte[] calculateSignatureFromSignedAttributes(AlgorithmID signatureAlgorithm, AlgorithmID digestAlgorithm, + PrivateKey privateKey, byte[] signedAttributes) throws SignatureException, InvalidKeyException, + NoSuchAlgorithmException { + stalSignatureException = null; log.debug("calculateSignatureFromSignedAttributes: " + signatureAlgorithm + ", " + digestAlgorithm); STALPrivateKey spk = (STALPrivateKey) privateKey; - SignRequest signRequest = getSTALSignRequest(keyboxIdentifier, signedAttributes, - spk.getAlgorithm(), spk.getDigestAlgorithm(), hashDataInput, excludedByteRange); + SignRequest signRequest = getSTALSignRequest(keyboxIdentifier, signedAttributes, spk.getAlgorithm(), + spk.getDigestAlgorithm(), hashDataInput, excludedByteRange); log.debug("Sending STAL request ({})", privateKey.getAlgorithm()); - List<STALResponse> responses = - stal.handleRequest(Collections.singletonList((STALRequest) signRequest)); + List<STALResponse> responses = stal.handleRequest(Collections.singletonList((STALRequest) signRequest)); if (responses == null || responses.size() != 1) { throw new SignatureException("Failed to access STAL."); @@ -114,9 +118,9 @@ public class STALSecurityProvider extends IaikProvider { } } - private static SignRequest getSTALSignRequest(String keyboxIdentifier, - byte[] signedAttributes, String signatureMethod, String digestMethod, - List<HashDataInput> hashDataInput, ExcludedByteRangeType excludedByteRange) { + private static SignRequest getSTALSignRequest(String keyboxIdentifier, byte[] signedAttributes, + String signatureMethod, String digestMethod, List<HashDataInput> hashDataInput, + ExcludedByteRangeType excludedByteRange) { SignRequest signRequest = new SignRequest(); signRequest.setKeyIdentifier(keyboxIdentifier); log.debug("SignedAttributes: " + Util.toBase64String(signedAttributes)); @@ -147,8 +151,7 @@ public class STALSecurityProvider extends IaikProvider { sigS.addComponent(new INTEGER(new BigInteger(1, r))); sigS.addComponent(new INTEGER(new BigInteger(1, s))); return DerCoder.encode(sigS); - } - else + } else return sig; } diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/Signature.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/Signature.java index 7be546de..4a94ca7f 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/Signature.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/Signature.java @@ -24,48 +24,32 @@ package at.gv.egiz.bku.slcommands.impl.cms; -import iaik.asn1.ASN1Object; -import iaik.asn1.CodingException; -import iaik.asn1.ObjectID; -import iaik.asn1.SEQUENCE; -import iaik.asn1.UTF8String; -import iaik.asn1.structures.AlgorithmID; -import iaik.asn1.structures.Attribute; -import iaik.asn1.structures.ChoiceOfTime; -import iaik.cms.CMSException; -import iaik.cms.CMSSignatureException; -import iaik.cms.CertificateIdentifier; -import iaik.cms.ContentInfo; -import iaik.cms.IssuerAndSerialNumber; -import iaik.cms.SignedData; -import iaik.cms.SignerInfo; -import iaik.smime.ess.ESSCertID; -import iaik.smime.ess.ESSCertIDv2; -import iaik.x509.X509ExtensionException; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; import java.security.InvalidParameterException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; -import java.security.PublicKey; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.security.interfaces.ECPublicKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.ECParameterSpec; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.List; +import javax.xml.crypto.dsig.DigestMethod; + import org.apache.commons.lang.ArrayUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.w3._2000._09.xmldsig_.DigestMethodType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.CMSDataObjectOptionalMetaType; import at.buergerkarte.namespaces.securitylayer._1_2_3.CMSDataObjectRequiredMetaType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.DigestAndRefType; import at.buergerkarte.namespaces.securitylayer._1_2_3.ExcludedByteRangeType; import at.gv.egiz.bku.slcommands.impl.xsect.AlgorithmMethodFactory; import at.gv.egiz.bku.slcommands.impl.xsect.AlgorithmMethodFactoryImpl; @@ -74,6 +58,24 @@ import at.gv.egiz.bku.slexceptions.SLCommandException; import at.gv.egiz.bku.utils.urldereferencer.URLDereferencer; import at.gv.egiz.stal.HashDataInput; import at.gv.egiz.stal.STAL; +import iaik.asn1.ASN1Object; +import iaik.asn1.CodingException; +import iaik.asn1.ObjectID; +import iaik.asn1.SEQUENCE; +import iaik.asn1.UTF8String; +import iaik.asn1.structures.AlgorithmID; +import iaik.asn1.structures.Attribute; +import iaik.asn1.structures.ChoiceOfTime; +import iaik.cms.CMSException; +import iaik.cms.CMSSignatureException; +import iaik.cms.CertificateIdentifier; +import iaik.cms.ContentInfo; +import iaik.cms.IssuerAndSerialNumber; +import iaik.cms.SignedData; +import iaik.cms.SignerInfo; +import iaik.smime.ess.ESSCertID; +import iaik.smime.ess.ESSCertIDv2; +import iaik.x509.X509ExtensionException; /** * This class represents a CMS-Signature as to be created by the @@ -90,25 +92,51 @@ public class Signature { */ private final Logger log = LoggerFactory.getLogger(Signature.class); - private SignedData signedData; - private SignerInfo signerInfo; - private byte[] signedDocument; - private String mimeType; - private AlgorithmID signatureAlgorithm; - private AlgorithmID digestAlgorithm; - private String signatureAlgorithmURI; - private String digestAlgorithmURI; - private ExcludedByteRangeType excludedByteRange; + protected SignedData signedData; + protected SignerInfo signerInfo; + protected byte[] signedDocument; + protected String mimeType; + protected AlgorithmID signatureAlgorithm; + protected AlgorithmID digestAlgorithm; + protected byte[] digestValue; + protected String signatureAlgorithmURI; + protected String digestAlgorithmURI; + protected ExcludedByteRangeType excludedByteRange; + private HashDataInput hashDataInput; + - public Signature(CMSDataObjectRequiredMetaType dataObject, String structure, +public Signature(CMSDataObjectOptionalMetaType dataObject, String structure, X509Certificate signingCertificate, Date signingTime, URLDereferencer urlDereferencer, boolean useStrongHash) throws NoSuchAlgorithmException, CertificateEncodingException, CertificateException, X509ExtensionException, InvalidParameterException, - CodingException, SLCommandException, IOException { - byte[] dataToBeSigned = getContent(dataObject, urlDereferencer); + CodingException, SLCommandException, IOException, CMSException { int mode = structure.equalsIgnoreCase("enveloping") ? SignedData.IMPLICIT : SignedData.EXPLICIT; + if (dataObject.getContent() != null) { + byte[] dataToBeSigned = getContent(dataObject, urlDereferencer); this.signedData = new SignedData(dataToBeSigned, mode); + if (dataObject.getMetaInfo() != null) { + this.mimeType = dataObject.getMetaInfo().getMimeType(); + } + + hashDataInput = new CMSHashDataInput(signedDocument, mimeType); + + } else { + DigestAndRefType digestAndRef = dataObject.getDigestAndRef(); + DigestMethodType digestMethod = digestAndRef.getDigestMethod(); + + hashDataInput = new ReferencedHashDataInput(dataObject.getMetaInfo().getMimeType(), urlDereferencer, + digestAndRef.getReference(), dataObject.getExcludedByteRange()); + + try { + digestAlgorithm = getAlgorithmID(digestMethod.getAlgorithm()); + } catch (URISyntaxException e) { + //TODO: choose proper execption + throw new NoSuchAlgorithmException(e); + } + digestValue = digestAndRef.getDigestValue(); + this.signedData = new SignedData(ObjectID.pkcs7_data); + } setAlgorithmIDs(signingCertificate, useStrongHash); createSignerInfo(signingCertificate); setSignerCertificate(signingCertificate); @@ -208,7 +236,7 @@ public class Signature { attributes.add(signingTime); } - private byte[] getContent(CMSDataObjectRequiredMetaType dataObject, URLDereferencer urlDereferencer) + private byte[] getContent(CMSDataObjectOptionalMetaType dataObject, URLDereferencer urlDereferencer) throws InvalidParameterException, SLCommandException, IOException { byte[] data = dataObject.getContent().getBase64Content(); if (data == null) { @@ -252,63 +280,36 @@ public class Signature { } private void setAlgorithmIDs(X509Certificate signingCertificate, boolean useStrongHash) throws NoSuchAlgorithmException { - PublicKey publicKey = signingCertificate.getPublicKey(); - String algorithm = publicKey.getAlgorithm(); AlgorithmMethodFactory amf = new AlgorithmMethodFactoryImpl(signingCertificate, useStrongHash); signatureAlgorithmURI = amf.getSignatureAlgorithmURI(); + signatureAlgorithm = amf.getSignatureAlgorithmID(); + if (digestAlgorithm != null) { + if (AlgorithmID.sha1.equals(digestAlgorithm)) { + digestAlgorithmURI = DigestMethod.SHA1; + } else if (AlgorithmID.sha256.equals(digestAlgorithm)) { + digestAlgorithmURI = DigestMethod.SHA256; + } else if (AlgorithmID.sha512.equals(digestAlgorithm)) { + digestAlgorithmURI = DigestMethod.SHA512; + } else if (AlgorithmID.ripeMd160.equals(digestAlgorithm)) { + digestAlgorithmURI = DigestMethod.RIPEMD160; + } else { + throw new NoSuchAlgorithmException("Algorithm '" + digestAlgorithm + "' not supported."); + } + } else { digestAlgorithmURI = amf.getDigestAlgorithmURI(); - - if ("DSA".equals(algorithm)) { - signatureAlgorithm = AlgorithmID.dsaWithSHA1; - } else if ("RSA".equals(algorithm)) { - - int keyLength = 0; - if (publicKey instanceof RSAPublicKey) { - keyLength = ((RSAPublicKey) publicKey).getModulus().bitLength(); + digestAlgorithm = amf.getDigestAlgorithmID(); } - - if (useStrongHash && keyLength >= 2048) { - signatureAlgorithm = AlgorithmID.sha256WithRSAEncryption; - digestAlgorithm = AlgorithmID.sha256; -// } else if (useStrongHash) { // Cannot be used if not enabled in AlgorithmMethodFactoryImpl -// signatureAlgorithm = AlgorithmID.rsaSignatureWithRipemd160; -// digestAlgorithm = AlgorithmID.ripeMd160; - } else { - signatureAlgorithm = AlgorithmID.sha1WithRSAEncryption; - digestAlgorithm = AlgorithmID.sha1; } - } else if (("EC".equals(algorithm)) || ("ECDSA".equals(algorithm))) { - int fieldSize = 0; - if (publicKey instanceof ECPublicKey) { - ECParameterSpec params = ((ECPublicKey) publicKey).getParams(); - fieldSize = params.getCurve().getField().getFieldSize(); - } else { - throw new NoSuchAlgorithmException("Public key type not supported."); - } + public HashDataInput getHashDataInput() { - if (useStrongHash && fieldSize >= 512) { - signatureAlgorithm = AlgorithmID.ecdsa_With_SHA512; - digestAlgorithm = AlgorithmID.sha512; - } else if (useStrongHash && fieldSize >= 256) { - signatureAlgorithm = AlgorithmID.ecdsa_With_SHA256; - digestAlgorithm = AlgorithmID.sha256; - } else if (useStrongHash) { - signatureAlgorithm = AlgorithmID.ecdsa_plain_With_RIPEMD160; - digestAlgorithm = AlgorithmID.ripeMd160; + if (hashDataInput != null) { + return hashDataInput; } else { - signatureAlgorithm = AlgorithmID.ecdsa_With_SHA1; - digestAlgorithm = AlgorithmID.sha1; - } - } else { - throw new NoSuchAlgorithmException("Public key algorithm '" + algorithm - + "' not supported."); + return new CMSHashDataInput(signedDocument, mimeType); } } - private HashDataInput getHashDataInput() { - return new CMSHashDataInput(signedDocument, mimeType); - } public byte[] sign(STAL stal, String keyboxIdentifier) throws CMSException, CMSSignatureException, SLCommandException { STALSecurityProvider securityProvider = new STALSecurityProvider(stal, keyboxIdentifier, getHashDataInput(), this.excludedByteRange); @@ -322,7 +323,29 @@ public class Signature { } throw new CMSSignatureException(e); } + if (digestValue != null) { + try { + signedData.setMessageDigest(digestAlgorithm, digestValue); + } catch (NoSuchAlgorithmException e) { + throw new CMSSignatureException(e); + } + } ContentInfo contentInfo = new ContentInfo(signedData); return contentInfo.getEncoded(); } + + protected AlgorithmID getAlgorithmID(String uri) throws URISyntaxException { + String oid = null; + URI urn = new URI(uri); + String scheme = urn.getScheme(); + if ("URN".equalsIgnoreCase(scheme)) { + String schemeSpecificPart = urn.getSchemeSpecificPart().toLowerCase(); + if (schemeSpecificPart.startsWith("oid:")) { + oid = schemeSpecificPart.substring(4, schemeSpecificPart.length()); +} + } + return new AlgorithmID(new ObjectID(oid)); + } } + + diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java index d2484b56..1b801ec5 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactory.java @@ -32,6 +32,8 @@ import javax.xml.crypto.dsig.CanonicalizationMethod; import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.SignatureMethod;
+import iaik.asn1.structures.AlgorithmID;
+
/**
* A factory for creating {@link AlgorithmMethod}s.
*
@@ -87,4 +89,8 @@ public interface AlgorithmMethodFactory { public String getSignatureAlgorithmURI(); public String getDigestAlgorithmURI(); + + AlgorithmID getSignatureAlgorithmID(); + + AlgorithmID getDigestAlgorithmID(); }
diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java index 896552d8..c3fcd146 100644 --- a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/xsect/AlgorithmMethodFactoryImpl.java @@ -24,6 +24,7 @@ package at.gv.egiz.bku.slcommands.impl.xsect;
+import iaik.asn1.structures.AlgorithmID; import iaik.xml.crypto.XmldsigMore; import java.security.InvalidAlgorithmParameterException; @@ -55,11 +56,21 @@ public class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { private String signatureAlgorithmURI; /** + * The signature algorithm ID. + */ + private AlgorithmID signatureAlgorithmID; + + /** * the digest algorithm URI. */ private String digestAlgorithmURI = DigestMethod.SHA1;
/**
+ * The digest algorithm ID. + */ + private AlgorithmID digestAlgorithmID = AlgorithmID.sha1;
+
+ /**
* The algorithm parameters for the signature algorithm.
*/
private SignatureMethodParameterSpec signatureMethodParameterSpec;
@@ -82,6 +93,7 @@ public class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { if ("DSA".equals(algorithm)) {
signatureAlgorithmURI = SignatureMethod.DSA_SHA1;
+ signatureAlgorithmID = AlgorithmID.dsaWithSHA1;
} else if ("RSA".equals(algorithm)) { int keyLength = 0; @@ -91,12 +103,12 @@ public class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { if (useStrongHash && keyLength >= 2048) { signatureAlgorithmURI = XmldsigMore.SIGNATURE_RSA_SHA256; + signatureAlgorithmID = AlgorithmID.sha256WithRSAEncryption; digestAlgorithmURI = DigestMethod.SHA256; -// } else if (useStrongHash) { -// signatureAlgorithmURI = XmldsigMore.SIGNATURE_RSA_RIPEMD160_ERRATA; -// digestAlgorithmURI = DigestMethod.RIPEMD160; + digestAlgorithmID = AlgorithmID.sha256; } else { signatureAlgorithmURI = SignatureMethod.RSA_SHA1; + signatureAlgorithmID = AlgorithmID.sha1WithRSAEncryption; } } else if (("EC".equals(algorithm)) || ("ECDSA".equals(algorithm))) { @@ -111,15 +123,22 @@ public class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { if (useStrongHash && fieldSize >= 512) { signatureAlgorithmURI = XmldsigMore.SIGNATURE_ECDSA_SHA512; + signatureAlgorithmID = AlgorithmID.ecdsa_With_SHA512; digestAlgorithmURI = DigestMethod.SHA512; + digestAlgorithmID = AlgorithmID.sha512; } else if (useStrongHash && fieldSize >= 256) { signatureAlgorithmURI = XmldsigMore.SIGNATURE_ECDSA_SHA256; + signatureAlgorithmID = AlgorithmID.ecdsa_With_SHA256; digestAlgorithmURI = DigestMethod.SHA256; + digestAlgorithmID = AlgorithmID.sha256; } else if (useStrongHash) { signatureAlgorithmURI = XmldsigMore.SIGNATURE_ECDSA_RIPEMD160; + signatureAlgorithmID = AlgorithmID.ecdsa_plain_With_RIPEMD160; digestAlgorithmURI = DigestMethod.RIPEMD160; + digestAlgorithmID = AlgorithmID.ripeMd160; } else { signatureAlgorithmURI = XmldsigMore.SIGNATURE_ECDSA_SHA1; + signatureAlgorithmID = AlgorithmID.ecdsa_With_SHA1; } } else {
@@ -185,4 +204,14 @@ public class AlgorithmMethodFactoryImpl implements AlgorithmMethodFactory { return digestAlgorithmURI; }
+ @Override + public AlgorithmID getSignatureAlgorithmID() { + return signatureAlgorithmID; + } + + @Override + public AlgorithmID getDigestAlgorithmID() { + return digestAlgorithmID; + }
+
}
|