Exemplo n.º 1
0
        /// <summary>
        /// Adds a Base64 signature to a feed or catalog stream.
        /// </summary>
        /// <param name="stream">The feed or catalog to sign.</param>
        /// <param name="secretKey">The secret key to use for signing the file.</param>
        /// <param name="passphrase">The passphrase to use to unlock the key.</param>
        /// <param name="openPgp">The OpenPGP-compatible system used to create signatures.</param>
        /// <exception cref="IOException">The OpenPGP implementation could not be launched or the file could not be read or written.</exception>
        /// <exception cref="WrongPassphraseException">Passphrase was incorrect.</exception>
        /// <remarks>
        /// The file is not parsed before signing; invalid XML files are signed as well.
        /// The existing file must end with a line break.
        /// Old signatures are not removed.
        /// </remarks>
        public static void SignFeed([NotNull] Stream stream, [NotNull] OpenPgpSecretKey secretKey, string passphrase, [NotNull] IOpenPgp openPgp)
        {
            #region Sanity checks
            if (stream == null)
            {
                throw new ArgumentNullException("stream");
            }
            if (secretKey == null)
            {
                throw new ArgumentNullException("secretKey");
            }
            if (openPgp == null)
            {
                throw new ArgumentNullException("openPgp");
            }
            #endregion

            // Calculate the signature in-memory
            string signature = openPgp.DetachSign(stream, secretKey.Fingerprint, passphrase);

            // Add the signature to the end of the file
            var writer = new StreamWriter(stream, encoding: Store.Feeds.FeedUtils.Encoding)
            {
                NewLine = "\n"
            };
            writer.Write(Store.Feeds.FeedUtils.SignatureBlockStart);
            writer.WriteLine(signature);
            writer.Write(Store.Feeds.FeedUtils.SignatureBlockEnd);
            writer.Flush();
        }
Exemplo n.º 2
0
    /// <summary>
    /// Adds a Base64 signature to a feed or catalog stream.
    /// </summary>
    /// <param name="stream">The feed or catalog to sign.</param>
    /// <param name="secretKey">The secret key to use for signing the file.</param>
    /// <param name="passphrase">The passphrase to use to unlock the key.</param>
    /// <param name="openPgp">The OpenPGP-compatible system used to create signatures.</param>
    /// <exception cref="IOException">The file could not be read or written.</exception>
    /// <exception cref="UnauthorizedAccessException">Read or write access to the file is not permitted.</exception>
    /// <exception cref="KeyNotFoundException">The specified <paramref name="secretKey"/> could not be found on the system.</exception>
    /// <exception cref="WrongPassphraseException"><paramref name="passphrase"/> was incorrect.</exception>
    /// <remarks>
    /// The file is not parsed before signing; invalid XML files are signed as well.
    /// The existing file must end with a line break.
    /// Old signatures are not removed.
    /// </remarks>
    public static void SignFeed(Stream stream, OpenPgpSecretKey secretKey, string?passphrase, IOpenPgp openPgp)
    {
        #region Sanity checks
        if (stream == null)
        {
            throw new ArgumentNullException(nameof(stream));
        }
        if (secretKey == null)
        {
            throw new ArgumentNullException(nameof(secretKey));
        }
        if (openPgp == null)
        {
            throw new ArgumentNullException(nameof(openPgp));
        }
        #endregion

        // Calculate the signature in-memory
        var signature = openPgp.Sign(stream.ReadAll(), secretKey, passphrase);

        // Add the signature to the end of the file
        var writer = new StreamWriter(stream, EncodingUtils.Utf8)
        {
            NewLine = "\n"
        };
        writer.Write(StoreFeedUtils.SignatureBlockStart);
        writer.WriteLine(Convert.ToBase64String(signature));
        writer.Write(StoreFeedUtils.SignatureBlockEnd);
        writer.Flush();
    }
Exemplo n.º 3
0
        /// <summary>
        /// Creates a new signed feed.
        /// </summary>
        /// <param name="feed">The wrapped <see cref="Feed"/>.</param>
        /// <param name="secretKey">The secret key used to sign the <see cref="Feed"/>; <c>null</c> for no signature.</param>
        public SignedFeed([NotNull] Feed feed, [CanBeNull] OpenPgpSecretKey secretKey = null)
        {
            #region Sanity checks
            if (feed == null) throw new ArgumentNullException(nameof(feed));
            #endregion

            Feed = feed;
            SecretKey = secretKey;
        }
Exemplo n.º 4
0
        /// <inheritdoc/>
        public string ExportKey(OpenPgpSecretKey secretKey)
        {
            #region Sanity checks
            if (secretKey == null) throw new ArgumentNullException("secretKey");
            #endregion

            return new CliControl(_homeDir).Execute("--batch", "--no-secmem-warning", "--armor", "--export", secretKey.KeyID)
                .Replace(Environment.NewLine, "\n") + "\n";
        }
