commit: Add `--sign-from-file`
authorColin Walters <walters@verbum.org>
Fri, 14 Jul 2023 23:20:45 +0000 (19:20 -0400)
committerColin Walters <walters@verbum.org>
Sat, 15 Jul 2023 13:50:40 +0000 (09:50 -0400)
Passing the private key via a direct command line argument
is just a bad idea because it's highly likely to get logged
or appear in `ps`.
Spotted in review of work for composefs signatures.

man/ostree-commit.xml
src/ostree/ot-builtin-commit.c
tests/test-signed-pull.sh

index e9640643b0e53e6d376b1bbb3767557aed5887e3..3e22b1723fdd3ecfaf948f6a81e7a0bb58708041 100644 (file)
@@ -311,10 +311,22 @@ License along with this library. If not, see <https://www.gnu.org/licenses/>.
                 </para></listitem>
 
             </varlistentry>
+
+            <varlistentry>
+                <term><option>--sign-from-file</option>="PATH"</term>
+                <listitem><para>
+                        This will read a key (corresponding to the provided <literal>--sign-type</literal> from the provided path.  The key should be base64 encoded.
+                </para></listitem>
+            </varlistentry>
+
             <varlistentry>
                 <term><option>--sign</option>="KEY-ID"</term>
                 <listitem><para>
-                        There <literal>KEY-ID</literal> is:
+                        In new code, avoid using this because passing private keys via command line arguments
+                        are prone to leakage in logs and process listings.
+                        </para>
+                        <para>
+                        The <literal>KEY-ID</literal> is:
                         <variablelist>
                             <varlistentry>
                                 <term><option>for ed25519:</option></term>
index 760496715afd4c20a8746a1be3b5bd075cda4630..fad6de619e63addc96a0a243396ecf7c51062174 100644 (file)
@@ -68,6 +68,7 @@ static char **opt_gpg_key_ids;
 static char *opt_gpg_homedir;
 #endif
 static char **opt_key_ids;
+static char **opt_key_files;
 static char *opt_sign_name;
 static gboolean opt_generate_sizes;
 static gboolean opt_composefs_metadata;
@@ -158,6 +159,8 @@ static GOptionEntry options[] = {
     "GPG Homedir to use when looking for keyrings", "HOMEDIR" },
 #endif
   { "sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_ids, "Sign the commit with", "KEY_ID" },
+  { "sign-from-file", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_key_files,
+    "Sign the commit with key from the provided file", "PATH" },
   { "sign-type", 0, 0, G_OPTION_ARG_STRING, &opt_sign_name,
     "Signature type to use (defaults to 'ed25519')", "NAME" },
   { "generate-sizes", 0, 0, G_OPTION_ARG_NONE, &opt_generate_sizes,
@@ -918,31 +921,47 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
             goto out;
         }
 
-      if (opt_key_ids)
+      const char *sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519;
+      if (opt_key_files || opt_key_ids)
         {
-          /* Initialize crypto system */
-          opt_sign_name = opt_sign_name ?: OSTREE_SIGN_NAME_ED25519;
-
-          sign = ostree_sign_get_by_name (opt_sign_name, error);
+          sign = ostree_sign_get_by_name (sign_name, error);
           if (sign == NULL)
             goto out;
+        }
 
-          char **iter;
-
-          for (iter = opt_key_ids; iter && *iter; iter++)
-            {
-              const char *keyid = *iter;
-              g_autoptr (GVariant) secret_key = NULL;
+      // Loop over the inline private keys on the command line; this should be
+      // avoided in new code in favor of --sign-from-file.
+      for (char **iter = opt_key_ids; iter && *iter; iter++)
+        {
+          const char *keyid = *iter;
+          g_autoptr (GVariant) secret_key = g_variant_new_string (keyid);
+          g_assert (sign);
+          if (!ostree_sign_set_sk (sign, secret_key, error))
+            goto out;
 
-              secret_key = g_variant_new_string (keyid);
-              if (!ostree_sign_set_sk (sign, secret_key, error))
-                goto out;
+          if (!ostree_sign_commit (sign, repo, commit_checksum, cancellable, error))
+            goto out;
+        }
 
-              if (!ostree_sign_commit (sign, repo, commit_checksum, cancellable, error))
-                goto out;
+      // Load each base64 encoded private key in a file and sign with it.
+      for (char **iter = opt_key_files; iter && *iter; iter++)
+        {
+          const char *path = *iter;
+          g_autofree char *b64key
+              = glnx_file_get_contents_utf8_at (AT_FDCWD, path, NULL, NULL, error);
+          if (!b64key)
+            {
+              g_prefix_error (error, "Reading %s", path);
+              goto out;
             }
-        }
+          g_autoptr (GVariant) secret_key = g_variant_new_string (b64key);
+          g_assert (sign);
+          if (!ostree_sign_set_sk (sign, secret_key, error))
+            goto out;
 
+          if (!ostree_sign_commit (sign, repo, commit_checksum, cancellable, error))
+            goto out;
+        }
 #ifndef OSTREE_DISABLE_GPGME
       if (opt_gpg_key_ids)
         {
index 372287f6b369ca45c148e9931531ce8dafea339f..7a42357b8b2c1e376b2d9ce2505f5475fe126b16 100755 (executable)
@@ -157,8 +157,9 @@ gen_ed25519_keys
 PUBLIC=${ED25519PUBLIC}
 SEED=${ED25519SEED}
 SECRET=${ED25519SECRET}
-
-COMMIT_ARGS="--sign=${SECRET} --sign-type=ed25519"
+# Other tests verify --sign, we will verify --sign-from-file here
+echo ${ED25519SECRET} > key
+COMMIT_ARGS="--sign-from-file=key --sign-type=ed25519"
 
 repo_init --set=sign-verify=true
 ${CMD_PREFIX} ostree --repo=repo config set 'remote "origin"'.verification-ed25519-key "${PUBLIC}"