예제 #1
0
        public void TestMessage()
        {
            var output = ("The following certificates were considered:\r\n    " +
                          "Issued to: localhost\r\n    Issued by: localhost\r\n    " +
                          "Expires:   Wed May 05 23:39:42 2021\r\n    " +
                          "SHA1 hash: E323874CD3FB890842AB09791CD605F8D3A5340F\r\n    " +
                          "Issued to: ddfe70e5-4d2b-4940-a550-66f4f7d8307c\r\n    " +
                          "Issued by: MS-Organization-Access\r\n    " +
                          "Expires:   Sun May 05 23:57:34 2030\r\n    " +
                          "SHA1 hash: D1AABEE4733FE30E1D6317427E88CA973406025B\r\n    " +
                          "Issued to: Marcin Otorowski\r\n    " +
                          "Issued by: Certum Code Signing CA SHA2\r\n    " +
                          "Expires:   Tue Dec 29 13:55:03 2020\r\n    " +
                          "SHA1 hash: C362045164EFCDA4E40473F0B3B6B1D3E647CA6F\r\n    " +
                          "Issued to: bc64c50169ddad94\r\n    " +
                          "Issued by: Token Signing Public Key\r\n    " +
                          "Expires:   Wed May 13 01:07:14 2020\r\n    " +
                          "SHA1 hash: A33983F854D4C7C6FAC5CC754656DC7CCA5ACEEF\r\n" +
                          "After EKU filter, 1 certs were left.\r\n" +
                          "After expiry filter, 1 certs were left.\r\n" +
                          "After Hash filter, 0 certs were left.\r\n" +
                          "After Private Key filter, 0 certs were left.	\r\n")
                         .Split("\r\n").ToList();

            MsixSdkWrapper.TryGetErrorMessageFromSignToolOutput(output, out var error);
            Assert.IsTrue(error.Contains("EKU", StringComparison.CurrentCultureIgnoreCase));
        }
예제 #2
0
        public override async Task <int> Execute()
        {
            var msixSdkWrapper = new MsixSdkWrapper();

            Logger.Info($"Packing [{this.Verb.Directory}] to [{this.Verb.Package}]...");

            try
            {
                await this.Console.WriteInfo($"Packing [{this.Verb.Directory}] to [{this.Verb.Package}]...").ConfigureAwait(false);

                await msixSdkWrapper.PackPackageDirectory(this.Verb.Directory, this.Verb.Package, !this.Verb.NoCompression, !this.Verb.NoValidation).ConfigureAwait(false);

                await this.Console.WriteSuccess($"Package [{this.Verb.Package}] has been created.");

                return(0);
            }
            catch (SdkException e)
            {
                Logger.Error(e);
                await this.Console.WriteError(e.Message);

                return(e.ExitCode);
            }
            catch (Exception e)
            {
                Logger.Error(e);
                await this.Console.WriteError(e.Message);

                return(1);
            }
        }
예제 #3
0
        public override async Task <int> Execute()
        {
            var msixSdkWrapper = new MsixSdkWrapper();

            Logger.Info($"Unpacking [{this.Verb.Package}] to [{this.Verb.Directory}]...");

            try
            {
                await this.Console.WriteInfo($"Unpacking [{this.Verb.Directory}] to [{this.Verb.Package}]...").ConfigureAwait(false);

                await msixSdkWrapper.UnpackPackage(this.Verb.Package, this.Verb.Directory).ConfigureAwait(false);

                await this.Console.WriteSuccess($"Package has been unpacked to [{this.Verb.Directory}].");

                return(0);
            }
            catch (SdkException e)
            {
                Logger.Error(e);
                await this.Console.WriteError(e.Message);

                return(e.ExitCode);
            }
            catch (Exception e)
            {
                Logger.Error(e);
                await this.Console.WriteError(e.Message);

                return(1);
            }
        }
예제 #4
0
        private static string GetVersion(string sdkFile)
        {
            var path = MsixSdkWrapper.GetSdkPath(sdkFile);

            if (!File.Exists(path))
            {
                return(null);
            }

            return(FileVersionInfo.GetVersionInfo(path).ProductVersion);
        }
