NAME

Mail::GPG - Handling of GnuPG encrypted / signed mails

SYNOPSIS

  use Mail::GPG;

  my $mg = Mail::GPG->new;

  my %keys_id2mail = $mg->query_keyring (
    search => 'joern@zyn.de',
  );

  my $entity = MIME::Entity->build (
    From     => 'joern@zyn.de',
    Subject  => "Mail::GPG Testmail",
    Data     => [ "Hiho, a nice encrypted mail" ],
    Encoding => "quoted-printable",
    Charset  => "iso-8859-1",
  );

  my $encrypted_entity = $mg->mime_sign_encrypt (
    entity     => $entity,
    key_id     => $key_id,
    password   => 'topsecret',
    recipients => [ 'niceguy@zyn.de' ],
  );

  my $mail_text = $encrypted_entity->as_string;

  # and a lot more...

  $mg->mime_sign ( ... );
  $mg->mime_encrypt ( ... );
  $mg->mime_sign_encrypt ( ... );

  $mg->armor_sign ( ... );
  $mg->armor_encrypt ( ... );
  $mg->armor_sign_encrypt ( ... );

  $mg->parse ( ... );

  $mg->decrypt ( ... );
  $mg->verify ( ... );

  $mg->is_encrypted ( ... );
  $mg->is_signed ( ... );
  $mg->is_signed_quick ( ... );

  $mg->get_decrypt_key ( ... );
  $mg->get_key_trust ( ... );

DESCRIPTION

This Perl modules handles all the details of encrypting and signing Mails using GnuPG according to RFC 3156 and RFC 2440, that is OpenPGP MIME and traditional armor signed/encrypted mails.

PREREQUISITES

  Perl              >= 5.00503
  MIME-tools        >= 5.419
  MIME::QuotedPrint >= 2.20  (part of MIME-Base64 distribution)
  GnuPG::Interface  >= 0.52
  List::MoreUtils   >= 0.410
  AnyEvent

INSTALLATION

Then install Mail::GPG

  % cd ../Mail-GPG-x.xx
  % perl Makefile.PL
  % make test
  % make install

Mail::GPG has a bunch of tests which will create a temporary gpg keyring to be able to do real encryption and stuff. You need to have gpg in your path for the tests to succeed, otherwise all useful tests will be skipped.

Note that the test 04.big needs some time, on an Athlon 1800XP about 12 seconds, so be patient ;)

KNOWN BUGS

Currently none. Please report any bugs to the author: Joern Reder <joern AT zyn.de>.

EXAMPLES

The Mail::GPG distribution contains the program mgpg-test:

  Usage: mgpg-test file ...

It takes one or more filenames of mails as arguments, analyzes them, prints information about signatures and decrypts encrypteded mails (after asking for the correspondent passphrases). The script is rather small and a good example of Mail::GPG usage.

The regression tests in the t/ directory of the distribution show exemplary usage of all Mail::GPG features.

CONSTRUCTOR AND ATTRIBUTES

new

  $mg = Mail::GPG->new (
    attribute => value,
    ...
  );

The new class method returns a new instance of the Mail::GPG class, initialized with the attributes passed as hash parameters.

Attributes

This is the list of attributes you can pass to the new method and access using the methods set_attribute and get_attribute:

default_key_id

The default_key_id takes a GnuPG key id. It is used for all methods which expect a key id, if you don't pass a specific key id to them.

default_passphrase

You can store the passphrase of the default_key_id using this attribute. All methods expecting the passphrase will take it from here by default.

WARNING

Aware that storing the secret key password in many variables in your program increases the risk of being attacked by memory inspection. So you probably don't want to use the default_passphrase attribute.

debug

Setting the debug attribute to a true value will cause Mail::GPG to dump files into the debug_dir (see beyond). This way you can track entities, if signature validation or decryption fails for some reason.

debug_dir

This defaults to File::Spec->tmpdir. The directory is used to store debug files (see debug above).

gnupg_hash_init

This attribute corresponds to the GnuPG::Interface hash_init attribute. Please refer to the GnuPG::Interface manpage for details. E.g. you can set gpg's --homedir option this way and much more.

digest

This is the digest used by GnuPG to calculate hash values for signatures. By default Mail::GPG sets it to "RIPEMD160", which is needed to handle DSA keys (which are very common). You can check the supported digests of your gpg installation by executing 'gpg --version'.

