示例#1
0
        static public ValueGenerator Exponential(double mn, double mx, SignMode signMode = SignMode.Direct)
        {
            Debug.Assert(Math.Sign(mn) == Math.Sign(mx));
            Debug.Assert(Math.Abs(mn) < Math.Abs(mx));

            double ratio = Math.Log(mx / mn, 2.0);

            return((Random rnd, int count) =>
            {
                double[] values = new double[count];
                switch (signMode)
                {
                case SignMode.Direct:
                    for (int i = 0; i < count; i++)
                    {
                        values[i] = mn * Math.Pow(2.0, ratio * rnd.NextDouble());
                    }
                    break;

                case SignMode.Negate:
                    for (int i = 0; i < count; i++)
                    {
                        values[i] = -mn *Math.Pow(2.0, ratio *rnd.NextDouble());
                    }
                    break;

                case SignMode.Random:
                    for (int i = 0; i < count; i++)
                    {
                        values[i] = ((i & 2) - 1) * mn * Math.Pow(2.0, ratio * rnd.NextDouble());
                    }
                    break;
                }
                return values;
            });
        }
        public XElement ReceivePaymentNotification(string guid, XElement paymentNotification)
        {
            MFEPMessage <PaymentNotificationTransaction> deserializedResponse = new MFEPMessage <PaymentNotificationTransaction>();
            XElement serializedResponse = null;
            string   fileName           = Guid.NewGuid().ToString();

            try
            {
                MFEPMessage <PaymentNotificationTransaction> deserializedRequest = paymentNotification.FromXElement <MFEPMessage <PaymentNotificationTransaction> >();
                deserializedResponse.Header.TimeStamp    = DateTime.Now.ToString("s");
                deserializedResponse.Header.Guid         = guid;
                deserializedResponse.Header.TransmitInfo = new TransmitInfo()
                {
                    SenderCode   = deserializedRequest.Header.TransmitInfo.ReceiverCode,
                    ResponseType = ProcessesCodes.BLRPMTNTFRS
                };

                deserializedResponse.Header.Result = new Result();
                fileName = deserializedRequest.Body.Transactions[0].ServiceType.SrvsTypValue.ToString() + fileName;
                if (!IsTestReponse)
                {
                    // Verifying
                    if (EnableSecuity)
                    {
                        if (deserializedRequest == null || deserializedRequest.Footer.Security == null || deserializedRequest.Footer.Security.Signature == null || string.IsNullOrWhiteSpace(deserializedRequest.Footer.Security.Signature.Trim()))
                        {
                            Result result = new Result();
                            result.ErrorCode = (int)ServiceErrors.InvalidSignature;
                            result.ErrorDesc = ServiceErrors.InvalidSignature.ToString();
                            result.Severity  = Severity.Error;
                            deserializedResponse.Header.Result = result;
                            WriteToPhysicalPath(paymentNotification, FailedPMTNotiRequestPath, fileName); // Write to failed notifications
                            serializedResponse = deserializedResponse.ToXElement <MFEPMessage <PaymentNotificationTransaction> >();
                            WriteToPhysicalPath(serializedResponse, FailedPMTNotiResponsePath, fileName);
                            return(serializedResponse);
                        }
                        else
                        {
                            VerifyMode verifyMode = VerifyMode.WithFormat;
                            if (SecurityMode.Equals("WithOutFormat", StringComparison.CurrentCultureIgnoreCase))
                            {
                                verifyMode = VerifyMode.WithOutFormat;
                            }
                            Collection <string> xPath = new Collection <string> {
                                XPath
                            };
                            bool verifiedSuccessfully = CertificateManager.VerifyMessageSignature(paymentNotification, xPath, deserializedRequest.Footer.Security.Signature, BillerCertificateSerialNumber, verifyMode);
                            if (!verifiedSuccessfully)
                            {
                                Result result = new Result();
                                result.ErrorCode = (int)ServiceErrors.InvalidSignature;
                                result.ErrorDesc = ServiceErrors.InvalidSignature.ToString();
                                result.Severity  = Severity.Error;
                                deserializedResponse.Header.Result = result;
                                WriteToPhysicalPath(paymentNotification, FailedPMTNotiRequestPath, fileName); // Write to failed notifications
                                serializedResponse = deserializedResponse.ToXElement <MFEPMessage <PaymentNotificationTransaction> >();
                                WriteToPhysicalPath(serializedResponse, FailedPMTNotiResponsePath, fileName);
                                return(serializedResponse);
                            }
                        }
                    }

                    // Validation
                    // Validate  MFEP code
                    if (deserializedRequest.Header.TransmitInfo.SenderCode != MFEPCode)
                    {
                        Result result = new Result();
                        result.ErrorCode = (int)ServiceErrors.InvalidSenderCode;
                        result.ErrorDesc = ServiceErrors.InvalidSenderCode.ToString();
                        result.Severity  = Severity.Error;
                        deserializedResponse.Header.Result = result;
                        WriteToPhysicalPath(paymentNotification, FailedPMTNotiRequestPath, fileName); // Write to failed notifications
                        serializedResponse = deserializedResponse.ToXElement <MFEPMessage <PaymentNotificationTransaction> >();
                        WriteToPhysicalPath(serializedResponse, FailedPMTNotiResponsePath, fileName);
                        return(serializedResponse);
                    }

                    // Validate Biller code
                    if (deserializedRequest.Header.TransmitInfo.ReceiverCode != BillerCode)
                    {
                        Result result = new Result();
                        result.ErrorCode = (int)ServiceErrors.UnsuccessfulPaymentNotification;
                        result.ErrorDesc = ServiceErrors.UnsuccessfulPaymentNotification.ToString();
                        result.Severity  = Severity.Error;
                        deserializedResponse.Header.Result = result;
                        WriteToPhysicalPath(paymentNotification, FailedPMTNotiRequestPath, fileName); // Write to failed notifications
                        serializedResponse = deserializedResponse.ToXElement <MFEPMessage <PaymentNotificationTransaction> >();
                        WriteToPhysicalPath(serializedResponse, FailedPMTNotiResponsePath, fileName);
                        return(serializedResponse);
                    }
                    // if the serviceType is IndividualSecurity then insert it to database otherwise just write it ti physical directory
                    if (ServiceType.Equals(deserializedRequest.Body.Transactions[0].ServiceType.SrvsTypValue.ToString(), StringComparison.CurrentCultureIgnoreCase))
                    {
                        // Insert this payment
                        DAL dal = new DAL();
                        dal.InsertPaymentNotification(deserializedRequest.Body.Transactions[0].AccountInfo.BillingNumber);
                    }
                    PaymentNotificationTransaction transaction = new PaymentNotificationTransaction
                    {
                        Transactions = new Collection <PaymentNotificationEntity>()
                    };
                    foreach (PaymentNotificationEntity pne in deserializedRequest.Body.Transactions)
                    {
                        PaymentNotificationEntity notificationEntity = new PaymentNotificationEntity
                        {
                            JOEBPPSTrx  = pne.JOEBPPSTrx,
                            ProcessDate = pne.ProcessDate,
                            STMTDate    = pne.STMTDate,
                            Result      = new Result()
                        };
                        transaction.Transactions.Add(notificationEntity);
                    }
                    deserializedResponse.Body = transaction;
                    // Sign the response
                    if (EnableSecuity)
                    {
                        SignMode signMode = SignMode.WithFormat;
                        if (SecurityMode.Equals("WithOutFormat", StringComparison.CurrentCultureIgnoreCase))
                        {
                            signMode = SignMode.WithOutFormat;
                        }
                        Collection <string> xPath = new Collection <string> {
                            XPath
                        };
                        deserializedResponse.Footer = new MFEPFooter();

                        deserializedResponse.Footer.Security.Signature = CertificateManager.SignMessage(deserializedResponse.ToXElement <MFEPMessage <PaymentNotificationTransaction> >(), xPath, BillerCertificateSerialNumber, signMode);
                    }
                    else
                    {
                        deserializedResponse.Footer = new MFEPFooter();
                    }
                    WriteToPhysicalPath(paymentNotification, SuccessPMTNotiRequestPath, fileName); // Write to success notifications
                    serializedResponse = deserializedResponse.ToXElement <MFEPMessage <PaymentNotificationTransaction> >();
                    WriteToPhysicalPath(serializedResponse, SuccessPMTNotiResponsePath, fileName);
                    return(serializedResponse);
                }
                else
                {
                    return(GenerateAutoResponse(guid, deserializedRequest, guid));
                }
            }
            catch (Exception exception)
            {
                string ex = exception.Message + "\n" + exception.StackTrace;
                WriteException(ex, ExceptionPath);

                Result result = new Result();
                result.ErrorCode = (int)ServiceErrors.InternalError;
                result.ErrorDesc = ServiceErrors.InternalError.ToString();
                result.Severity  = Severity.Error;
                deserializedResponse.Header.Result = result;
                WriteToPhysicalPath(paymentNotification, FailedPMTNotiRequestPath, fileName); // Write to success notifications
                serializedResponse = deserializedResponse.ToXElement <MFEPMessage <PaymentNotificationTransaction> >();
                WriteToPhysicalPath(serializedResponse, FailedPMTNotiResponsePath, fileName);
                return(serializedResponse);
            }
        }
        public XElement BillPull(string guid, XElement billPullRequest)
        {
            MFEPMessage <BillsRecord> deserializedResponse = new MFEPMessage <BillsRecord>();
            XElement serializedResponse = null;
            string   fileGuid           = Guid.NewGuid().ToString();

            try
            {
                // Write the request to physical path
                WriteToPhysicalPath(billPullRequest, BillPullRequestPath, fileGuid);
                MFEPMessage <BillInquiryRequestEntity> deserializedRequest = billPullRequest.FromXElement <MFEPMessage <BillInquiryRequestEntity> >();

                deserializedResponse.Header.TimeStamp    = DateTime.Now.ToString("s");
                deserializedResponse.Header.Guid         = guid;
                deserializedResponse.Header.TransmitInfo = new TransmitInfo()
                {
                    SenderCode   = deserializedRequest.Header.TransmitInfo.ReceiverCode,
                    ResponseType = ProcessesCodes.BILPULRS
                };

                deserializedResponse.Header.Result = new Result();
                bool isTestReponse = IsTestReponse;
                if (!isTestReponse)
                {
                    // Verifying
                    if (EnableSecuity)
                    {
                        if (deserializedRequest == null || deserializedRequest.Footer.Security == null || deserializedRequest.Footer.Security.Signature == null || string.IsNullOrWhiteSpace(deserializedRequest.Footer.Security.Signature.Trim()))
                        {
                            Result result_1 = new Result();
                            result_1.ErrorCode = (int)ServiceErrors.InvalidSignature;
                            result_1.ErrorDesc = ServiceErrors.InvalidSignature.ToString();
                            result_1.Severity  = Severity.Error;
                            deserializedResponse.Header.Result = result_1;
                            serializedResponse = deserializedResponse.ToXElement <MFEPMessage <BillsRecord> >();
                            // Write the request to physical path
                            WriteToPhysicalPath(serializedResponse, BillPullResponsePath, fileGuid);

                            return(serializedResponse);
                        }
                        else
                        {
                            VerifyMode verifyMode = VerifyMode.WithFormat;
                            if (SecurityMode.Equals("WithOutFormat", StringComparison.CurrentCultureIgnoreCase))
                            {
                                verifyMode = VerifyMode.WithOutFormat;
                            }
                            Collection <string> xPath = new Collection <string> {
                                XPath
                            };
                            bool verifiedSuccessfully = CertificateManager.VerifyMessageSignature(deserializedRequest.ToXElement <MFEPMessage <BillInquiryRequestEntity> >(), xPath, deserializedRequest.Footer.Security.Signature, BillerCertificateSerialNumber, verifyMode);
                            if (!verifiedSuccessfully)
                            {
                                Result result_2 = new Result();
                                result_2.ErrorCode = (int)ServiceErrors.InvalidSignature;
                                result_2.ErrorDesc = ServiceErrors.InvalidSignature.ToString();
                                result_2.Severity  = Severity.Error;
                                deserializedResponse.Header.Result = result_2;
                                serializedResponse = deserializedResponse.ToXElement <MFEPMessage <BillsRecord> >();

                                WriteToPhysicalPath(serializedResponse, BillPullResponsePath, fileGuid);

                                return(serializedResponse);
                            }
                        }


                        if (deserializedRequest.Header.TransmitInfo.SenderCode != MFEPCode)
                        {
                            Result result_3 = new Result();
                            result_3.ErrorCode = (int)ServiceErrors.InvalidSenderCode;
                            result_3.ErrorDesc = ServiceErrors.InvalidSenderCode.ToString();
                            result_3.Severity  = Severity.Error;
                            deserializedResponse.Header.Result = result_3;
                            serializedResponse = deserializedResponse.ToXElement <MFEPMessage <BillsRecord> >();
                            // Write the request to physical path
                            WriteToPhysicalPath(serializedResponse, BillPullResponsePath, fileGuid);
                            return(serializedResponse);
                        }

                        // Validate Biller code
                        if (deserializedRequest.Header.TransmitInfo.ReceiverCode != BillerCode)
                        {
                            Result result_4 = new Result();
                            result_4.ErrorCode = (int)ServiceErrors.UnsuccessfulBillPullRequest;
                            result_4.ErrorDesc = ServiceErrors.UnsuccessfulBillPullRequest.ToString();
                            result_4.Severity  = Severity.Error;
                            deserializedResponse.Header.Result = result_4;
                            serializedResponse = deserializedResponse.ToXElement <MFEPMessage <BillsRecord> >();
                            // Write the request to physical path
                            WriteToPhysicalPath(serializedResponse, BillPullResponsePath, fileGuid);

                            return(serializedResponse);
                        }

                        // Validate Service Type
                        if (!ServiceType.Equals(deserializedRequest.Body.ServiceType, StringComparison.CurrentCultureIgnoreCase))
                        {
                            Result result_5 = new Result();
                            result_5.ErrorCode = (int)ServiceErrors.UnrecognizedServiceType;
                            result_5.ErrorDesc = ServiceErrors.UnrecognizedServiceType.ToString();
                            result_5.Severity  = Severity.Error;
                            deserializedResponse.Header.Result = result_5;
                            serializedResponse = deserializedResponse.ToXElement <MFEPMessage <BillsRecord> >();
                            // Write the request to physical path
                            WriteToPhysicalPath(serializedResponse, BillPullResponsePath, fileGuid);


                            return(serializedResponse);
                        }

                        // Get Bill and generate the response
                        DAL        dal        = new DAL();
                        BillRecord billRecord = dal.GetBillInfo(deserializedRequest.Body.AccountInfo.BillNumber, deserializedRequest.Body.AccountInfo.BillingNumber, deserializedRequest.Body.ServiceType);
                        if (billRecord != null)
                        {
                            billRecord.IssueDate      = billRecord.IssueDate.Value.AddMinutes(TimeDifference);
                            billRecord.DueDate        = billRecord.DueDate.Value.AddMinutes(TimeDifference);
                            deserializedResponse.Body = new BillsRecord()
                            {
                                RecCount = 1
                            };
                            deserializedResponse.Body.BillRecords.Add(billRecord);
                        }
                        else
                        {
                            deserializedResponse.Body = new BillsRecord()
                            {
                                RecCount = 0, BillRecords = null
                            };
                        }
                        // Sign the response
                        if (EnableSecuity)
                        {
                            SignMode signMode = SignMode.WithFormat;
                            if (SecurityMode.Equals("WithOutFormat", StringComparison.CurrentCultureIgnoreCase))
                            {
                                signMode = SignMode.WithOutFormat;
                            }
                            Collection <string> xPath = new Collection <string> {
                                XPath
                            };
                            deserializedResponse.Footer = new MFEPFooter();
                            deserializedResponse.Footer.Security.Signature = CertificateManager.SignMessage(deserializedResponse.ToXElement <MFEPMessage <BillsRecord> >(), xPath, BillerCertificateSerialNumber, signMode);
                        }
                        else
                        {
                            SignMode signMode = SignMode.WithFormat;
                            if (SecurityMode.Equals("WithOutFormat", StringComparison.CurrentCultureIgnoreCase))
                            {
                                signMode = SignMode.WithOutFormat;
                            }
                            Collection <string> xPath = new Collection <string> {
                                XPath
                            };
                            deserializedResponse.Footer = new MFEPFooter();
                            deserializedResponse.Footer.Security.Signature = CertificateManager.SignMessage(deserializedResponse.ToXElement <MFEPMessage <BillsRecord> >(), xPath, BillerCertificateSerialNumber, signMode);
                        }
                        serializedResponse = deserializedResponse.ToXElement <MFEPMessage <BillsRecord> >();
                        // Write the request to physical path
                        WriteToPhysicalPath(serializedResponse, BillPullResponsePath, fileGuid);


                        return(serializedResponse);
                    }



                    // Sign the response
                    return(GenerateAutoResponse(guid, billPullRequest));

                    /* serializedResponse = deserializedResponse.ToXElement<MFEPMessage<BillsRecord>>();
                     * // Write the request to physical path
                     * WriteToPhysicalPath(serializedResponse, BillPullResponsePath, fileGuid);
                     *
                     */
                    /*return serializedResponse;*/
                }
                else
                {
                    return(GenerateAutoResponse(guid, billPullRequest));
                }
            }
            catch (Exception exception)
            {
                string ex = exception.Message + "\n" + exception.StackTrace;
                WriteException(ex, ExceptionPath);
                Result result = new Result();
                result.ErrorCode = (int)ServiceErrors.InternalError;
                result.ErrorDesc = ServiceErrors.InternalError.ToString();
                result.Severity  = Severity.Error;
                deserializedResponse.Header.Result = result;
                return(deserializedResponse.ToXElement <MFEPMessage <BillsRecord> >());
            }
        }
