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

# rpmdb/signature.c

Go to the documentation of this file.

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