예제 #5
0
        public async Task<string> GetSubjectFromDeviceGuardSigning(string dgssTokenPath, CancellationToken cancellationToken = default)
        {
            Logger.Info("Getting certificate subject for Device Guard signing...");

            var tempFilePath = Path.Combine(Path.GetTempPath(), "msix-hero-" + Guid.NewGuid().ToString("N") + ".cat");
            try
            {
                var name = typeof(DeviceGuardHelper).Assembly.GetManifestResourceNames().First(n => n.EndsWith("MSIXHeroTest.cat"));
                using (var manifestResourceStream = typeof(DeviceGuardHelper).Assembly.GetManifestResourceStream(name))
                {
                    if (manifestResourceStream == null)
                    {
                        throw new InvalidOperationException("Cannot extract temporary file.");
                    }

                    Logger.Debug($"Creating temporary file path {tempFilePath}");
                    using (var fileStream = File.Create(tempFilePath))
                    {
                        manifestResourceStream.Seek(0L, SeekOrigin.Begin);
                        await manifestResourceStream.CopyToAsync(fileStream, cancellationToken).ConfigureAwait(false);
                    }
                }

                var sdk = new MsixSdkWrapper();
                Logger.Debug($"Signing temporary file path {tempFilePath}");
                await sdk.SignPackageWithDeviceGuard(new[] {tempFilePath}, "SHA256", dgssTokenPath, null, cancellationToken).ConfigureAwait(false);

                using (var fromSignedFile = X509Certificate.CreateFromSignedFile(tempFilePath))
                {
                    Logger.Info($"Certificate subject is {tempFilePath}");
                    return fromSignedFile.Subject;
                }
            }
            catch (Exception e)
            {
                Logger.Error("Could not read subject from Device Guard certificate.", e);
                throw;
            }
            finally
            {
                if (File.Exists(tempFilePath))
                {
                    Logger.Debug($"Removing {tempFilePath}");
                    ExceptionGuard.Guard(() => File.Delete(tempFilePath));
                }
            }
        }
예제 #6
0
        public async Task SignPackageWithPfx(
            string package,
            bool updatePublisher,
            string pfxPath,
            SecureString password,
            string timestampUrl = null,
            IncreaseVersionMethod increaseVersion = IncreaseVersionMethod.None,
            CancellationToken cancellationToken   = default,
            IProgress <ProgressData> progress     = null)
        {
            Logger.Info("Signing package {0} using PFX {1}.", package, pfxPath);

            if (!File.Exists(pfxPath))
            {
                throw new FileNotFoundException($"File {pfxPath} does not exit.");
            }

            Logger.Debug("Analyzing given certificate...");
            var x509 = new X509Certificate2(await File.ReadAllBytesAsync(pfxPath, cancellationToken).ConfigureAwait(false), password);

            var localCopy = await this.PreparePackageForSigning(package, updatePublisher, increaseVersion, x509, cancellationToken).ConfigureAwait(false);

            try
            {
                cancellationToken.ThrowIfCancellationRequested();
                string type;
                if (x509.SignatureAlgorithm.FriendlyName.EndsWith("rsa", StringComparison.OrdinalIgnoreCase))
                {
                    type = x509.SignatureAlgorithm.FriendlyName.Substring(0, x509.SignatureAlgorithm.FriendlyName.Length - 3).ToUpperInvariant();
                }
                else
                {
                    throw new NotSupportedException($"Signature algorithm {x509.SignatureAlgorithm.FriendlyName} is not supported.");
                }

                var openTextPassword = new System.Net.NetworkCredential(string.Empty, password).Password;

                Logger.Debug("Signing package {0} with algorithm {1}.", localCopy, x509.SignatureAlgorithm.FriendlyName);

                var sdk = new MsixSdkWrapper();
                progress?.Report(new ProgressData(25, "Signing..."));
                await sdk.SignPackageWithPfx(new[] { localCopy }, type, pfxPath, openTextPassword, timestampUrl, cancellationToken).ConfigureAwait(false);

                progress?.Report(new ProgressData(75, "Signing..."));
                await Task.Delay(500, cancellationToken).ConfigureAwait(false);

                Logger.Debug("Moving {0} to {1}.", localCopy, package);
                File.Copy(localCopy, package, true);
                progress?.Report(new ProgressData(95, "Signing..."));
            }
            finally
            {
                try
                {
                    if (File.Exists(localCopy))
                    {
                        File.Delete(localCopy);
                    }
                }
                catch (Exception e)
                {
                    Logger.Warn(e, "Clean-up of a temporary file {0} failed.", localCopy);
                }
            }
        }
