Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SecurityAPI PKCS7/CMS standard signature implementation #966

Merged
merged 2 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
<Compile Include="..\..\dotnetframework\GeneXusCryptography\AsymmetricUtils\AsymmetricEncryptionAlgorithm.cs" Link="AsymmetricUtils\AsymmetricEncryptionAlgorithm.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\AsymmetricUtils\AsymmetricEncryptionPadding.cs" Link="AsymmetricUtils\AsymmetricEncryptionPadding.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\AsymmetricUtils\AsymmetricSigningAlgorithm.cs" Link="AsymmetricUtils\AsymmetricSigningAlgorithm.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\AsymmetricUtils\SignatureStandardUtils.cs" Link="AsymmetricUtils\SignatureStandardUtils.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\AsymmetricUtils\SignatureStandardOptions.cs" Link="AsymmetricUtils\SignatureStandardOptions.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\Asymmetric\AsymmetricCipher.cs" Link="Asymmetric\AsymmetricCipher.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\Asymmetric\AsymmetricSigner.cs" Link="Asymmetric\AsymmetricSigner.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\Asymmetric\StandardSigner.cs" Link="Asymmetric\StandardSigner.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\ChecksumUtils\ChecksumAlgorithm.cs" Link="ChecksumUtils\ChecksumAlgorithm.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\ChecksumUtils\ChecksumInputType.cs" Link="ChecksumUtils\ChecksumInputType.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\ChecksumUtils\CRCParameters.cs" Link="ChecksumUtils\CRCParameters.cs" />
Expand All @@ -30,6 +33,7 @@
<Compile Include="..\..\dotnetframework\GeneXusCryptography\Commons\IPasswordDerivationObject.cs" Link="Commons\IPasswordDerivationObject.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\Commons\ISymmectricStreamCipherObject.cs" Link="Commons\ISymmectricStreamCipherObject.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\Commons\ISymmetricBlockCipherObject.cs" Link="Commons\ISymmetricBlockCipherObject.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\Commons\IStandardSignerObject.cs" Link="Commons\IStandardSignerObject.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\Config\CryptographyEncodingUtil.cs" Link="Config\CryptographyEncodingUtil.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\HashUtils\HashAlgorithm.cs" Link="HashUtils\HashAlgorithm.cs" />
<Compile Include="..\..\dotnetframework\GeneXusCryptography\Hash\Hashing.cs" Link="Hash\Hashing.cs" />
Expand All @@ -45,10 +49,6 @@
<Compile Include="..\..\dotnetframework\GeneXusCryptography\Symmetric\SymmetricStreamCipher.cs" Link="Symmetric\SymmetricStreamCipher.cs" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\SecurityAPICommonsNetCore\SecurityAPICommonsNetCore.csproj" />
</ItemGroup>
Expand All @@ -67,4 +67,8 @@
<Folder Include="Symmetric\" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="6.34.0" />
<PackageReference Include="Microsoft.IdentityModel.Logging" Version="6.34.0" />
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="6.34.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.34.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
<PackageReference Include="System.Security.Cryptography.Xml" Version="4.7.1" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Portable.BouncyCastle" Version="1.9.0" />
<PackageReference Include="BouncyCastle.Cryptography" Version="2.2.1" />
<PackageReference Include="System.Security.Cryptography.Cng" Version="4.7.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.0" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
using System;
using System.Collections.Generic;
using System.Security;
using GeneXusCryptography.AsymmetricUtils;
using GeneXusCryptography.Commons;
using Org.BouncyCastle.Cms;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities.Encoders;
using SecurityAPICommons.Commons;
using SecurityAPICommons.Config;
using SecurityAPICommons.Keys;
using SecurityAPICommons.Utils;
using Org.BouncyCastle.Utilities.Collections;


namespace GeneXusCryptography.Asymmetric
{
[SecuritySafeCritical]
public class StandardSigner : SecurityAPIObject, IStandardSignerObject
{

public StandardSigner() : base()
{

}

/******** EXTERNAL OBJECT PUBLIC METHODS - BEGIN ********/

[SecuritySafeCritical]
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.Message);
result = "";
}

return result;
}

[SecuritySafeCritical]

public bool 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;
}

bool result = false;
try
{
result = Verify_internal(Base64.Decode(signed), plainText_bytes, options.GetEncapsulated());
}
catch (Exception e)
{
error.setError("SS002", e.Message);
result = false;
}

return result;
}

/******** EXTERNAL OBJECT PUBLIC METHODS - END ********/

