public void SignFile_NoAnonymousSigning_Fails() { var configuration = new SigningServerConfiguration { Certificates = new[] { new CertificateConfiguration { Username = "******", Password = "******", Thumbprint = _certificateHelper.Certificate.Thumbprint, StoreName = (StoreName)Enum.Parse(typeof(StoreName), _certificateHelper.Store.Name), StoreLocation = _certificateHelper.Store.Location } }, WorkingDirectory = "WorkingDirectory" }; var server = new Server.SigningServer(configuration, _emptySigningToolProvider); var testData = new MemoryStream(File.ReadAllBytes(Path.Combine(ExecutionDirectory, "TestFiles/unsigned/unsigned.exe"))); var request = new SignFileRequest { FileName = "unsigned.exe", FileSize = testData.Length, FileContent = testData }; var response = server.SignFile(request); Assert.AreEqual(SignFileResponseResult.FileNotSignedUnauthorized, response.Result); }
public void SignFile(string inputFileName, X509Certificate2 certificate, string timestampServer, SignFileRequest signFileRequest, SignFileResponse signFileResponse) { var successResult = SignFileResponseResult.FileSigned; if (IsFileSigned(inputFileName)) { if (signFileRequest.OverwriteSignature) { UnsignFile(inputFileName); successResult = SignFileResponseResult.FileResigned; } else { signFileResponse.Result = SignFileResponseResult.FileAlreadySigned; return; } } SignatureHelper.SignFile(SigningOption.Default, inputFileName, certificate, timestampServer, signFileRequest.HashAlgorithm); signFileResponse.Result = successResult; signFileResponse.FileContent = new FileStream(inputFileName, FileMode.Open, FileAccess.Read); signFileResponse.FileSize = signFileResponse.FileContent.Length; }
protected void CanResign(ISigningTool signingTool, string fileName, string pfx) { var certificate = new X509Certificate2(pfx); Assert.IsTrue(signingTool.IsFileSupported(fileName)); var response = new SignFileResponse(); var request = new SignFileRequest { FileName = fileName, OverwriteSignature = true }; signingTool.SignFile(fileName, certificate, ConfigurationManager.AppSettings["TimestampServer"], request, response); try { Assert.AreEqual(SignFileResponseResult.FileResigned, response.Result); Assert.IsTrue(signingTool.IsFileSigned(fileName)); Assert.IsNotNull(response.FileContent); Assert.IsTrue(response.FileSize > 0); using (var data = new MemoryStream()) { using (response.FileContent) { response.FileContent.CopyTo(data); Assert.AreEqual(response.FileSize, data.ToArray().Length); } } } finally { response.Dispose(); } }
public void SignFile_EmptyFile_Fails() { var server = new Server.SigningServer(_configuration, _emptySigningToolProvider); var request = new SignFileRequest { FileSize = 0, FileContent = null }; var response = server.SignFile(request); Assert.AreEqual(SignFileResponseResult.FileNotSignedError, response.Result); request = new SignFileRequest { FileSize = 100, FileContent = null }; response = server.SignFile(request); Assert.AreEqual(SignFileResponseResult.FileNotSignedError, response.Result); request = new SignFileRequest { FileSize = 0, FileContent = new MemoryStream() }; response = server.SignFile(request); Assert.AreEqual(SignFileResponseResult.FileNotSignedError, response.Result); }
public void SignFile_ResponseDisposeCleansFile() { var server = new Server.SigningServer(_configuration, _simultateSigningToolProvider); var testData = new MemoryStream(File.ReadAllBytes(Path.Combine(ExecutionDirectory, "TestFiles/unsigned/unsigned.exe"))); var request = new SignFileRequest { FileName = "unsigned.exe", FileSize = testData.Length, FileContent = testData }; var response = server.SignFile(request); Assert.AreEqual(SignFileResponseResult.FileSigned, response.Result); var files = Directory.GetFileSystemEntries(_configuration.WorkingDirectory).ToArray(); Assert.AreEqual(1, files.Length); response.Dispose(); files = Directory.GetFileSystemEntries(_configuration.WorkingDirectory).ToArray(); Assert.AreEqual(0, files.Length); }
protected void CannotResign(ISigningTool signingTool, string fileName, string pfx) { var certificate = new X509Certificate2(pfx); Assert.IsTrue(signingTool.IsFileSupported(fileName)); var response = new SignFileResponse(); var request = new SignFileRequest { FileName = fileName, OverwriteSignature = false }; signingTool.SignFile(fileName, certificate, ConfigurationManager.AppSettings["TimestampServer"], request, response); Trace.WriteLine(response); try { Assert.AreEqual(SignFileResponseResult.FileAlreadySigned, response.Result); Assert.IsTrue(signingTool.IsFileSigned(fileName)); Assert.AreEqual(0, response.FileSize); } finally { response.Dispose(); } }
public void SignFile(string inputFileName, X509Certificate2 certificate, string timestampServer, SignFileRequest signFileRequest, SignFileResponse signFileResponse) { SignFileResponseResult successResult = SignFileResponseResult.FileSigned; if (IsFileSigned(inputFileName)) { if (signFileRequest.OverwriteSignature) { UnsignFile(inputFileName); successResult = SignFileResponseResult.FileResigned; } else { signFileResponse.Result = SignFileResponseResult.FileAlreadySigned; return; } } SecurityUtilities.SignFile(certificate, new Uri(timestampServer), inputFileName); signFileResponse.Result = successResult; signFileResponse.FileContent = new FileStream(inputFileName, FileMode.Open, FileAccess.Read); signFileResponse.FileSize = signFileResponse.FileContent.Length; }
public void SignFile(string inputFileName, X509Certificate2 certificate, string timestampServer, SignFileRequest signFileRequest, SignFileResponse signFileResponse) { SignFileResponseResult successResult = SignFileResponseResult.FileSigned; if (IsFileSigned(inputFileName)) { if (signFileRequest.OverwriteSignature) { successResult = SignFileResponseResult.FileResigned; } else { signFileResponse.Result = SignFileResponseResult.FileAlreadySigned; return; } } var outputFileName = inputFileName + ".signed"; try { if (string.IsNullOrEmpty(signFileRequest.HashAlgorithm) || !ApkSupportedHashAlgorithms.TryGetValue(signFileRequest.HashAlgorithm, out var digestAlgorithm)) { digestAlgorithm = null; } var isV2SigningEnabled = ".apk".Equals(Path.GetExtension(inputFileName), StringComparison.InvariantCultureIgnoreCase) && // v2 only for APKs not for JARs (digestAlgorithm == null || !digestAlgorithm.Equals(DigestAlgorithm.SHA1)) // v2 signing requires SHA256 or SHA512 ; var apkSigner = new ApkSigner(certificate, inputFileName, outputFileName) { V1SigningEnabled = true, V2SigningEnabled = isV2SigningEnabled, DigestAlgorithm = digestAlgorithm }; apkSigner.Sign(); File.Delete(inputFileName); File.Move(outputFileName, inputFileName); signFileResponse.Result = successResult; signFileResponse.FileContent = new FileStream(inputFileName, FileMode.Open, FileAccess.Read); signFileResponse.FileSize = signFileResponse.FileContent.Length; } catch { if (File.Exists(outputFileName)) { File.Delete(outputFileName); } throw; } }
public void SignFile_UnsupportedFormat_Fails() { var server = new Server.SigningServer(_configuration, _emptySigningToolProvider); var testData = new MemoryStream(File.ReadAllBytes(Path.Combine(ExecutionDirectory, "TestFiles/unsigned/unsigned.exe"))); var request = new SignFileRequest { FileName = "unsigned.exe", FileSize = testData.Length, FileContent = testData }; var response = server.SignFile(request); Assert.AreEqual(SignFileResponseResult.FileNotSignedUnsupportedFormat, response.Result); }
public void SignFile_AlreadySigned_ResponseDisposeCleansFile() { var simulateSigningTool = new Mock <ISigningTool>(); simulateSigningTool.Setup(t => t.SupportedFileExtensions).Returns(new[] { "*" }); simulateSigningTool.Setup(t => t.SupportedHashAlgorithms).Returns(new[] { "*" }); simulateSigningTool.Setup(t => t.IsFileSigned(It.IsAny <string>())).Returns(true); simulateSigningTool.Setup(t => t.IsFileSupported(It.IsAny <string>())).Returns(true); simulateSigningTool.Setup(t => t.SignFile(It.IsAny <string>(), It.IsAny <X509Certificate2>(), It.IsAny <string>(), It.IsAny <SignFileRequest>(), It.IsAny <SignFileResponse>())).Callback( (string file, X509Certificate2 cert, string timestampserver, SignFileRequest rq, SignFileResponse rs) => { rs.Result = SignFileResponseResult.FileAlreadySigned; var fs = new FileStream(file, FileMode.Open, FileAccess.Read); rs.FileContent = fs; rs.FileSize = fs.Length; }); var simultateSigningToolProvider = new EnumerableSigningToolProvider(new[] { simulateSigningTool.Object }); var server = new Server.SigningServer(_configuration, simultateSigningToolProvider); var testData = new MemoryStream(File.ReadAllBytes("TestFiles/unsigned/unsigned.exe")); var request = new SignFileRequest { FileName = "unsigned.exe", FileSize = testData.Length, FileContent = testData }; var response = server.SignFile(request); Assert.AreEqual(SignFileResponseResult.FileAlreadySigned, response.Result); var files = Directory.GetFileSystemEntries(_configuration.WorkingDirectory).ToArray(); Assert.AreEqual(1, files.Length); response.Dispose(); files = Directory.GetFileSystemEntries(_configuration.WorkingDirectory).ToArray(); Assert.AreEqual(0, files.Length); }
public void SignFile_Unsigned_WrongPublishedFails() { using (var signingTool = new AppxSigningTool(Log)) { var fileName = "Unsigned_WrongPublishedFails/error/UnsignedWrongPublisher.appx"; var certificate = new X509Certificate2("Certificates/SigningServer.Test.pfx"); Assert.IsTrue(signingTool.IsFileSupported(fileName)); var response = new SignFileResponse(); var request = new SignFileRequest { FileName = fileName, OverwriteSignature = true }; signingTool.SignFile(fileName, certificate, ConfigurationManager.AppSettings["TimestampServer"], request, response); Trace.WriteLine(response); Assert.AreEqual(SignFileResponseResult.FileNotSignedError, response.Result); Assert.IsFalse(signingTool.IsFileSigned(fileName)); Assert.IsInstanceOfType(response.FileContent, typeof(MemoryStream)); Assert.AreEqual(response.FileSize, response.FileContent.Length); Assert.AreEqual(0, response.FileSize); } }
public void SignFile(string inputFileName, X509Certificate2 certificate, string timestampServer, SignFileRequest signFileRequest, SignFileResponse signFileResponse) { SignFileResponseResult successResult = SignFileResponseResult.FileSigned; if (IsFileSigned(inputFileName)) { if (signFileRequest.OverwriteSignature) { UnsignFile(inputFileName); successResult = SignFileResponseResult.FileResigned; } else { signFileResponse.Result = SignFileResponseResult.FileAlreadySigned; signFileResponse.FileContent = null; return; } } var outputFileName = inputFileName + ".signed"; try { HashAlgorithmInfo hashAlgorithmInfo; if (!ApkSupportedHashAlgorithms.TryGetValue(signFileRequest.HashAlgorithm ?? DefaultHashAlgorithm, out hashAlgorithmInfo)) { hashAlgorithmInfo = ApkSupportedHashAlgorithms[DefaultHashAlgorithm]; } using (var inputJar = new ZipFile(inputFileName)) { using (var outputJar = ZipFile.Create(outputFileName)) { outputJar.BeginUpdate(); var manifest = CreateSignedManifest(inputJar, outputJar, hashAlgorithmInfo); var signatureFile = CreateSignatureFile(outputJar, manifest, hashAlgorithmInfo); CreateSignatureBlockFile(outputJar, certificate, signatureFile, timestampServer); outputJar.CommitUpdate(); outputJar.BeginUpdate(); foreach (var entry in inputJar.OfType <ZipEntry>()) { if (entry.IsDirectory) { outputJar.AddDirectory(entry.Name); } else if (outputJar.FindEntry(entry.Name, true) == -1) { Log.Trace($"Cloning file ${entry.Name} into new zip"); outputJar.Add(new ZipEntryDataSource(inputJar, entry), entry.Name); } } outputJar.CommitUpdate(); outputJar.Close(); } } File.Delete(inputFileName); File.Move(outputFileName, inputFileName); signFileResponse.Result = successResult; signFileResponse.FileContent = new FileStream(inputFileName, FileMode.Open, FileAccess.Read); signFileResponse.FileSize = signFileResponse.FileContent.Length; } catch { if (File.Exists(outputFileName)) { File.Delete(outputFileName); } throw; } }
public SignFileResponse SignFile(SignFileRequest signFileRequest) { var signFileResponse = new SignFileResponse(); signFileResponse.DeleteFailed += (response, file, exception) => { Log.Error(exception, $"Failed to delete file '{file}'"); }; signFileResponse.DeleteSkipped += (response, file) => { Log.Warn($"Skipped file delete '{file}'"); }; signFileResponse.DeleteSuccess += (response, file) => { Log.Trace($"Successfully deleted file '{file}'"); }; var remoteIp = RemoteIp; var isLegacy = IsLegacyEndpoint; string inputFileName = null; try { // // validate input if (isLegacy) { Log.Warn($"[{remoteIp}] Client is using legacy endpoint!"); } Log.Info($"[{remoteIp}] New sign request for file {signFileRequest.FileName} by {remoteIp} ({signFileRequest.FileSize} bytes)"); if (signFileRequest.FileSize == 0 || signFileRequest.FileContent == null) { signFileResponse.Result = SignFileResponseResult.FileNotSignedError; signFileResponse.ErrorMessage = "No file was received"; return(signFileResponse); } // // find certificate CertificateConfiguration certificate; if (string.IsNullOrWhiteSpace(signFileRequest.Username)) { certificate = Configuration.Certificates.FirstOrDefault(c => c.IsAnonymous); } else { certificate = Configuration.Certificates.FirstOrDefault( c => c.IsAuthorized(signFileRequest.Username, signFileRequest.Password)); } if (certificate == null) { Log.Warn("Unauthorized signing request"); signFileResponse.Result = SignFileResponseResult.FileNotSignedUnauthorized; return(signFileResponse); } // // find compatible signing tool var signingTool = SigningToolProvider.GetSigningTool(signFileRequest.FileName); if (signingTool == null) { signFileResponse.Result = SignFileResponseResult.FileNotSignedUnsupportedFormat; return(signFileResponse); } // // upload file to working directory inputFileName = signFileRequest.FileName ?? ""; inputFileName = DateTime.Now.ToString("yyyyMMdd_HHmmss") + "_" + Path.GetFileNameWithoutExtension(inputFileName) + "_" + Guid.NewGuid() + (Path.GetExtension(inputFileName)); inputFileName = Path.Combine(Configuration.WorkingDirectory, inputFileName); using (var targetFile = new FileStream(inputFileName, FileMode.Create, FileAccess.ReadWrite)) { signFileRequest.FileContent.CopyTo(targetFile); } // // sign file signingTool.SignFile(inputFileName, certificate.Certificate, Configuration.TimestampServer, signFileRequest, signFileResponse); Log.Info($"[{remoteIp}] New sign request for file {signFileRequest.FileName} finished ({signFileRequest.FileSize} bytes)"); switch (signFileResponse.Result) { case SignFileResponseResult.FileSigned: case SignFileResponseResult.FileResigned: break; case SignFileResponseResult.FileAlreadySigned: case SignFileResponseResult.FileNotSignedUnsupportedFormat: case SignFileResponseResult.FileNotSignedError: case SignFileResponseResult.FileNotSignedUnauthorized: // ensure input file is cleaned in error cases where the sign tool does not have a result if (!(signFileResponse.FileContent is FileStream)) { try { Log.Trace($"Deleting file {inputFileName}"); File.Delete(inputFileName); Log.Trace($"File successfully deleted {inputFileName}"); } catch (Exception e) { Log.Error(e, "Could not delete input file for failed request"); } } else { Log.Trace($"Delete file skipped for failed request {signFileResponse.Result} {inputFileName}, {signFileResponse.FileContent.GetType()}"); } break; } } catch (Exception e) { Log.Error(e, $"[{remoteIp}] Signing of {signFileRequest.FileName} failed: {e.Message}"); signFileResponse.Result = SignFileResponseResult.FileNotSignedError; signFileResponse.ErrorMessage = e.Message; if (!string.IsNullOrEmpty(inputFileName) && File.Exists(inputFileName)) { try { File.Delete(inputFileName); } catch (Exception fileException) { Log.Error(fileException, $"[{remoteIp}] Failed to delete file {inputFileName}"); } } } return(signFileResponse); }
private void InternalSignFile(string file) { var info = new FileInfo(file); SignFileResponse response; Log.Info("Signing file '{0}'", info.FullName); if (info.Attributes.HasFlag(FileAttributes.ReadOnly)) { Log.Info("File was readonly, cleaned readonly flag"); info.Attributes &= ~FileAttributes.ReadOnly; } int retry = _configuration.Retry; do { try { var sw = new Stopwatch(); sw.Start(); using (var request = new SignFileRequest { FileName = info.Name, FileSize = info.Length, OverwriteSignature = _configuration.OverwriteSignatures, Username = _configuration.Username, Password = _configuration.Password, FileContent = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read), HashAlgorithm = _configuration.HashAlgorithm }) { response = _client.SignFile(request); } using (response) { switch (response.Result) { case SignFileResponseResult.FileSigned: Log.Info("File signed, start downloading"); using (var fs = new FileStream(file, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) { response.FileContent.CopyTo(fs); } sw.Stop(); Log.Info("File downloaded, signing finished in {0}ms", sw.ElapsedMilliseconds); retry = 0; break; case SignFileResponseResult.FileResigned: Log.Info("File signed and old signature was removed, start downloading"); using (var fs = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { response.FileContent.CopyTo(fs); } sw.Stop(); Log.Info("File downloaded, signing finished in {0}ms", sw.ElapsedMilliseconds); retry = 0; break; case SignFileResponseResult.FileAlreadySigned: Log.Warn("File is already signed and was therefore skipped"); if (!_configuration.IgnoreExistingSignatures) { Log.Info("Signing failed"); throw new FileAlreadySignedException(); } else { retry = 0; } break; case SignFileResponseResult.FileNotSignedUnsupportedFormat: Log.Warn("File is not supported for signing"); if (!_configuration.IgnoreUnsupportedFiles) { Log.Error("Signing failed"); throw new UnsupportedFileFormatException(); } else { retry = 0; } break; case SignFileResponseResult.FileNotSignedError: throw new SigningFailedException(response.ErrorMessage); case SignFileResponseResult.FileNotSignedUnauthorized: Log.Error("The specified username and password are not recognized on the server"); throw new UnauthorizedAccessException(); default: throw new ArgumentOutOfRangeException(); } } } catch (Exception) { // wait 1sec if we haf if (retry > 0) { Log.Error("Waiting 1sec, then retry signing"); Thread.Sleep(1000); try { Dispose(); } catch (Exception e) { Log.Warn(e, "Cleanup of existing connection failed"); } Connect(); } else { throw; } } } while (retry-- > 0); }
public SignFileResponse SignFile(SignFileRequest signFileRequest) { var signFileResponse = new SignFileResponse(); var remoteIp = RemoteIp; string inputFileName = null; try { // // validate input Log.Info("New sign request for file {0} by {1} ({2} bytes)", signFileRequest.FileName, remoteIp, signFileRequest.FileSize); if (signFileRequest.FileSize == 0 || signFileRequest.FileContent == null) { signFileResponse.Result = SignFileResponseResult.FileNotSignedError; signFileResponse.ErrorMessage = "No file was received"; return(signFileResponse); } // // find certificate CertificateConfiguration certificate; if (string.IsNullOrWhiteSpace(signFileRequest.Username)) { certificate = Configuration.Certificates.FirstOrDefault(c => c.IsAnonymous); } else { certificate = Configuration.Certificates.FirstOrDefault( c => c.IsAuthorized(signFileRequest.Username, signFileRequest.Password)); } if (certificate == null) { Log.Warn("Unauthorized signing request"); signFileResponse.Result = SignFileResponseResult.FileNotSignedUnauthorized; return(signFileResponse); } // // find compatible signing tool var signingTool = SigningToolProvider.GetSigningTool(signFileRequest.FileName); if (signingTool == null) { signFileResponse.Result = SignFileResponseResult.FileNotSignedUnsupportedFormat; return(signFileResponse); } // // upload file to working directory inputFileName = signFileRequest.FileName ?? ""; inputFileName = DateTime.Now.ToString("yyyyMMdd_HHmmss") + "_" + Path.GetFileNameWithoutExtension(inputFileName) + "_" + Guid.NewGuid() + (Path.GetExtension(inputFileName)); inputFileName = Path.Combine(Configuration.WorkingDirectory, inputFileName); using (var targetFile = new FileStream(inputFileName, FileMode.Create, FileAccess.ReadWrite)) { signFileRequest.FileContent.CopyTo(targetFile); } // // sign file signingTool.SignFile(inputFileName, certificate.Certificate, Configuration.TimestampServer, signFileRequest, signFileResponse); Log.Info("New sign request for file {0} finished ({1} bytes)", signFileRequest.FileName, signFileRequest.FileSize); } catch (Exception e) { Log.Error(e, $"Signing of {signFileRequest.FileName} by {remoteIp} failed: {e.Message}"); signFileResponse.Result = SignFileResponseResult.FileNotSignedError; signFileResponse.ErrorMessage = e.Message; if (!string.IsNullOrEmpty(inputFileName) && File.Exists(inputFileName)) { try { File.Delete(inputFileName); } catch (Exception fileException) { Log.Error(fileException, $"Failed to delete file {inputFileName} by {remoteIp}"); } } } return(signFileResponse); }
private void InternalSignFile(string file) { var info = new FileInfo(file); SignFileResponse response; Log.Info("Signing file '{0}'", info.FullName); if (info.Attributes.HasFlag(FileAttributes.ReadOnly)) { Log.Info("File was readonly, cleaned readonly flag"); info.Attributes &= ~FileAttributes.ReadOnly; } using (var request = new SignFileRequest { FileName = info.Name, FileSize = info.Length, OverwriteSignature = _configuration.OverwriteSignatures, Username = _configuration.Username, Password = _configuration.Password, FileContent = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read), HashAlgorithm = _configuration.HashAlgorithm }) { response = _client.SignFile(request); } using (response) { switch (response.Result) { case SignFileResponseResult.FileSigned: Log.Info("File signed, start downloading"); using (var fs = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { response.FileContent.CopyTo(fs); } Log.Info("File downloaded"); break; case SignFileResponseResult.FileResigned: Log.Info("File signed and old signature was removed, start downloading"); using (var fs = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { response.FileContent.CopyTo(fs); } Log.Info("File downloaded"); break; case SignFileResponseResult.FileAlreadySigned: Log.Warn("File is already signed and was therefore skipped"); if (!_configuration.IgnoreExistingSignatures) { Log.Info("Signing failed"); throw new FileAlreadySignedException(); } break; case SignFileResponseResult.FileNotSignedUnsupportedFormat: Log.Warn("File is not supported for signing"); if (!_configuration.IgnoreUnsupportedFiles) { Log.Error("Signing failed"); throw new UnsupportedFileFormatException(); } break; case SignFileResponseResult.FileNotSignedError: throw new SigningFailedException(response.ErrorMessage); case SignFileResponseResult.FileNotSignedUnauthorized: Log.Error("The specified username and password are not recognized on the server"); throw new UnauthorizedAccessException(); default: throw new ArgumentOutOfRangeException(); } } }