示例#4
0
        private static SIGNER_SIGN_EX2_PARAMS GetSignerSignEx2ParametersPointer(string timestampUrl, SignMode type,
                                                                                IntPtr subjectInfo, IntPtr signerCertificate, IntPtr provider, out GCHandle?signerSignHandle, string timestampAlgorithmOid)
        {
            // signature info
            var signatureInfo = new SIGNER_SIGNATURE_INFO
            {
                cbSize            = (uint)Marshal.SizeOf <SIGNER_SIGNATURE_INFO>(),
                algidHash         = Constants.CALG_SHA_256,
                dwAttrChoice      = Constants.DONT_CARE,
                pAttrAuthCode     = IntPtr.Zero,
                psAuthenticated   = IntPtr.Zero,
                psUnauthenticated = IntPtr.Zero,
            };

            var signatureHandle = Marshal.AllocHGlobal(Marshal.SizeOf <SIGNER_SIGNATURE_INFO>());

            Marshal.StructureToPtr(signatureInfo, signatureHandle, false);

            // signer sign ex params
            var signerSignEx2Params = new SIGNER_SIGN_EX2_PARAMS
            {
                dwFlags        = Constants.DONT_CARE,
                pSubjectInfo   = subjectInfo,
                pSigningCert   = signerCertificate,
                pSignatureInfo = signatureHandle,
                pProviderInfo  = provider,
            };

            if (!string.IsNullOrEmpty(timestampUrl))
            {
                signerSignEx2Params.pwszTimestampURL = Marshal.StringToHGlobalUni(timestampUrl);
                if (string.IsNullOrEmpty(timestampAlgorithmOid))
                {
                    signerSignEx2Params.dwTimestampFlags = Constants.SIGNER_TIMESTAMP_AUTHENTICODE;
                }
                else
                {
                    signerSignEx2Params.dwTimestampFlags = Constants.SIGNER_TIMESTAMP_RFC3161;
                    signerSignEx2Params.pszAlgorithmOid  = Marshal.StringToHGlobalAnsi(timestampAlgorithmOid);
                }
            }

            signerSignHandle = null;
            if (type == SignMode.APPX)
            {
                var sipData = new APPX_SIP_CLIENT_DATA();
                signerSignHandle = GCHandle.Alloc(signerSignEx2Params, GCHandleType.Pinned);

                sipData.pSignerParams = signerSignHandle.Value.AddrOfPinnedObject();

                var sipHandle = Marshal.AllocHGlobal(Marshal.SizeOf <APPX_SIP_CLIENT_DATA>());
                Marshal.StructureToPtr(sipData, sipHandle, false);

                signerSignEx2Params.pSipData = sipHandle;
            }

            return(signerSignEx2Params);
        }
