public static DistinguishedName TryParse(string name, bool isForceValidation = true) { if (name.IsNullOrWhiteSpace()) { return(null); } var nameParts = DistinguishedNameParser.GetNameParts(name); return(isForceValidation && nameParts.None() ? null : nameParts.None() ? new DistinguishedName(name) : new DistinguishedName(nameParts)); }
void SubmitInternal(HashMode hashMode, string name, string description, string descriptionUrl, IList <string> files, string filter) { logger.LogInformation("Signing Mage job {0} with {1} files", name, files.Count()); var args = "-a sha256RSA"; if (!string.IsNullOrWhiteSpace(name)) { args += $@" -n ""{name}"""; } var certificate = keyVaultService.GetCertificateAsync().Result; var timeStampUrl = keyVaultService.CertificateInfo.TimestampUrl; using (var rsaPrivateKey = keyVaultService.ToRSA() .Result) { // This outer loop is for a .clickonce file Parallel.ForEach(files, options, (file, state) => { // We need to be explicit about the order these files are signed in. The data files must be signed first // Then the .manifest file // Then the nested clickonce/vsto file // finally the top-level clickonce/vsto file using (var zip = new TemporaryZipFile(file, filter, logger)) { // Look for the data files first - these are .deploy files // we need to rename them, sign, then restore the name var deployFilesToSign = zip.FilteredFilesInDirectory.Where(f => ".deploy".Equals(Path.GetExtension(f), StringComparison.OrdinalIgnoreCase)) .ToList(); var contentFiles = new List <string>(); foreach (var dfile in deployFilesToSign) { // Rename to file without extension var dest = dfile.Replace(".deploy", ""); File.Move(dfile, dest); contentFiles.Add(dest); } var filesToSign = contentFiles.ToList(); // copy it since we may add setup.exe var setupExe = zip.FilteredFilesInDirectory.Where(f => ".exe".Equals(Path.GetExtension(f), StringComparison.OrdinalIgnoreCase)); filesToSign.AddRange(setupExe); // Safe to call Wait here because we're in a Parallel.ForEach() // sign the inner files signToolAggregate.Value.Submit(hashMode, name, description, descriptionUrl, filesToSign, filter).Wait(); // rename the rest of the deploy files since signing the manifest will need them var deployFiles = zip.FilesExceptFiltered.Where(f => ".deploy".Equals(Path.GetExtension(f), StringComparison.OrdinalIgnoreCase)) .ToList(); foreach (var dfile in deployFiles) { // Rename to file without extension var dest = dfile.Replace(".deploy", ""); File.Move(dfile, dest); contentFiles.Add(dest); } // at this point contentFiles has all deploy files renamed // Inner files are now signed // now look for the manifest file and sign that var manifestFile = zip.FilteredFilesInDirectory.Single(f => ".manifest".Equals(Path.GetExtension(f), StringComparison.OrdinalIgnoreCase)); var fileArgs = $@"-update ""{manifestFile}"" {args}"; telemetryLogger.OnSignFile(manifestFile, signToolName); if (!Sign(fileArgs, manifestFile, hashMode, rsaPrivateKey, certificate, timeStampUrl)) { throw new Exception($"Could not sign {manifestFile}"); } // Read the publisher name from the manifest for use below var manifestDoc = XDocument.Load(manifestFile); var ns = manifestDoc.Root.GetDefaultNamespace(); var publisherEle = manifestDoc.Root.Element(ns + "publisherIdentity"); var pubName = publisherEle.Attribute("name").Value; var publisherParam = ""; var dict = DistinguishedNameParser.Parse(pubName); if (dict.TryGetValue("CN", out var cns)) { // get the CN. it may be quoted publisherParam = $@"-pub ""{string.Join("+", cns.Select(s => s.Replace("\"", "")))}"" "; } // Now sign the inner vsto/clickonce file // Order by desending length to put the inner one first var clickOnceFilesToSign = zip.FilteredFilesInDirectory .Where(f => ".vsto".Equals(Path.GetExtension(f), StringComparison.OrdinalIgnoreCase) || ".application".Equals(Path.GetExtension(f), StringComparison.OrdinalIgnoreCase)) .Select(f => new { file = f, f.Length }) .OrderByDescending(f => f.Length) .Select(f => f.file) .ToList(); foreach (var f in clickOnceFilesToSign) { fileArgs = $@"-update ""{f}"" {args} -appm ""{manifestFile}"" {publisherParam}"; if (!string.IsNullOrWhiteSpace(descriptionUrl)) { fileArgs += $@" -SupportURL {descriptionUrl}"; } telemetryLogger.OnSignFile(f, signToolName); if (!Sign(fileArgs, f, hashMode, rsaPrivateKey, certificate, timeStampUrl)) { throw new Exception($"Could not sign {f}"); } } // restore the deploy files foreach (var dfile in contentFiles) { File.Move(dfile, $"{dfile}.deploy"); } zip.Save(); } }); } }