home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 1999 May / pcp151c.iso / misc / src / rpm / lib / signature.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-17  |  11.6 KB  |  496 lines

  1. /* signature.c - RPM signature functions */
  2.  
  3. /* NOTES
  4.  *
  5.  * Things have been cleaned up wrt PGP.  We can now handle
  6.  * signatures of any length (which means you can use any
  7.  * size key you like).  We also honor PGPPATH finally.
  8.  */
  9.  
  10. #include "config.h"
  11. #include "miscfn.h"
  12.  
  13. #if HAVE_ASM_BYTEORDER_H
  14. #include <asm/byteorder.h>
  15. #endif
  16.  
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <unistd.h>
  20. #include <sys/time.h>
  21. #include <sys/resource.h>
  22. #include <sys/stat.h>
  23. #include <sys/wait.h>
  24. #include <fcntl.h>
  25. #include <string.h>
  26.  
  27. #include "intl.h"
  28. #include "md5.h"
  29. #include "misc.h"
  30. #include "rpmlib.h"
  31. #include "rpmlead.h"
  32. #include "signature.h"
  33. #include "tread.h"
  34. #include "messages.h"
  35.  
  36. typedef int (*md5func)(char * fn, unsigned char * digest);
  37.  
  38. static int makePGPSignature(char *file, void **sig, int_32 *size,
  39.                 char *passPhrase);
  40. static int checkSize(int fd, int size, int sigsize);
  41. static int verifySizeSignature(char *datafile, int_32 size, char *result);
  42. static int verifyMD5Signature(char *datafile, unsigned char *sig,
  43.                   char *result, md5func fn);
  44. static int verifyPGPSignature(char *datafile, void *sig,
  45.                   int count, char *result);
  46. static int checkPassPhrase(char *passPhrase);
  47.  
  48. int rpmLookupSignatureType(void)
  49. {
  50.     char *name;
  51.  
  52.     if (! (name = rpmGetVar(RPMVAR_SIGTYPE))) {
  53.     return 0;
  54.     }
  55.  
  56.     if (!strcasecmp(name, "none")) {
  57.     return 0;
  58.     } else if (!strcasecmp(name, "pgp")) {
  59.     return RPMSIGTAG_PGP;
  60.     } else {
  61.     return -1;
  62.     }
  63. }
  64.  
  65. /* rpmReadSignature() emulates the new style signatures if it finds an */
  66. /* old-style one.  It also immediately verifies the header+archive  */
  67. /* size and returns an error if it doesn't match.                   */
  68.  
  69. int rpmReadSignature(int fd, Header *header, short sig_type)
  70. {
  71.     unsigned char buf[2048];
  72.     int sigSize, pad;
  73.     int_32 type, count;
  74.     int_32 *archSize;
  75.     Header h;
  76.  
  77.     if (header) {
  78.     *header = NULL;
  79.     }
  80.     
  81.     switch (sig_type) {
  82.       case RPMSIG_NONE:
  83.     rpmMessage(RPMMESS_DEBUG, "No signature\n");
  84.     break;
  85.       case RPMSIG_PGP262_1024:
  86.     rpmMessage(RPMMESS_DEBUG, "Old PGP signature\n");
  87.     /* These are always 256 bytes */
  88.     if (timedRead(fd, buf, 256) != 256) {
  89.         return 1;
  90.     }
  91.     if (header) {
  92.         *header = headerNew();
  93.         headerAddEntry(*header, RPMSIGTAG_PGP, RPM_BIN_TYPE, buf, 152);
  94.     }
  95.     break;
  96.       case RPMSIG_MD5:
  97.       case RPMSIG_MD5_PGP:
  98.     rpmError(RPMERR_BADSIGTYPE,
  99.           _("Old (internal-only) signature!  How did you get that!?"));
  100.     return 1;
  101.     break;
  102.       case RPMSIG_HEADERSIG:
  103.     rpmMessage(RPMMESS_DEBUG, "New Header signature\n");
  104.     /* This is a new style signature */
  105.     h = headerRead(fd, HEADER_MAGIC_YES);
  106.     if (! h) {
  107.         return 1;
  108.     }
  109.     sigSize = headerSizeof(h, HEADER_MAGIC_YES);
  110.     pad = (8 - (sigSize % 8)) % 8; /* 8-byte pad */
  111.     rpmMessage(RPMMESS_DEBUG, "Signature size: %d\n", sigSize);
  112.     rpmMessage(RPMMESS_DEBUG, "Signature pad : %d\n", pad);
  113.     if (! headerGetEntry(h, RPMSIGTAG_SIZE, &type, (void **)&archSize, &count)) {
  114.         headerFree(h);
  115.         return 1;
  116.     }
  117.     if (checkSize(fd, *archSize, sigSize + pad)) {
  118.         headerFree(h);
  119.         return 1;
  120.     }
  121.     if (pad) {
  122.         if (timedRead(fd, buf, pad) != pad) {
  123.         headerFree(h);
  124.         return 1;
  125.         }
  126.     }
  127.     if (header) {
  128.         *header = h;
  129.     } else {
  130.         headerFree(h);
  131.     }
  132.     break;
  133.       default:
  134.     return 1;
  135.     }
  136.  
  137.     return 0;
  138. }
  139.  
  140. int rpmWriteSignature(int fd, Header header)
  141. {
  142.     int sigSize, pad;
  143.     unsigned char buf[8];
  144.     
  145.     headerWrite(fd, header, HEADER_MAGIC_YES);
  146.     sigSize = headerSizeof(header, HEADER_MAGIC_YES);
  147.     pad = (8 - (sigSize % 8)) % 8;
  148.     if (pad) {
  149.     rpmMessage(RPMMESS_DEBUG, "Signature size: %d\n", sigSize);
  150.     rpmMessage(RPMMESS_DEBUG, "Signature pad : %d\n", pad);
  151.     memset(buf, 0, pad);
  152.     write(fd, buf, pad);
  153.     }
  154.     return 0;
  155. }
  156.  
  157. Header rpmNewSignature(void)
  158. {
  159.     return headerNew();
  160. }
  161.  
  162. void rpmFreeSignature(Header h)
  163. {
  164.     headerFree(h);
  165. }
  166.  
  167. int rpmAddSignature(Header header, char *file, int_32 sigTag, char *passPhrase)
  168. {
  169.     struct stat statbuf;
  170.     int_32 size;
  171.     unsigned char buf[16];
  172.     void *sig;
  173.     
  174.     switch (sigTag) {
  175.       case RPMSIGTAG_SIZE:
  176.     stat(file, &statbuf);
  177.     size = statbuf.st_size;
  178.     headerAddEntry(header, RPMSIGTAG_SIZE, RPM_INT32_TYPE, &size, 1);
  179.     break;
  180.       case RPMSIGTAG_MD5:
  181.     mdbinfile(file, buf);
  182.     headerAddEntry(header, sigTag, RPM_BIN_TYPE, buf, 16);
  183.     break;
  184.       case RPMSIGTAG_PGP:
  185.     makePGPSignature(file, &sig, &size, passPhrase);
  186.     headerAddEntry(header, sigTag, RPM_BIN_TYPE, sig, size);
  187.     break;
  188.     }
  189.  
  190.     return 0;
  191. }
  192.  
  193. static int makePGPSignature(char *file, void **sig, int_32 *size,
  194.                 char *passPhrase)
  195. {
  196.     char name[1024];
  197.     char sigfile[1024];
  198.     int pid, status;
  199.     int fd, inpipe[2];
  200.     FILE *fpipe;
  201.     struct stat statbuf;
  202.  
  203.     sprintf(name, "+myname=\"%s\"", rpmGetVar(RPMVAR_PGP_NAME));
  204.  
  205.     sprintf(sigfile, "%s.sig", file);
  206.  
  207.     pipe(inpipe);
  208.     
  209.     if (!(pid = fork())) {
  210.     close(0);
  211.     dup2(inpipe[0], 3);
  212.     close(inpipe[1]);
  213.     dosetenv("PGPPASSFD", "3", 1);
  214.     if (rpmGetVar(RPMVAR_PGP_PATH)) {
  215.         dosetenv("PGPPATH", rpmGetVar(RPMVAR_PGP_PATH), 1);
  216.     }
  217.     /* dosetenv("PGPPASS", passPhrase, 1); */
  218.     execlp("pgp", "pgp",
  219.            "+batchmode=on", "+verbose=0", "+armor=off",
  220.            name, "-sb", file, sigfile,
  221.            NULL);
  222.     rpmError(RPMERR_EXEC, _("Couldn't exec pgp"));
  223.     _exit(RPMERR_EXEC);
  224.     }
  225.  
  226.     fpipe = fdopen(inpipe[1], "w");
  227.     close(inpipe[0]);
  228.     fprintf(fpipe, "%s\n", passPhrase);
  229.     fclose(fpipe);
  230.  
  231.     waitpid(pid, &status, 0);
  232.     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
  233.     rpmError(RPMERR_SIGGEN, _("pgp failed"));
  234.     return 1;
  235.     }
  236.  
  237.     if (stat(sigfile, &statbuf)) {
  238.     /* PGP failed to write signature */
  239.     unlink(sigfile);  /* Just in case */
  240.     rpmError(RPMERR_SIGGEN, _("pgp failed to write signature"));
  241.     return 1;
  242.     }
  243.  
  244.     *size = statbuf.st_size;
  245.     rpmMessage(RPMMESS_DEBUG, "PGP sig size: %d\n", *size);
  246.     *sig = malloc(*size);
  247.     
  248.     fd = open(sigfile, O_RDONLY);
  249.     if (timedRead(fd, *sig, *size) != *size) {
  250.     unlink(sigfile);
  251.     close(fd);
  252.     free(*sig);
  253.     rpmError(RPMERR_SIGGEN, _("unable to read the signature"));
  254.     return 1;
  255.     }
  256.     close(fd);
  257.     unlink(sigfile);
  258.  
  259.     rpmMessage(RPMMESS_DEBUG, "Got %d bytes of PGP sig\n", *size);
  260.     
  261.     return 0;
  262. }
  263.  
  264. static int checkSize(int fd, int size, int sigsize)
  265. {
  266.     int headerArchiveSize;
  267.     struct stat statbuf;
  268.  
  269.     fstat(fd, &statbuf);
  270.  
  271.     if (S_ISREG(statbuf.st_mode)) {
  272.     headerArchiveSize = statbuf.st_size - sizeof(struct rpmlead) - sigsize;
  273.  
  274.     rpmMessage(RPMMESS_DEBUG, "sigsize         : %d\n", sigsize);
  275.     rpmMessage(RPMMESS_DEBUG, "Header + Archive: %d\n", headerArchiveSize);
  276.     rpmMessage(RPMMESS_DEBUG, "expected size   : %d\n", size);
  277.  
  278.     return size - headerArchiveSize;
  279.     } else {
  280.     rpmMessage(RPMMESS_DEBUG, "file is not regular -- skipping size check\n");
  281.     return 0;
  282.     }
  283. }
  284.  
  285. int rpmVerifySignature(char *file, int_32 sigTag, void *sig, int count,
  286.             char *result)
  287. {
  288.     switch (sigTag) {
  289.       case RPMSIGTAG_SIZE:
  290.     if (verifySizeSignature(file, *(int_32 *)sig, result)) {
  291.         return RPMSIG_BAD;
  292.     }
  293.     break;
  294.       case RPMSIGTAG_MD5:
  295.     if (verifyMD5Signature(file, sig, result, mdbinfile)) {
  296.         return 1;
  297.     }
  298.     break;
  299.       case RPMSIGTAG_LEMD5_1:
  300.       case RPMSIGTAG_LEMD5_2:
  301.     if (verifyMD5Signature(file, sig, result, mdbinfileBroken)) {
  302.         return 1;
  303.     }
  304.     break;
  305.       case RPMSIGTAG_PGP:
  306.     return verifyPGPSignature(file, sig, count, result);
  307.     break;
  308.       default:
  309.     sprintf(result, "Do not know how to verify sig type %d\n", sigTag);
  310.     return RPMSIG_UNKNOWN;
  311.     }
  312.  
  313.     return RPMSIG_OK;
  314. }
  315.  
  316. static int verifySizeSignature(char *datafile, int_32 size, char *result)
  317. {
  318.     struct stat statbuf;
  319.  
  320.     stat(datafile, &statbuf);
  321.     if (size != statbuf.st_size) {
  322.     sprintf(result, "Header+Archive size mismatch.\n"
  323.         "Expected %d, saw %d.\n",
  324.         size, (int)statbuf.st_size);
  325.     return 1;
  326.     }
  327.  
  328.     sprintf(result, "Header+Archive size OK: %d bytes\n", size);
  329.     return 0;
  330. }
  331.  
  332. static int verifyMD5Signature(char *datafile, unsigned char *sig, 
  333.                   char *result, md5func fn)
  334. {
  335.     unsigned char md5sum[16];
  336.  
  337.     fn(datafile, md5sum);
  338.     if (memcmp(md5sum, sig, 16)) {
  339.     sprintf(result, "MD5 sum mismatch\n"
  340.         "Expected: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
  341.         "%02x%02x%02x%02x%02x\n"
  342.         "Saw     : %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
  343.         "%02x%02x%02x%02x%02x\n",
  344.         sig[0],  sig[1],  sig[2],  sig[3],
  345.         sig[4],  sig[5],  sig[6],  sig[7],
  346.         sig[8],  sig[9],  sig[10], sig[11],
  347.         sig[12], sig[13], sig[14], sig[15],
  348.         md5sum[0],  md5sum[1],  md5sum[2],  md5sum[3],
  349.         md5sum[4],  md5sum[5],  md5sum[6],  md5sum[7],
  350.         md5sum[8],  md5sum[9],  md5sum[10], md5sum[11],
  351.         md5sum[12], md5sum[13], md5sum[14], md5sum[15]);
  352.     return 1;
  353.     }
  354.  
  355.     sprintf(result, "MD5 sum OK: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x"
  356.                     "%02x%02x%02x%02x%02x\n",
  357.         md5sum[0],  md5sum[1],  md5sum[2],  md5sum[3],
  358.         md5sum[4],  md5sum[5],  md5sum[6],  md5sum[7],
  359.         md5sum[8],  md5sum[9],  md5sum[10], md5sum[11],
  360.         md5sum[12], md5sum[13], md5sum[14], md5sum[15]);
  361.  
  362.     return 0;
  363. }
  364.  
  365. static int verifyPGPSignature(char *datafile, void *sig,
  366.                   int count, char *result)
  367. {
  368.     int pid, status, outpipe[2], sfd;
  369.     char *sigfile;
  370.     unsigned char buf[8192];
  371.     FILE *file;
  372.     int res = RPMSIG_OK;
  373.  
  374.     /* Write out the signature */
  375.     sigfile = tempnam(rpmGetVar(RPMVAR_TMPPATH), "rpmsig");
  376.     sfd = open(sigfile, O_WRONLY|O_CREAT|O_TRUNC, 0644);
  377.     write(sfd, sig, count);
  378.     close(sfd);
  379.  
  380.     /* Now run PGP */
  381.     pipe(outpipe);
  382.  
  383.     if (!(pid = fork())) {
  384.     close(1);
  385.     close(outpipe[0]);
  386.     dup2(outpipe[1], 1);
  387.     if (rpmGetVar(RPMVAR_PGP_PATH)) {
  388.         dosetenv("PGPPATH", rpmGetVar(RPMVAR_PGP_PATH), 1);
  389.     }
  390.     execlp("pgp", "pgp",
  391.            "+batchmode=on", "+verbose=0",
  392.            sigfile, datafile,
  393.            NULL);
  394.     printf("exec failed!\n");
  395.     rpmError(RPMERR_EXEC, 
  396.          _("Could not run pgp.  Use --nopgp to skip PGP checks."));
  397.     _exit(RPMERR_EXEC);
  398.     }
  399.  
  400.     close(outpipe[1]);
  401.     file = fdopen(outpipe[0], "r");
  402.     result[0] = '\0';
  403.     while (fgets(buf, 1024, file)) {
  404.     if (strncmp("File '", buf, 6) &&
  405.         strncmp("Text is assu", buf, 12) &&
  406.         buf[0] != '\n') {
  407.         strcat(result, buf);
  408.     }
  409.     if (!strncmp("WARNING: Can't find the right public key", buf, 40)) {
  410.         res = RPMSIG_NOKEY;
  411.     }
  412.     }
  413.     fclose(file);
  414.  
  415.     waitpid(pid, &status, 0);
  416.     unlink(sigfile);
  417.     if (!res && (!WIFEXITED(status) || WEXITSTATUS(status))) {
  418.     res = RPMSIG_BAD;
  419.     }
  420.     
  421.     return res;
  422. }
  423.  
  424. char *rpmGetPassPhrase(char *prompt)
  425. {
  426.     char *pass;
  427.  
  428.     if (! rpmGetVar(RPMVAR_PGP_NAME)) {
  429.     rpmError(RPMERR_SIGGEN,
  430.              _("You must set \"pgp_name:\" in your rpmrc file"));
  431.     return NULL;
  432.     }
  433.  
  434.     if (prompt) {
  435.         pass = getpass(prompt);
  436.     } else {
  437.         pass = getpass("");
  438.     }
  439.  
  440.     if (checkPassPhrase(pass)) {
  441.     return NULL;
  442.     }
  443.  
  444.     return pass;
  445. }
  446.  
  447. static int checkPassPhrase(char *passPhrase)
  448. {
  449.     char name[1024];
  450.     int passPhrasePipe[2];
  451.     FILE *fpipe;
  452.     int pid, status;
  453.     int fd;
  454.  
  455.     sprintf(name, "+myname=\"%s\"", rpmGetVar(RPMVAR_PGP_NAME));
  456.  
  457.     pipe(passPhrasePipe);
  458.     if (!(pid = fork())) {
  459.     close(0);
  460.     close(1);
  461.     if (! rpmIsVerbose()) {
  462.         close(2);
  463.     }
  464.     if ((fd = open("/dev/null", O_RDONLY)) != 0) {
  465.         dup2(fd, 0);
  466.     }
  467.     if ((fd = open("/dev/null", O_WRONLY)) != 1) {
  468.         dup2(fd, 1);
  469.     }
  470.     dup2(passPhrasePipe[0], 3);
  471.     dosetenv("PGPPASSFD", "3", 1);
  472.     if (rpmGetVar(RPMVAR_PGP_PATH)) {
  473.         dosetenv("PGPPATH", rpmGetVar(RPMVAR_PGP_PATH), 1);
  474.     }
  475.     execlp("pgp", "pgp",
  476.            "+batchmode=on", "+verbose=0",
  477.            name, "-sf",
  478.            NULL);
  479.     rpmError(RPMERR_EXEC, _("Couldn't exec pgp"));
  480.     _exit(RPMERR_EXEC);
  481.     }
  482.  
  483.     fpipe = fdopen(passPhrasePipe[1], "w");
  484.     close(passPhrasePipe[0]);
  485.     fprintf(fpipe, "%s\n", passPhrase);
  486.     fclose(fpipe);
  487.  
  488.     waitpid(pid, &status, 0);
  489.     if (!WIFEXITED(status) || WEXITSTATUS(status)) {
  490.     return 1;
  491.     }
  492.  
  493.     /* passPhrase is good */
  494.     return 0;
  495. }
  496.