示例#5
0
        private static void SignFile(IntPtr certificate, string path, string timestampUrl, SignMode type, string containerName, string dllPath, Logger logger, string timestampAlgorithmOid)
        {
            logger.WriteLine("Beginning the signing process", true);
            var subjectInfo         = GetSubjectInfoPointer(path);
            var signerCertificate   = GetSignerCertificatePointer(certificate);
            var provider            = GetProviderPointer(containerName);
            var signerSignEx2Params = GetSignerSignEx2ParametersPointer(timestampUrl, type, subjectInfo, signerCertificate, provider, out var signerSignHandle, timestampAlgorithmOid);

            try
            {
                IntPtr signModule;
                if (string.IsNullOrEmpty(dllPath))
                {
                    logger.WriteLine("Loading MSSign32.dll from default path", true);
                    signModule = NativeMethods.LoadLibraryEx("MSSign32.dll", IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_SEARCH_SYSTEM32);
                }
                else
                {
                    logger.WriteLine($"Loading MSSign32.dll from specific path: {dllPath}", true);
                    signModule = NativeMethods.LoadLibraryEx(dllPath, IntPtr.Zero, LoadLibraryFlags.LOAD_WITH_ALTERED_SEARCH_PATH);
                }

                if (signModule == IntPtr.Zero)
                {
                    var errorResult = Marshal.GetHRForLastWin32Error();
                    throw new SigningException($"Win32 error in LoadLibraryEx: {errorResult}", Marshal.GetExceptionForHR(errorResult));
                }

                logger.WriteLine("Getting SignerSignEx2 pointer", true);
                var signerSignEx2Pointer = NativeMethods.GetProcAddress(signModule, "SignerSignEx2");

                if (signModule == IntPtr.Zero)
                {
                    var errorResult = Marshal.GetHRForLastWin32Error();
                    throw new SigningException($"Win32 error in GetProcAddress: {errorResult}", Marshal.GetExceptionForHR(errorResult));
                }

                NativeMethods.SignerSignEx2Delegate signerSignEx2;

                try
                {
                    logger.WriteLine("Marshalling SignerSignEx2 pointer to a delegate", true);
                    signerSignEx2 = Marshal.GetDelegateForFunctionPointer <NativeMethods.SignerSignEx2Delegate>(
                        signerSignEx2Pointer);
                }
                catch (Exception e)
                {
                    throw new SigningException("Error while marshalling SignerSignEx2 pointer to a managed delegate.", e);
                }

                logger.WriteLine("Invoking SignerSignEx2", true);
                var result = signerSignEx2(signerSignEx2Params.dwFlags, signerSignEx2Params.pSubjectInfo,
                                           signerSignEx2Params.pSigningCert,
                                           signerSignEx2Params.pSignatureInfo,
                                           signerSignEx2Params.pProviderInfo,
                                           signerSignEx2Params.dwTimestampFlags,
                                           signerSignEx2Params.pszAlgorithmOid,
                                           signerSignEx2Params.pwszTimestampURL,
                                           signerSignEx2Params.pCryptAttrs,
                                           signerSignEx2Params.pSipData,
                                           signerSignEx2Params.pSignerContext,
                                           signerSignEx2Params.pCryptoPolicy,
                                           signerSignEx2Params.pReserved);

                Marshal.FreeHGlobal(signerSignEx2Params.pwszTimestampURL);
                Marshal.FreeHGlobal(signerSignEx2Params.pszAlgorithmOid);
                if (type == SignMode.APPX)
                {
                    var sipData = Marshal.PtrToStructure <APPX_SIP_CLIENT_DATA>(signerSignEx2Params.pSipData);
                    if (sipData.pAppxSipState != IntPtr.Zero)
                    {
                        Marshal.Release(sipData.pAppxSipState);
                    }
                }

                if (result != 0)
                {
                    throw new SigningException("Win32 error in SignerSignEx2:", Marshal.GetExceptionForHR(result));
                }

                logger.WriteLine("DONE", true);
            }
            finally
            {
                signerSignHandle?.Free();
            }
        }
