public static SignatureDetails ValidateSignature(Stream SignedData, Stream Signature) { if (SignedData == null) { throw new ArgumentNullException("SignedData"); } if (Signature == null) { throw new ArgumentNullException("Signature"); } //Make sure the SAPI Library is loaded SAPIInit(); SignatureDetails SigDetails = new SignatureDetails(); int rc; SAPICrypt SAPI = new SAPICrypt(); SESHandle hSession = new SESHandle(); if ((rc = SAPI.HandleAcquire(out hSession)) != 0) { throw new Exception(string.Format( "Memory allocation error (#{0})", rc.ToString("X"))); } //Extract Signer Data from the Signature stream //Read Signature content from stream to the SAPI bytes array Array baSignature = new byte[(int)Signature.Length]; Signature.Read((byte[])baSignature, 0, (int)Signature.Length); SAPIByteArray sSignature = new SAPIByteArray(); sSignature.FromArray(ref baSignature); //SAPIByteArray sSignedData = new SAPIByteArray(); //Array t1 = (Array)SignedData; sSignedData.FromArray(ref t1); object Certificate; // Extract the signer's certificate from signature SAPI_ENUM_DATA_TYPE SAPIType = SAPI_ENUM_DATA_TYPE.SAPI_ENUM_DATA_TYPE_NONE; if ((rc = SAPI.PKCS7BlobGetValue(hSession, sSignature, SAPI_ENUM_PKCS7_FIELD.SAPI_ENUM_PKCS7_FIELD_CERT, out Certificate, ref SAPIType)) != 0) { SAPI.HandleRelease(hSession); throw new Exception(string.Format( "An error occured while extracting the signer's certificate from the signature stream (#{0})", rc.ToString("X"))); } SigDetails.SignerCertificate = new X509Certificate2((byte[])(((SAPIByteArray)Certificate).ToArray())); SigDetails.SignerName = SigDetails.SignerCertificate.GetNameInfo(X509NameType.SimpleName, false); SigDetails.SignerEmail = SigDetails.SignerCertificate.GetNameInfo(X509NameType.EmailName, false); //Run the signature validation process SAPIContext ctxValidateSignature = new SAPIContext(); if ((rc = SAPI.BufferVerifySignatureInit(hSession, ctxValidateSignature, sSignature, 0)) != 0) { SAPI.HandleRelease(hSession); throw new Exception(string.Format( "An error occured while initializing the signature validation process (#{0})", rc.ToString("X"))); } int remaining = (int)SignedData.Length; int chunkMaxSize = 1 << 20; //1MB //Calculate first chunk size int chunkSize = remaining < chunkMaxSize ? remaining : chunkMaxSize; while (remaining > 0) { Array chunk = new byte[chunkSize]; //Read in chunks of 1MB int read = SignedData.Read((byte[])chunk, 0, chunkSize); if (read <= 0) { throw new EndOfStreamException(String.Format("End of stream reached with {0} bytes left to read", remaining)); } //Build SAPI-Compatible byte array SAPIByteArray tmpBuff = new SAPIByteArray(); tmpBuff.FromArray(ref chunk); //Add read buffer to the validation calculation if ((rc = SAPI.BufferVerifySignatureCont(hSession, ctxValidateSignature, tmpBuff)) != 0) { SAPI.ContextRelease(ctxValidateSignature); SAPI.HandleRelease(hSession); throw new Exception(string.Format( "An error occured while validating the digital signature (#{0})", rc.ToString("X"))); } remaining -= read; chunkSize = Math.Min(remaining, chunkSize); } //Get the final validation result SAPIFileTime signingTime = new SAPIFileTime(); rc = SAPI.BufferVerifySignatureEnd(hSession, ctxValidateSignature, signingTime, new CertStatus()); if ((uint)rc == 0x90030360) //SAPI_SIGNATURE_NOT_VALID { SigDetails.isValid = false; SigDetails.SignatureTimeTicks = 0; } else if (rc == 0) { SigDetails.isValid = true; //Convert FILE_TIME to ticks ulong filetime = signingTime.HighDateTime; filetime <<= 32; filetime += signingTime.LowDateTime; SigDetails.SignatureTimeTicks = DateTime.FromFileTimeUtc((long)filetime).Ticks; } else { SAPI.ContextRelease(ctxValidateSignature); SAPI.HandleRelease(hSession); throw new Exception(string.Format( "Failed to validate Digital Signature (#{0})", rc.ToString("X"))); } //Cleanup memory SAPI.ContextRelease(ctxValidateSignature); SAPI.HandleRelease(hSession); return(SigDetails); }