Exemplo n.º 5
0
        /// <summary>
        /// Creates a new signed catalog.
        /// </summary>
        /// <param name="catalog">The wrapped <see cref="Catalog"/>.</param>
        /// <param name="secretKey">The secret key used to sign the <see cref="Catalog"/>; <c>null</c> for no signature.</param>
        public SignedCatalog([NotNull] Catalog catalog, [CanBeNull] OpenPgpSecretKey secretKey)
        {
            #region Sanity checks
            if (catalog == null) throw new ArgumentNullException(nameof(catalog));
            #endregion

            Catalog = catalog;
            SecretKey = secretKey;
        }
Exemplo n.º 6
0
        /// <summary>
        /// Creates a new signed catalog.
        /// </summary>
        /// <param name="catalog">The wrapped <see cref="Catalog"/>.</param>
        /// <param name="secretKey">The secret key used to sign the <see cref="Catalog"/>; <see langword="null"/> for no signature.</param>
        public SignedCatalog([NotNull] Catalog catalog, [CanBeNull] OpenPgpSecretKey secretKey)
        {
            #region Sanity checks
            if (catalog == null)
            {
                throw new ArgumentNullException("catalog");
            }
            #endregion

            Catalog   = catalog;
            SecretKey = secretKey;
        }
Exemplo n.º 7
0
        /// <summary>
        /// Creates a new signed feed.
        /// </summary>
        /// <param name="feed">The wrapped <see cref="Feed"/>.</param>
        /// <param name="secretKey">The secret key used to sign the <see cref="Feed"/>; <c>null</c> for no signature.</param>
        public SignedFeed([NotNull] Feed feed, [CanBeNull] OpenPgpSecretKey secretKey = null)
        {
            #region Sanity checks
            if (feed == null)
            {
                throw new ArgumentNullException(nameof(feed));
            }
            #endregion

            Feed      = feed;
            SecretKey = secretKey;
        }
Exemplo n.º 8
0
        /// <summary>
        /// Signs a number of <see cref="Feed"/>s with a single <see cref="OpenPgpSecretKey"/>.
        /// </summary>
        /// <param name="secretKey">The private key to use for signing the files.</param>
        /// <param name="passphrase">The passphrase to use to unlock the key.</param>
        /// <exception cref="IOException">The feed file could not be read or written.</exception>
        /// <exception cref="UnauthorizedAccessException">Read or write access to the feed file is not permitted.</exception>
        private void SignFiles(OpenPgpSecretKey secretKey, string passphrase)
        {
            var task = ForEachTask.Create("Signing feeds", _files, file =>
            {
                SignedFeed signedFeed;
                try
                {
                    signedFeed = SignedFeed.Load(file.FullName);
                }
                #region Error handling
                catch (UnauthorizedAccessException ex)
                {
                    // Wrap exception since only certain exception types are allowed
                    throw new IOException(ex.Message, ex);
                }
                catch (InvalidDataException ex)
                {
                    // Wrap exception since only certain exception types are allowed
                    throw new IOException(ex.Message + (ex.InnerException == null ? "" : Environment.NewLine + ex.InnerException.Message), ex);
                }
                #endregion

                signedFeed.SecretKey = secretKey;
                try
                {
                    signedFeed.Save(file.FullName, passphrase);
                }
                #region Error handling
                catch (UnauthorizedAccessException ex)
                {
                    // Wrap exception since only certain exception types are allowed
                    throw new IOException(ex.Message, ex);
                }
                catch (KeyNotFoundException ex)
                {
                    // Wrap exception since only certain exception types are allowed
                    throw new IOException(ex.Message, ex);
                }
                catch (WrongPassphraseException ex)
                {
                    // Wrap exception since only certain exception types are allowed
                    throw new IOException(ex.Message, ex);
                }
                #endregion
            });

            using (var handler = new DialogTaskHandler(this)) handler.RunTask(task);
            Msg.Inform(this, "Successfully signed files.", MsgSeverity.Info);
        }
Exemplo n.º 9
0
        public void TestDeployPublicKey()
        {
            using (var tempDir = new TemporaryDirectory("0install-unit-tests"))
            {
                var          secretKey   = new OpenPgpSecretKey("fingerprint", "key", "*****@*****.**", new DateTime(2000, 1, 1), OpenPgpAlgorithm.Rsa, 128);
                const string publicKey   = "public";
                var          openPgpMock = MockRepository.Create <IOpenPgp>();

                openPgpMock.Setup(x => x.GetPublicKey(secretKey.Fingerprint)).Returns(publicKey);
                FeedUtils.DeployPublicKey(tempDir.Path, secretKey, openPgpMock.Object);

                Assert.AreEqual(publicKey, File.ReadAllText(tempDir + Path.DirectorySeparatorChar + secretKey.KeyID + ".gpg"),
                                "Public key should be written to parallel file in directory");
            }
        }