示例#6
0
        public static void SignFile(string certificateThumbprint, string pin, string containerName,
                                    CertificateStore store, string path, string timestampUrl, SignMode mode, string dllPath, Logger logger, string timestampAlgorithmOid = null)
        {
            logger.WriteLine("Validating certificate thumbprint", true);
            if (certificateThumbprint?.Length != 40 || !ValidateThumbprint(certificateThumbprint))
            {
                throw new SigningException(
                          $"Invalid certificate thumbprint provided: {certificateThumbprint}. The thumbprint must be a valid SHA1 thumbprint - 40 characters long and consisting of only hexadecimal characters (0-9 and A-F)");
            }

            logger.WriteLine("Converting thumbprint to bytes", true);
            var binaryHash = StringToByteArray(certificateThumbprint);

            var cryptoProvider = AcquireContext(containerName, Constants.CryptoProviderName, logger);

            try
            {
                SetPin(cryptoProvider, pin, logger);

                var certStore = OpenCertificateStore(store, logger);
                try
                {
                    var certificate = RetrieveCertificate(binaryHash, certStore, out var hashHandle, out var hashBlobHandle, logger);

                    try
                    {
                        SignFile(certificate, path, timestampUrl, mode, containerName, dllPath, logger, timestampAlgorithmOid);
                    }
                    finally
                    {
                        hashHandle?.Free();
                        hashBlobHandle?.Free();
                        NativeMethods.CertFreeCertificateContext(certificate);
                    }
                }
                finally
                {
                    NativeMethods.CertCloseStore(certStore, 0);
                }
            }
            finally
            {
                NativeMethods.CryptReleaseContext(cryptoProvider, 0);
            }
        }
        private static void SignFile(IntPtr certificate, string path, string timestampUrl, SignMode type, Action <string> logger)
        {
            logger("Beginning the signing process");
            var subjectInfo       = GetSubjectInfoPointer(path);
            var signerCertificate = GetSignerCertificatePointer(certificate);

            GCHandle?signerSignHandle = null;

            try
            {
                var signerSignEx2Params = GetsignersignEx2ParametersPointer(timestampUrl, type, subjectInfo, signerCertificate, out signerSignHandle);

                logger("Loading MSSign32.dll");
                var signModule = NativeMethods.LoadLibraryEx("MSSign32.dll", IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_SEARCH_SYSTEM32);

                if (signModule == IntPtr.Zero)
                {
                    var errorResult = Marshal.GetHRForLastWin32Error();
                    throw new SigningException($"Win32 error in LoadLibraryEx: {errorResult}", Marshal.GetExceptionForHR(errorResult));
                }

                logger("Getting SignerSignEx2 pointer");
                var signerSignEx2Pointer = NativeMethods.GetProcAddress(signModule, "SignerSignEx2");

                if (signModule == IntPtr.Zero)
                {
                    var errorResult = Marshal.GetHRForLastWin32Error();
                    throw new SigningException($"Win32 error in GetProcAddress: {errorResult}", Marshal.GetExceptionForHR(errorResult));
                }

                NativeMethods.SignerSignEx2Delegate signerSignEx2;

                try
                {
                    logger("Marshalling SignerSignEx2 pointer to a delegate");
                    signerSignEx2 = Marshal.GetDelegateForFunctionPointer <NativeMethods.SignerSignEx2Delegate>(
                        signerSignEx2Pointer);
                }
                catch (Exception e)
                {
                    throw new SigningException("Error while marshalling SignerSignEx2 pointer to a managed delegate.", e);
                }

                logger("Invoking SignerSignEx2");
                var result = signerSignEx2(signerSignEx2Params.dwFlags, signerSignEx2Params.pSubjectInfo,
                                           signerSignEx2Params.pSigningCert,
                                           signerSignEx2Params.pSignatureInfo,
                                           signerSignEx2Params.pProviderInfo,
                                           signerSignEx2Params.dwTimestampFlags,
                                           signerSignEx2Params.pszAlgorithmOid,
                                           signerSignEx2Params.pwszTimestampURL,
                                           signerSignEx2Params.pCryptAttrs,
                                           signerSignEx2Params.pSipData,
                                           signerSignEx2Params.pSignerContext,
                                           signerSignEx2Params.pCryptoPolicy,
                                           signerSignEx2Params.pReserved);

                if (result != 0)
                {
                    throw new SigningException($"Win32 error in SignerSignEx2:", Marshal.GetExceptionForHR(result));
                }

                logger("DONE");
            }
            finally
            {
                signerSignHandle?.Free();
            }
        }
        public static void SignFile(string certificateThumbprint, string pin, string containerName,
                                    CertificateStore store, string path, string timestampUrl, SignMode mode, Action <string> logger)
        {
            logger("Validating certificate thumbprint");
            if (certificateThumbprint?.Length != 40 || !ValidateThumbprint(certificateThumbprint))
            {
                throw new SigningException(
                          $"Invalid certificate thumbprint provided: {certificateThumbprint}. The thumbprint must be a valid SHA1 thumbprint - 40 characters long and consisting of only hexadecimal characters (0-9 and A-F)");
            }

            logger("Converting thumbprint to bytes");
            var binaryHash = StringToByteArray(certificateThumbprint);

            UnlockToken(containerName, Constants.CryptoProviderName, pin, logger);
            var systemStore = GetSystemStore(store);

            logger($"Opening system-level cryptographic store {systemStore}/{Constants.CryptoStoreName}");
            var certStore = NativeMethods.CertOpenStore(new IntPtr(Constants.CERT_STORE_PROV_SYSTEM),
                                                        Constants.DONT_CARE, IntPtr.Zero, systemStore, Constants.CryptoStoreName);

            if (certStore == IntPtr.Zero)
            {
                var errorResult = Marshal.GetHRForLastWin32Error();
                throw new SigningException($"Win32 error in CertOpenStore: {errorResult}",
                                           Marshal.GetExceptionForHR(errorResult));
            }

            GCHandle?h1 = null;
            GCHandle?h2 = null;

            try
            {
                var certificate = RetrieveCertificate(binaryHash, certStore, out h1, out h2, logger);
                SignFile(certificate, path, timestampUrl, mode, logger);
            }
            finally
            {
                h1?.Free();
                h2?.Free();
            }
        }