home *** CD-ROM | disk | FTP | other *** search
-
- PGP(7) User Manual PGP(7)
-
- DESCRIPTION
- This document describes the process of integrating PGP with third party
- applications.
-
- STRATEGIES
- There are two basic possible strategies for PGP integration: source level
- (calling the PGP libraries directly) and executable level (using system(2)
- or some other method to call the PGP executables).
-
- This document will not detail the library method at this time. When PGP
- 5.5 is released, all support will be migrated to the new Source Development
- Kit (SDK) from the existing APIs. Developers are encouraged to either use
- the executable integration method detailed here or wait for the SDK to be
- released.
-
- EXECUTABLE INTEGRATION
- The most straightforward means of integrating PGP support into your appli-
- cation is to open input and output pipes to the PGP executables. For a
- very thorough example of PGP integration, see the "plugins" directory of
- the PGP 5.0 source distribution, which has a patch for the mutt email
- client. Most of the ideas in this text are a result of experiences modify-
- ing Michael Elkins' PGP integration code from mutt.
-
- The basic strategy is to use the PGP executables to perform encryption,
- decryption and verification. While it is possible to take a much more com-
- plex approach (for example, Mr. Elkins' code actually parses the output of
- pgpk(1) in order to present users with a list of keys), the more complex
- efforts are outside the scope of this document.
-
- All examples are in "C", and assume the following variables:
-
- char *recipients; /*A space-delimited list of message recipients*/
- char *buf; /*The message to be operated on*/
- char *passphrase; /*The user's passphrase*/
-
- All allocation is assumed already handled by the application. The reader
- is assumed to be familiar with concepts of C programming and to have read
- and understood the pgp.cfg(5) man page. Also be aware that the following
- code assumes all buffers are big enough and isn't always perfect about han-
- dling errors gracefully. This should be considered a starting point, not a
- complete system.
-
- COMMON ROUTINE
- The following routine uses fork(2) and pipe(2) to open both read and write
- file handles to a child process. It is used to invoke PGP in these exam-
- ples. You may use it effectively without understanding how it works.
-
- /*Runs cmd, and hooks in to the process' stdin, and out to its stdout.
- *Inspiration stolen from Michael Elkins; see mutt for how to do this
- *properly with error checking, etc.
- */
- int run_pgp(char *cmd, FILE **in, FILE **out)
- {
- int pin[2], pout[2], child_pid;
-
- *in = *out = NULL;
-
- pipe(pin);
- pipe(pout);
-
- if(!(child_pid = fork()))
- {
- /*We're the child.*/
- close(pin[1]);
- dup2(pin[0], 0);
- close(pin[0]);
-
- close(pout[0]);
- dup2(pout[1], 1);
- close(pout[1]);
-
- execl("/bin/sh", "sh", "-c", cmd, NULL);
- _exit(127);
- }
-
- /*Only get here if we're the parent.*/
- close(pout[1]);
- *out = fdopen(pout[0], "r");
-
- close(pin[0]);
- *in = fdopen(pin[1], "w");
-
- return(child_pid);
- }
-
- ENCRYPTION
- The easiest case is to simply pass your buffer to PGP. The most minimal
- form of this would be to write your data out, and have PGP encrypt it.
- Unfortunately, this would mean that the cleartext document would be placed
- on the hard drive, which is undesirable. However, we can use PGP's stream
- mode (the -f option) to get PGP to accept the plaintext on stdin and place
- the encrypted text on stdout:
-
- /*Takes the buffer you wish to encrypt and the recipients; writes the
- *result into encrypt_buffer.
- */
- void encrypt_buffer(char *buf, char *recipients)
- {
- FILE *pgpin, *pgpout;
- char sys_buf[256], tmpbuf[1024] = "\0";
-
- sprintf(sys_buf, "pgpe -at -r %s -f +batchmode=1", recipients);
- run_pgp(sys_buf, &pgpin, &pgpout); /*Execute PGP*/
- if(pgpin && pgpout)
- {
- /*Output buffer to PGP:*/
- fwrite(buf, sizeof(char), strlen(buf), pgpin);
- fclose(pgpin);
-
- /*Now, read the result back from PGP:*/
- *buf = '\0';
- fgets(tmpbuf, sizeof(tmpbuf), pgpout);
- while(!feof(pgpout))
- {
- strcat(buf, tmpbuf);
- fgets(tmpbuf, sizeof(tmpbuf), pgpout);
- }
- fclose(pgpout);
- }
- }
-
- Additional functionality would include using the -s flag to sign the mes-
- sage if the user so requested. Implementation is quite similar to the
- pgps(1) integration, shown next.
-
- If you find that PGP is mysteriously failing during this step, it may be
- because you are encrypting to keys that are not completely valid. By
- default, PGP will fail during batch mode when this is encountered. The
- solution is to place NoBatchInvalidKeys = off in your pgp.cfg file. It is
- requested that you not pass this option on the command line, as some users
- will prefer not to encrypt to invalid keys.
-
- SIGNING
- Conceptually, signing is quite similar, but with a twist - the user must
- specify a passphrase! The simple way to handle this is to allow PGP to ask
- the user for the passphrase. However, if you wish to hide PGP's func-
- tionality a little bit more, you may wish to ask for the passphrase your-
- self, prior to signing, and pass it through.
-
- There are a number of ways to get the passphrase to PGP, but the best is
- probably using the environment variable PGPPASSFD. This allows you to
- specify a file descriptor on which you will pass the passphrase as the
- first input. Commonly, this is set to 0, stdin:
-
- /*Signs a buffer. The output is placed in buf.*/
- void sign_buffer(char *buf, char *passphrase)
- {
- FILE *pgpin, *pgpout;
- char tmpbuf[1024] = " ";
-
- setenv("PGPPASSFD", "0", 1);
- run_pgp("pgps -at -f +batchmode=1", &pgpin, &pgpout);
- if(pgpin && pgpout)
- {
- fprintf(pgpin, "%s\n", passphrase); /*Send the passphrase in, first*/
- memset(passphrase, '\0', strlen(passphrase)); /*Burn the passphrase*/
- fwrite(buf, sizeof(char), strlen(buf), pgpin);
- fclose(pgpin);
-
- *buf = '\0';
- fgets(tmpbuf, sizeof(tmpbuf), pgpout);
- while(!feof(pgpout))
- {
- strcat(buf, tmpbuf);
- fgets(tmpbuf, sizeof(tmpbuf), pgpout);
- }
-
- wait(NULL);
-
- fclose(pgpout);
- }
- unsetenv("PGPPASSFD");
- }
-
- Note the use of memset(3) to clear the passphrase immediately after use.
- Not clearing the passphrase can result in numerous security issues.
-
- DECRYPTION/VERIFICATION
- Decryption is almost identical to signing (the same passphrase requirements
- apply). The options passed in are slightly different, however:
-
- /*Verifies a PGP buffer. Note that, if the buffer is only signed, the
- *passphrase may be unnecessary - a complete program should probably
- *check for the "BEGIN PGP SIGNED MESSAGE" tag before prompting the
- *user for a passphrase. The output is placed in buf, as well.
- */
- void verify_buffer(char *buf, char *passphrase)
- {
- FILE *pgpin, *pgpout;
- char tmpbuf[1024] = " ";
-
- setenv("PGPPASSFD", "0", 1);
- run_pgp("pgpv -f +batchmode=1 +OutputInformationFD=1",
- &pgpin, &pgpout);
- if(pgpin && pgpout)
- {
- fprintf(pgpin, "%s\n", passphrase); /*Send the passphrase in, first*/
- memset(passphrase, '\0', strlen(passphrase)); /*Burn the passphrase*/
- fprintf(pgpin, "%s", buf);
- fclose(pgpin);
-
- *buf = '\0';
- fgets(tmpbuf, sizeof(tmpbuf), pgpout);
- while(!feof(pgpout))
- {
- strcat(buf, tmpbuf);
- fgets(tmpbuf, sizeof(tmpbuf), pgpout);
- }
-
- wait(NULL);
-
- fclose(pgpout);
- }
- unsetenv("PGPPASSFD");
- }
-
- The +OutputInformationFD option is used to have PGP output information
- about the message (in this case, who signed it, if anyone) on the same
- stream as the decrypted or verified data.
-
- CONFIGURATION OPTIONS
- Application integrators are encourages to read the pgp.cfg(5) documenta-
- tion, which details how to pass configuration options on the command line,
- including the public and private keyrings your application wishes to use.
-
- SEE ALSO
- pgp(1), pgpe(1), pgpv(1), pgps(1), pgpk(1), http://www.pgp.com (US ver-
- sions) and http://www.pgpi.com (International versions)
-