• 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 #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 }

Generated on Mon Nov 29 2010 05:18:47 for rpm by  doxygen 1.7.2