Exemplo n.º 1
0
        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);
        }