default_key_encrypt

Set this attribute to a true value if you whish to have the default_key_id always added as a recipient for encrypted mails.

no_strict_7bit_encoding

By default this attribute is false, that means that all data which should be signed or encrypted is firstly checked for a RFC 3156 conform 7bit encoding. Until you set no_strict_7bit_encoding to true, an exception will be raised for non 7bit transparent encodings.

use_long_key_ids

Mail::GPG prior version 1.0.4 always used short 32 bit key id's. By setting this attribute to TRUE you can switch to long 64bit key id's. This affects the query_keyring() method and the key id's stored in Mail::GPG::Result.

gpg_call

This defaults to 'gpg' and is the path of the gpg program executed through GnuPG::Interface. Change this attribute if the 'gpg' program is not in your PATH.

METHODS TO CREATE MIME OpenPGP MESSAGES (RFC 3156)

mime_sign

  $signed_entity = $mg->mime_sign (
      entity     => $entity,
    [ key_id     => $key_id,
      passphrase => $passphrase ]
  );

This method returns the MIME signed version of an entity.

entity

The MIME::Entity object to be signed. By default it must not contain any parts with non 7bit content transfer encodings, because RFC 3156 forbids that. If you want to be able to pass 8bit also (and thus create non RFC conform data), you have to set the no_strict_7bit_encoding attribute.

key_id

The id of the key used to sign the entity. This defaults to default_key_id if omitted here.

passphrase

The corresponding passphrase of the key. This defaults to default_passphrase if omitted here.

mime_encrypt

  $encrypted_entity = $mg->mime_encrypt (
      entity     => $entity,
      recipients => \@recipients,
  );

Returns the MIME encrypted version of an entity.

entity

The MIME::Entity object to be encrypted. By default it must not contain any parts with non 7bit content transfer encodings, because RFC 3156 forbids that. If you want to be able to pass 8bit also (and thus create non RFC conform data), you have to set the no_strict_7bit_encoding attribute.

recipients

This is a reference to an array of recipients, which may be email adresses or key id's. If default_key_encrypt is set, the default_key_id will be added as a recipient automatically.

mime_sign_encrypt

  $encrypted_signed_entity = $mg->mime_sign_encrypt (
      entity     => $entity,
      recipients => \@recipients,
    [ key_id     => $key_id,
      passphrase => $passphrase ]
  );

Returns the encrypted and signed version of an entity.

entity

The MIME::Entity object to be signed and encrypted. By default it must not contain any parts with non 7bit content transfer encodings, because RFC 3156 forbids that. If you want to be able to pass 8bit also (and thus create non RFC conform data), you have to set the no_strict_7bit_encoding attribute.

recipients

This is a reference to an array of recipients, which may be email adresses or key id's. If default_key_encrypt is set, the default_key_id will be added as an recipient automatically.

key_id

The id of the key used to sign the entity. This defaults to default_key_id if omitted here.

passphrase

The corresponding passphrase of the key. This defaults to default_passphrase if omitted here.

METHODS TO CREATE ARMOR OpenPGP MESSAGES (RFC 2440)

armor_sign

  $signed_entity = $mg->armor_sign (
      entity     => $entity,
    [ key_id     => $key_id,
      passphrase => $passphrase ]
  );

This method returns the armor signed version of a MIME::Entity.

entity

The MIME::Entity object to be signed. It must not have any parts and a 7bit clean content transfer encoding.

key_id

The id of the key used to sign the entity. This defaults to default_key_id if omitted here.

passphrase

The corresponding passphrase of the key. This defaults to default_passphrase if omitted here.

armor_encrypt

  $signed_entity = $mg->armor_encrypt (
      entity     => $entity,
      recipients => \@recipients,
  );

Returns the armor encrypted version of an entity.

entity

The MIME::Entity object to be encrypted. It must not have any parts and a 7bit clean content transfer encoding.

recipients

This is a reference to an array of recipients, which may be email adresses or key id's. If default_key_encrypt is set, the default_key_id will be added as an recipient automatically.

armor_sign_encrypt

  $signed_entity = $mg->mime_sign_encrypt (
      entity     => $entity,
      recipients => \@recipients,
    [ key_id     => $key_id,
      passphrase => $passphrase ]
  );

