rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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 }