rpm  5.2.1
rpmdb/signature.c
Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmio.h>
00008 #include <rpmurl.h>
00009 #include <rpmcb.h>      /* XXX rpmIsVerbose() */
00010 #define _RPMPGP_INTERNAL
00011 #include <rpmpgp.h>
00012 #include <rpmmacro.h>   /* XXX for rpmGetPath() */
00013 #include <rpmku.h>
00014 
00015 #include <rpmtag.h>
00016 #include "rpmdb.h"
00017 #include <pkgio.h>      /* XXX expects <rpmts.h> */
00018 #include "legacy.h"     /* XXX for dodogest() */
00019 #include "signature.h"
00020 
00021 #include "debug.h"
00022 
00023 /*@access FD_t@*/               /* XXX ufdio->read arg1 is void ptr */
00024 /*@access Header@*/             /* XXX compared with NULL */
00025 /*@access DIGEST_CTX@*/         /* XXX compared with NULL */
00026 /*@access pgpDig@*/
00027 /*@access pgpDigParams@*/
00028 
00029 int rpmTempFile(const char * prefix, const char ** fnptr, void * fdptr)
00030 {
00031     const char * tpmacro = "%{?_tmppath}%{!?_tmppath:/var/tmp/}";
00032     const char * tempfn = NULL;
00033     const char * tfn = NULL;
00034     static int _initialized = 0;
00035     int temput;
00036     FD_t fd = NULL;
00037     unsigned int ran;
00038 
00039     if (!prefix) prefix = "";
00040 
00041     /* Create the temp directory if it doesn't already exist. */
00042     if (!_initialized) {
00043         _initialized = 1;
00044         tempfn = rpmGenPath(prefix, tpmacro, NULL);
00045         if (rpmioMkpath(tempfn, 0755, (uid_t) -1, (gid_t) -1))
00046             goto errxit;
00047     }
00048 
00049     /* XXX should probably use mkstemp here */
00050     ran = (unsigned) time(NULL);
00051     srand(ran);
00052     ran = rand() % 100000;
00053 
00054     /* maybe this should use link/stat? */
00055 
00056     do {
00057         char tfnbuf[64];
00058 #ifndef NOTYET
00059         sprintf(tfnbuf, "rpm-tmp.%u", ran++);
00060         tempfn = _free(tempfn);
00061         tempfn = rpmGenPath(prefix, tpmacro, tfnbuf);
00062 #else
00063         strcpy(tfnbuf, "rpm-tmp.XXXXXX");
00064         tempfn = _free(tempfn);
00065         tempfn = rpmGenPath(prefix, tpmacro, mktemp(tfnbuf));
00066 #endif
00067 
00068         temput = urlPath(tempfn, &tfn);
00069         if (*tfn == '\0') goto errxit;
00070 
00071         switch (temput) {
00072         case URL_IS_DASH:
00073         case URL_IS_HKP:
00074             goto errxit;
00075             /*@notreached@*/ /*@switchbreak@*/ break;
00076         case URL_IS_HTTPS:
00077         case URL_IS_HTTP:
00078         case URL_IS_FTP:
00079         default:
00080             /*@switchbreak@*/ break;
00081         }
00082 
00083         fd = Fopen(tempfn, "w+x.fdio");
00084         /* XXX FIXME: errno may not be correct for ufdio */
00085     } while ((fd == NULL || Ferror(fd)) && errno == EEXIST);
00086 
00087     if (fd == NULL || Ferror(fd)) {
00088         rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tempfn);
00089         goto errxit;
00090     }
00091 
00092     switch(temput) {
00093     case URL_IS_PATH:
00094     case URL_IS_UNKNOWN:
00095       { struct stat sb, sb2;
00096         if (!stat(tfn, &sb) && S_ISLNK(sb.st_mode)) {
00097             rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
00098             goto errxit;
00099         }
00100 
00101         if (sb.st_nlink != 1) {
00102             rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
00103             goto errxit;
00104         }
00105 
00106         if (fstat(Fileno(fd), &sb2) == 0) {
00107             if (sb2.st_ino != sb.st_ino || sb2.st_dev != sb.st_dev) {
00108                 rpmlog(RPMLOG_ERR, _("error creating temporary file %s\n"), tfn);
00109                 goto errxit;
00110             }
00111         }
00112       } break;
00113     default:
00114         break;
00115     }
00116 
00117     if (fnptr)
00118         *fnptr = tempfn;
00119     else 
00120         tempfn = _free(tempfn);
00121     if (fdptr)
00122         *(FD_t *)fdptr = fd;
00123 
00124     return 0;
00125 
00126 errxit:
00127     tempfn = _free(tempfn);
00128     if (fnptr)
00129         *fnptr = NULL;
00130     /*@-usereleased@*/
00131     if (fd != NULL) (void) Fclose(fd);
00132     /*@=usereleased@*/
00133     return 1;
00134 }
00135 
00136 
00146 static int makeGPGSignature(const char * file, rpmSigTag * sigTagp,
00147                 /*@out@*/ rpmuint8_t ** pktp, /*@out@*/ rpmuint32_t * pktlenp,
00148                 /*@null@*/ const char * passPhrase)
00149         /*@globals rpmGlobalMacroContext, h_errno,
00150                 fileSystem, internalState @*/
00151         /*@modifies *pktp, *pktlenp, *sigTagp, rpmGlobalMacroContext,
00152                 fileSystem, internalState @*/
00153 {
00154     char * sigfile = alloca(strlen(file)+sizeof(".sig"));
00155     pid_t pid;
00156     int status;
00157     int inpipe[2];
00158     FILE * fpipe;
00159     struct stat st;
00160     const char * cmd;
00161     char *const *av;
00162     pgpDig dig = NULL;
00163     pgpDigParams sigp = NULL;
00164     const char * pw = NULL;
00165     int rc;
00166 
00167     (void) stpcpy( stpcpy(sigfile, file), ".sig");
00168 
00169     addMacro(NULL, "__plaintext_filename", NULL, file, -1);
00170     addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
00171 
00172     inpipe[0] = inpipe[1] = 0;
00173     if (pipe(inpipe) < 0) {
00174         rpmlog(RPMLOG_ERR, _("Couldn't create pipe for signing: %m"));
00175         return 1;
00176     }
00177 
00178     if (!(pid = fork())) {
00179         const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00180 
00181         (void) dup2(inpipe[0], 3);
00182         (void) close(inpipe[1]);
00183 
00184         if (gpg_path && *gpg_path != '\0')
00185             (void) setenv("GNUPGHOME", gpg_path, 1);
00186 
00187         unsetenv("MALLOC_CHECK_");
00188         cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
00189         rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00190         if (!rc)
00191             rc = execve(av[0], av+1, environ);
00192 
00193         rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg",
00194                         strerror(errno));
00195         _exit(EXIT_FAILURE);
00196     }
00197 
00198     delMacro(NULL, "__plaintext_filename");
00199     delMacro(NULL, "__signature_filename");
00200 
00201     pw = rpmkuPassPhrase(passPhrase);
00202     if (pw == NULL) {
00203         rpmlog(RPMLOG_ERR, _("Failed rpmkuPassPhrase(passPhrase): %s\n"),
00204                         strerror(errno));
00205         return 1;
00206     }
00207 
00208     fpipe = fdopen(inpipe[1], "w");
00209     (void) close(inpipe[0]);
00210     if (fpipe) {
00211         fprintf(fpipe, "%s\n", (pw ? pw : ""));
00212         (void) fclose(fpipe);
00213     }
00214 
00215     if (pw != NULL) {
00216         (void) memset((void *)pw, 0, strlen(pw));
00217         pw = _free(pw);
00218     }
00219 
00220 /*@+longunsignedintegral@*/
00221     (void) waitpid(pid, &status, 0);
00222 /*@=longunsignedintegral@*/
00223     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
00224         rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status));
00225         return 1;
00226     }
00227 
00228     if (Stat(sigfile, &st)) {
00229         /* GPG failed to write signature */
00230         if (sigfile) (void) Unlink(sigfile);  /* Just in case */
00231         rpmlog(RPMLOG_ERR, _("gpg failed to write signature\n"));
00232         return 1;
00233     }
00234 
00235     *pktlenp = (rpmuint32_t)st.st_size;
00236     rpmlog(RPMLOG_DEBUG, D_("GPG sig size: %u\n"), (unsigned)*pktlenp);
00237     *pktp = xmalloc(*pktlenp);
00238 
00239     {   FD_t fd;
00240 
00241         rc = 0;
00242         fd = Fopen(sigfile, "r.ufdio");
00243         if (fd != NULL && !Ferror(fd)) {
00244             rc = (int) Fread(*pktp, sizeof((*pktp)[0]), *pktlenp, fd);
00245             if (sigfile) (void) Unlink(sigfile);
00246             (void) Fclose(fd);
00247         }
00248         if ((rpmuint32_t)rc != *pktlenp) {
00249             *pktp = _free(*pktp);
00250             rpmlog(RPMLOG_ERR, _("unable to read the signature\n"));
00251             return 1;
00252         }
00253     }
00254 
00255     rpmlog(RPMLOG_DEBUG, D_("Got %u bytes of GPG sig\n"), (unsigned)*pktlenp);
00256 
00257     /* Parse the signature, change signature tag as appropriate. */
00258     dig = pgpDigNew(0);
00259 
00260     (void) pgpPrtPkts(*pktp, *pktlenp, dig, 0);
00261     sigp = pgpGetSignature(dig);
00262 
00263     /* Identify the type of signature being returned. */
00264     switch (*sigTagp) {
00265     default:
00266 assert(0);      /* XXX never happens. */
00267         /*@notreached@*/ break;
00268     case RPMSIGTAG_SIZE:
00269     case RPMSIGTAG_MD5:
00270     case RPMSIGTAG_SHA1:
00271         break;
00272     case RPMSIGTAG_DSA:
00273         /* XXX check hash algorithm too? */
00274         if (sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA)
00275             *sigTagp = RPMSIGTAG_RSA;
00276         break;
00277     case RPMSIGTAG_RSA:
00278         if (sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_DSA)
00279             *sigTagp = RPMSIGTAG_DSA;
00280         break;
00281     }
00282 
00283     dig = pgpDigFree(dig, "makeGPGSignature");
00284 
00285     return 0;
00286 }
00287 
00296 /*@-mustmod@*/ /* sigh is modified */
00297 static int makeHDRSignature(Header sigh, const char * file, rpmSigTag sigTag,
00298                 /*@null@*/ const char * passPhrase)
00299         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00300         /*@modifies sigh, sigTag, rpmGlobalMacroContext, fileSystem, internalState @*/
00301 {
00302     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00303     Header h = NULL;
00304     FD_t fd = NULL;
00305     rpmuint8_t * pkt;
00306     rpmuint32_t pktlen;
00307     const char * fn = NULL;
00308     const char * msg;
00309     rpmRC rc;
00310     int ret = -1;       /* assume failure. */
00311     int xx;
00312 
00313     switch (sigTag) {
00314     default:
00315 assert(0);      /* XXX never happens. */
00316         /*@notreached@*/ break;
00317     case RPMSIGTAG_SIZE:
00318     case RPMSIGTAG_MD5:
00319     case RPMSIGTAG_PGP5:        /* XXX legacy */
00320     case RPMSIGTAG_PGP:
00321     case RPMSIGTAG_GPG:
00322         goto exit;
00323         /*@notreached@*/ break;
00324     case RPMSIGTAG_SHA1:
00325     {   const char * SHA1 = NULL;
00326         fd = Fopen(file, "r.fdio");
00327         if (fd == NULL || Ferror(fd))
00328             goto exit;
00329         {   const char item[] = "Header";
00330             msg = NULL;
00331             rc = rpmpkgRead(item, fd, &h, &msg);
00332             if (rc != RPMRC_OK) {
00333                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
00334                 msg = _free(msg);
00335                 goto exit;
00336             }
00337             msg = _free(msg);
00338         }
00339         (void) Fclose(fd);      fd = NULL;
00340 
00341         if (headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
00342             unsigned char * hmagic = NULL;
00343             size_t nmagic = 0;
00344             DIGEST_CTX ctx;
00345         
00346             he->tag = RPMTAG_HEADERIMMUTABLE;
00347             if (!headerGet(h, he, 0) || he->p.ptr == NULL)
00348             {
00349                 (void)headerFree(h);
00350                 h = NULL;
00351                 goto exit;
00352             }
00353             (void) headerGetMagic(NULL, &hmagic, &nmagic);
00354             ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
00355             if (hmagic && nmagic > 0)
00356                 (void) rpmDigestUpdate(ctx, hmagic, nmagic);
00357             (void) rpmDigestUpdate(ctx, he->p.ptr, he->c);
00358             (void) rpmDigestFinal(ctx, &SHA1, NULL, 1);
00359             he->p.ptr = _free(he->p.ptr);
00360         }
00361         (void)headerFree(h);
00362         h = NULL;
00363 
00364         if (SHA1 == NULL)
00365             goto exit;
00366         he->tag = (rpmTag) RPMSIGTAG_SHA1;
00367         he->t = RPM_STRING_TYPE;
00368         he->p.str = SHA1;
00369         he->c = 1;
00370         xx = headerPut(sigh, he, 0);
00371         SHA1 = _free(SHA1);
00372         if (!xx)
00373             goto exit;
00374         ret = 0;
00375    }    break;
00376    case RPMSIGTAG_DSA:
00377         fd = Fopen(file, "r.fdio");
00378         if (fd == NULL || Ferror(fd))
00379             goto exit;
00380         {   const char item[] = "Header";
00381             msg = NULL;
00382             rc = rpmpkgRead(item, fd, &h, &msg);
00383             if (rc != RPMRC_OK) {
00384                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
00385                 msg = _free(msg);
00386                 goto exit;
00387             }
00388             msg = _free(msg);
00389         }
00390         (void) Fclose(fd);      fd = NULL;
00391 
00392         if (rpmTempFile(NULL, &fn, &fd))
00393             goto exit;
00394         {   const char item[] = "Header";
00395             msg = NULL;
00396             rc = rpmpkgWrite(item, fd, h, &msg);
00397             if (rc != RPMRC_OK) {
00398                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", fn, item, msg);
00399                 msg = _free(msg);
00400                 goto exit;
00401             }
00402             msg = _free(msg);
00403         }
00404         (void) Fclose(fd);      fd = NULL;
00405 
00406         if (makeGPGSignature(fn, &sigTag, &pkt, &pktlen, passPhrase))
00407             goto exit;
00408         he->tag = (rpmTag) sigTag;
00409         he->t = RPM_BIN_TYPE;
00410         he->p.ptr = pkt;
00411         he->c = pktlen;
00412         xx = headerPut(sigh, he, 0);
00413         if (!xx)
00414             goto exit;
00415         ret = 0;
00416         break;
00417     }
00418 
00419 exit:
00420     if (fn) {
00421         (void) Unlink(fn);
00422         fn = _free(fn);
00423     }
00424     (void)headerFree(h);
00425     h = NULL;
00426     if (fd != NULL) (void) Fclose(fd);
00427     return ret;
00428 }
00429 /*@=mustmod@*/
00430 
00431 int rpmAddSignature(Header sigh, const char * file, rpmSigTag sigTag,
00432                 const char * passPhrase)
00433 {
00434     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00435     struct stat st;
00436     rpmuint8_t * pkt;
00437     rpmuint32_t pktlen;
00438     int ret = -1;       /* assume failure. */
00439     int xx;
00440 
00441     switch (sigTag) {
00442     default:
00443 assert(0);      /* XXX never happens. */
00444         /*@notreached@*/ break;
00445     case RPMSIGTAG_SIZE:
00446         if (Stat(file, &st) != 0)
00447             break;
00448         pktlen = (rpmuint32_t)st.st_size;
00449         he->tag = (rpmTag) sigTag;
00450         he->t = RPM_UINT32_TYPE;
00451         he->p.ui32p = &pktlen;
00452         he->c = 1;
00453 /*@-compmempass@*/
00454         xx = headerPut(sigh, he, 0);
00455 /*@=compmempass@*/
00456         if (!xx)
00457             break;
00458         ret = 0;
00459         break;
00460     case RPMSIGTAG_MD5:
00461         pktlen = 128/8;
00462         pkt = memset(alloca(pktlen), 0, pktlen);
00463         if (dodigest(PGPHASHALGO_MD5, file, (unsigned char *)pkt, 0, NULL))
00464             break;
00465         he->tag = (rpmTag) sigTag;
00466         he->t = RPM_BIN_TYPE;
00467         he->p.ptr = pkt;
00468         he->c = pktlen;
00469         xx = headerPut(sigh, he, 0);
00470         if (!xx)
00471             break;
00472         ret = 0;
00473         break;
00474     case RPMSIGTAG_GPG:
00475         ret = makeHDRSignature(sigh, file, RPMSIGTAG_DSA, passPhrase);
00476         break;
00477     case RPMSIGTAG_RSA:
00478     case RPMSIGTAG_DSA:
00479     case RPMSIGTAG_SHA1:
00480         ret = makeHDRSignature(sigh, file, sigTag, passPhrase);
00481         break;
00482     }
00483 
00484     return ret;
00485 }
00486 
00487 int rpmCheckPassPhrase(const char * passPhrase)
00488 {
00489     const char *pw;
00490     int p[2];
00491     pid_t pid;
00492     int status;
00493     int rc;
00494     int xx;
00495 
00496     p[0] = p[1] = 0;
00497     xx = pipe(p);
00498 
00499     if (!(pid = fork())) {
00500         const char * cmd;
00501         char *const *av;
00502         int fdno;
00503 
00504         xx = close(STDIN_FILENO);
00505         xx = close(STDOUT_FILENO);
00506         xx = close(p[1]);
00507         if (!rpmIsVerbose())
00508             xx = close(STDERR_FILENO);
00509         if ((fdno = open("/dev/null", O_RDONLY)) != STDIN_FILENO) {
00510             xx = dup2(fdno, STDIN_FILENO);
00511             xx = close(fdno);
00512         }
00513         if ((fdno = open("/dev/null", O_WRONLY)) != STDOUT_FILENO) {
00514             xx = dup2(fdno, STDOUT_FILENO);
00515             xx = close(fdno);
00516         }
00517         xx = dup2(p[0], 3);
00518 
00519         unsetenv("MALLOC_CHECK_");
00520         {   const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
00521 
00522             if (gpg_path && *gpg_path != '\0')
00523                 (void) setenv("GNUPGHOME", gpg_path, 1);
00524 
00525             cmd = rpmExpand("%{?__gpg_check_password_cmd}", NULL);
00526             rc = poptParseArgvString(cmd, NULL, (const char ***)&av);
00527             if (!rc)
00528                 rc = execve(av[0], av+1, environ);
00529 
00530             rpmlog(RPMLOG_ERR, _("Could not exec %s: %s\n"), "gpg",
00531                         strerror(errno));
00532         }
00533     }
00534 
00535     pw = rpmkuPassPhrase(passPhrase);
00536     if (pw == NULL) {
00537         rpmlog(RPMLOG_ERR, _("Failed rpmkuPassPhrase(passPhrase): %s\n"),
00538                         strerror(errno));
00539         return 1;
00540     }
00541 
00542     xx = close(p[0]);
00543     xx = (int) write(p[1], pw, strlen(pw));
00544     xx = (int) write(p[1], "\n", 1);
00545     xx = close(p[1]);
00546 
00547     if (pw != NULL) {
00548         (void) memset((void *)pw, 0, strlen(pw));
00549         pw = _free(pw);
00550     }
00551 
00552 /*@+longunsignedintegral@*/
00553     (void) waitpid(pid, &status, 0);
00554 /*@=longunsignedintegral@*/
00555 
00556     return ((!WIFEXITED(status) || WEXITSTATUS(status)) ? 1 : 0);
00557 }
00558 
00559 static /*@observer@*/ const char * rpmSigString(rpmRC res)
00560         /*@*/
00561 {
00562     const char * str;
00563     switch (res) {
00564     case RPMRC_OK:              str = "OK";             break;
00565     case RPMRC_FAIL:            str = "BAD";            break;
00566     case RPMRC_NOKEY:           str = "NOKEY";          break;
00567     case RPMRC_NOTTRUSTED:      str = "NOTRUSTED";      break;
00568     default:
00569     case RPMRC_NOTFOUND:        str = "UNKNOWN";        break;
00570     }
00571     return str;
00572 }
00573 
00574 static rpmRC
00575 verifySize(const pgpDig dig, /*@out@*/ char * t)
00576         /*@modifies *t @*/
00577 {
00578     const void * sig = pgpGetSig(dig);
00579     rpmRC res;
00580     rpmuint32_t size = 0xffffffff;
00581 
00582     *t = '\0';
00583     t = stpcpy(t, _("Header+Payload size: "));
00584 
00585     if (sig == NULL || dig == NULL || dig->nbytes == 0) {
00586         res = RPMRC_NOKEY;
00587         t = stpcpy(t, rpmSigString(res));
00588         goto exit;
00589     }
00590 
00591     memcpy(&size, sig, sizeof(size));
00592 
00593     if (size !=(rpmuint32_t) dig->nbytes) {
00594         res = RPMRC_FAIL;
00595         t = stpcpy(t, rpmSigString(res));
00596         sprintf(t, " Expected(%u) != (%u)\n", (unsigned)size, (unsigned)dig->nbytes);
00597     } else {
00598         res = RPMRC_OK;
00599         t = stpcpy(t, rpmSigString(res));
00600         sprintf(t, " (%u)", (unsigned)dig->nbytes);
00601     }
00602 
00603 exit:
00604     return res;
00605 }
00606 
00607 static rpmRC
00608 verifyMD5(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX md5ctx)
00609         /*@globals internalState @*/
00610         /*@modifies *t, internalState @*/
00611 {
00612     const void * sig = pgpGetSig(dig);
00613     rpmuint32_t siglen = pgpGetSiglen(dig);
00614     rpmRC res;
00615     rpmuint8_t * md5sum = NULL;
00616     size_t md5len = 0;
00617 
00618 assert(dig != NULL);
00619 assert(md5ctx != NULL);
00620 assert(sig != NULL);
00621 
00622     *t = '\0';
00623 
00624     /* Identify the hash. */
00625     t = stpcpy(t, rpmDigestName(md5ctx));
00626     t = stpcpy(t, _(" digest: "));
00627 
00628     if (sig == NULL) {          /* XXX can't happen, DYING */
00629         res = RPMRC_NOKEY;
00630         t = stpcpy(t, rpmSigString(res));
00631         goto exit;
00632     }
00633 
00634     {   rpmop op = pgpStatsAccumulator(dig, 10);        /* RPMTS_OP_DIGEST */
00635         (void) rpmswEnter(op, 0);
00636         (void) rpmDigestFinal(rpmDigestDup(md5ctx), &md5sum, &md5len, 0);
00637         (void) rpmswExit(op, 0);
00638         if (op != NULL) op->count--;    /* XXX one too many */
00639     }
00640 
00641     if (md5len != siglen || memcmp(md5sum, sig, md5len)) {
00642         res = RPMRC_FAIL;
00643         t = stpcpy(t, rpmSigString(res));
00644         t = stpcpy(t, " Expected(");
00645         (void) pgpHexCvt(t, sig, siglen);
00646         t += strlen(t);
00647         t = stpcpy(t, ") != (");
00648     } else {
00649         res = RPMRC_OK;
00650         t = stpcpy(t, rpmSigString(res));
00651         t = stpcpy(t, " (");
00652     }
00653     (void) pgpHexCvt(t, md5sum, md5len);
00654     t += strlen(t);
00655     t = stpcpy(t, ")");
00656 
00657 exit:
00658     md5sum = _free(md5sum);
00659     return res;
00660 }
00661 
00669 static rpmRC
00670 verifySHA1(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX shactx)
00671         /*@globals internalState @*/
00672         /*@modifies *t, internalState @*/
00673 {
00674     const void * sig = pgpGetSig(dig);
00675 #ifdef  NOTYET
00676     rpmuint32_t siglen = pgpGetSiglen(dig);
00677 #endif
00678     rpmRC res;
00679     const char * SHA1 = NULL;
00680 
00681 assert(dig != NULL);
00682 assert(shactx != NULL);
00683 assert(sig != NULL);
00684 
00685     *t = '\0';
00686     t = stpcpy(t, _("Header "));
00687 
00688     /* Identify the hash. */
00689     t = stpcpy(t, rpmDigestName(shactx));
00690     t = stpcpy(t, _(" digest: "));
00691 
00692     if (sig == NULL) {          /* XXX can't happen, DYING */
00693         res = RPMRC_NOKEY;
00694         t = stpcpy(t, rpmSigString(res));
00695         goto exit;
00696     }
00697 
00698     {   rpmop op = pgpStatsAccumulator(dig, 10);        /* RPMTS_OP_DIGEST */
00699         (void) rpmswEnter(op, 0);
00700         (void) rpmDigestFinal(rpmDigestDup(shactx), &SHA1, NULL, 1);
00701         (void) rpmswExit(op, 0);
00702     }
00703 
00704     if (SHA1 == NULL || strlen(SHA1) != strlen(sig) || strcmp(SHA1, sig)) {
00705         res = RPMRC_FAIL;
00706         t = stpcpy(t, rpmSigString(res));
00707         t = stpcpy(t, " Expected(");
00708         t = stpcpy(t, sig);
00709         t = stpcpy(t, ") != (");
00710     } else {
00711         res = RPMRC_OK;
00712         t = stpcpy(t, rpmSigString(res));
00713         t = stpcpy(t, " (");
00714     }
00715     if (SHA1)
00716         t = stpcpy(t, SHA1);
00717     t = stpcpy(t, ")");
00718 
00719 exit:
00720     SHA1 = _free(SHA1);
00721     return res;
00722 }
00723 
00731 static rpmRC
00732 verifyRSA(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX rsactx)
00733         /*@globals internalState @*/
00734         /*@modifies dig, *t, internalState */
00735 {
00736     const void * sig = pgpGetSig(dig);
00737 #ifdef  NOTYET
00738     rpmuint32_t siglen = pgpGetSiglen(dig);
00739 #endif
00740     pgpDigParams sigp = pgpGetSignature(dig);
00741     rpmRC res = RPMRC_OK;
00742     int xx;
00743 
00744 assert(dig != NULL);
00745 assert(rsactx != NULL);
00746 assert(sigp != NULL);
00747 assert(sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_RSA);
00748 assert(sigp->hash_algo == (rpmuint8_t)rpmDigestAlgo(rsactx));
00749 assert(pgpGetSigtag(dig) == RPMSIGTAG_RSA);
00750 assert(sig != NULL);
00751 
00752     *t = '\0';
00753     if (dig->hdrctx == rsactx)
00754         t = stpcpy(t, _("Header "));
00755 
00756     /* Identify the signature version. */
00757     *t++ = 'V';
00758     switch (sigp->version) {
00759     case 3:     *t++ = '3';     break;
00760     case 4:     *t++ = '4';     break;
00761     }
00762 
00763     /* Identify the RSA/hash. */
00764     {   const char * hashname = rpmDigestName(rsactx);
00765         t = stpcpy(t, " RSA");
00766         if (strcmp(hashname, "UNKNOWN")) {
00767             *t++ = '/';
00768             t = stpcpy(t, hashname);
00769         }
00770     }
00771     t = stpcpy(t, _(" signature: "));
00772 
00773     {   rpmop op = pgpStatsAccumulator(dig, 10);        /* RPMTS_OP_DIGEST */
00774         DIGEST_CTX ctx = rpmDigestDup(rsactx);
00775 
00776         (void) rpmswEnter(op, 0);
00777         if (sigp->hash != NULL)
00778             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
00779 
00780         if (sigp->version == (rpmuint8_t) 4) {
00781             rpmuint32_t nb = (rpmuint32_t) sigp->hashlen;
00782             rpmuint8_t trailer[6];
00783             nb = (rpmuint32_t) htonl(nb);
00784             trailer[0] = sigp->version;
00785             trailer[1] = (rpmuint8_t)0xff;
00786             memcpy(trailer+2, &nb, sizeof(nb));
00787             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
00788         }
00789         (void) rpmswExit(op, sigp->hashlen);
00790         if (op != NULL) op->count--;    /* XXX one too many */
00791 
00792         if ((xx = pgpImplSetRSA(ctx, dig, sigp)) != 0) {
00793             res = RPMRC_FAIL;
00794             goto exit;
00795         }
00796     }
00797 
00798     /* Retrieve the matching public key. */
00799     res = pgpFindPubkey(dig);
00800     if (res != RPMRC_OK)
00801         goto exit;
00802 
00803     /* Verify the RSA signature. */
00804     {   rpmop op = pgpStatsAccumulator(dig, 11);        /* RPMTS_OP_SIGNATURE */
00805         (void) rpmswEnter(op, 0);
00806         xx = pgpImplVerifyRSA(dig);
00807         (void) rpmswExit(op, 0);
00808         res = (xx ? RPMRC_OK : RPMRC_FAIL);
00809     }
00810 
00811 exit:
00812     /* Identify the pubkey fingerprint. */
00813     t = stpcpy(t, rpmSigString(res));
00814     if (sigp != NULL) {
00815         t = stpcpy(t, ", key ID ");
00816         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
00817         t += strlen(t);
00818     }
00819     return res;
00820 }
00821 
00829 static rpmRC
00830 verifyDSA(pgpDig dig, /*@out@*/ char * t, /*@null@*/ DIGEST_CTX dsactx)
00831         /*@globals internalState @*/
00832         /*@modifies dig, *t, internalState */
00833 {
00834     const void * sig = pgpGetSig(dig);
00835 #ifdef  NOTYET
00836     rpmuint32_t siglen = pgpGetSiglen(dig);
00837 #endif
00838     pgpDigParams sigp = pgpGetSignature(dig);
00839     rpmRC res;
00840     int xx;
00841 
00842 assert(dig != NULL);
00843 assert(dsactx != NULL);
00844 assert(sigp != NULL);
00845 assert(sigp->pubkey_algo == (rpmuint8_t)PGPPUBKEYALGO_DSA);
00846 assert(sigp->hash_algo == (rpmuint8_t)rpmDigestAlgo(dsactx));
00847 assert(pgpGetSigtag(dig) == RPMSIGTAG_DSA);
00848 assert(sig != NULL);
00849 
00850     *t = '\0';
00851     if (dig != NULL && dig->hdrsha1ctx == dsactx)
00852         t = stpcpy(t, _("Header "));
00853 
00854     /* Identify the signature version. */
00855     *t++ = 'V';
00856     switch (sigp->version) {
00857     case 3:    *t++ = '3';     break;
00858     case 4:    *t++ = '4';     break;
00859     }
00860 
00861     /* Identify the DSA/hash. */
00862     {   const char * hashname = rpmDigestName(dsactx);
00863         t = stpcpy(t, " DSA");
00864         if (strcmp(hashname, "UNKNOWN") && strcmp(hashname, "SHA1")) {
00865             *t++ = '/';
00866             t = stpcpy(t, hashname);
00867         }
00868     }
00869     t = stpcpy(t, _(" signature: "));
00870 
00871     {   rpmop op = pgpStatsAccumulator(dig, 10);        /* RPMTS_OP_DIGEST */
00872         DIGEST_CTX ctx = rpmDigestDup(dsactx);
00873 
00874         (void) rpmswEnter(op, 0);
00875         if (sigp->hash != NULL)
00876             xx = rpmDigestUpdate(ctx, sigp->hash, sigp->hashlen);
00877 
00878         if (sigp->version == (rpmuint8_t) 4) {
00879             rpmuint32_t nb = (rpmuint32_t) sigp->hashlen;
00880             rpmuint8_t trailer[6];
00881             nb = (rpmuint32_t) htonl(nb);
00882             trailer[0] = sigp->version;
00883             trailer[1] = (rpmuint8_t)0xff;
00884             memcpy(trailer+2, &nb, sizeof(nb));
00885             xx = rpmDigestUpdate(ctx, trailer, sizeof(trailer));
00886         }
00887         (void) rpmswExit(op, sigp->hashlen);
00888         if (op != NULL) op->count--;    /* XXX one too many */
00889 
00890         if (pgpImplSetDSA(ctx, dig, sigp)) {
00891             res = RPMRC_FAIL;
00892             goto exit;
00893         }
00894     }
00895 
00896     /* Retrieve the matching public key. */
00897     res = pgpFindPubkey(dig);
00898     if (res != RPMRC_OK)
00899         goto exit;
00900 
00901     /* Verify the DSA signature. */
00902     {   rpmop op = pgpStatsAccumulator(dig, 11);        /* RPMTS_OP_SIGNATURE */
00903         (void) rpmswEnter(op, 0);
00904         xx = pgpImplVerifyDSA(dig);
00905         res = (xx ? RPMRC_OK : RPMRC_FAIL);
00906         (void) rpmswExit(op, 0);
00907     }
00908 
00909 exit:
00910     /* Identify the pubkey fingerprint. */
00911     t = stpcpy(t, rpmSigString(res));
00912     if (sigp != NULL) {
00913         t = stpcpy(t, ", key ID ");
00914         (void) pgpHexCvt(t, sigp->signid+4, sizeof(sigp->signid)-4);
00915         t += strlen(t);
00916     }
00917     return res;
00918 }
00919 
00920 rpmRC
00921 rpmVerifySignature(void * _dig, char * result)
00922 {
00923     pgpDig dig = _dig;
00924     const void * sig = pgpGetSig(dig);
00925     rpmuint32_t siglen = pgpGetSiglen(dig);
00926     rpmSigTag sigtag = pgpGetSigtag(dig);
00927     rpmRC res;
00928 
00929     if (dig == NULL || sig == NULL || siglen == 0) {
00930         sprintf(result, _("Verify signature: BAD PARAMETERS\n"));
00931         return RPMRC_NOTFOUND;
00932     }
00933 
00934     switch (sigtag) {
00935     case RPMSIGTAG_SIZE:
00936         res = verifySize(dig, result);
00937         break;
00938     case RPMSIGTAG_MD5:
00939         res = verifyMD5(dig, result, dig->md5ctx);
00940         break;
00941     case RPMSIGTAG_SHA1:
00942         res = verifySHA1(dig, result, dig->hdrsha1ctx);
00943         break;
00944     case RPMSIGTAG_RSA:
00945         res = verifyRSA(dig, result, dig->hdrctx);
00946         break;
00947     case RPMSIGTAG_DSA:
00948         res = verifyDSA(dig, result, dig->hdrsha1ctx);
00949         break;
00950     default:
00951         sprintf(result, _("Signature: UNKNOWN (%u)\n"), (unsigned)sigtag);
00952         res = RPMRC_NOTFOUND;
00953         break;
00954     }
00955     return res;
00956 }