Returns the encrypted and signed version of an entity.

entity

The MIME::Entity object to be encrypted. It must not have any parts and a 7bit clean content transfer encoding.

recipients

This is a reference to an array of recipients, which may be email adresses or key id's. If default_key_encrypt is set, the default_key_id will be added as an recipient automatically.

key_id

The id of the key used to sign the entity. This defaults to default_key_id if omitted here.

passphrase

The corresponding passphrase of the key. This defaults to default_passphrase if omitted here.

METHODS FOR PARSING, DECRYPTION AND VERIFICATION

parse

  $entity = Mail::GPG->parse (
      mail_fh   => $filehandle,
    | mail_sref => \$mail_data
  );

This is a convenience method for parsing a mail message. It uses MIME::Parser and distinguish between MIME and non-MIME messages, doing the right thing regarding reading decoded or encoded bodies.

mail_fh

An opened filehandle of the mail message in question.

mail_sref

A reference to a scalar holding the mail message to be parsed.

Details about parsing with MIME::Parser for Mail::GPG

Parsing is not trivial, because we have a basic problem with MIME::Parser and MIME::Entity. If the mail in question is text/plain and contains an ASCII armor PGP message, Mail::GPG must see the decoded data.

But if it's a MIME PGP message, Mail::GPG needs the encoded data.

You can advice MIME::Parser to create an encoded entity (by default it creates decoded entities and encodes them on demand). You can activate this transparent encoding mode by setting decode_bodies attribute of MIME::Parser to 0 (it defaults to 1):

  $parser = MIME::Parser->new;
  $parser->decode_bodies(0);

So you need to set decode_bodies(0) for MIME messages and keep the default of decode_bodies(1) for armor messages. But how can you know in advance which is right without having the entity parsed already? You can't.

So the solution is to parse the entity twice if it's MIME, and keep the decoded version from the first parse run otherwise, or you do some quick analysis on the data in question, without really parsing it.

  $parser = MIME::Parser->new;
  $parser->decode_bodies(0);
  $entity = $parser->parse_data($mail_data);
  if ( $entity->effective_type ne 'multipart/signed' and
       $entity->effective_type ne 'multipart/encrypted' ) {
    $parser->decode_bodies(1);
    $entity = $parser->parse_data($mail_data);
  }

That's exactly what the parse() method does for you, so it's a good idea to use it instead of fiddling with all the details yourself ;)

decrypt

  ($decrypted_entity, $result) = $mg->decrypt (
      entity     => $entity,
    [ passphrase => $passphrase ]
  );

Returns the decrypted version of an entity and a Mail::GPG::Result object with detailed information about the entities encryption (refer to the manpage of Mail::GPG::Result).

entity

The MIME::Entity to be decrypted. Please read the chapter about the parse() method of details about this entity.

passphrase

The corresponding passphrase of the secret key which is needed to decrypt the message. Use get_decrypt_key to determine the corresponding key. This defaults to default_passphrase if omitted here.

verify

  $result = $mg->verify (
      entity => $entity,
  );

Returns a Mail::GPG::Result object with detailed information about the signature of an entity. Refer to the manpage of Mail::GPG::Result.

entity

The signed MIME::Entity to be verified. Please read the chapter about the parse() method of details about this entity.

METHODS FOR ENTITY INSPECTION

is_signed

  $signed = $mg->is_signed (
      entity => $entity,
  );

Returns whether an entity is signed or not.

entity

The entity to be checked for a signature.

is_signed_quick

  $signed = $mg->is_signed_quick (
      mail_fh   => $filehandle,
    | mail_sref => \$mail_data
  );

Does some very quick and rough detection whether a message is signed or not. Note: the special about this method is it doesn't require a MIME::Entity. Creating a MIME::Entity is the opposite of being "quick" ;)

Major drawback is, you can't really rely on the result of this method. It can't detect base64 encoded armor signed messages (it reports always false on them).

Also it may report a signature although it's not signed at all. E.g. the message is a reply to a armor signed message and the quoted parts contain the -----BEGIN PGP SIGNATURE----- string or something like that. To be really sure you should call is_signed() afterwards.

Just use is_signed_quick() to decide whether you want to do deeper inspection or not, but don't rely only on its result.