Exemplo n.º 10
0
        public void TestDeployPublicKey()
        {
            using (var tempDir = new TemporaryDirectory("0install-unit-tests"))
            {
                const string publicKey = "public";
                var secretKey = new OpenPgpSecretKey(keyID: 123, fingerprint: new byte[] { 1, 2, 3 }, userID: "user");

                var openPgpMock = CreateMock<IOpenPgp>();
                openPgpMock.Setup(x => x.ExportKey(secretKey)).Returns(publicKey);
                openPgpMock.Object.DeployPublicKey(secretKey, tempDir.Path);

                File.ReadAllText(tempDir + Path.DirectorySeparatorChar + secretKey.FormatKeyID() + ".gpg")
                    .Should().Be(publicKey, because: "Public key should be written to parallel file in directory");
            }
        }
Exemplo n.º 11
0
        public void TestSignFeed()
        {
            using (var stream = new MemoryStream())
            {
                var          feed       = FeedTest.CreateTestFeed();
                const string passphrase = "passphrase123";
                var          signature  = new byte[] { 1, 2, 3 };
                var          secretKey  = new OpenPgpSecretKey(keyID: 123, fingerprint: new byte[] { 1, 2, 3 }, userID: "user");

                var openPgpMock = CreateMock <IOpenPgp>();
                openPgpMock.Setup(x => x.Sign(It.IsAny <byte[]>(), secretKey, passphrase))
                .Returns(signature);
                feed.SaveXml(stream);
                FeedUtils.SignFeed(stream, secretKey, passphrase, openPgpMock.Object);

                string signedFeed   = stream.ReadToString();
                string expectedFeed = feed.ToXmlString() + Store.Feeds.FeedUtils.SignatureBlockStart +
                                      Convert.ToBase64String(signature) + "\n" + Store.Feeds.FeedUtils.SignatureBlockEnd;
                signedFeed.Should().Be(expectedFeed, because: "Feed should remain unchanged except for appended XML signatre");
            }
        }
Exemplo n.º 12
0
        public void TestSignFeed()
        {
            using (var stream = new MemoryStream())
            {
                var feed = FeedTest.CreateTestFeed();
                const string passphrase = "passphrase123";
                var signature = new byte[] {1, 2, 3};
                var secretKey = new OpenPgpSecretKey(keyID: 123, fingerprint: new byte[] {1, 2, 3}, userID: "user");

                var openPgpMock = CreateMock<IOpenPgp>();
                openPgpMock.Setup(x => x.Sign(It.IsAny<byte[]>(), secretKey, passphrase))
                    .Returns(signature);
                feed.SaveXml(stream);
                FeedUtils.SignFeed(stream, secretKey, passphrase, openPgpMock.Object);

                string signedFeed = stream.ReadToString();
                string expectedFeed = feed.ToXmlString() + Store.Feeds.FeedUtils.SignatureBlockStart +
                                      Convert.ToBase64String(signature) + "\n" + Store.Feeds.FeedUtils.SignatureBlockEnd;
                signedFeed.Should().Be(expectedFeed, because: "Feed should remain unchanged except for appended XML signatre");
            }
        }
Exemplo n.º 13
0
    /// <inheritdoc/>
    public byte[] Sign(ArraySegment <byte> data, OpenPgpSecretKey secretKey, string?passphrase = null)
    {
        #region Sanity checks
        if (secretKey == null)
        {
            throw new ArgumentNullException(nameof(secretKey));
        }
        #endregion

        var pgpSecretKey = SecretBundle.GetSecretKey(secretKey.KeyID);
        if (pgpSecretKey == null)
        {
            throw new KeyNotFoundException("Specified OpenPGP key not found on system");
        }
        var pgpPrivateKey = GetPrivateKey(pgpSecretKey, passphrase);

        var signatureGenerator = new PgpSignatureGenerator(pgpSecretKey.PublicKey.Algorithm, HashAlgorithmTag.Sha1);
        signatureGenerator.InitSign(PgpSignature.BinaryDocument, pgpPrivateKey);
        signatureGenerator.Update(data.Array, data.Offset, data.Count);
        return(signatureGenerator.Generate().GetEncoded());
    }
