Lift the signature generation in all its g(l)ory to rpmgensig.c
authorPanu Matilainen <pmatilai@redhat.com>
Wed, 29 Sep 2010 08:27:26 +0000 (11:27 +0300)
committerPanu Matilainen <pmatilai@redhat.com>
Wed, 29 Sep 2010 08:27:26 +0000 (11:27 +0300)
- signature.c is now entirely free of all actual signing activities,
  which requires stuff that like gpg that nothing else needs.

lib/rpmgensig.c
lib/signature.c

index 75cd24f..4bc22ca 100644 (file)
@@ -5,6 +5,10 @@
 
 #include "system.h"
 
+#include <errno.h>
+#include <sys/wait.h>
+#include <popt.h>
+
 #include <rpm/rpmlib.h>                        /* RPMSIGTAG & related */
 #include <rpm/rpmpgp.h>
 #include <rpm/rpmcli.h>
 
 #include "debug.h"
 
+#if !defined(__GLIBC__) && !defined(__APPLE__)
+char ** environ = NULL;
+#endif
+
 static int closeFile(FD_t *fdp)
 {
     if (fdp == NULL || *fdp == NULL)
@@ -98,6 +106,254 @@ exit:
     return rc;
 }
 
+/*
+ * NSS doesn't support everything GPG does. Basic tests to see if the 
+ * generated signature is something we can use.
+ */
+static int validatePGPSig(pgpDigParams sigp)
+{
+    pgpPubkeyAlgo pa = sigp->pubkey_algo;
+    /* TODO: query from the implementation instead of hardwiring here */
+    if (pa != PGPPUBKEYALGO_DSA && pa != PGPPUBKEYALGO_RSA) {
+       rpmlog(RPMLOG_ERR, _("Unsupported PGP pubkey algorithm %d\n"),
+               sigp->pubkey_algo);
+       return 1;
+    }
+
+    if (rpmDigestLength(sigp->hash_algo) == 0) {
+       rpmlog(RPMLOG_ERR, _("Unsupported PGP hash algorithm %d\n"),
+              sigp->hash_algo);
+       return 1;
+    }
+
+    return 0;
+}
+
+/**
+ * Generate GPG signature(s) for a header+payload file.
+ * @param file         header+payload file name
+ * @retval *sigTagp    signature tag
+ * @retval *pktp       signature packet(s)
+ * @retval *pktlenp    signature packet(s) length
+ * @param passPhrase   private key pass phrase
+ * @return             0 on success, 1 on failure
+ */
+static int makeGPGSignature(const char * file, rpmSigTag * sigTagp,
+               uint8_t ** pktp, size_t * pktlenp,
+               const char * passPhrase)
+{
+    char * sigfile = NULL;
+    int pid, status;
+    int inpipe[2];
+    FILE * fpipe;
+    struct stat st;
+    const char * cmd;
+    char *const *av;
+    pgpDig dig = NULL;
+    pgpDigParams sigp = NULL;
+    int rc = 1; /* assume failure */
+
+    rasprintf(&sigfile, "%s.sig", file);
+
+    addMacro(NULL, "__plaintext_filename", NULL, file, -1);
+    addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
+
+    inpipe[0] = inpipe[1] = 0;
+    if (pipe(inpipe) < 0) {
+       rpmlog(RPMLOG_ERR, _("Couldn't create pipe for signing: %m"));
+       goto exit;
+    }
+
+    if (!(pid = fork())) {
+       const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
+
+       (void) dup2(inpipe[0], 3);
+       (void) close(inpipe[1]);
+
+       if (gpg_path && *gpg_path != '\0')
+           (void) setenv("GNUPGHOME", gpg_path, 1);
+       (void) setenv("LC_ALL", "C", 1);
+
+       unsetenv("MALLOC_CHECK_");
+       cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
+       rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
+       if (!rc)
+           rc = execve(av[0], av+1, environ);
+
+       rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg",
+                       strerror(errno));
+       _exit(EXIT_FAILURE);
+    }
+
+    delMacro(NULL, "__plaintext_filename");
+    delMacro(NULL, "__signature_filename");
+
+    fpipe = fdopen(inpipe[1], "w");
+    (void) close(inpipe[0]);
+    if (fpipe) {
+       fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : ""));
+       (void) fclose(fpipe);
+    }
+
+    (void) waitpid(pid, &status, 0);
+    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+       rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status));
+       goto exit;
+    }
+
+    if (stat(sigfile, &st)) {
+       /* GPG failed to write signature */
+       rpmlog(RPMLOG_ERR, _("gpg failed to write signature\n"));
+       goto exit;
+    }
+
+    *pktlenp = st.st_size;
+    rpmlog(RPMLOG_DEBUG, "GPG sig size: %zd\n", *pktlenp);
+    *pktp = xmalloc(*pktlenp);
+
+    {  FD_t fd;
+
+       rc = 0;
+       fd = Fopen(sigfile, "r.ufdio");
+       if (fd != NULL && !Ferror(fd)) {
+           rc = Fread(*pktp, sizeof(**pktp), *pktlenp, fd);
+           (void) Fclose(fd);
+       }
+       if (rc != *pktlenp) {
+           *pktp = _free(*pktp);
+           rpmlog(RPMLOG_ERR, _("unable to read the signature\n"));
+           goto exit;
+       }
+    }
+
+    rpmlog(RPMLOG_DEBUG, "Got %zd bytes of GPG sig\n", *pktlenp);
+
+    /* Parse the signature, change signature tag as appropriate. */
+    dig = pgpNewDig();
+
+    (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
+    sigp = &dig->signature;
+
+    switch (*sigTagp) {
+    case RPMSIGTAG_GPG:
+       /* XXX check MD5 hash too? */
+       if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA)
+           *sigTagp = RPMSIGTAG_PGP;
+       break;
+    case RPMSIGTAG_PGP5:       /* XXX legacy */
+    case RPMSIGTAG_PGP:
+       if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA)
+           *sigTagp = RPMSIGTAG_GPG;
+       break;
+    case RPMSIGTAG_DSA:
+       /* XXX check MD5 hash too? */
+       if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA)
+           *sigTagp = RPMSIGTAG_RSA;
+       break;
+    case RPMSIGTAG_RSA:
+       if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA)
+           *sigTagp = RPMSIGTAG_DSA;
+       break;
+    default:
+       break;
+    }
+
+    rc = validatePGPSig(sigp);
+    dig = pgpFreeDig(dig);
+
+exit:
+    (void) unlink(sigfile);
+    free(sigfile);
+
+    return rc;
+}
+
+/**
+ * Generate header only signature(s) from a header+payload file.
+ * @param sigh         signature header
+ * @param file         header+payload file name
+ * @param sigTag       type of signature(s) to add
+ * @param passPhrase   private key pass phrase
+ * @return             0 on success, -1 on failure
+ */
+static int makeHDRSignature(Header sigh, const char * file, rpmSigTag sigTag,
+               const char * passPhrase)
+{
+    Header h = NULL;
+    FD_t fd = NULL;
+    uint8_t * pkt = NULL;
+    size_t pktlen;
+    char * fn = NULL;
+    int ret = -1;      /* assume failure. */
+
+    switch (sigTag) {
+    case RPMSIGTAG_DSA:
+    case RPMSIGTAG_RSA:
+       fd = Fopen(file, "r.fdio");
+       if (fd == NULL || Ferror(fd))
+           goto exit;
+       h = headerRead(fd, HEADER_MAGIC_YES);
+       if (h == NULL)
+           goto exit;
+       (void) Fclose(fd);
+       fd = rpmMkTempFile(NULL, &fn);
+       if (fd == NULL || Ferror(fd))
+           goto exit;
+       if (headerWrite(fd, h, HEADER_MAGIC_YES))
+           goto exit;
+       (void) Fclose(fd);      fd = NULL;
+       if (makeGPGSignature(fn, &sigTag, &pkt, &pktlen, passPhrase)
+        || !sighdrPut(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
+           goto exit;
+       ret = 0;
+       break;
+    default:
+       goto exit;
+       break;
+    }
+
+exit:
+    if (fn) {
+       (void) unlink(fn);
+       free(fn);
+    }
+    free(pkt);
+    h = headerFree(h);
+    if (fd != NULL) (void) Fclose(fd);
+    return ret;
+}
+
+int rpmGenSignature(Header sigh, const char * file, rpmSigTag sigTag,
+               const char * passPhrase)
+{
+    uint8_t * pkt = NULL;
+    size_t pktlen;
+    int ret = -1;      /* assume failure. */
+
+    switch (sigTag) {
+    case RPMSIGTAG_PGP5:       /* XXX legacy */
+    case RPMSIGTAG_PGP:
+    case RPMSIGTAG_GPG: {
+       rpmSigTag hdrtag;
+       if (makeGPGSignature(file, &sigTag, &pkt, &pktlen, passPhrase)
+        || !sighdrPut(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
+           break;
+       /* XXX Piggyback a header-only DSA/RSA signature as well. */
+       hdrtag = (sigTag == RPMSIGTAG_GPG) ?  RPMSIGTAG_DSA : RPMSIGTAG_RSA;
+       ret = makeHDRSignature(sigh, file, hdrtag, passPhrase);
+       } break;
+    case RPMSIGTAG_RSA:
+    case RPMSIGTAG_DSA:
+       ret = makeHDRSignature(sigh, file, sigTag, passPhrase);
+       break;
+    default:
+       break;
+    }
+    free(pkt);
+
+    return ret;
+}
+
 /**
  * Retrieve signature from header tag
  * @param sigh         signature header
index ef5ecd6..d38cf35 100644 (file)
@@ -4,13 +4,9 @@
 
 #include "system.h"
 
-#include <errno.h>
 #include <inttypes.h>
-#include <sys/wait.h>
-#include <popt.h>
 
 #include <rpm/rpmtypes.h>
-#include <rpm/rpmmacro.h>      /* XXX for rpmExpand() */
 #include <rpm/rpmstring.h>
 #include <rpm/rpmfileutil.h>
 #include <rpm/rpmlog.h>
 
 #include "debug.h"
 
-#if !defined(__GLIBC__) && !defined(__APPLE__)
-char ** environ = NULL;
-#endif
-
 /**
  * Print package size.
  * @todo rpmio: use fdSize rather than fstat(2) to get file size.
@@ -271,254 +263,6 @@ Header rpmFreeSignature(Header sigh)
     return headerFree(sigh);
 }
 
-/*
- * NSS doesn't support everything GPG does. Basic tests to see if the 
- * generated signature is something we can use.
- */
-static int validatePGPSig(pgpDigParams sigp)
-{
-    pgpPubkeyAlgo pa = sigp->pubkey_algo;
-    /* TODO: query from the implementation instead of hardwiring here */
-    if (pa != PGPPUBKEYALGO_DSA && pa != PGPPUBKEYALGO_RSA) {
-       rpmlog(RPMLOG_ERR, _("Unsupported PGP pubkey algorithm %d\n"),
-               sigp->pubkey_algo);
-       return 1;
-    }
-
-    if (rpmDigestLength(sigp->hash_algo) == 0) {
-       rpmlog(RPMLOG_ERR, _("Unsupported PGP hash algorithm %d\n"),
-              sigp->hash_algo);
-       return 1;
-    }
-
-    return 0;
-}
-
-/**
- * Generate GPG signature(s) for a header+payload file.
- * @param file         header+payload file name
- * @retval *sigTagp    signature tag
- * @retval *pktp       signature packet(s)
- * @retval *pktlenp    signature packet(s) length
- * @param passPhrase   private key pass phrase
- * @return             0 on success, 1 on failure
- */
-static int makeGPGSignature(const char * file, rpmSigTag * sigTagp,
-               uint8_t ** pktp, size_t * pktlenp,
-               const char * passPhrase)
-{
-    char * sigfile = NULL;
-    int pid, status;
-    int inpipe[2];
-    FILE * fpipe;
-    struct stat st;
-    const char * cmd;
-    char *const *av;
-    pgpDig dig = NULL;
-    pgpDigParams sigp = NULL;
-    int rc = 1; /* assume failure */
-
-    rasprintf(&sigfile, "%s.sig", file);
-
-    addMacro(NULL, "__plaintext_filename", NULL, file, -1);
-    addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
-
-    inpipe[0] = inpipe[1] = 0;
-    if (pipe(inpipe) < 0) {
-       rpmlog(RPMLOG_ERR, _("Couldn't create pipe for signing: %m"));
-       goto exit;
-    }
-
-    if (!(pid = fork())) {
-       const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
-
-       (void) dup2(inpipe[0], 3);
-       (void) close(inpipe[1]);
-
-       if (gpg_path && *gpg_path != '\0')
-           (void) setenv("GNUPGHOME", gpg_path, 1);
-       (void) setenv("LC_ALL", "C", 1);
-
-       unsetenv("MALLOC_CHECK_");
-       cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
-       rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
-       if (!rc)
-           rc = execve(av[0], av+1, environ);
-
-       rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg",
-                       strerror(errno));
-       _exit(EXIT_FAILURE);
-    }
-
-    delMacro(NULL, "__plaintext_filename");
-    delMacro(NULL, "__signature_filename");
-
-    fpipe = fdopen(inpipe[1], "w");
-    (void) close(inpipe[0]);
-    if (fpipe) {
-       fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : ""));
-       (void) fclose(fpipe);
-    }
-
-    (void) waitpid(pid, &status, 0);
-    if (!WIFEXITED(status) || WEXITSTATUS(status)) {
-       rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status));
-       goto exit;
-    }
-
-    if (stat(sigfile, &st)) {
-       /* GPG failed to write signature */
-       rpmlog(RPMLOG_ERR, _("gpg failed to write signature\n"));
-       goto exit;
-    }
-
-    *pktlenp = st.st_size;
-    rpmlog(RPMLOG_DEBUG, "GPG sig size: %zd\n", *pktlenp);
-    *pktp = xmalloc(*pktlenp);
-
-    {  FD_t fd;
-
-       rc = 0;
-       fd = Fopen(sigfile, "r.ufdio");
-       if (fd != NULL && !Ferror(fd)) {
-           rc = Fread(*pktp, sizeof(**pktp), *pktlenp, fd);
-           (void) Fclose(fd);
-       }
-       if (rc != *pktlenp) {
-           *pktp = _free(*pktp);
-           rpmlog(RPMLOG_ERR, _("unable to read the signature\n"));
-           goto exit;
-       }
-    }
-
-    rpmlog(RPMLOG_DEBUG, "Got %zd bytes of GPG sig\n", *pktlenp);
-
-    /* Parse the signature, change signature tag as appropriate. */
-    dig = pgpNewDig();
-
-    (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
-    sigp = &dig->signature;
-
-    switch (*sigTagp) {
-    case RPMSIGTAG_GPG:
-       /* XXX check MD5 hash too? */
-       if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA)
-           *sigTagp = RPMSIGTAG_PGP;
-       break;
-    case RPMSIGTAG_PGP5:       /* XXX legacy */
-    case RPMSIGTAG_PGP:
-       if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA)
-           *sigTagp = RPMSIGTAG_GPG;
-       break;
-    case RPMSIGTAG_DSA:
-       /* XXX check MD5 hash too? */
-       if (sigp->pubkey_algo == PGPPUBKEYALGO_RSA)
-           *sigTagp = RPMSIGTAG_RSA;
-       break;
-    case RPMSIGTAG_RSA:
-       if (sigp->pubkey_algo == PGPPUBKEYALGO_DSA)
-           *sigTagp = RPMSIGTAG_DSA;
-       break;
-    default:
-       break;
-    }
-
-    rc = validatePGPSig(sigp);
-    dig = pgpFreeDig(dig);
-
-exit:
-    (void) unlink(sigfile);
-    free(sigfile);
-
-    return rc;
-}
-
-/**
- * Generate header only signature(s) from a header+payload file.
- * @param sigh         signature header
- * @param file         header+payload file name
- * @param sigTag       type of signature(s) to add
- * @param passPhrase   private key pass phrase
- * @return             0 on success, -1 on failure
- */
-static int makeHDRSignature(Header sigh, const char * file, rpmSigTag sigTag,
-               const char * passPhrase)
-{
-    Header h = NULL;
-    FD_t fd = NULL;
-    uint8_t * pkt = NULL;
-    size_t pktlen;
-    char * fn = NULL;
-    int ret = -1;      /* assume failure. */
-
-    switch (sigTag) {
-    case RPMSIGTAG_DSA:
-    case RPMSIGTAG_RSA:
-       fd = Fopen(file, "r.fdio");
-       if (fd == NULL || Ferror(fd))
-           goto exit;
-       h = headerRead(fd, HEADER_MAGIC_YES);
-       if (h == NULL)
-           goto exit;
-       (void) Fclose(fd);
-       fd = rpmMkTempFile(NULL, &fn);
-       if (fd == NULL || Ferror(fd))
-           goto exit;
-       if (headerWrite(fd, h, HEADER_MAGIC_YES))
-           goto exit;
-       (void) Fclose(fd);      fd = NULL;
-       if (makeGPGSignature(fn, &sigTag, &pkt, &pktlen, passPhrase)
-        || !sighdrPut(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
-           goto exit;
-       ret = 0;
-       break;
-    default:
-       goto exit;
-       break;
-    }
-
-exit:
-    if (fn) {
-       (void) unlink(fn);
-       free(fn);
-    }
-    free(pkt);
-    h = headerFree(h);
-    if (fd != NULL) (void) Fclose(fd);
-    return ret;
-}
-
-int rpmGenSignature(Header sigh, const char * file, rpmSigTag sigTag,
-               const char * passPhrase)
-{
-    uint8_t * pkt = NULL;
-    size_t pktlen;
-    int ret = -1;      /* assume failure. */
-
-    switch (sigTag) {
-    case RPMSIGTAG_PGP5:       /* XXX legacy */
-    case RPMSIGTAG_PGP:
-    case RPMSIGTAG_GPG: {
-       rpmSigTag hdrtag;
-       if (makeGPGSignature(file, &sigTag, &pkt, &pktlen, passPhrase)
-        || !sighdrPut(sigh, sigTag, RPM_BIN_TYPE, pkt, pktlen))
-           break;
-       /* XXX Piggyback a header-only DSA/RSA signature as well. */
-       hdrtag = (sigTag == RPMSIGTAG_GPG) ?  RPMSIGTAG_DSA : RPMSIGTAG_RSA;
-       ret = makeHDRSignature(sigh, file, hdrtag, passPhrase);
-       } break;
-    case RPMSIGTAG_RSA:
-    case RPMSIGTAG_DSA:
-       ret = makeHDRSignature(sigh, file, sigTag, passPhrase);
-       break;
-    default:
-       break;
-    }
-    free(pkt);
-
-    return ret;
-}
-
 static int makeHDRDigest(Header sigh, const char * file, rpmSigTag sigTag)
 {
     Header h = NULL;