#include "system.h" #include #include #include #include #include #include #include "cliutils.h" #include "debug.h" enum modes { MODE_NONE = 0, MODE_ADDSIGN = (1 << 0), MODE_RESIGN = (1 << 1), MODE_DELSIGN = (1 << 2), MODE_DELFILESIGN = (1 << 3), }; static int mode = MODE_NONE; #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) static int fskpass = 0; static char * fileSigningKey = NULL; #endif #ifdef WITH_FSVERITY static char * fileSigningCert = NULL; static char * verityAlgorithm = NULL; #endif static struct rpmSignArgs sargs = {NULL, 0, 0}; static struct poptOption signOptsTable[] = { { "addsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_ADDSIGN, N_("sign package(s)"), NULL }, { "resign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_RESIGN, N_("sign package(s) (identical to --addsign)"), NULL }, { "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN, N_("delete package signatures"), NULL }, #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) { "delfilesign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELFILESIGN, N_("delete IMA and fsverity file signatures"), NULL }, #endif { "rpmv3", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &sargs.signflags, RPMSIGN_FLAG_RPMV3, N_("create rpm v3 header+payload signatures") }, #ifdef WITH_IMAEVM { "signfiles", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &sargs.signflags, RPMSIGN_FLAG_IMA, N_("sign package(s) files"), NULL}, #endif #ifdef WITH_FSVERITY { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &sargs.signflags, RPMSIGN_FLAG_FSVERITY, N_("generate fsverity signatures for package(s) files"), NULL}, { "verityalgo", '\0', POPT_ARG_STRING, &verityAlgorithm, 0, N_("algorithm to use for verity signatures, default sha256"), N_("") }, { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0, N_("use file signing cert "), N_("") }, #endif #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0, N_("use file signing key "), N_("") }, { "fskpass", '\0', POPT_ARG_NONE, &fskpass, 0, N_("prompt for file signing key password"), NULL}, #endif POPT_TABLEEND }; static struct poptOption optionsTable[] = { { NULL, '\0', POPT_ARG_INCLUDE_TABLE, signOptsTable, 0, N_("Signature options:"), NULL }, { NULL, '\0', POPT_ARG_INCLUDE_TABLE, rpmcliAllPoptTable, 0, N_("Common options for all rpm modes and executables:"), NULL }, POPT_AUTOALIAS POPT_AUTOHELP POPT_TABLEEND }; #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) static int flags_sign_files(int flags) { return (flags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY) ? 1 : 0); } static char *get_fskpass(void) { struct termios flags, tmp_flags; int passlen = 64; char *password = xmalloc(passlen); char *pwd = NULL; tcgetattr(fileno(stdin), &flags); tmp_flags = flags; tmp_flags.c_lflag &= ~ECHO; tmp_flags.c_lflag |= ECHONL; if (tcsetattr(fileno(stdin), TCSANOW, &tmp_flags) != 0) { perror("tcsetattr"); goto exit; } printf("PEM password: "); pwd = fgets(password, passlen, stdin); if (tcsetattr(fileno(stdin), TCSANOW, &flags) != 0) { perror("tcsetattr"); pwd = NULL; goto exit; } exit: if (pwd) pwd[strlen(pwd) - 1] = '\0'; /* remove newline */ else free(password); return pwd; } #endif /* TODO: permit overriding macro setup on the command line */ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) { int rc = EXIT_FAILURE; char * name = rpmExpand("%{?_gpg_name}", NULL); if (rstreq(name, "")) { fprintf(stderr, _("You must set \"%%_gpg_name\" in your macro file\n")); goto exit; } #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) if (fileSigningKey) { rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL); } #ifdef WITH_FSVERITY if (fileSigningCert) { rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL); } if (verityAlgorithm) { rpmPushMacro(NULL, "_verity_algorithm", NULL, verityAlgorithm, RMIL_GLOBAL); } #endif if (flags_sign_files(sargs->signflags)) { char *fileSigningKeyPassword = NULL; char *key = rpmExpand("%{?_file_signing_key}", NULL); if (rstreq(key, "")) { fprintf(stderr, _("You must set \"%%_file_signing_key\" in your macro file or on the command line with --fskpath\n")); goto exit; } if (fskpass) { fileSigningKeyPassword = get_fskpass(); } if (fileSigningKeyPassword) { rpmPushMacro(NULL, "_file_signing_key_password", NULL, fileSigningKeyPassword, RMIL_CMDLINE); memset(fileSigningKeyPassword, 0, strlen(fileSigningKeyPassword)); free(fileSigningKeyPassword); } free(key); } #endif const char *arg; rc = 0; while ((arg = poptGetArg(optCon)) != NULL) { if (rpmPkgSign(arg, sargs) < 0) rc++; } exit: free(name); return rc; } int main(int argc, char *argv[]) { int ec = EXIT_FAILURE; poptContext optCon = NULL; const char *arg; optCon = rpmcliInit(argc, argv, optionsTable); if (argc <= 1) { printUsage(optCon, stderr, 0); goto exit; } if (poptPeekArg(optCon) == NULL) { argerror(_("no arguments given")); } #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) if (fileSigningKey && !(flags_sign_files(sargs.signflags))) { argerror(_("--fskpath may only be specified when signing files")); } #endif switch (mode) { case MODE_ADDSIGN: case MODE_RESIGN: ec = doSign(optCon, &sargs); break; case MODE_DELSIGN: ec = 0; while ((arg = poptGetArg(optCon)) != NULL) { if (rpmPkgDelSign(arg, &sargs) < 0) ec++; } break; case MODE_DELFILESIGN: ec = 0; while ((arg = poptGetArg(optCon)) != NULL) { if (rpmPkgDelFileSign(arg, &sargs) < 0) ec++; } break; case MODE_NONE: printUsage(optCon, stderr, 0); break; default: argerror(_("only one major mode may be specified")); break; } exit: rpmcliFini(optCon); return RETVAL(ec); }