/// <summary> /// Verifies that a digital signature is valid by determining the hash value in the signature using the specified hash algorithm and padding, and comparing it to the provided hash value /// </summary> /// <param name="hash">he hash value of the signed data</param> /// <param name="signature">The signature data to be verified</param> /// <param name="hashAlgorithm">The hash algorithm used to create the hash value</param> /// <param name="padding">The padding mode</param> /// <returns>True if the signature is valid, false otherwise</returns> public override bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { if (hash == null || hash.Length == 0) { throw new ArgumentNullException(nameof(hash)); } if (signature == null || signature.Length == 0) { throw new ArgumentNullException(nameof(signature)); } if (hashAlgorithm == null) { throw new ArgumentNullException(nameof(hashAlgorithm)); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } if (padding == RSASignaturePadding.Pkcs1) { byte[] pkcs1DigestInfo = CreatePkcs1DigestInfo(hash, hashAlgorithm); if (pkcs1DigestInfo == null) { throw new NotSupportedException(string.Format("Algorithm {0} is not supported", hashAlgorithm)); } using (Session session = _certContext.TokenContext.SlotContext.Slot.OpenSession(SessionType.ReadOnly)) using (var mechanism = new Mechanism(CKM.CKM_RSA_PKCS)) { session.Verify(mechanism, _certContext.PubKeyHandle, pkcs1DigestInfo, signature, out bool isValid); return(isValid); } } else if (padding == RSASignaturePadding.Pss) { CkRsaPkcsPssParams pssMechanismParams = CreateCkRsaPkcsPssParams(hash, hashAlgorithm); if (pssMechanismParams == null) { throw new NotSupportedException(string.Format("Algorithm {0} is not supported", hashAlgorithm.Name)); } using (Session session = _certContext.TokenContext.SlotContext.Slot.OpenSession(SessionType.ReadOnly)) using (var mechanism = new Mechanism(CKM.CKM_RSA_PKCS_PSS, pssMechanismParams)) { session.Verify(mechanism, _certContext.PubKeyHandle, hash, signature, out bool isValid); return(isValid); } } else { throw new NotSupportedException(string.Format("Padding {0} is not supported", padding)); } }
/// <summary> /// Generates PKCS#7 signature of specified data /// </summary> /// <param name="data">Data to be signed</param> /// <param name="detached">Flag indicating whether detached signature should be produced</param> /// <param name="signingCertificate">Signing certificate</param> /// <param name="certPath">Certification path for signing certificate</param> /// <returns>DER encoded PKCS#7 signature of specified data</returns> public byte[] GenerateSignature(byte[] data, bool detached, BCX509.X509Certificate signingCertificate, ICollection <BCX509.X509Certificate> certPath) { if (this._disposed) { throw new ObjectDisposedException(this.GetType().FullName); } string hashOid = HashAlgorithmUtils.GetHashOid(_hashAlgorihtm); IDigest hashGenerator = HashAlgorithmUtils.GetHashGenerator(_hashAlgorihtm); // Compute hash of input data byte[] dataHash = ComputeDigest(hashGenerator, data); // Construct SignerInfo.signedAttrs Asn1EncodableVector signedAttributesVector = new Asn1EncodableVector(); // Add PKCS#9 contentType signed attribute signedAttributesVector.Add( new Org.BouncyCastle.Asn1.Cms.Attribute( attrType: new DerObjectIdentifier(OID.PKCS9AtContentType), attrValues: new DerSet(new DerObjectIdentifier(OID.PKCS7IdData)))); // Add PKCS#9 messageDigest signed attribute signedAttributesVector.Add( new Org.BouncyCastle.Asn1.Cms.Attribute( attrType: new DerObjectIdentifier(OID.PKCS9AtMessageDigest), attrValues: new DerSet(new DerOctetString(dataHash)))); // Add PKCS#9 signingTime signed attribute signedAttributesVector.Add( new Org.BouncyCastle.Asn1.Cms.Attribute( attrType: new DerObjectIdentifier(OID.PKCS9AtSigningTime), attrValues: new DerSet(new Org.BouncyCastle.Asn1.Cms.Time(new DerUtcTime(DateTime.UtcNow))))); // Compute digest of SignerInfo.signedAttrs DerSet signedAttributes = new DerSet(signedAttributesVector); byte[] signedAttributesDigest = ComputeDigest(hashGenerator, signedAttributes.GetDerEncoded()); // Sign digest of SignerInfo.signedAttrs with private key stored on PKCS#11 compatible device Asn1OctetString digestSignature = null; AlgorithmIdentifier digestSignatureAlgorithm = null; if (_signatureScheme == SignatureScheme.RSASSA_PKCS1_v1_5) { // Construct DigestInfo byte[] digestInfo = CreateDigestInfo(signedAttributesDigest, hashOid); // Sign DigestInfo with CKM_RSA_PKCS mechanism byte[] signature = null; using (Session session = _slot.OpenSession(SessionType.ReadOnly)) using (Mechanism mechanism = new Mechanism(CKM.CKM_RSA_PKCS)) signature = session.Sign(mechanism, _privateKeyHandle, digestInfo); // Construct SignerInfo.signature digestSignature = new DerOctetString(signature); // Construct SignerInfo.signatureAlgorithm digestSignatureAlgorithm = new AlgorithmIdentifier( algorithm: new DerObjectIdentifier(OID.PKCS1RsaEncryption), parameters: DerNull.Instance ); } else if (_signatureScheme == SignatureScheme.RSASSA_PSS) { // Construct parameters for CKM_RSA_PKCS_PSS mechanism CkRsaPkcsPssParams pssMechanismParams = CreateCkRsaPkcsPssParams(_hashAlgorihtm); // Sign digest with CKM_RSA_PKCS_PSS mechanism byte[] signature = null; using (Session session = _slot.OpenSession(SessionType.ReadOnly)) using (Mechanism mechanism = new Mechanism(CKM.CKM_RSA_PKCS_PSS, pssMechanismParams)) signature = session.Sign(mechanism, _privateKeyHandle, signedAttributesDigest); // Construct SignerInfo.signature digestSignature = new DerOctetString(signature); // Construct SignerInfo.signatureAlgorithm digestSignatureAlgorithm = new AlgorithmIdentifier( algorithm: new DerObjectIdentifier(OID.PKCS1RsassaPss), parameters: new Org.BouncyCastle.Asn1.Pkcs.RsassaPssParameters( hashAlgorithm: new AlgorithmIdentifier( algorithm: new DerObjectIdentifier(hashOid), parameters: DerNull.Instance ), maskGenAlgorithm: new AlgorithmIdentifier( algorithm: new DerObjectIdentifier(OID.PKCS1Mgf1), parameters: new AlgorithmIdentifier( algorithm: new DerObjectIdentifier(hashOid), parameters: DerNull.Instance ) ), saltLength: new DerInteger(hashGenerator.GetDigestSize()), trailerField: new DerInteger(1) ) ); } else { throw new NotSupportedException("Unsupported signature scheme"); } // Construct SignerInfo SignerInfo signerInfo = new SignerInfo( sid: new SignerIdentifier(new IssuerAndSerialNumber(signingCertificate.IssuerDN, signingCertificate.SerialNumber)), digAlgorithm: new AlgorithmIdentifier( algorithm: new DerObjectIdentifier(hashOid), parameters: DerNull.Instance ), authenticatedAttributes: signedAttributes, digEncryptionAlgorithm: digestSignatureAlgorithm, encryptedDigest: digestSignature, unauthenticatedAttributes: null ); // Construct SignedData.digestAlgorithms Asn1EncodableVector digestAlgorithmsVector = new Asn1EncodableVector(); digestAlgorithmsVector.Add( new AlgorithmIdentifier( algorithm: new DerObjectIdentifier(hashOid), parameters: DerNull.Instance)); // Construct SignedData.encapContentInfo ContentInfo encapContentInfo = new ContentInfo( contentType: new DerObjectIdentifier(OID.PKCS7IdData), content: (detached) ? null : new DerOctetString(data)); // Construct SignedData.certificates Asn1EncodableVector certificatesVector = new Asn1EncodableVector(); foreach (BCX509.X509Certificate cert in certPath) { certificatesVector.Add(X509CertificateStructure.GetInstance(Asn1Object.FromByteArray(cert.GetEncoded()))); } // Construct SignedData.signerInfos Asn1EncodableVector signerInfosVector = new Asn1EncodableVector(); signerInfosVector.Add(signerInfo.ToAsn1Object()); // Construct SignedData SignedData signedData = new SignedData( digestAlgorithms: new DerSet(digestAlgorithmsVector), contentInfo: encapContentInfo, certificates: new BerSet(certificatesVector), crls: null, signerInfos: new DerSet(signerInfosVector)); // Construct top level ContentInfo ContentInfo contentInfo = new ContentInfo( contentType: new DerObjectIdentifier(OID.PKCS7IdSignedData), content: signedData); return(contentInfo.GetDerEncoded()); }
/// <summary> /// Computes the signature for the specified hash value by encrypting it with the private key using the specified padding /// </summary> /// <param name="hash">The hash value of the data to be signed</param> /// <param name="hashAlgorithm">The hash algorithm used to create the hash value of the data</param> /// <param name="padding">The padding</param> /// <returns>The RSA signature for the specified hash value</returns> public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { if (hash == null || hash.Length == 0) { throw new ArgumentNullException(nameof(hash)); } if (hashAlgorithm == null) { throw new ArgumentNullException(nameof(hashAlgorithm)); } if (padding == null) { throw new ArgumentNullException(nameof(padding)); } if (padding == RSASignaturePadding.Pkcs1) { byte[] pkcs1DigestInfo = CreatePkcs1DigestInfo(hash, hashAlgorithm); if (pkcs1DigestInfo == null) { throw new NotSupportedException(string.Format("Algorithm {0} is not supported", hashAlgorithm.Name)); } using (Session session = _certContext.TokenContext.SlotContext.Slot.OpenSession(SessionType.ReadOnly)) using (var mechanism = new Mechanism(CKM.CKM_RSA_PKCS)) { if (_certContext.KeyUsageRequiresLogin) { return(session.Sign(mechanism, _certContext.PrivKeyHandle, pkcs1DigestInfo, PinProviderUtils.GetKeyPin(_certContext))); } else { return(session.Sign(mechanism, _certContext.PrivKeyHandle, pkcs1DigestInfo)); } } } else if (padding == RSASignaturePadding.Pss) { CkRsaPkcsPssParams pssMechanismParams = CreateCkRsaPkcsPssParams(hash, hashAlgorithm); if (pssMechanismParams == null) { throw new NotSupportedException(string.Format("Algorithm {0} is not supported", hashAlgorithm.Name)); } using (Session session = _certContext.TokenContext.SlotContext.Slot.OpenSession(SessionType.ReadOnly)) using (var mechanism = new Mechanism(CKM.CKM_RSA_PKCS_PSS, pssMechanismParams)) { if (_certContext.KeyUsageRequiresLogin) { return(session.Sign(mechanism, _certContext.PrivKeyHandle, hash, PinProviderUtils.GetKeyPin(_certContext))); } else { return(session.Sign(mechanism, _certContext.PrivKeyHandle, hash)); } } } else { throw new NotSupportedException(string.Format("Padding {0} is not supported", padding)); } }
/// <summary> /// Creates parameters for CKM_RSA_PKCS_PSS mechanism /// </summary> /// <param name="hash">Hash value</param> /// <param name="hashAlgorithm">Hash algorithm</param> /// <returns>Parameters for CKM_RSA_PKCS_PSS mechanism or null</returns> private static CkRsaPkcsPssParams CreateCkRsaPkcsPssParams(byte[] hash, HashAlgorithmName hashAlgorithm) { if (hash == null || hash.Length == 0) { throw new ArgumentNullException(nameof(hash)); } CkRsaPkcsPssParams pssParams = null; if (hashAlgorithm == HashAlgorithmName.SHA1) { if (hash.Length != 20) { throw new ArgumentException("Invalid lenght of hash value"); } pssParams = new CkRsaPkcsPssParams( hashAlg: (ulong)CKM.CKM_SHA_1, mgf: (ulong)CKG.CKG_MGF1_SHA1, len: (ulong)hash.Length ); } else if (hashAlgorithm == HashAlgorithmName.SHA256) { if (hash.Length != 32) { throw new ArgumentException("Invalid lenght of hash value"); } pssParams = new CkRsaPkcsPssParams( hashAlg: (ulong)CKM.CKM_SHA256, mgf: (ulong)CKG.CKG_MGF1_SHA256, len: (ulong)hash.Length ); } else if (hashAlgorithm == HashAlgorithmName.SHA384) { if (hash.Length != 48) { throw new ArgumentException("Invalid lenght of hash value"); } pssParams = new CkRsaPkcsPssParams( hashAlg: (ulong)CKM.CKM_SHA384, mgf: (ulong)CKG.CKG_MGF1_SHA384, len: (ulong)hash.Length ); } else if (hashAlgorithm == HashAlgorithmName.SHA512) { if (hash.Length != 64) { throw new ArgumentException("Invalid lenght of hash value"); } pssParams = new CkRsaPkcsPssParams( hashAlg: (ulong)CKM.CKM_SHA512, mgf: (ulong)CKG.CKG_MGF1_SHA512, len: (ulong)hash.Length ); } return(pssParams); }