diff options
| author | tkellner <tkellner@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2013-11-28 13:23:09 +0000 | 
|---|---|---|
| committer | tkellner <tkellner@8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4> | 2013-11-28 13:23:09 +0000 | 
| commit | 624dc3a0b6ef39948b9e78841ef7f75f27fee8da (patch) | |
| tree | bc729d9f6e0f8604a4b48b375312886dccdcc223 | |
| parent | 4a4302351610a5bcc24cd0e296a40232228c1b5f (diff) | |
| download | mocca-624dc3a0b6ef39948b9e78841ef7f75f27fee8da.tar.gz mocca-624dc3a0b6ef39948b9e78841ef7f75f27fee8da.tar.bz2 mocca-624dc3a0b6ef39948b9e78841ef7f75f27fee8da.zip | |
Implement CreateCMSSignatureRequest
git-svn-id: https://joinup.ec.europa.eu/svn/mocca/trunk@1234 8a26b1a7-26f0-462f-b9ef-d0e30c41f5a4
13 files changed, 830 insertions, 1 deletions
| diff --git a/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml b/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml index f2953982..b75db261 100644 --- a/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml +++ b/BKULocal/src/main/webapp/WEB-INF/applicationContext.xml @@ -147,6 +147,14 @@  			value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" />  		<constructor-arg value="CreateXMLSignatureRequest" />  	</bean> +	<bean id="createCMSSignatureCommandFactory" +		class="at.gv.egiz.bku.slcommands.impl.CreateCMSSignatureCommandFactory" +		parent="abstractCommandFactory" /> +	<bean id="createCMSSignatureRequest" class="javax.xml.namespace.QName"> +		<constructor-arg +			value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" /> +		<constructor-arg value="CreateCMSSignatureRequest" /> +	</bean>  	<bean id="getStatusCommandFactory" class="at.gv.egiz.bku.slcommands.impl.GetStatusCommandFactory"  		parent="abstractCommandFactory" />  	<bean id="getStatusRequest" class="javax.xml.namespace.QName"> @@ -163,6 +171,7 @@  				<entry key-ref="infoboxReadRequest" value-ref="infoboxReadCommandFactory" />  				<entry key-ref="infoboxUpdateRequest" value-ref="infoboxUpdateCommandFactory" />  				<entry key-ref="createXMLSignatureRequest" value-ref="createXMLSignatureCommandFactory" /> +				<entry key-ref="createCMSSignatureRequest" value-ref="createCMSSignatureCommandFactory" />  				<entry key-ref="getStatusRequest" value-ref="getStatusCommandFactory" />  			</map>  		</property> @@ -215,4 +224,4 @@      <property name="bindingProcessorManager" ref="bindingProcessorManager" />    </bean> -</beans>
\ No newline at end of file +</beans> diff --git a/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml b/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml index 80932320..f85875c9 100644 --- a/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml +++ b/BKUOnline/src/main/webapp/WEB-INF/applicationContext.xml @@ -135,6 +135,14 @@  			value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" />  		<constructor-arg value="CreateXMLSignatureRequest" />  	</bean> +	<bean id="createCMSSignatureCommandFactory" +		class="at.gv.egiz.bku.slcommands.impl.CreateCMSSignatureCommandFactory" +		parent="abstractCommandFactory" /> +	<bean id="createCMSSignatureRequest" class="javax.xml.namespace.QName"> +		<constructor-arg +			value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" /> +		<constructor-arg value="CreateCMSSignatureRequest" /> +	</bean>  	<bean id="getStatusCommandFactory" class="at.gv.egiz.bku.slcommands.impl.GetStatusCommandFactory"  		parent="abstractCommandFactory" />  	<bean id="getStatusRequest" class="javax.xml.namespace.QName"> @@ -151,6 +159,7 @@  				<entry key-ref="infoboxReadRequest" value-ref="infoboxReadCommandFactory" />  				<entry key-ref="infoboxUpdateRequest" value-ref="infoboxUpdateCommandFactory" />  				<entry key-ref="createXMLSignatureRequest" value-ref="createXMLSignatureCommandFactory" /> +				<entry key-ref="createCMSSignatureRequest" value-ref="createCMSSignatureCommandFactory" />  				<entry key-ref="getStatusRequest" value-ref="getStatusCommandFactory" />  			</map>  		</property> diff --git a/bkucommon/pom.xml b/bkucommon/pom.xml index 96fe94f2..f6e0f0c6 100644 --- a/bkucommon/pom.xml +++ b/bkucommon/pom.xml @@ -91,6 +91,10 @@      </dependency>      <dependency>        <groupId>iaik</groupId> +      <artifactId>iaik_cms</artifactId> +    </dependency> +    <dependency> +      <groupId>iaik</groupId>        <artifactId>iaik_pki</artifactId>        <scope>compile</scope>      </dependency> diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureCommand.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureCommand.java new file mode 100644 index 00000000..a68c0125 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureCommand.java @@ -0,0 +1,34 @@ +/* + * Copyright 2013 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * 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 at.gv.egiz.bku.slexceptions.SLCommandException; +import at.gv.egiz.bku.slexceptions.SLRequestException; + +public interface CreateCMSSignatureCommand extends SLCommand { + +  public void prepareCMSSignature(SLCommandContext commandContext) throws SLCommandException, SLRequestException; + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureResult.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureResult.java new file mode 100644 index 00000000..8f215843 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/CreateCMSSignatureResult.java @@ -0,0 +1,33 @@ +/* + * Copyright 2013 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * 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 CreateCMSSignatureResult extends SLResult { + +  public Element getContent(); + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandFactory.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandFactory.java new file mode 100644 index 00000000..2a642f95 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandFactory.java @@ -0,0 +1,43 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * 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 CreateCMSSignatureCommandFactory extends AbstractSLCommandFactory { + +  @Override +  public SLCommand createSLCommand(JAXBElement<?> element) throws SLCommandException { +    CreateCMSSignatureCommandImpl command = new CreateCMSSignatureCommandImpl(); +    command.init(element); +    command.setConfiguration(configuration); +    return command; +  } +} 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 new file mode 100644 index 00000000..4825351b --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureCommandImpl.java @@ -0,0 +1,201 @@ +/* + * Copyright 2013 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * 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.cms.CMSException; + +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.Date; +import java.util.List; + +import org.apache.commons.configuration.Configuration; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.CreateCMSSignatureRequestType; +import at.gv.egiz.bku.conf.MoccaConfigurationFacade; +import at.gv.egiz.bku.slcommands.CreateCMSSignatureCommand; +import at.gv.egiz.bku.slcommands.SLCommandContext; +import at.gv.egiz.bku.slcommands.SLResult; +import at.gv.egiz.bku.slcommands.impl.cms.Signature; +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.InfoboxReadRequest; +import at.gv.egiz.stal.STALRequest; + +/** + * This class implements the security layer command + * <code>CreateCMSSignatureRequest</code>. + *  + * @author tkellner + */ +public class CreateCMSSignatureCommandImpl extends +    SLCommandImpl<CreateCMSSignatureRequestType> implements +    CreateCMSSignatureCommand { + +  /** +   * Logging facility. +   */ +  private final Logger log = LoggerFactory.getLogger(CreateCMSSignatureCommandImpl.class); + +  /** +   * The signing certificate. +   */ +  protected X509Certificate signingCertificate; + +  /** +   * The keybox identifier of the key used for signing. +   */ +  protected String keyboxIdentifier; + +  /** +   * The to-be signed signature. +   */ +  protected Signature signature; + +  /** +   * 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); +    } +} + +  public void setConfiguration(Configuration configuration) { +    configurationFacade.setConfiguration(configuration); +  } + +  @Override +  public void prepareCMSSignature(SLCommandContext commandContext) throws SLCommandException, +      SLRequestException { + +    CreateCMSSignatureRequestType request = getRequestValue(); + +    // DataObject, SigningCertificate, SigningTime +    Date signingTime = new Date(); +    try { +      signature = new Signature(request.getDataObject(), signingCertificate, +          signingTime, configurationFacade.getUseStrongHash()); +    } catch (Exception e) { +      log.error("Error creating CMS Signature.", e); +      throw new SLCommandException(4000); +    } +  } + +  /** +   * Gets the signing certificate from STAL. +   * @param commandContext TODO +   *  +   * @throws SLCommandException +   *           if getting the singing certificate fails +   */ +  private void getSigningCertificate(SLCommandContext commandContext) throws SLCommandException { + +    CreateCMSSignatureRequestType request = getRequestValue(); +    keyboxIdentifier = request.getKeyboxIdentifier(); + +    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); +    } +    signingCertificate = certificates.get(0); + +  } + +  /** +   * Signs the signature. +   * @param commandContext TODO +   * @return the CMS signature +   * @throws SLCommandException +   *           if signing the signature fails +   * @throws SLViewerException +   */ +  private byte[] signCMSSignature(SLCommandContext commandContext) throws SLCommandException, SLViewerException { + +    try { +      return signature.sign(commandContext.getSTAL(), keyboxIdentifier); +    } catch (CMSException e) { +      log.error("Error creating CMSSignature", e); +      throw new SLCommandException(4000); +    } +  } + +  @Override +  public SLResult execute(SLCommandContext commandContext) { +    try { + +      // get certificate in order to select appropriate algorithms for hashing +      // and signing +      log.info("Requesting signing certificate."); +      getSigningCertificate(commandContext); +      if (log.isDebugEnabled()) { +        log.debug("Got signing certificate. {}", signingCertificate); +      } else { +        log.info("Got signing certificate."); +      } + +      // prepare the CMSSignature for signing +      log.info("Preparing CMS signature."); +      prepareCMSSignature(commandContext); + +      // sign the CMSSignature +      log.info("Signing CMS signature."); +      byte[] sig = signCMSSignature(commandContext); +      log.info("CMS signature signed."); + +      return new CreateCMSSignatureResultImpl(sig); + +    } catch (SLException e) { +      return new ErrorResultImpl(e, commandContext.getLocale()); +    } +  } + +  @Override +  public String getName() { +    return "CreateCMSSignatureRequest"; +  } + +} diff --git a/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureResultImpl.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureResultImpl.java new file mode 100644 index 00000000..66b24a82 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/CreateCMSSignatureResultImpl.java @@ -0,0 +1,117 @@ +/* + * Copyright 2011 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * 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 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.CreateCMSSignatureResponseType; +import at.buergerkarte.namespaces.securitylayer._1_2_3.ObjectFactory; +import at.gv.egiz.bku.slcommands.CreateCMSSignatureResult; +import at.gv.egiz.bku.slcommands.SLMarshallerFactory; +import at.gv.egiz.bku.slexceptions.SLRuntimeException; + +/** + * This implements the result of the security layer command <code>CreateCMSSignature</code>. + *  + * @author tkellner + */ +public class CreateCMSSignatureResultImpl extends SLResultImpl implements CreateCMSSignatureResult { + +  /** +   * Logging facility. +   */ +  private final Logger log = LoggerFactory.getLogger(CreateCMSSignatureResultImpl.class); + +  /** +   * The CMSSignature data. +   */ +  protected byte[] signature; + +  /** +   * The CMSSignatureResponse. +   */ +  private Element content; + +  /** +   * Creates a new instance of this CreateCMSSignatureResultImpl with the given +   * signature <code>signature</code>. +   *  +   * @param document the signature document +   *  +   * @throws NullPointerException if <code>document</code> is <code>null</code> +   */ +  public CreateCMSSignatureResultImpl(byte[] signature) { +    super(); + +    if (signature == null) +      throw new NullPointerException("Argument 'signature' must not be null."); +    this.signature = signature; + +    marshallCreateCMSSignatureResponse(); +  } + +  /** +   * Marshalls the <code>CreateCMSSignatureResponse</code>. +   */ +  private void marshallCreateCMSSignatureResponse() { + +    ObjectFactory factory = new ObjectFactory(); + +    CreateCMSSignatureResponseType createCreateCMSSignatureResponseType = factory.createCreateCMSSignatureResponseType(); +    createCreateCMSSignatureResponseType.setCMSSignature(signature); +    JAXBElement<CreateCMSSignatureResponseType> createCreateCMSSignatureResponse = factory.createCreateCMSSignatureResponse(createCreateCMSSignatureResponseType); + +    DOMResult res = new DOMResult(); + +    Marshaller marshaller = SLMarshallerFactory.getInstance().createMarshaller(false); +    try { +      marshaller.marshal(createCreateCMSSignatureResponse, res); +    } catch (JAXBException e) { +      log.error("Failed to marshall 'CreateCMSSignatureResponse'.", 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/cms/STALPrivateKey.java b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALPrivateKey.java new file mode 100644 index 00000000..8da52227 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALPrivateKey.java @@ -0,0 +1,34 @@ +package at.gv.egiz.bku.slcommands.impl.cms; + +import java.security.PrivateKey; + +/** + * Dummy PrivateKey implementation for CMS signing using STAL + * @author tkellner + */ +public class STALPrivateKey implements PrivateKey { + +  private static final long serialVersionUID = 1L; + +  private String algorithm; + +  public STALPrivateKey(String algorithm) { +    this.algorithm = algorithm; +  } + +  @Override +  public String getAlgorithm() { +    return algorithm; +  } + +  @Override +  public byte[] getEncoded() { +    throw new UnsupportedOperationException("STALPrivateKey does not support the getEncoded() method."); +  } + +  @Override +  public String getFormat() { +    return null; +  } + +} 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 new file mode 100644 index 00000000..437d29ef --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/STALSecurityProvider.java @@ -0,0 +1,76 @@ +package at.gv.egiz.bku.slcommands.impl.cms; + +import iaik.asn1.structures.AlgorithmID; +import iaik.cms.IaikProvider; +import iaik.utils.Util; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.SignatureException; +import java.util.Collections; +import java.util.List; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.bku.slcommands.impl.xsect.STALSignatureException; +import at.gv.egiz.stal.ErrorResponse; +import at.gv.egiz.stal.STAL; +import at.gv.egiz.stal.STALRequest; +import at.gv.egiz.stal.STALResponse; +import at.gv.egiz.stal.SignRequest; +import at.gv.egiz.stal.SignResponse; + +public class STALSecurityProvider extends IaikProvider { + +  private final Logger log = LoggerFactory.getLogger(STALSecurityProvider.class); + +  private String keyboxIdentifier; + +  private STAL stal; + +  public STALSecurityProvider(STAL stal, String keyboxIdentifier) { +    this.keyboxIdentifier = keyboxIdentifier; +    this.stal = stal; +  } + +  /* (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); + +    SignRequest signRequest = new SignRequest(); +    signRequest.setKeyIdentifier(keyboxIdentifier); +    log.debug("SignedAttributes: " + Util.toBase64String(signedAttributes)); +    signRequest.setSignedInfo(signedAttributes); +    signRequest.setSignedInfoIsRawData(true); +    signRequest.setSignatureMethod(privateKey.getAlgorithm()); + +    log.debug("Sending STAL request"); +    List<STALResponse> responses = +      stal.handleRequest(Collections.singletonList((STALRequest) signRequest)); + +    if (responses == null || responses.size() != 1) { +      throw new SignatureException("Failed to access STAL."); +    } + +    STALResponse response = responses.get(0); +    if (response instanceof SignResponse) { +      log.debug("Got STAL response: " + Util.toBase64String(((SignResponse) response).getSignatureValue())); +      return ((SignResponse) response).getSignatureValue(); +    } else if (response instanceof ErrorResponse) { +      ErrorResponse err = (ErrorResponse) response; +      STALSignatureException se = new STALSignatureException(err.getErrorCode(), err.getErrorMessage()); +      throw new SignatureException(se); +    } else { +      throw new SignatureException("Failed to access STAL."); +    } +  } + +} 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 new file mode 100644 index 00000000..9f97e363 --- /dev/null +++ b/bkucommon/src/main/java/at/gv/egiz/bku/slcommands/impl/cms/Signature.java @@ -0,0 +1,255 @@ +/* + * Copyright 2013 by Graz University of Technology, Austria + * MOCCA has been developed by the E-Government Innovation Center EGIZ, a joint + * initiative of the Federal Chancellery Austria and Graz University of Technology. + * + * 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.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.CertificateIdentifier; +import iaik.cms.ContentInfo; +import iaik.cms.IssuerAndSerialNumber; +import iaik.cms.SignedData; +import iaik.cms.SignerInfo; +import iaik.security.ecc.interfaces.ECDSAParams; +import iaik.smime.ess.ESSCertID; +import iaik.smime.ess.ESSCertIDv2; +import iaik.x509.X509ExtensionException; + +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 org.apache.commons.lang.ArrayUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.buergerkarte.namespaces.securitylayer._1_2_3.CMSDataObjectRequiredMetaType; +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; +import at.gv.egiz.stal.STAL; + +/** + * This class represents a CMS-Signature as to be created by the + * security layer command <code>CreateCMSSignatureRequest</code>. + *  + * @author tkellner + */ +public class Signature { +  /** +   * Logging facility. +   */ +  private final Logger log = LoggerFactory.getLogger(Signature.class); + +  private SignedData signedData; +  private SignerInfo signerInfo; +  private AlgorithmID signatureAlgorithm; +  private AlgorithmID digestAlgorithm; +  private String signatureAlgorithmURI; +  @SuppressWarnings("unused") +  private String digestAlgorithmURI; + +  public Signature(CMSDataObjectRequiredMetaType dataObject, +      X509Certificate signingCertificate, Date signingTime, boolean useStrongHash) throws NoSuchAlgorithmException, CertificateEncodingException, CertificateException, X509ExtensionException, InvalidParameterException, CodingException { +    byte[] data = getContent(dataObject); +    this.signedData = new SignedData(data, SignedData.EXPLICIT); +    setAlgorithmIDs(signingCertificate, useStrongHash); +    createSignerInfo(signingCertificate); +    setSignerCertificate(signingCertificate); +    setAttributes(dataObject.getMetaInfo().getMimeType(), signingCertificate, signingTime); +  } + +  private void createSignerInfo(X509Certificate signingCertificate) throws CertificateEncodingException, CertificateException { +    iaik.x509.X509Certificate sigcert = +        new iaik.x509.X509Certificate(signingCertificate.getEncoded()); +    CertificateIdentifier signerIdentifier = +        new IssuerAndSerialNumber(sigcert); +    PrivateKey privateKey = new STALPrivateKey(signatureAlgorithmURI); +    signerInfo = new SignerInfo(signerIdentifier, digestAlgorithm, +        signatureAlgorithm, privateKey); +  } + +  private void setSignerCertificate(X509Certificate signingCertificate) { +    X509Certificate[] sigcerts = new X509Certificate[] { signingCertificate }; +    signedData.addCertificates(sigcerts); +  } + +  private void setAttributes(String mimeType, X509Certificate signingCertificate, Date signingTime) throws CertificateException, NoSuchAlgorithmException, CodingException { +    List<Attribute> attributes = new ArrayList<Attribute>(); +    setMimeTypeAttrib(attributes, mimeType); +    setContentTypeAttrib(attributes); +    setSigningCertificateAttrib(attributes, signingCertificate); +    setSigningTimeAttrib(attributes, signingTime); +    Attribute[] attributeArray = attributes.toArray(new Attribute[attributes.size()]); +    signerInfo.setSignedAttributes(attributeArray); +  } + +  private void setMimeTypeAttrib(List<Attribute> attributes, String mimeType) { +    String oidStr = "0.4.0.1733.2.1"; +    String name = "mime-type"; +    ObjectID mimeTypeOID = new ObjectID(oidStr, name); + +    Attribute mimeTypeAtt = new Attribute(mimeTypeOID, new ASN1Object[] {new UTF8String(mimeType)}); +    attributes.add(mimeTypeAtt); +  } + +  private void setContentTypeAttrib(List<Attribute> attributes) { +    Attribute contentType = new Attribute(ObjectID.contentType, new ASN1Object[] {ObjectID.cms_data}); +    attributes.add(contentType); +  } + +  private void setSigningCertificateAttrib(List<Attribute> attributes, X509Certificate signingCertificate) throws CertificateException, NoSuchAlgorithmException, CodingException { +    ObjectID id; +    ASN1Object value = new SEQUENCE(); +    if (digestAlgorithm.equals(AlgorithmID.sha1)) { +      id = ObjectID.signingCertificate; +      value.addComponent(new ESSCertID(signingCertificate, true).toASN1Object()); +    } +    else { +      id = ObjectID.signingCertificateV2; +      value.addComponent(new ESSCertIDv2(digestAlgorithm, signingCertificate, true).toASN1Object()); +    } +    ASN1Object signingCert = new SEQUENCE(); +    signingCert.addComponent(value); +    Attribute signingCertificateAttrib = new Attribute(id, new ASN1Object[] {signingCert}); +    attributes.add(signingCertificateAttrib); +  } + +  private void setSigningTimeAttrib(List<Attribute> attributes, Date date) { +    Attribute signingTime = new Attribute(ObjectID.signingTime, new ASN1Object[] {new ChoiceOfTime(date).toASN1Object()}); +    attributes.add(signingTime); +  } + +  private byte[] getContent(CMSDataObjectRequiredMetaType dataObject) throws InvalidParameterException { +    byte[] data = dataObject.getContent().getBase64Content(); +    ExcludedByteRangeType ebr = dataObject.getExcludedByteRange(); +    if (ebr == null) +      return data; + +    int from = dataObject.getExcludedByteRange().getFrom().intValue(); +    int to = dataObject.getExcludedByteRange().getTo().intValue(); +    if (from > data.length || to > data.length || from > to) +      throw new InvalidParameterException("ExcludeByteRange contains invalid data: [" + +      from + "-" + to + "], Content length: " + data.length); +    byte[] first = null; +    byte[] second = null; +    if (from > 0) +      first = Arrays.copyOfRange(data, 0, from); +    if ((to + 1) < data.length) +      second = Arrays.copyOfRange(data, to + 1, data.length); +    data = ArrayUtils.addAll(first, second); +    log.debug("ExcludeByteRange [" + from + "-" + to + "], Content length: " + data.length); +    return data; +  } + +  private void setSignerInfo() { +    try { +      signedData.addSignerInfo(signerInfo); +    } catch (NoSuchAlgorithmException e) { +      log.error("Error setting signer info", e); +    } +  } + +  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(); +    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(); +      } + +      if (useStrongHash && keyLength >= 2048) { +        signatureAlgorithm = AlgorithmID.sha256WithRSAEncryption; +        digestAlgorithm = AlgorithmID.sha256; +      } else if (useStrongHash) { +        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 iaik.security.ecc.ecdsa.ECPublicKey) { +        ECDSAParams params = ((iaik.security.ecc.ecdsa.ECPublicKey) publicKey).getParameter(); +        fieldSize = params.getG().getCurve().getField().getSize().bitLength(); +      } else if (publicKey instanceof ECPublicKey) { +        ECParameterSpec params = ((ECPublicKey) publicKey).getParams(); +        fieldSize = params.getCurve().getField().getFieldSize(); +      } +       +      if (useStrongHash && fieldSize >= 512) { +        signatureAlgorithm = AlgorithmID.ecdsa_plain_With_SHA512; +        digestAlgorithm = AlgorithmID.sha512; +      } else if (useStrongHash && fieldSize >= 256) { +        signatureAlgorithm = AlgorithmID.ecdsa_plain_With_SHA256; +        digestAlgorithm = AlgorithmID.sha256; +      } else if (useStrongHash) { +          signatureAlgorithm = AlgorithmID.ecdsa_plain_With_RIPEMD160; +          digestAlgorithm = AlgorithmID.ripeMd160; +      } else { +        signatureAlgorithm = AlgorithmID.ecdsa_plain_With_SHA1; +        digestAlgorithm = AlgorithmID.sha1; +      } +    } else { +      throw new NoSuchAlgorithmException("Public key algorithm '" + algorithm +          + "' not supported."); +    } +  } + +  public byte[] sign(STAL stal, String keyboxIdentifier) throws CMSException { +    signedData.setSecurityProvider(new STALSecurityProvider(stal, keyboxIdentifier)); +    setSignerInfo(); +    ContentInfo contentInfo = new ContentInfo(signedData); +    return contentInfo.getEncoded(); +  } +} diff --git a/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/testApplicationContext.xml b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/testApplicationContext.xml index 3ec44394..7d7c967f 100644 --- a/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/testApplicationContext.xml +++ b/bkucommon/src/test/resources/at/gv/egiz/bku/slcommands/testApplicationContext.xml @@ -110,6 +110,14 @@        value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" />      <constructor-arg value="CreateXMLSignatureRequest" />    </bean> +  <bean id="createCMSSignatureCommandFactory" +    class="at.gv.egiz.bku.slcommands.impl.CreateCMSSignatureCommandFactory" +    parent="abstractCommandFactory" /> +  <bean id="createCMSSignatureRequest" class="javax.xml.namespace.QName"> +    <constructor-arg +      value="http://www.buergerkarte.at/namespaces/securitylayer/1.2#" /> +    <constructor-arg value="CreateCMSSignatureRequest" /> +  </bean>    <bean id="getStatusCommandFactory" class="at.gv.egiz.bku.slcommands.impl.GetStatusCommandFactory"      parent="abstractCommandFactory" />    <bean id="getStatusRequest" class="javax.xml.namespace.QName"> @@ -126,6 +134,7 @@          <entry key-ref="infoboxReadRequest" value-ref="infoboxReadCommandFactory" />          <entry key-ref="infoboxUpdateRequest" value-ref="infoboxUpdateCommandFactory" />          <entry key-ref="createXMLSignatureRequest" value-ref="createXMLSignatureCommandFactory" /> +        <entry key-ref="createCMSSignatureRequest" value-ref="createCMSSignatureCommandFactory" />          <entry key-ref="getStatusRequest" value-ref="getStatusCommandFactory" />        </map>      </property> @@ -335,6 +335,11 @@        </dependency>        <dependency>          <groupId>iaik</groupId> +        <artifactId>iaik_cms</artifactId> +        <version>4.1</version> +      </dependency> +      <dependency> +        <groupId>iaik</groupId>          <artifactId>iaik_pki</artifactId>          <version>1.0-MOCCA</version>          <scope>compile</scope> | 
