/// <summary>
        /// Invokes signtool.exe and returns exit-code along with standard-output and standard-error.
        /// </summary>
        public static int ExecuteCommand(string path, SignData arguments, out string output, out string error)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException("path");
            }

            string commandArguments;

            if (!string.IsNullOrEmpty(arguments.Thumbprint) && arguments.CertificateStore != null)
            {
                commandArguments = String.Format(SignBinaryWithCertCmd,
                                                 arguments.HashAlgorithm.Name,
                                                 arguments.Thumbprint,
                                                 arguments.CertificateStore.Name,
                                                 arguments.CertificateStore.Location == StoreLocation.LocalMachine ? " /sm" : string.Empty,
                                                 arguments.TimestampServer,
                                                 path);
            }
            else
            {
                commandArguments = String.Format(SignBinaryWithPfxCmd,
                                                 arguments.HashAlgorithm.Name,
                                                 arguments.TimestampServer,
                                                 arguments.CertificatePath,
                                                 arguments.CertificatePassword,
                                                 path);
            }

            return(ExecuteCommand(commandArguments, out output, out error));
        }
        /// <summary>
        /// Signs the binary.
        /// </summary>
        public static void Sign(string binaryPath, SignData arguments, bool signContentInVsix, Action <SignCompletionEventArgs> finishAction)
        {
            if (string.IsNullOrEmpty(binaryPath))
            {
                throw new ArgumentNullException("binaryPath");
            }
            if (arguments == null)
            {
                throw new ArgumentNullException("arguments");
            }

            var  extension    = Path.GetExtension(binaryPath);
            var  outputBuffer = new StringBuilder();
            var  errorBuffer  = new StringBuilder();
            bool result       = false;

            try
            {
                // is it a VSIX package?
                if (string.Compare(extension, ".vsix", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    result = SignVsix(binaryPath, arguments, outputBuffer, errorBuffer, signContentInVsix);
                }
                else
                {
                    // or just a single binary to sign?
                    result = SignBinary(binaryPath, arguments, outputBuffer, errorBuffer);
                }
            }
            catch (Exception ex)
            {
                result = false;
                outputBuffer.AppendLine("Signing internally failed: " + ex.Message);
            }

            if (finishAction != null)
            {
                finishAction(new SignCompletionEventArgs(result, outputBuffer.ToString(), errorBuffer.ToString()));
            }
        }
        private static bool SignBinary(string path, SignData arguments, StringBuilder outputBuffer, StringBuilder errorBuffer)
        {
            if (arguments == null)
            {
                throw new ArgumentNullException("arguments");
            }

            string output;
            string error;
            int    exitCode = SignToolRunner.ExecuteCommand(path, arguments, out output, out error);

            if (!string.IsNullOrEmpty(output) && outputBuffer != null)
            {
                outputBuffer.AppendLine(output);
            }

            if (!string.IsNullOrEmpty(error) && errorBuffer != null)
            {
                errorBuffer.AppendLine(error);
            }

            return(exitCode == 0);
        }
        private static bool SignVsix(string vsixPackagePath,
                                     SignData arguments,
                                     StringBuilder outputBuffer,
                                     StringBuilder errorBuffer,
                                     bool signContentInVsix = false)
        {
            if (arguments == null)
            {
                throw new ArgumentNullException("arguments");
            }

            // try to load the certificate:
            try
            {
                arguments.VerifyCertificate();
            }
            catch (Exception ex)
            {
                if (errorBuffer != null)
                {
                    errorBuffer.AppendLine("Certificate error.");
                    errorBuffer.AppendLine(ex.Message);
                }
                return(false);
            }

            // many thanks to Jeff Wilcox for the idea and code
            // check for details: http://www.jeff.wilcox.name/2010/03/vsixcodesigning/
            using (var package = Package.Open(vsixPackagePath))
            {
                var signatureManager = new PackageDigitalSignatureManager(package);
                signatureManager.CertificateOption = CertificateEmbeddingOption.InSignaturePart;

                // select respective hashing algorithm (http://www.w3.org/TR/2001/WD-xmlenc-core-20010626/):
                if (arguments.HashAlgorithm == null || string.IsNullOrEmpty(arguments.HashAlgorithm.Uri))
                {
                    // fail gracefully:
                    if (errorBuffer != null)
                    {
                        errorBuffer.AppendLine("Unable to sign VSIX with requested '" + (arguments.HashAlgorithm != null ? arguments.HashAlgorithm.Name : "<unknown>") + "' algorithm.");
                    }
                    return(false);
                }

                signatureManager.HashAlgorithm = arguments.HashAlgorithm.Uri;

                var partsToSign = new List <Uri>();
                foreach (var packagePart in package.GetParts())
                {
                    if (signContentInVsix)
                    {
                        var fileName  = Path.GetFileName(packagePart.Uri.OriginalString);
                        var name      = Path.Combine(Path.GetTempPath(), fileName);
                        var extension = Path.GetExtension(name);
                        using (var stream = packagePart.GetStream(FileMode.Open, FileAccess.Read))
                        {
                            using (var fileStream = new FileStream(name, FileMode.Create))
                            {
                                stream.CopyTo(fileStream);
                            }
                        }
                        if ((extension.Equals(".dll") || extension.Equals(".exe")) && !VerifyBinaryDigitalSignature(name))
                        {
                            if (!SignBinary(name, arguments, outputBuffer, errorBuffer))
                            {
                                return(false);
                            }

                            using (var stream = packagePart.GetStream(FileMode.Open, FileAccess.Write))
                            {
                                using (var fileStream = new FileStream(name, FileMode.Open))
                                {
                                    fileStream.CopyTo(stream);
                                }
                            }
                        }
                    }

                    partsToSign.Add(packagePart.Uri);
                }

                partsToSign.Add(PackUriHelper.GetRelationshipPartUri(signatureManager.SignatureOrigin));
                partsToSign.Add(signatureManager.SignatureOrigin);
                partsToSign.Add(PackUriHelper.GetRelationshipPartUri(new Uri("/", UriKind.RelativeOrAbsolute)));

                try
                {
                    signatureManager.Sign(partsToSign, arguments.Certificate);
                }
                catch (CryptographicException ex)
                {
                    if (errorBuffer != null)
                    {
                        errorBuffer.AppendLine("Signing could not be completed: " + ex.Message);
                    }
                    return(false);
                }
                finally
                {
                    signatureManager.HashAlgorithm = PackageDigitalSignatureManager.DefaultHashAlgorithm;
                }

                if (ValidateSignatures(package))
                {
                    if (outputBuffer != null)
                    {
                        outputBuffer.AppendLine("VSIX signing completed successfully.");
                    }
                    return(true);
                }

                if (outputBuffer != null)
                {
                    outputBuffer.AppendLine("The digital signature is invalid, there may have been a problem with the signing process.");
                }

                return(false);
            }
        }