]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
measure: Add pcrpkey verb
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 7 Nov 2024 13:44:44 +0000 (14:44 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 7 Nov 2024 19:33:08 +0000 (20:33 +0100)
This verb writes a public key to stdout extracted from either a public key
path, from a certificate (path or provider) or from a private key (path,
engine, provider). We'll use this in ukify to get rid of the use of the
python cryptography module to convert a private key or certificate to a
public key.

man/systemd-measure.xml
src/measure/measure.c

index c7e5a5e9e2171822f55b5c11c3e8d5e877f9d923..5ca373f1814411705917181383645e92f60470c2 100644 (file)
 
         <xi:include href="version-info.xml" xpointer="v252"/></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><command>pcrpkey</command></term>
+
+        <listitem><para>This commands prints the public key either given with <option>--public-key=</option>,
+        or extracted from the certificate given with <option>--certificate=</option> or the private key given
+        with <option>--private-key=</option>.</para>
+
+        <xi:include href="version-info.xml" xpointer="v257"/></listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 979426c18fd2d913cdfc92fbc404acb0b441563b..ac294d28b36cc396118656ed88fa3bb1aaae5824 100644 (file)
@@ -77,6 +77,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "  status                 Show current PCR values\n"
                "  calculate              Calculate expected PCR values\n"
                "  sign                   Calculate and sign expected PCR values\n"
+               "  pcrpkey                Extract the PCR public key\n"
                "\n%3$sOptions:%4$s\n"
                "  -h --help              Show this help\n"
                "     --version           Print version\n"
@@ -1173,12 +1174,100 @@ static int verb_status(int argc, char *argv[], void *userdata) {
         return 0;
 }
 
+static int verb_pcrpkey(int argc, char *argv[], void *userdata) {
+        _cleanup_(EVP_PKEY_freep) EVP_PKEY *public_key = NULL;
+        int r;
+
+        if (arg_public_key) {
+                _cleanup_fclose_ FILE *public_keyf = NULL;
+
+                public_keyf = fopen(arg_public_key, "re");
+                if (!public_keyf)
+                        return log_error_errno(errno, "Failed to open public key file '%s': %m", arg_public_key);
+
+                public_key = PEM_read_PUBKEY(public_keyf, NULL, NULL, NULL);
+                if (!public_key)
+                        return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to parse public key '%s'.", arg_public_key);
+
+        } else if (arg_certificate) {
+                _cleanup_(X509_freep) X509 *certificate = NULL;
+
+                if (arg_certificate_source_type == OPENSSL_CERTIFICATE_SOURCE_FILE) {
+                        r = parse_path_argument(arg_certificate, /*suppress_root=*/ false, &arg_certificate);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = openssl_load_x509_certificate(
+                                arg_certificate_source_type,
+                                arg_certificate_source,
+                                arg_certificate,
+                                &certificate);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to load X.509 certificate from %s: %m", arg_certificate);
+
+                public_key = X509_get_pubkey(certificate);
+                if (!public_key)
+                        return log_error_errno(
+                                        SYNTHETIC_ERRNO(EIO),
+                                        "Failed to extract public key from certificate %s.",
+                                        arg_certificate);
+
+        } else if (arg_private_key) {
+                _cleanup_(openssl_ask_password_ui_freep) OpenSSLAskPasswordUI *ui = NULL;
+                _cleanup_(EVP_PKEY_freep) EVP_PKEY *private_key = NULL;
+
+                if (arg_private_key_source_type == OPENSSL_KEY_SOURCE_FILE) {
+                        r = parse_path_argument(arg_private_key, /* suppress_root= */ false, &arg_private_key);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse private key path %s: %m", arg_private_key);
+                }
+
+                r = openssl_load_private_key(
+                                arg_private_key_source_type,
+                                arg_private_key_source,
+                                arg_private_key,
+                                &(AskPasswordRequest) {
+                                        .id = "measure-private-key-pin",
+                                        .keyring = arg_private_key,
+                                        .credential = "measure.private-key-pin",
+                                },
+                                &private_key,
+                                &ui);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to load private key from %s: %m", arg_private_key);
+
+                _cleanup_(memstream_done) MemStream m = {};
+                FILE *tf = memstream_init(&m);
+                if (!tf)
+                        return log_oom();
+
+                if (i2d_PUBKEY_fp(tf, private_key) != 1)
+                        return log_error_errno(SYNTHETIC_ERRNO(EIO),
+                                               "Failed to extract public key from private key file '%s'.", arg_private_key);
+
+                fflush(tf);
+                rewind(tf);
+
+                if (!d2i_PUBKEY_fp(tf, &public_key))
+                        return log_error_errno(SYNTHETIC_ERRNO(EIO),
+                                               "Failed to parse extracted public key of private key file '%s'.", arg_private_key);
+        } else
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "One of --public-key=, --certificate=, or --private-key= must be specified");
+
+        if (PEM_write_PUBKEY(stdout, public_key) == 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to write public key to stdout");
+
+        return 0;
+}
+
 static int measure_main(int argc, char *argv[]) {
         static const Verb verbs[] = {
                 { "help",      VERB_ANY, VERB_ANY, 0,            help           },
                 { "status",    VERB_ANY, 1,        VERB_DEFAULT, verb_status    },
                 { "calculate", VERB_ANY, 1,        0,            verb_calculate },
                 { "sign",      VERB_ANY, 1,        0,            verb_sign      },
+                { "pcrpkey",   VERB_ANY, 1,        0,            verb_pcrpkey   },
                 {}
         };