public void TestExportFeeds() { using var feedFile1 = new TemporaryFile("0install-unit-tests"); using var feedFile2 = new TemporaryFile("0install-unit-tests"); var feedCacheMock = CreateMock <IFeedCache>(); feedCacheMock.Setup(x => x.GetPath(Fake.SubFeed1Uri)).Returns(feedFile1); feedCacheMock.Setup(x => x.GetPath(Fake.SubFeed2Uri)).Returns(feedFile2); var signature = new ValidSignature(123, new byte[0], new DateTime(2000, 1, 1)); feedCacheMock.Setup(x => x.GetSignatures(Fake.SubFeed1Uri)).Returns(new OpenPgpSignature[] { signature }); feedCacheMock.Setup(x => x.GetSignatures(Fake.SubFeed2Uri)).Returns(new OpenPgpSignature[] { signature }); var openPgpMock = CreateMock <IOpenPgp>(); openPgpMock.Setup(x => x.ExportKey(signature)).Returns("abc"); _target.ExportFeeds(feedCacheMock.Object, openPgpMock.Object); string contentDir = Path.Combine(_destination, "content"); File.Exists(Path.Combine(contentDir, Fake.SubFeed1Uri.PrettyEscape())).Should().BeTrue(); File.Exists(Path.Combine(contentDir, Fake.SubFeed2Uri.PrettyEscape())).Should().BeTrue(); File.ReadAllText(Path.Combine(contentDir, "000000000000007B.gpg")).Should() .Be("abc", because: "GPG keys should be exported."); }
/// <summary> /// Detects attacks such as feed substitution or replay attacks. /// </summary> /// <param name="data">The content of the feed file as a byte array.</param> /// <param name="uri">The URI the feed originally came from.</param> /// <param name="signature">The first trusted signature for the feed.</param> /// <exception cref="ReplayAttackException">A replay attack was detected.</exception> /// <exception cref="UriFormatException"><see cref="Feed.Uri"/> is missing or does not match <paramref name="uri"/>.</exception> private void DetectAttacks(byte[] data, FeedUri uri, ValidSignature signature) { // Detect feed substitution var feed = XmlStorage.LoadXml <Feed>(new MemoryStream(data)); if (feed.Uri == null) { throw new UriFormatException(string.Format(Resources.FeedUriMissing, uri)); } if (feed.Uri != uri) { throw new UriFormatException(string.Format(Resources.FeedUriMismatch, feed.Uri, uri)); } // Detect replay attacks try { var oldSignature = _feedCache.GetSignatures(uri).OfType <ValidSignature>().FirstOrDefault(); if (oldSignature != null && signature.Timestamp < oldSignature.Timestamp) { throw new ReplayAttackException(uri, oldSignature.Timestamp, signature.Timestamp); } } catch (KeyNotFoundException) { // No existing feed to be replaced } }
private bool TrustNew(TrustDB trustDB, FeedUri uri, ValidSignature signature, Domain domain) { if (AskKeyApproval(uri, signature, domain)) { trustDB.TrustKey(signature.Fingerprint, domain); trustDB.Save(); return(true); } else { return(false); } }
private bool AskKeyApproval(FeedUri uri, ValidSignature signature, Domain domain) { bool goodVote; var keyInformation = GetKeyInformation(signature.Fingerprint, out goodVote) ?? Resources.NoKeyInfoServerData; // Automatically trust key for _new_ feeds if voted good by key server if (_config.AutoApproveKeys && goodVote && !_feedCache.Contains(uri)) { Log.Info("Auto-approving key for " + uri.ToStringRfc()); return(true); } // Otherwise ask user return(_handler.Ask( string.Format(Resources.AskKeyTrust, uri, signature.Fingerprint, keyInformation, domain), defaultAnswer: false, alternateMessage: Resources.UntrustedKeys)); }