Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation

GnuPG tie to gpg binary gives broken pipe error in CGI output

by mattr (Curate)
on Mar 07, 2003 at 10:58 UTC ( #241103=perlquestion: print w/replies, xml ) Need Help??
mattr has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks!

I ask your help in a little mystery on which I've been beating my head. Solving it will make reasonable public key encryption on old perls a reality, I think. The purpose is to encrypt some user data which can be decrypted on a client PC with WinPT (Gnu's PGP-compatible GPG program with Windows Privacy Tray freeware).

First, the problem in short: This script works just fine from the command line, spitting out a PGP-style ascii-armored block of encrypted data. But when run in a browser, it dies on the line where it prints to the tied handle (see below).

The longer story: I need to encrypt some data using public key encryption on a server which has perl 5.00503 / FreeBSD 4.3. All the nice looking modules including the so-called pure perl ones in reality require a web of dependencies that seem to roll right up to perl 5.8.

Since this server also has limited resources, there is not enough memory to build perl 5.8, which I tried. I also built bits and pieces of it and other modules to get around various nitpicking errors like using strict, symbols not being defined in old Fcntl, constant not defined in, and trouble with Math::Pari and File:: modules. One nasty problem came up in that I wanted to use an IO handle to work with another GPG module and discovered that in this version of perl there are some problems with seek on these handles which make them less than full-fledged. Anyway, that sheaf of strategies and all the Crypt:: modules (well I didn't try all of them of course..) were not the Way To Do It.

I found GnuPG, which seems nice. It has a tie interface which lets you print to a tied filehandle which encrypts your data into a buffer, then you can read the encrypted data back out. This is exactly what I want.

Run on the command line it works as mentioned above. But run as a CGI it dies at the print CIPHER $plaintext line, printing to the browser a wierd error.. "error on write: Broken pipe". I have a theory that STDOUT gets trashed by this tying,.. anyway as brain cells have undergone sludge conversion I request the help of more experienced or masochistic monks!

#!/usr/local/bin/perl -w print "Content-type: text/html\n\n"; use lib qw(/home/www/davxw000/data/sitelib); use CGI::Carp qw(fatalsToBrowser warningsToBrowser); use GnuPG::Tie::Encrypt; $s = "This is a test.\nAnd another test."; $m = ''; # registered in gpg key ring $e = &encrypted($s,$m); print "Encrypted: <PRE>\n" . $e; sub encrypted { my ($plaintext,$recip) = @_; my $encrypted = ""; tie(*CIPHER,'GnuPG::Tie::Encrypt',armor=>1,recipient=>$recip); # tie interface. open buffer print CIPHER $plaintext; # and encrypt into buffer. $encrypted .= $_ while (<CIPHER>); # now read from buffer close CIPHER; # the encrypted data untie *CIPHER; # and close buffer return $encrypted; }
Thank you very much for your help. If you have any idea of what the problem is, or if anyone has been able to build pgp or gpg perl modules on an old perl I'd like to know. My last chance beyond this would be to attempt to open a pipe right to the binary and see if I can deal with that. I'd rather not be sending the data to another server to be encrypted even over SSL. FYI code also in mattr's scratchpad.



Replies are listed 'Best First'.
Re: GnuPG tie to gpg binary gives broken pipe error in CGI output
by zentara (Archbishop) on Mar 07, 2003 at 13:40 UTC
    This script works just fine from the command line, spitting out a PGP-style ascii-armored block of encrypted data. But when run in a browser, it dies on the line where it prints to the tied handle That is a clue all right. Usually it means it has something to do with the server running as nobody::nogroup. But since you say the permisions are fine, I'm thinking it has to do with user nobody dosn't have a key to encrypt with. Either it can't access the key ring, or it needs a key. Maybe those keys are mode 600? Have you tried making a set of keys for the user "nobody" so the webserver has it's own keyring?
Re: GnuPG tie to gpg binary gives broken pipe error in CGI output
by robartes (Priest) on Mar 07, 2003 at 11:07 UTC
    Hi Matt,

    You probably have thought of this, but did you check that the gpg binary is accessible and executable (permission wise) to the webserver CGI user? Usually, when something works on the command line, but doesn't from CGI, there is a permission problem involved somewhere.


      Thank you. I tried print "V: ". `gpg --version`; and got: V: gpg (GnuPG) 1.0.6 Copyright (C) 2001 Free Software Foundation, Inc. This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions. See the file COPYING for details. Home: ~/.gnupg Supported algorithms: Cipher: 3DES, CAST5, BLOWFISH, RIJNDAEL, RIJNDAEL192, RIJNDAEL256, TWOFISH Pubkey: RSA, RSA-E, RSA-S, ELG-E, DSA, ELG Hash: MD5, SHA1, RIPEMD160
        Update: While I can open and write to a file in the current (cgi) directory from within the program when running as a CGI, gpg as called from the CGI doesn't seem to write anything. I tried:
        `gpg --export -a --batch -o /home/...../cgi-bin/NEW`;
        but it only works on command line fwiw. I think I got it to do something a little while ago but it would only create a zero byte file.

        I wonder how I'd go about trying to do this without using GnuPG or any other module, just the cgi talking to the binary..

        Ah yes, I tried $gpg->export_keys( armor => 1, output => "" );
        which creates a file in the appropriate place but one of zero bytes only. Permissions were cool.

        Update: By cool I mean that it could write something. I could write successfully to files from the CGI. But it is not cool that only a zero byte file came out.. I tried it in different directories, and made a file chmod 777 in a 777 directory and gpg still wouldn't write to it from CGI. I have a whole application working on this system already so I don't think it is permissions.. I'm wondering if Io::Pipe will work.

Re: GnuPG tie to gpg binary gives broken pipe error in CGI output
by fglock (Vicar) on Mar 07, 2003 at 17:13 UTC

    There is a problem calling GnuPG from a CGI. It is related to using open2/open3 (which your library probably uses).

    There is some info here, I hope it helps.

Re: GnuPG tie to gpg binary gives broken pipe error in CGI output
by mattr (Curate) on Mar 09, 2003 at 13:28 UTC
    SUCCESS. Thank you all very much.

    I got both GnuPG::Interface and the code with Open3 working. GnuPG::Interface built okay on perl 5.005_03/FreeBSD 4.3 after also building Class::MethodMaker and editting my way around some tests. This no longer needed me to set $ENV{GNUPGHOME} as this is done in an init hash with the Interface module. A final hurdle was to get gpg's stderr and debug it, as explained below.

    Since I gave the server no key pair of its own, gpg was unable to trust an imported public key even though I told it to do so using the --edit-key function. It was necessary to edit the options file in the .gnupg directory to designate an ultimately trusted key to stop gpg from trying to validate it and failing. Also the key had to be designated as a "long key id", which is found (as the options file comment says) embedded in the output of gpg --list-key --with-colons (which is not the fingerprint).

    I was able to download the ascii-armored encrypted file and easily decrypt it with WinPT, which also worked well on a clipboard copied off a browser window.

    I will use GnuPG::Interface, and see if I can post something here after cleaning it up. Many thanks!

      Hi again, I cleaned up what I now have to share with others.
      #!/usr/local/bin/perl -w # gpgtest.cgi -- Encrypt to a Public Key from CGI # Runs on perl 5.005_03 / FreeBSD 4.3 $|=1; print "Content-type: text/html\n\nSTARTED<BR>"; use lib qw(/home/www/myusername/data/sitelib); use CGI::Carp qw(fatalsToBrowser warningsToBrowser); use IO::Handle; use GnuPG::Interface; # Note you should have imported a public key into gpg already. # It must be trusted, which can be done without any secret keys # being installed by editting .gnupg/options (read the comments). # The encrypted text is ascii armored and can be copied or # downloaded for decryption with a GPG client like WinPT / GPG # See for documentation and links to client software. # Perl libs including Class::MethodMaker built with local prefix # using perl Makefile.PL LIB=~/data/sitelib my @plaintext = ("just another perl hacker"); # plaintext lines $m = ''; # email address my $gpghomedir = '/home/www/myusername/.gnupg'; # path to .gnupg my $gnupg = GnuPG::Interface->new(); # instantiate $gnupg->options->hash_init( armor => 1, homedir => $gpghomedir, verbose => 1, meta_interactive => 0 ); # init $gnupg->options->push_recipients($m); # email addresses # Set up some handles to communicate with gpg my ( $input, $output, $error ) = ( IO::Handle->new(), IO::Handle->new() , IO::Handle->new() ); my $handles = GnuPG::Handles->new( stdin => $input, stdout => $output, stderr => $error ); my $pid = $gnupg->encrypt( handles => $handles );# open write connxn foreach (@plaintext) { print $input $_; } # send msg to gpg close $input; # close write. my @ciphertext =(); # now read encrypted while (<$output>) { push(@ciphertext,$_); } # msg from gpg. waitpid $pid, 0; # clean up the done # GnuPG process. open (OUT,">testoutput"); # Save to disk. foreach (@ciphertext) { print OUT $_ ; }; close(OUT); print "<PRE>OK:\n" . join("",@ciphertext); # View in browser. print "\nWARNINGS:<BR>\n"; # View gpg stderr print $_ while (<$error>); # reading in buffer. close $error; # close buf handle. exit 0; Output: STARTED -----BEGIN PGP MESSAGE----- Version: GnuPG v1.0.6 (FreeBSD) Comment: For info see hQGOA6gWzASXj2Y7EAX+OYWAWeuP52WbB1/zc90H9VBgHBI/DUTROLzjxguyiFa8 HfRx1zgbeeALaJqmaSnM2uALdjFyIK0wfMwj7HtdUyOGFKZmW4g8fSolbLSMq++H SWoggl+grK2OfsL06ScKKu7ycq6TKRKg+/tkHSkf5pHDg1wBY+yPCSssTINtnL+W 0c1vb9+WOXUSbS6x7O7sZjY+b+YzTAL78gWqcYExm+yLXaURHGF2MbhKAS8+L9VH MfsdSinLGW3m1ddgP1bGBf0WLWYTrhTjb2eASHOLoAYCkedI6meCQklOOjcnGd6P jYSgJusmdiztuXOFOetL8q53H2X9Vvc9zOuqGdgmSV6VqLFvocb6gMzXzR/kdowZ hzq7iAWHWs6yNXn7NprCgujetHMLpMwpFeKAN45rkEvQjSyiObuwxhYRkNQclYoT I39QlRG7TRiXbeaKrrpY+RhsP96vPOT9wBb93fXkKlOVVXGm7farR2ces+/6RZFG c3RRcAWXJwUpLxi6TurdRgrSSAGa1oCjFkzEW4zudhKvAp5TzS7x/fXK+Nd5TTSJ uMiYWzOxpuBUY2gACoJwoHdlfjE/TFd4kyJ+FA+u+3ZHlJ7a0SESCNo82Q== =A/7j -----END PGP MESSAGE----- WARNINGS: gpg: Warning: using insecure memory! gpg: using secondary key XXXXXXXX instead of primary key XXXXXXXX gpg: This key belongs to us gpg: reading from `[stdin]' gpg: writing to stdout gpg: ELG-E/RIJNDAEL encrypted for: XXXXXXXX XXXX (XXXXXXXXX)
      Thank you again for your much appreciated help.
Re: GnuPG tie to gpg binary gives broken pipe error in CGI output
by jnarins (Initiate) on Mar 07, 2003 at 21:50 UTC
    Matt> Since this server also has limited resources, there is not enough memory to build perl 5.8, Matt, Perl is very friendly about building perls for other machines, even with different layouts. Find yourself a bigger 4.3BSD box and compile away :)