private string Sign_internal(byte[] input, PrivateKeyManager key, CertificateX509 cert, SignatureStandard signatureStandard, bool encapsulated)
{

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 = AsymmetricSigningAlgorithmUtils
.GetAsymmetricSigningAlgorithm(keyMan.getAlgorithm(), this.error);
string encryptAlg = AsymmetricSigningAlgorithmUtils.GetCMSSigningAlgortithm(asymmetricSigningAlgorithm, this.error);
if (this.HasError()) { return ""; }

Org.BouncyCastle.X509.X509Certificate cert2 = DotNetUtilities.FromX509Certificate(certificate.Cert);

CmsSignedDataGenerator generator = new CmsSignedDataGenerator();
string digest = asymmetricSigningAlgorithm == AsymmetricSigningAlgorithm.ECDSA ? CmsSignedGenerator.DigestSha1 : DigestCalculator(certificate);

generator.AddSigner(keyMan.getAsymmetricKeyParameter(), cert2, encryptAlg, digest);

List<Org.BouncyCastle.X509.X509Certificate> certList = new List<Org.BouncyCastle.X509.X509Certificate>();
certList.Add(cert2);

IStore<Org.BouncyCastle.X509.X509Certificate> certStore = CollectionUtilities.CreateStore(certList);

generator.AddCertificates(certStore);

CmsSignedData signedData = generator.Generate(new CmsProcessableByteArray(input), encapsulated);


return Base64.ToBase64String(signedData.GetEncoded());

}


private bool Verify_internal(byte[] cmsSignedData, byte[] data, bool encapsulated)
{
CmsSignedData cms = encapsulated ? new CmsSignedData(cmsSignedData) : new CmsSignedData(new CmsProcessableByteArray(data), cmsSignedData);

SignerInformationStore signers = cms.GetSignerInfos();

IStore<Org.BouncyCastle.X509.X509Certificate> certificates = cms.GetCertificates();
var signerInfos = signers.GetSigners();
foreach (SignerInformation signer in signerInfos)
{
var certCollection = certificates.EnumerateMatches(signer.SignerID);
var certEnum = certCollection.GetEnumerator();

certEnum.MoveNext();
Org.BouncyCastle.X509.X509Certificate cert = certEnum.Current;
var publicKey = cert.GetPublicKey();
bool res = false;

res = signer.Verify(publicKey);

if (!res)
{
return false;
}
}
return true;
}



private string DigestCalculator(CertificateX509 cert)
{
string value = cert.getPublicKeyHash();
switch (value)
{
case "SHA1":
return CmsSignedGenerator.DigestSha1;
case "SHA256":
return CmsSignedGenerator.DigestSha256;
case "SHA512":
return CmsSignedGenerator.DigestSha512;
default:
this.error.setError("SS003", "Unrecognizable certificate hash algorithm");
return "";
}

}

}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

using Org.BouncyCastle.Cms;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Signers;
using SecurityAPICommons.Commons;
Expand Down Expand Up @@ -97,6 +98,21 @@ public static ISigner GetSigner(AsymmetricSigningAlgorithm asymmetricSigningAlgo
return sig;
}

public static string GetCMSSigningAlgortithm(AsymmetricSigningAlgorithm asymmetricSigningAlgorithm, Error error)
{
if (error == null) return null;
switch (asymmetricSigningAlgorithm)
{
case AsymmetricSigningAlgorithm.RSA:
return CmsSignedDataGenerator.EncryptionRsa;
case AsymmetricSigningAlgorithm.ECDSA:
return CmsSignedDataGenerator.EncryptionECDsa;
default:
error.setError("AE008", "Not recogrnized AsymmetricSigningAlgorithm");
return "";
}
}

/// <summary>
/// Manage Enumerable enum
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using System.Security;
using SecurityAPICommons.Commons;
using SecurityAPICommons.Keys;

namespace GeneXusCryptography.AsymmetricUtils
{
[SecuritySafeCritical]
public class SignatureStandardOptions : SecurityAPIObject
{
private CertificateX509 certificate;
private PrivateKeyManager privateKey;

private SignatureStandard signatureStandard;

private bool encapsulated;

[SecuritySafeCritical]
public SignatureStandardOptions() : base()
{
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 bool SetSignatureStandard(String standard)
{
this.signatureStandard = SignatureStandardUtils.getSignatureStandard(standard, this.error);
return this.HasError() ? false : true;
}

public void SetEncapsulated(bool 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 bool GetEncapsulated() { return this.encapsulated; }
}
}
Loading
Loading