mail_fh

An opened filehandle of the mail message to be analyzed. Note: the filehandle is rewinded by the method using seek($mail_fh, 0, 0).

mail_sref

A reference to a scalar holding the mail message to be analyzed.

is_encrypted

  $encrypted = $mg->is_encrypted (
      entity     => $entity,
  );

Return whether an entity is encrypted or not.

entity

The entity to be checked for a encryption.

get_decrypt_key

  ($key_id, $key_mail) = $mg->get_decrypt_key (
      entity => $entity,
  );

Returns secret key id and mail address which is needed to decrypt an encrypted entity.

entity

The entity to inspect.

METHODS FOR KEY RING INSPECTION

query_keyring

  %result              = $mg->query_keyring ( search => $search );
  $key_id              = $mg->query_keyring ( search => $search );
  ($key_id, $key_mail) = $mg->query_keyring ( search => $search );
  %mails_by_key_id     = $mg->query_keyring ( search => $search, coerce => 1 );

Searches the keyring for a key id or email address. In list context a subsequent list of key id and mail address pairs (suitable for a hash variable) is returned. In scalar context the key id of the first entry is returned. If nothing was found undef is returned.

If you need more detailed control about the query result, use GnuPG::Interface->get_public_keys and GnuPG::Interface->get_secret_keys instead. For details refer to the GnuPG::PrimaryKey manpage.

If you use Perl 5.8.0 or better email addresses will be returned as an utf8 enabled scalar, because gpg always lists email adresses in utf8. Since Perl > 5.8.0 handles utf8 very nice and transparently, you mostly don't need to care about this ;)

If you use the module with older Perl versions you need to handle utf8 encoded data yourself.

coerce option & GPGv2

When using GPGv2, the current implementation tries to simulate the former behaviour. The first entry will be the PK-ID (pub: not sub:). The second entry will be the first valid (i.e. not expired, not revoked, etc.) email entry.

If there are sub-keys (sub:) or more email entries (uid:), all combinations are returned and the user needs to further filter the result. Since there may be many emails assigned to a given key-id, assigning to a hash will probably clobber previous id/email entries.

In order to allow assignment to a hash again, the parameter coerce => 1 can be used. When active, a list of pairs is returned where the first item is the key-id and the second item is an array-ref to a list of email addresses.

 %result = $mg->query_keyring ( search => $search, coerce => 1 );
 # (
 #   '999F00DAE20F5123',  [ 'Valid Test Key   <userX@localdomain>',
 #                          'Valid Test Key   <new@localdomain>' ],
 #   'CAFE333F196ED333',  [ 'Valid Test Key   <userX@localdomain>',
 #                          'Valid Test Key   <new@localdomain>' ]
 # )

Key id or email address to query for.

coerce

When true, returns all emails belonging to a key as an array-reference. (patched version only!)

Tests: All temporary files are created in directory /tmp/mail-gpg-test now. The environment variable DUMPDIR can be used to select an alternative directory.

get_key_trust

  $trust = $mg->get_key_trust (
    key_id => $key_id
  );
  

Reports the trust level of the given key. The known levels are listed in the DETAILS file of the gnupg distribution, but qouted here for convenience (gnupg 1.2.5):

  o = Unknown (this key is new to the system)
  i = The key is invalid (e.g. due to a missing self-signature)
  d = The key has been disabled
      (deprecated - use the 'D' in field 12 instead)
  r = The key has been revoked
  e = The key has expired
  - = Unknown trust (i.e. no value assigned)
  q = Undefined trust
      '-' and 'q' may safely be treated as the same
      value for most purposes
  n = Don't trust this key at all
  m = There is marginal trust in this key
  f = The key is fully trusted
  u = The key is ultimately trusted.  This often means
      that the secret key is available, but any key may
      be marked as ultimately trusted.
key_id

Key id to query for.

AUTHOR

Joern Reder <joern AT zyn.de>

CONTACT

You can contact me by email. Please place the module name "Mail::GPG" somewhere in the subject, because I filter my mails that way. I'm a native German speaker, but you can contact me in english as well.

COPYRIGHT

Copyright (C) 2004-2006 by Joern Reder, All Rights Reserved.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

SEE ALSO

Mail::GPG::Result, perl(1).