Re: GnuPG tie to gpg binary gives broken pipe error in CGI output
by mattr (Curate) on Mar 09, 2003 at 09:57 UTC
    Thanks zentara, user nobody didn't have access but it doesn't fix anything. Actually the server should be coming in with my username, at least it makes files with my login on them. I also cannot do chown in this environment. Encryption to a public key should not require having one's own keys.. I didn't make keys for the account itself, and now that I try to I find there is not enough entropy in the system (literally) to generate keys, anyway.

    fglock Thanks. I am not aware of using open2/3 but this is very useful information. I will certainly look at this some more.

    Also thank you, jnarins. I believe I can fit perl 5.8 in the 100mb I have (yes it's sad) maybe I can cross compile from a sparc or cygwin? Will look at that. ..My main linux machine is waiting to be rescued from an untimely lobotomy, it resembles me).

      I am testing the code from fglock's link. Interesting, I am able to run shell commands and confirmed the cgi definitely is coming in with my id and current dir, yet even though I have a .gnupg directory (not in current dir though) I get "gpg: fatal: ~/.gnupg: can't create directory: No such file or directory" when trying --list-keys.

      Also it isn't possible to generate a key fwiw due to lack of entropy (never had that problem before. ;|

      Update:..which error is solved by adding $ENV{"GNUPGHOME"}="/home/www/myusername/.gnupg"; thanks to this googled link.

      That thread inspired me to try GnuPG::Interface which is the successor to PGP::GPG::MessageProcessor which is discussed there.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://241103]
Approved by Tomte
Front-paged by broquaint
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (5)
As of 2018-02-24 22:55 GMT
Find Nodes?
    Voting Booth?
    When it is dark outside I am happiest to see ...

    Results (311 votes). Check out past polls.