Exemplo n.º 14
0
        /// <summary>
        /// Exports an OpenPGP public key to a key file.
        /// </summary>
        /// <param name="path">The directory to write the key file to.</param>
        /// <param name="secretKey">The secret key to get the public kyey for.</param>
        /// <param name="openPgp">The OpenPGP-compatible system used to create signatures.</param>
        /// <exception cref="IOException">The OpenPGP implementation could not be launched or the file could not be read or written.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to the directory is not permitted.</exception>
        public static void DeployPublicKey([NotNull] string path, [NotNull] OpenPgpSecretKey secretKey, [NotNull] IOpenPgp openPgp)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException("path");
            }
            if (secretKey == null)
            {
                throw new ArgumentNullException("secretKey");
            }
            if (openPgp == null)
            {
                throw new ArgumentNullException("openPgp");
            }
            #endregion

            File.WriteAllText(
                path: Path.Combine(path, secretKey.KeyID + ".gpg"),
                contents: openPgp.GetPublicKey(secretKey.Fingerprint),
                encoding: Encoding.ASCII);
        }
Exemplo n.º 15
0
        public void TestSignFeed()
        {
            using (var stream = new MemoryStream())
            {
                var          feed        = FeedTest.CreateTestFeed();
                var          secretKey   = new OpenPgpSecretKey("fingerprint", "key", "*****@*****.**", new DateTime(2000, 1, 1), OpenPgpAlgorithm.Rsa, 128);
                var          openPgpMock = MockRepository.Create <IOpenPgp>();
                const string passphrase  = "passphrase123";
                const string signature   = "iQEcB";

                openPgpMock.Setup(x => x.DetachSign(It.IsAny <Stream>(), secretKey.Fingerprint, passphrase))
                .Returns(signature);
                feed.SaveXml(stream);
                FeedUtils.SignFeed(stream, secretKey, passphrase, openPgpMock.Object);

                string signedFeed   = stream.ReadToString();
                string expectedFeed = feed.ToXmlString() + Store.Feeds.FeedUtils.SignatureBlockStart +
                                      signature + "\n" + Store.Feeds.FeedUtils.SignatureBlockEnd;
                Assert.AreEqual(expectedFeed, signedFeed,
                                "Feed should remain unchanged except for appended XML signatre");
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Signs a number of <see cref="Feed"/>s with a single <see cref="OpenPgpSecretKey"/>.
        /// </summary>
        /// <param name="secretKey">The private key to use for signing the files.</param>
        /// <param name="passphrase">The passphrase to use to unlock the key.</param>
        /// <exception cref="IOException">The feed file could not be read or written.</exception>
        /// <exception cref="UnauthorizedAccessException">Read or write access to the feed file is not permitted.</exception>
        private void SignFiles(OpenPgpSecretKey secretKey, string passphrase)
        {
            var task = new ForEachTask<FileInfo>("Signing feeds", _files, file =>
            {
                SignedFeed signedFeed;
                try
                {
                    signedFeed = SignedFeed.Load(file.FullName);
                }
                    #region Error handling
                catch (UnauthorizedAccessException ex)
                {
                    // Wrap exception since only certain exception types are allowed
                    throw new IOException(ex.Message, ex);
                }
                catch (InvalidDataException ex)
                {
                    // Wrap exception since only certain exception types are allowed
                    throw new IOException(ex.Message + (ex.InnerException == null ? "" : "\n" + ex.InnerException.Message), ex);
                }
                #endregion

                signedFeed.SecretKey = secretKey;
                try
                {
                    signedFeed.Save(file.FullName, passphrase);
                }
                    #region Error handling
                catch (UnauthorizedAccessException ex)
                {
                    // Wrap exception since only certain exception types are allowed
                    throw new IOException(ex.Message, ex);
                }
                catch (KeyNotFoundException ex)
                {
                    // Wrap exception since only certain exception types are allowed
                    throw new IOException(ex.Message, ex);
                }
                catch (WrongPassphraseException ex)
                {
                    // Wrap exception since only certain exception types are allowed
                    throw new IOException(ex.Message, ex);
                }
                #endregion
            });
            using (var handler = new GuiTaskHandler(this)) handler.RunTask(task);
            Msg.Inform(this, "Successfully signed files.", MsgSeverity.Info);
        }
Exemplo n.º 17
0
        /// <inheritdoc/>
        public byte[] Sign(byte[] data, OpenPgpSecretKey secretKey, string passphrase = null)
        {
            #region Sanity checks
            if (data == null) throw new ArgumentNullException("data");
            if (secretKey == null) throw new ArgumentNullException("secretKey");
            #endregion

            string output = new CliControl(_homeDir, data).Execute("--batch", "--no-secmem-warning", "--passphrase", passphrase ?? "", "--local-user", secretKey.KeyID, "--detach-sign", "--armor", "--output", "-", "-");
            string signatureBase64 = output
                .GetRightPartAtFirstOccurrence(Environment.NewLine + Environment.NewLine)
                .GetLeftPartAtLastOccurrence(Environment.NewLine + "=")
                .Replace(Environment.NewLine, "\n");
            return Convert.FromBase64String(signatureBase64);
        }