diff --git a/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/StandardSigner.java b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/StandardSigner.java new file mode 100644 index 0000000..4fb0304 --- /dev/null +++ b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/StandardSigner.java @@ -0,0 +1,176 @@ +package com.genexus.cryptography.asymmetric; + +import com.genexus.cryptography.asymmetric.utils.AsymmetricSigningAlgorithm; +import com.genexus.cryptography.asymmetric.utils.SignatureStandard; +import com.genexus.cryptography.asymmetric.utils.SignatureStandardOptions; +import com.genexus.cryptography.commons.StandardSignerObject; +import com.genexus.securityapicommons.config.EncodingUtil; +import com.genexus.securityapicommons.keys.CertificateX509; +import com.genexus.securityapicommons.keys.PrivateKeyManager; +import com.genexus.securityapicommons.utils.SecurityUtils; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaCertStore; +import org.bouncycastle.cms.*; +import org.bouncycastle.cms.jcajce.JcaSignerInfoGeneratorBuilder; +import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.DigestCalculatorProvider; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.bc.BcContentSignerBuilder; +import org.bouncycastle.operator.bc.BcDigestCalculatorProvider; +import org.bouncycastle.util.Store; +import org.bouncycastle.util.encoders.Base64; + +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +public class StandardSigner extends StandardSignerObject { + + public StandardSigner() { + super(); + } + + /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ + + public String sign(String plainText, SignatureStandardOptions options) + { + this.error.cleanError(); + + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateObjectInput("signatureStandardOptions", options, this.error); + SecurityUtils.validateObjectInput("private key", options.getPrivateKey(), this.error); + SecurityUtils.validateObjectInput("certificate", options.getCertificate(), this.error); + SecurityUtils.validateStringInput("plainText", plainText, this.error); + if (this.hasError()) { + return ""; + } + + /******* INPUT VERIFICATION - END *******/ + + EncodingUtil eu = new EncodingUtil(); + byte[] inputText = eu.getBytes(plainText); + if (eu.hasError()) { + this.error = eu.getError(); + return ""; + } + + String result = ""; + try { + result = sign_internal(inputText, options.getPrivateKey(), options.getCertificate(), options.getSignatureStandard(), options.getEncapsulated()); + } catch (Exception e) { + error.setError("SS002", e.getMessage()); + result = ""; + } + + return result; + } + + public boolean verify(String signed, String plainText, SignatureStandardOptions options) + { + this.error.cleanError(); + + /******* INPUT VERIFICATION - BEGIN *******/ + SecurityUtils.validateObjectInput("signatureStandardOptions", options, this.error); + //SecurityUtils.validateStringInput("plainText", plainText, this.error); + SecurityUtils.validateStringInput("signed", signed, this.error); + if (this.hasError()) { + return false; + } + + /******* INPUT VERIFICATION - END *******/ + + EncodingUtil eu = new EncodingUtil(); + byte[] plainText_bytes = eu.getBytes(plainText); + if (eu.hasError()) { + this.error = eu.getError(); + return false; + } + + boolean result = false; + try { + result = verify_internal(Base64.decode(signed), plainText_bytes, options.getEncapsulated()); + } catch (Exception e) { + error.setError("SS002", e.getMessage()); + result = false; + } + + return result; + } + + /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ + + private String sign_internal(byte[] input, PrivateKeyManager key, CertificateX509 cert, SignatureStandard signatureStandard, boolean encapsulated) throws OperatorCreationException, CertificateEncodingException, CMSException, IOException { + PrivateKeyManager keyMan = (PrivateKeyManager) key; + if (keyMan.hasError()) { + this.error = keyMan.getError(); + return ""; + } + CertificateX509 certificate = (CertificateX509) cert; + if (certificate.hasError()) { + this.error = certificate.getError(); + return ""; + } + AsymmetricSigningAlgorithm asymmetricSigningAlgorithm = AsymmetricSigningAlgorithm + .getAsymmetricSigningAlgorithm(keyMan.getAlgorithm(), this.error); + BcContentSignerBuilder bcContentSignerBuilder = AsymmetricSigningAlgorithm.getBcContentSignerBuilder(asymmetricSigningAlgorithm, certificate, this.error); + if (this.hasError()) + return ""; + + List certList = new ArrayList(); + certList.add(cert.Cert()); + Store certs = new JcaCertStore(certList); + + DigestCalculatorProvider digestCalculatorProvider = new BcDigestCalculatorProvider(); + JcaSignerInfoGeneratorBuilder signerInfoGeneratorBuilder = new JcaSignerInfoGeneratorBuilder(digestCalculatorProvider); + ContentSigner signer = bcContentSignerBuilder.build(keyMan.getAsymmetricKeyParameter()); + + CMSSignedDataGenerator gen = new CMSSignedDataGenerator(); + + gen.addSignerInfoGenerator(signerInfoGeneratorBuilder.build(signer, cert.Cert())); + + gen.addCertificates(certs); + + CMSTypedData msg = new CMSProcessableByteArray(input); + byte[] encoded = gen.generate(msg,encapsulated).getEncoded(); + return Base64.toBase64String(encoded); + } + + private boolean verify_internal(byte[] cmsSignedData, byte[] data, boolean encapsulated) + throws GeneralSecurityException, OperatorCreationException, CMSException, CertificateException { + + CMSSignedData signedData = encapsulated ? new CMSSignedData(cmsSignedData): new CMSSignedData(new CMSProcessableByteArray(data), cmsSignedData); + + Store certStore = signedData.getCertificates(); + SignerInformationStore signers = signedData.getSignerInfos(); + + Collection c = signers.getSigners(); + Iterator it = c.iterator(); + + while (it.hasNext()) + { + + SignerInformation signer = (SignerInformation)it.next(); + Collection certCollection = certStore.getMatches(signer.getSID()); + + Iterator certIt = certCollection.iterator(); + X509CertificateHolder cert1 = (X509CertificateHolder)certIt.next(); + + SignerInformationVerifier signerInformationVerifier = new JcaSimpleSignerInfoVerifierBuilder() + .build(cert1); + boolean verifies = signer.verify(signerInformationVerifier); + if(!verifies) + { + return false; + } + } + return true; + } + +} diff --git a/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/utils/AsymmetricSigningAlgorithm.java b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/utils/AsymmetricSigningAlgorithm.java index a4971e6..0b2cec6 100644 --- a/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/utils/AsymmetricSigningAlgorithm.java +++ b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/utils/AsymmetricSigningAlgorithm.java @@ -1,5 +1,6 @@ package com.genexus.cryptography.asymmetric.utils; +import org.bouncycastle.asn1.x509.AlgorithmIdentifier; import org.bouncycastle.crypto.Digest; import org.bouncycastle.crypto.Signer; import org.bouncycastle.crypto.signers.DSADigestSigner; @@ -7,6 +8,12 @@ import org.bouncycastle.crypto.signers.RSADigestSigner; import com.genexus.securityapicommons.commons.Error; +import com.genexus.securityapicommons.keys.CertificateX509; +import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder; +import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder; +import org.bouncycastle.operator.bc.BcContentSignerBuilder; +import org.bouncycastle.operator.bc.BcECContentSignerBuilder; +import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder; /** * @author sgrampone @@ -79,4 +86,24 @@ public static Signer getSigner(AsymmetricSigningAlgorithm asymmetricSigningAlgor } return sig; } + + public static BcContentSignerBuilder getBcContentSignerBuilder(AsymmetricSigningAlgorithm asymmetricSigningAlgorithm, CertificateX509 cert, Error error) + { + AlgorithmIdentifier signatureAlgorithm = new DefaultSignatureAlgorithmIdentifierFinder().find( + cert.Cert().getSigAlgName()); + AlgorithmIdentifier digestAlgorithm = new DefaultDigestAlgorithmIdentifierFinder().find(signatureAlgorithm); + + BcContentSignerBuilder sig = null; + switch (asymmetricSigningAlgorithm) { + case RSA: + sig = new BcRSAContentSignerBuilder(signatureAlgorithm, digestAlgorithm); + break; + case ECDSA: + sig = new BcECContentSignerBuilder(signatureAlgorithm, digestAlgorithm); + break; + default: + error.setError("AE007", "Unrecognized AsymmetricSigningAlgorithm"); + } + return sig; + } } diff --git a/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/utils/SignatureStandard.java b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/utils/SignatureStandard.java new file mode 100644 index 0000000..4489d6e --- /dev/null +++ b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/utils/SignatureStandard.java @@ -0,0 +1,25 @@ +package com.genexus.cryptography.asymmetric.utils; + +import com.genexus.securityapicommons.commons.Error; +public enum SignatureStandard { + CMS,; + public static SignatureStandard getSignatureStandard(String signatureStandard, + Error error) { + switch (signatureStandard.toUpperCase().trim()) { + case "CMS": + return SignatureStandard.CMS; + default: + error.setError("SS001", "Unrecognized SignatureStandard"); + return null; + } + } + public static String valueOf(SignatureStandard signatureStandard, Error error) { + switch (signatureStandard) { + case CMS: + return "CMS"; + default: + error.setError("SS002", "Unrecognized SignatureStandard"); + return ""; + } + } +} diff --git a/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/utils/SignatureStandardOptions.java b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/utils/SignatureStandardOptions.java new file mode 100644 index 0000000..8a6dba5 --- /dev/null +++ b/GeneXusCryptography/src/main/java/com/genexus/cryptography/asymmetric/utils/SignatureStandardOptions.java @@ -0,0 +1,49 @@ +package com.genexus.cryptography.asymmetric.utils; + +import com.genexus.securityapicommons.commons.SecurityAPIObject; +import com.genexus.securityapicommons.keys.CertificateX509; +import com.genexus.securityapicommons.keys.PrivateKeyManager; +public class SignatureStandardOptions extends SecurityAPIObject{ + + private CertificateX509 certificate; + private PrivateKeyManager privateKey; + + private SignatureStandard signatureStandard; + + private boolean encapsulated; + + + public SignatureStandardOptions() + { + this.signatureStandard = SignatureStandard.CMS; + this.encapsulated = false; + } + /******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/ + public void setPrivateKey(PrivateKeyManager key) { + this.privateKey = key; + } + + public void setCertificate(CertificateX509 cert) { + this.certificate = cert; + } + + public boolean setSignatureStandard(String standard) + { + this.signatureStandard = SignatureStandard.getSignatureStandard(standard, this.error); + return this.hasError() ? false: true; + } + + public void setEncapsulated(boolean value) {this.encapsulated = value; } + + /******** EXTERNAL OBJECT PUBLIC METHODS - END ********/ + + public PrivateKeyManager getPrivateKey() { + return this.privateKey; + } + + public CertificateX509 getCertificate() { return this.certificate;} + + public SignatureStandard getSignatureStandard() { return this.signatureStandard;} + + public boolean getEncapsulated() { return this.encapsulated; } +} diff --git a/GeneXusCryptography/src/main/java/com/genexus/cryptography/commons/StandardSignerObject.java b/GeneXusCryptography/src/main/java/com/genexus/cryptography/commons/StandardSignerObject.java new file mode 100644 index 0000000..e2f74c9 --- /dev/null +++ b/GeneXusCryptography/src/main/java/com/genexus/cryptography/commons/StandardSignerObject.java @@ -0,0 +1,15 @@ +package com.genexus.cryptography.commons; + +import com.genexus.cryptography.asymmetric.utils.SignatureStandardOptions; +import com.genexus.securityapicommons.commons.SecurityAPIObject; + +public abstract class StandardSignerObject extends SecurityAPIObject { + + public StandardSignerObject() + { + super(); + } + + public abstract String sign(String plainText, SignatureStandardOptions options); + public abstract boolean verify(String signed, String plainText, SignatureStandardOptions options); +}