home *** CD-ROM | disk | FTP | other *** search
/ PC World 1999 February / PCWorld_1999-02_cd.bin / software / servis / Pgp31 / pgp-integration.doc < prev    next >
Text File  |  1998-03-10  |  9KB  |  232 lines

  1.  
  2. PGP(7)                           User Manual                           PGP(7)
  3.  
  4. DESCRIPTION
  5.   This document describes the process of integrating PGP with third party
  6.   applications.
  7.  
  8. STRATEGIES
  9.   There are two basic possible strategies for PGP integration:  source level
  10.   (calling the PGP libraries directly) and executable level (using system(2)
  11.   or some other method to call the PGP executables).
  12.  
  13.   This document will not detail the library method at this time.  When PGP
  14.   5.5 is released, all support will be migrated to the new Source Development
  15.   Kit (SDK) from the existing APIs.  Developers are encouraged to either use
  16.   the executable integration method detailed here or wait for the SDK to be
  17.   released.
  18.  
  19. EXECUTABLE INTEGRATION
  20.   The most straightforward means of integrating PGP support into your appli-
  21.   cation is to open input and output pipes to the PGP executables.  For a
  22.   very thorough example of PGP integration, see the "plugins" directory of
  23.   the PGP 5.0 source distribution, which has a patch for the mutt email
  24.   client.  Most of the ideas in this text are a result of experiences modify-
  25.   ing Michael Elkins' PGP integration code from mutt.
  26.  
  27.   The basic strategy is to use the PGP executables to perform encryption,
  28.   decryption and verification.  While it is possible to take a much more com-
  29.   plex approach (for example, Mr. Elkins' code actually parses the output of
  30.   pgpk(1) in order to present users with a list of keys), the more complex
  31.   efforts are outside the scope of this document.
  32.  
  33.   All examples are in "C", and assume the following variables:
  34.  
  35.   char *recipients; /*A space-delimited list of message recipients*/
  36.   char *buf;        /*The message to be operated on*/
  37.   char *passphrase; /*The user's passphrase*/
  38.  
  39.   All allocation is assumed already handled by the application.  The reader
  40.   is assumed to be familiar with concepts of C programming and to have read
  41.   and understood the pgp.cfg(5) man page.  Also be aware that the following
  42.   code assumes all buffers are big enough and isn't always perfect about han-
  43.   dling errors gracefully.  This should be considered a starting point, not a
  44.   complete system.
  45.  
  46. COMMON ROUTINE
  47.   The following routine uses fork(2) and pipe(2) to open both read and write
  48.   file handles to a child process.  It is used to invoke PGP in these exam-
  49.   ples.  You may use it effectively without understanding how it works.
  50.  
  51.   /*Runs cmd, and hooks in to the process' stdin, and out to its stdout.
  52.    *Inspiration stolen from Michael Elkins; see mutt for how to do this
  53.    *properly with error checking, etc.
  54.    */
  55.   int run_pgp(char *cmd, FILE **in, FILE **out)
  56.   {
  57.     int pin[2], pout[2], child_pid;
  58.  
  59.     *in = *out = NULL;
  60.  
  61.     pipe(pin);
  62.     pipe(pout);
  63.  
  64.     if(!(child_pid = fork()))
  65.     {
  66.       /*We're the child.*/
  67.       close(pin[1]);
  68.       dup2(pin[0], 0);
  69.       close(pin[0]);
  70.  
  71.       close(pout[0]);
  72.       dup2(pout[1], 1);
  73.       close(pout[1]);
  74.  
  75.       execl("/bin/sh", "sh", "-c", cmd, NULL);
  76.       _exit(127);
  77.     }
  78.  
  79.     /*Only get here if we're the parent.*/
  80.     close(pout[1]);
  81.     *out = fdopen(pout[0], "r");
  82.  
  83.     close(pin[0]);
  84.     *in = fdopen(pin[1], "w");
  85.  
  86.     return(child_pid);
  87.   }
  88.  
  89. ENCRYPTION
  90.   The easiest case is to simply pass your buffer to PGP.  The most minimal
  91.   form of this would be to write your data out, and have PGP encrypt it.
  92.   Unfortunately, this would mean that the cleartext document would be placed
  93.   on the hard drive, which is undesirable.  However, we can use PGP's stream
  94.   mode (the -f option) to get PGP to accept the plaintext on stdin and place
  95.   the encrypted text on stdout:
  96.  
  97.   /*Takes the buffer you wish to encrypt and the recipients; writes the
  98.    *result into encrypt_buffer.
  99.    */
  100.   void encrypt_buffer(char *buf, char *recipients)
  101.   {
  102.     FILE *pgpin, *pgpout;
  103.     char sys_buf[256], tmpbuf[1024] = "\0";
  104.  
  105.     sprintf(sys_buf, "pgpe -at -r %s -f +batchmode=1", recipients);
  106.     run_pgp(sys_buf, &pgpin, &pgpout); /*Execute PGP*/
  107.     if(pgpin && pgpout)
  108.     {
  109.       /*Output buffer to PGP:*/
  110.       fwrite(buf, sizeof(char), strlen(buf), pgpin);
  111.       fclose(pgpin);
  112.  
  113.       /*Now, read the result back from PGP:*/
  114.       *buf = '\0';
  115.       fgets(tmpbuf, sizeof(tmpbuf), pgpout);
  116.       while(!feof(pgpout))
  117.       {
  118.          strcat(buf, tmpbuf);
  119.          fgets(tmpbuf, sizeof(tmpbuf), pgpout);
  120.       }
  121.       fclose(pgpout);
  122.     }
  123.   }
  124.  
  125.   Additional functionality would include using the -s flag to sign the mes-
  126.   sage if the user so requested.  Implementation is quite similar to the
  127.   pgps(1) integration, shown next.
  128.  
  129.   If you find that PGP is mysteriously failing during this step, it may be
  130.   because you are encrypting to keys that are not completely valid.  By
  131.   default, PGP will fail during batch mode when this is encountered.  The
  132.   solution is to place NoBatchInvalidKeys = off in your pgp.cfg file.  It is
  133.   requested that you not pass this option on the command line, as some users
  134.   will prefer not to encrypt to invalid keys.
  135.  
  136. SIGNING
  137.   Conceptually, signing is quite similar, but with a twist - the user must
  138.   specify a passphrase!  The simple way to handle this is to allow PGP to ask
  139.   the user for the passphrase.  However, if you wish to hide PGP's func-
  140.   tionality a little bit more, you may wish to ask for the passphrase your-
  141.   self, prior to signing, and pass it through.
  142.  
  143.   There are a number of ways to get the passphrase to PGP, but the best is
  144.   probably using the environment variable PGPPASSFD.  This allows you to
  145.   specify a file descriptor on which you will pass the passphrase as the
  146.   first input.  Commonly, this is set to 0, stdin:
  147.  
  148.   /*Signs a buffer.  The output is placed in buf.*/
  149.   void sign_buffer(char *buf, char *passphrase)
  150.   {
  151.     FILE *pgpin, *pgpout;
  152.     char tmpbuf[1024] = " ";
  153.  
  154.     setenv("PGPPASSFD", "0", 1);
  155.     run_pgp("pgps -at -f +batchmode=1", &pgpin, &pgpout);
  156.     if(pgpin && pgpout)
  157.     {
  158.       fprintf(pgpin, "%s\n", passphrase); /*Send the passphrase in, first*/
  159.       memset(passphrase, '\0', strlen(passphrase)); /*Burn the passphrase*/
  160.       fwrite(buf, sizeof(char), strlen(buf), pgpin);
  161.       fclose(pgpin);
  162.  
  163.       *buf = '\0';
  164.       fgets(tmpbuf, sizeof(tmpbuf), pgpout);
  165.       while(!feof(pgpout))
  166.       {
  167.         strcat(buf, tmpbuf);
  168.         fgets(tmpbuf, sizeof(tmpbuf), pgpout);
  169.       }
  170.  
  171.       wait(NULL);
  172.  
  173.       fclose(pgpout);
  174.     }
  175.     unsetenv("PGPPASSFD");
  176.   }
  177.  
  178.   Note the use of memset(3) to clear the passphrase immediately after use.
  179.   Not clearing the passphrase can result in numerous security issues.
  180.  
  181. DECRYPTION/VERIFICATION
  182.   Decryption is almost identical to signing (the same passphrase requirements
  183.   apply).  The options passed in are slightly different, however:
  184.  
  185.   /*Verifies a PGP buffer.  Note that, if the buffer is only signed, the
  186.    *passphrase may be unnecessary - a complete program should probably
  187.    *check for the "BEGIN PGP SIGNED MESSAGE" tag before prompting the
  188.    *user for a passphrase.  The output is placed in buf, as well.
  189.    */
  190.   void verify_buffer(char *buf, char *passphrase)
  191.   {
  192.     FILE *pgpin, *pgpout;
  193.     char tmpbuf[1024] = " ";
  194.  
  195.     setenv("PGPPASSFD", "0", 1);
  196.     run_pgp("pgpv -f +batchmode=1 +OutputInformationFD=1",
  197.             &pgpin, &pgpout);
  198.     if(pgpin && pgpout)
  199.     {
  200.       fprintf(pgpin, "%s\n", passphrase); /*Send the passphrase in, first*/
  201.       memset(passphrase, '\0', strlen(passphrase)); /*Burn the passphrase*/
  202.       fprintf(pgpin, "%s", buf);
  203.       fclose(pgpin);
  204.  
  205.       *buf = '\0';
  206.       fgets(tmpbuf, sizeof(tmpbuf), pgpout);
  207.       while(!feof(pgpout))
  208.       {
  209.         strcat(buf, tmpbuf);
  210.         fgets(tmpbuf, sizeof(tmpbuf), pgpout);
  211.       }
  212.  
  213.       wait(NULL);
  214.  
  215.       fclose(pgpout);
  216.     }
  217.     unsetenv("PGPPASSFD");
  218.   }
  219.  
  220.   The +OutputInformationFD option is used to have PGP output information
  221.   about the message (in this case, who signed it, if anyone) on the same
  222.   stream as the decrypted or verified data.
  223.  
  224. CONFIGURATION OPTIONS
  225.   Application integrators are encourages to read the pgp.cfg(5) documenta-
  226.   tion, which details how to pass configuration options on the command line,
  227.   including the public and private keyrings your application wishes to use.
  228.  
  229. SEE ALSO
  230.   pgp(1), pgpe(1), pgpv(1), pgps(1), pgpk(1), http://www.pgp.com (US ver-
  231.   sions) and http://www.pgpi.com (International versions)
  232.