예제 #7
0
        public async Task SignPackageWithDeviceGuard(string package,
                                                     bool updatePublisher,
                                                     DeviceGuardConfig config,
                                                     string timestampUrl = null,
                                                     IncreaseVersionMethod increaseVersion = IncreaseVersionMethod.None,
                                                     CancellationToken cancellationToken   = default,
                                                     IProgress <ProgressData> progress     = null)
        {
            Logger.Info("Signing package {0} using Device Guard for {1}.", package, config.Subject);

            var dgssTokenPath = await new DgssTokenCreator().CreateDeviceGuardJsonTokenFile(config, cancellationToken);

            try
            {
                var publisherName = config.Subject;
                if (publisherName == null)
                {
                    var dgh = new DeviceGuardHelper();
                    publisherName = await dgh.GetSubjectFromDeviceGuardSigning(dgssTokenPath, cancellationToken).ConfigureAwait(false);
                }

                var localCopy = await this.PreparePackageForSigning(package, updatePublisher, increaseVersion, publisherName, cancellationToken).ConfigureAwait(false);

                try
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var sdk = new MsixSdkWrapper();
                    progress?.Report(new ProgressData(25, "Signing with Device Guard..."));
                    await sdk.SignPackageWithDeviceGuard(new[] { localCopy }, "SHA256", dgssTokenPath, timestampUrl, cancellationToken).ConfigureAwait(false);

                    progress?.Report(new ProgressData(75, "Signing with Device Guard..."));
                    await Task.Delay(500, cancellationToken).ConfigureAwait(false);

                    Logger.Debug("Moving {0} to {1}.", localCopy, package);
                    File.Copy(localCopy, package, true);
                    progress?.Report(new ProgressData(95, "Signing with Device Guard..."));
                }
                finally
                {
                    try
                    {
                        if (File.Exists(localCopy))
                        {
                            File.Delete(localCopy);
                        }
                    }
                    catch (Exception e)
                    {
                        Logger.Warn(e, "Clean-up of a temporary file {0} failed.", localCopy);
                    }
                }
            }
            finally
            {
                if (File.Exists(dgssTokenPath))
                {
                    ExceptionGuard.Guard(() => File.Delete(dgssTokenPath));
                }
            }
        }
예제 #8
0
        public async Task SignPackageWithInstalled(
            string package,
            bool updatePublisher,
            PersonalCertificate certificate,
            string timestampUrl = null,
            IncreaseVersionMethod increaseVersion = IncreaseVersionMethod.None,
            CancellationToken cancellationToken   = default,
            IProgress <ProgressData> progress     = null)
        {
            if (certificate == null)
            {
                throw new ArgumentNullException(nameof(certificate));
            }

            Logger.Info("Signing package {0} using personal certificate {1}.", package, certificate.Subject);

            StoreLocation loc;

            switch (certificate.StoreType)
            {
            case CertificateStoreType.User:
                loc = StoreLocation.CurrentUser;
                break;

            case CertificateStoreType.Machine:
                loc = StoreLocation.LocalMachine;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            using var store = new X509Store(StoreName.My, loc);
            store.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);

            var x509 = store.Certificates.Find(X509FindType.FindByThumbprint, certificate.Thumbprint, false);

            if (x509.Count < 1)
            {
                throw new ArgumentException("Certificate could not be located in the store.");
            }

            var isForCodeSigning = x509[0].Extensions.OfType <X509KeyUsageExtension>().Any(ke => ke.KeyUsages.HasFlag(X509KeyUsageFlags.DigitalSignature));

            if (!isForCodeSigning)
            {
                throw new ArgumentException("Selected certificate is not for code-signing.");
            }

            if (!x509[0].HasPrivateKey)
            {
                throw new ArgumentException("Selected certificate does not contain a private key.");
            }

            var localCopy = await this.PreparePackageForSigning(
                package,
                updatePublisher,
                increaseVersion,
                x509[0],
                cancellationToken).ConfigureAwait(false);

            try
            {
                cancellationToken.ThrowIfCancellationRequested();
                string type;
                if (x509[0].SignatureAlgorithm.FriendlyName.EndsWith("rsa", StringComparison.OrdinalIgnoreCase))
                {
                    type = x509[0].SignatureAlgorithm.FriendlyName.Substring(0, x509[0].SignatureAlgorithm.FriendlyName.Length - 3).ToUpperInvariant();
                }
                else
                {
                    throw new NotSupportedException($"Signature algorithm {x509[0].SignatureAlgorithm.FriendlyName} is not supported.");
                }

                Logger.Debug("Signing package {0} with algorithm {1}.", localCopy, x509[0].SignatureAlgorithm.FriendlyName);

                var sdk = new MsixSdkWrapper();
                progress?.Report(new ProgressData(25, "Signing..."));

                await sdk.SignPackageWithPersonal(new[] { localCopy }, type, certificate.Thumbprint, certificate.StoreType == CertificateStoreType.Machine, timestampUrl, cancellationToken).ConfigureAwait(false);

                progress?.Report(new ProgressData(75, "Signing..."));
                await Task.Delay(500, cancellationToken).ConfigureAwait(false);

                Logger.Debug("Moving {0} to {1}.", localCopy, package);
                File.Copy(localCopy, package, true);
                progress?.Report(new ProgressData(95, "Signing..."));
            }
            finally
            {
                try
                {
                    if (File.Exists(localCopy))
                    {
                        File.Delete(localCopy);
                    }
                }
                catch (Exception e)
                {
                    Logger.Warn(e, "Clean-up of a temporary file {0} failed.", localCopy);
                }
            }
        }