]> gitweb.fluxo.info Git - firma.git/commitdiff
Adding misc files
authorSilvio Rhatto <rhatto@riseup.net>
Mon, 15 Feb 2010 17:19:55 +0000 (15:19 -0200)
committerSilvio Rhatto <rhatto@riseup.net>
Mon, 15 Feb 2010 17:19:55 +0000 (15:19 -0200)
30 files changed:
.gitignore [new file with mode: 0644]
CHANGELOG [changed mode: 0755->0644]
COPYING [changed mode: 0755->0644]
DETAILS [new file with mode: 0644]
GUIDELINES [changed mode: 0755->0644]
README [changed mode: 0755->0644]
misc/poc/README [new file with mode: 0644]
misc/poc/firma-0.1 [new file with mode: 0755]
misc/poc/firma-0.1.5 [new file with mode: 0755]
misc/poc/firma-0.1.6 [new file with mode: 0755]
misc/poc/firma-0.2 [new file with mode: 0755]
misc/poc/firma-0.2.1 [new file with mode: 0755]
misc/poc/firma-0.2.2 [new file with mode: 0755]
misc/poc/firma-0.2.3 [new file with mode: 0755]
misc/poc/firma-0.2.4 [new file with mode: 0755]
misc/poc/firma-0.2.x [new file with mode: 0755]
misc/python/README [new file with mode: 0644]
misc/python/firma.py [new file with mode: 0755]
releases/firma-0.1.tar.gz [new file with mode: 0644]
releases/firma-0.2.1.tar.gz [new file with mode: 0644]
releases/firma-0.2.2.tar.gz [new file with mode: 0644]
releases/firma-0.2.3.tar.gz [new file with mode: 0644]
releases/firma-0.2.4.tar.gz [new file with mode: 0644]
releases/firma-0.2.5.tar.gz [new file with mode: 0644]
releases/firma-0.2.6.tar.gz [new file with mode: 0644]
releases/firma-0.2.tar.gz [new file with mode: 0644]
releases/firma-0.3pre1.tar.gz [new file with mode: 0644]
releases/firma-0.3pre2.tar.gz [new file with mode: 0644]
releases/firma-0.3pre3.tar.gz [new file with mode: 0644]
www/index.html [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..1377554
--- /dev/null
@@ -0,0 +1 @@
+*.swp
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/COPYING b/COPYING
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/DETAILS b/DETAILS
new file mode 100644 (file)
index 0000000..03af065
--- /dev/null
+++ b/DETAILS
@@ -0,0 +1,1226 @@
+                                                              -*- text -*-
+Format of colon listings
+========================
+First an example:
+
+$ gpg --fixed-list-mode --with-colons --list-keys \
+   --with-fingerprint --with-fingerprint wk@gnupg.org
+
+pub:f:1024:17:6C7EE1B8621CC013:899817715:1055898235::m:::scESC:
+fpr:::::::::ECAF7590EB3443B5C7CF3ACB6C7EE1B8621CC013:
+uid:f::::::::Werner Koch <wk@g10code.com>:
+uid:f::::::::Werner Koch <wk@gnupg.org>:
+sub:f:1536:16:06AD222CADF6A6E1:919537416:1036177416:::::e:
+fpr:::::::::CF8BCC4B18DE08FCD8A1615906AD222CADF6A6E1:
+sub:r:1536:20:5CE086B5B5A18FF4:899817788:1025961788:::::esc:
+fpr:::::::::AB059359A3B81F410FCFF97F5CE086B5B5A18FF4:
+
+The double --with-fingerprint prints the fingerprint for the subkeys
+too, --fixed-list-mode is themodern listing way printing dates in
+seconds since Epoch and does not merge the first userID with the pub
+record.
+
+
+ 1. Field:  Type of record
+           pub = public key
+            crt = X.509 certificate
+            crs = X.509 certificate and private key available
+           sub = subkey (secondary key)
+           sec = secret key
+           ssb = secret subkey (secondary key)
+           uid = user id (only field 10 is used).
+           uat = user attribute (same as user id except for field 10).
+            sig = signature
+            rev = revocation signature
+           fpr = fingerprint: (fingerprint is in field 10)
+           pkd = public key data (special field format, see below)
+            grp = reserved for gpgsm
+            rvk = revocation key
+            tru = trust database information
+            spk = signature subpacket
+
+ 2. Field:  A letter describing the calculated trust. This is a single
+           letter, but be prepared that additional information may follow
+           in some future versions. (not used for secret keys)
+               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.
+ 3. Field:  length of key in bits.
+ 4. Field:  Algorithm: 1 = RSA
+                      16 = Elgamal (encrypt only)
+                      17 = DSA (sometimes called DH, sign only)
+                      20 = Elgamal (sign and encrypt - don't use them!)
+           (for other id's see include/cipher.h)
+ 5. Field:  KeyID
+ 6. Field:  Creation Date (in UTC).  For UID and UAT records, this is the
+            self-signature date.  Note that the dae is usally printed
+            in seconds since epoch, however, we are migrating to an ISO
+            8601 format (e.g. "19660205T091500").  This is currently
+            only relevant for X.509, A simple way to detect the format
+            is be scannning for the 'T'.
+ 7. Field:  Key or user ID/user attribute expiration date or empty if none.
+ 8. Field:  Used for serial number in crt records (used to be the Local-ID).
+            For UID and UAT records, this is a hash of the user ID contents
+            used to represent that exact user ID.  For trust signatures,
+            this is the trust depth seperated by the trust value by a
+            space.
+ 9. Field:  Ownertrust (primary public keys only)
+           This is a single letter, but be prepared that additional
+           information may follow in some future versions.  For trust
+           signatures with a regular expression, this is the regular
+           expression value, quoted as in field 10.
+10. Field:  User-ID.  The value is quoted like a C string to avoid
+           control characters (the colon is quoted "\x3a").
+            This is not used with --fixed-list-mode in gpg.
+            A UAT record puts the attribute subpacket count here, a
+           space, and then the total attribute subpacket size.
+            In gpgsm the issuer name comes here
+            An FPR record stores the fingerprint here.
+            The fingerprint of an revocation key is stored here.
+11. Field:  Signature class.  This is a 2 digit hexnumber followed by
+            either the letter 'x' for an exportable signature or the
+            letter 'l' for a local-only signature.
+            The class byte of an revocation key is also given here,
+            'x' and 'l' ist used the same way.
+12. Field:  Key capabilities:
+                e = encrypt
+                s = sign
+                c = certify
+                a = authentication
+           A key may have any combination of them in any order.  In
+           addition to these letters, the primary key has uppercase
+           versions of the letters to denote the _usable_
+           capabilities of the entire key, and a potential letter 'D'
+           to indicate a disabled key.
+13. Field:  Used in FPR records for S/MIME keys to store the fingerprint of
+            the issuer certificate.  This is useful to build the
+            certificate path based on certificates stored in the local
+            keyDB; it is only filled if the issue certificate is
+            available. The advantage of using this value is that it is
+            guaranteed to have been been build by the same lookup
+            algorithm as gpgsm uses.
+            For "uid" recods this lists the preferences n the sameway the 
+            -edit menu does.
+           For "sig" records, this is the fingerprint of the key that
+           issued the signature.  Note that this is only filled in if
+           the signature verified correctly.  Note also that for
+           various technical reasons, this fingerprint is only
+           available if --no-sig-cache is used.
+
+14. Field   Flag field used in the --edit menu output:
+
+15. Field   Used in sec/sbb to print the serial number of a token
+            (internal protect mode 1002) or a '#' if that key is a
+            simple stub (internal protect mode 1001)
+
+All dates are displayed in the format yyyy-mm-dd unless you use the
+option --fixed-list-mode in which case they are displayed as seconds
+since Epoch.  More fields may be added later, so parsers should be
+prepared for this. When parsing a number the parser should stop at the
+first non-number character so that additional information can later be
+added.
+
+If field 1 has the tag "pkd", a listing looks like this:
+pkd:0:1024:B665B1435F4C2 .... FF26ABB:
+    !  !   !-- the value
+    !  !------ for information number of bits in the value
+    !--------- index (eg. DSA goes from 0 to 3: p,q,g,y)
+
+
+The "tru" trust database records have the fields:
+
+ 2: Reason for staleness of trust.  If this field is empty, then the
+    trustdb is not stale.  This field may have multiple flags in it:
+
+    o: Trustdb is old
+    t: Trustdb was built with a different trust model than the one we
+       are using now.
+
+ 3: Trust model:
+    0: Classic trust model, as used in PGP 2.x.
+    1: PGP trust model, as used in PGP 6 and later.  This is the same
+       as the classic trust model, except for the addition of trust
+       signatures.
+
+    GnuPG before version 1.4 used the classic trust model by default.
+    GnuPG 1.4 and later uses the PGP trust model by default.
+
+ 4: Date trustdb was created in seconds since 1/1/1970.
+ 5: Date trustdb will expire in seconds since 1/1/1970.
+
+The "spk" signature subpacket records have the fields:
+
+ 2: Subpacket number as per RFC-2440 and later.
+ 3: Flags in hex.  Currently the only two bits assigned are 1, to
+    indicate that the subpacket came from the hashed part of the
+    signature, and 2, to indicate the subpacket was marked critical.
+ 4: Length of the subpacket.  Note that this is the length of the
+    subpacket, and not the length of field 5 below.  Due to the need
+    for %-encoding, the length of field 5 may be up to 3x this value.
+ 5: The subpacket data.  Printable ASCII is shown as ASCII, but other
+    values are rendered as %XX where XX is the hex value for the byte.
+
+
+Format of the "--status-fd" output
+==================================
+Every line is prefixed with "[GNUPG:] ", followed by a keyword with
+the type of the status line and a some arguments depending on the
+type (maybe none); an application should always be prepared to see
+more arguments in future versions.
+
+
+    NEWSIG
+        May be issued right before a signature verification starts.  This
+        is useful to define a context for parsing ERROR status
+        messages.  No arguments are currently defined.
+
+    GOODSIG    <long keyid>  <username>
+       The signature with the keyid is good.  For each signature only
+        one of the three codes GOODSIG, BADSIG or ERRSIG will be
+        emitted and they may be used as a marker for a new signature.
+        The username is the primary one encoded in UTF-8 and %XX
+        escaped.
+
+    EXPSIG     <long keyid>  <username>
+       The signature with the keyid is good, but the signature is
+       expired. The username is the primary one encoded in UTF-8 and
+       %XX escaped.
+
+    EXPKEYSIG  <long keyid>  <username>
+       The signature with the keyid is good, but the signature was
+       made by an expired key. The username is the primary one
+       encoded in UTF-8 and %XX escaped.
+
+    REVKEYSIG  <long keyid>  <username>
+       The signature with the keyid is good, but the signature was
+       made by a revoked key. The username is the primary one
+       encoded in UTF-8 and %XX escaped.
+
+    BADSIG     <long keyid>  <username>
+       The signature with the keyid has not been verified okay.
+        The username is the primary one encoded in UTF-8 and %XX
+        escaped.
+
+    ERRSIG  <long keyid>  <pubkey_algo> <hash_algo> \
+           <sig_class> <timestamp> <rc>
+       It was not possible to check the signature.  This may be
+       caused by a missing public key or an unsupported algorithm.
+       A RC of 4 indicates unknown algorithm, a 9 indicates a missing
+       public key. The other fields give more information about
+       this signature.  sig_class is a 2 byte hex-value.
+
+        Note, that TIMESTAMP may either be a number with seconds since
+        epoch or an ISO 8601 string which can be detected by the
+        presence of the letter 'T' inside.
+
+    VALIDSIG   <fingerprint in hex> <sig_creation_date> <sig-timestamp>
+               <expire-timestamp> <sig-version> <reserved> <pubkey-algo>
+               <hash-algo> <sig-class> <primary-key-fpr>
+
+       The signature with the keyid is good. This is the same as
+       GOODSIG but has the fingerprint as the argument. Both status
+       lines are emitted for a good signature.  All arguments here
+       are on one long line.  sig-timestamp is the signature creation
+       time in seconds after the epoch. expire-timestamp is the
+       signature expiration time in seconds after the epoch (zero
+       means "does not expire"). sig-version, pubkey-algo, hash-algo,
+       and sig-class (a 2-byte hex value) are all straight from the
+       signature packet.  PRIMARY-KEY-FPR is the fingerprint of the
+       primary key or identical to the first argument.  This is
+       useful to get back to the primary key without running gpg
+       again for this purpose.
+
+        Note, that *-TIMESTAMP may either be a number with seconds
+        since epoch or an ISO 8601 string which can be detected by the
+        presence of the letter 'T' inside.
+
+    SIG_ID  <radix64_string>  <sig_creation_date>  <sig-timestamp>
+       This is emitted only for signatures of class 0 or 1 which
+       have been verified okay.  The string is a signature id
+       and may be used in applications to detect replay attacks
+       of signed messages.  Note that only DLP algorithms give
+       unique ids - others may yield duplicated ones when they
+       have been created in the same second.
+
+        Note, that SIG-TIMESTAMP may either be a number with seconds
+        since epoch or an ISO 8601 string which can be detected by the
+        presence of the letter 'T' inside.
+
+
+    ENC_TO  <long keyid>  <keytype>  <keylength>
+       The message is encrypted to this keyid.
+       keytype is the numerical value of the public key algorithm,
+       keylength is the length of the key or 0 if it is not known
+       (which is currently always the case).
+
+    NODATA  <what>
+       No data has been found. Codes for what are:
+           1 - No armored data.
+           2 - Expected a packet but did not found one.
+           3 - Invalid packet found, this may indicate a non OpenPGP message.
+       You may see more than one of these status lines.
+
+    UNEXPECTED <what>
+        Unexpected data has been encountered
+            0 - not further specified               1       
+  
+
+    TRUST_UNDEFINED <error token>
+    TRUST_NEVER  <error token>
+    TRUST_MARGINAL
+    TRUST_FULLY
+    TRUST_ULTIMATE
+       For good signatures one of these status lines are emitted
+       to indicate how trustworthy the signature is.  The error token
+        values are currently only emiited by gpgsm.
+
+    SIGEXPIRED
+       This is deprecated in favor of KEYEXPIRED.
+
+    KEYEXPIRED <expire-timestamp>
+       The key has expired.  expire-timestamp is the expiration time
+       in seconds after the epoch.
+
+        Note, that TIMESTAMP may either be a number with seconds since
+        epoch or an ISO 8601 string which can be detected by the
+        presence of the letter 'T' inside.
+
+    KEYREVOKED
+       The used key has been revoked by its owner.  No arguments yet.
+
+    BADARMOR
+       The ASCII armor is corrupted.  No arguments yet.
+
+    RSA_OR_IDEA
+       The IDEA algorithms has been used in the data.  A
+       program might want to fallback to another program to handle
+       the data if GnuPG failed.  This status message used to be emitted
+        also for RSA but this has been dropped after the RSA patent expired.
+        However we can't change the name of the message.
+
+    SHM_INFO
+    SHM_GET
+    SHM_GET_BOOL
+    SHM_GET_HIDDEN
+
+    GET_BOOL
+    GET_LINE
+    GET_HIDDEN
+    GOT_IT
+
+    NEED_PASSPHRASE <long main keyid> <long keyid> <keytype> <keylength>
+       Issued whenever a passphrase is needed.
+       keytype is the numerical value of the public key algorithm
+       or 0 if this is not applicable, keylength is the length
+       of the key or 0 if it is not known (this is currently always the case).
+
+    NEED_PASSPHRASE_SYM <cipher_algo> <s2k_mode> <s2k_hash>
+       Issued whenever a passphrase for symmetric encryption is needed.
+
+    NEED_PASSPHRASE_PIN <card_type> <chvno>
+        Issued whenever a PIN is requested to unlock a card.
+
+    MISSING_PASSPHRASE
+       No passphrase was supplied.  An application which encounters this
+       message may want to stop parsing immediately because the next message
+       will probably be a BAD_PASSPHRASE.  However, if the application
+       is a wrapper around the key edit menu functionality it might not
+       make sense to stop parsing but simply ignoring the following
+       BAD_PASSPHRASE.
+
+    BAD_PASSPHRASE <long keyid>
+       The supplied passphrase was wrong or not given.  In the latter case
+       you may have seen a MISSING_PASSPHRASE.
+
+    GOOD_PASSPHRASE
+       The supplied passphrase was good and the secret key material
+       is therefore usable.
+
+    BAD_PASSPHRASE_PIN
+        Reserved for future use.
+
+    DECRYPTION_FAILED
+       The symmetric decryption failed - one reason could be a wrong
+       passphrase for a symmetrical encrypted message.
+
+    DECRYPTION_OKAY
+       The decryption process succeeded.  This means, that either the
+       correct secret key has been used or the correct passphrase
+       for a conventional encrypted message was given.  The program
+       itself may return an errorcode because it may not be possible to
+       verify a signature for some reasons.
+
+    NO_PUBKEY  <long keyid>
+    NO_SECKEY  <long keyid>
+       The key is not available
+
+    IMPORT_CHECK <long keyid> <fingerprint> <user ID>
+        This status is emitted in interactive mode right before
+        the "import.okay" prompt.
+
+    IMPORTED   <long keyid>  <username>
+       The keyid and name of the signature just imported
+
+    IMPORT_OK  <reason> [<fingerprint>]
+        The key with the primary key's FINGERPRINT has been imported.
+        Reason flags:
+          0 := Not actually changed
+          1 := Entirely new key.
+          2 := New user IDs
+          4 := New signatures
+          8 := New subkeys 
+         16 := Contains private key.
+        The flags may be ORed.
+
+    IMPORT_PROBLEM <reason> [<fingerprint>]
+        Issued for each import failure.  Reason codes are:
+          0 := "No specific reason given".
+          1 := "Invalid Certificate".
+          2 := "Issuer Certificate missing".
+          3 := "Certificate Chain too long".
+          4 := "Error storing certificate".
+
+    IMPORT_RES <count> <no_user_id> <imported> <imported_rsa> <unchanged>
+       <n_uids> <n_subk> <n_sigs> <n_revoc> <sec_read> <sec_imported> <sec_dups> <not_imported>
+       Final statistics on import process (this is one long line)
+
+    FILE_START <what> <filename>
+       Start processing a file <filename>.  <what> indicates the performed
+       operation:
+           1 - verify
+            2 - encrypt
+            3 - decrypt        
+
+    FILE_DONE
+       Marks the end of a file processing which has been started
+       by FILE_START.
+
+    BEGIN_DECRYPTION
+    END_DECRYPTION
+       Mark the start and end of the actual decryption process.  These
+       are also emitted when in --list-only mode.
+
+    BEGIN_ENCRYPTION  <mdc_method> <sym_algo>
+    END_ENCRYPTION
+       Mark the start and end of the actual encryption process.
+
+    DELETE_PROBLEM reason_code
+       Deleting a key failed.  Reason codes are:
+           1 - No such key
+           2 - Must delete secret key first
+            3 - Ambigious specification
+
+    PROGRESS what char cur total
+       Used by the primegen and Public key functions to indicate progress.
+       "char" is the character displayed with no --status-fd enabled, with
+       the linefeed replaced by an 'X'.  "cur" is the current amount
+       done and "total" is amount to be done; a "total" of 0 indicates that
+       the total amount is not known.  100/100 may be used to detect the
+       end of operation.
+        Well known values for WHAT:
+             "pk_dsa"   - DSA key generation
+             "pk_elg"   - Elgamal key generation
+             "primegen" - Prime generation
+             "need_entropy" - Waiting for new entropy in the RNG
+             "file:XXX" - processing file XXX
+                          (note that current gpg versions leave out the
+                           "file:" prefix).
+             "tick"     - generic tick without any special meaning - useful
+                          for letting clients know that the server is
+                          still working.
+             "starting_agent" - A gpg-agent was started because it is not
+                          running as a daemon.
+
+        
+    SIG_CREATED <type> <pubkey algo> <hash algo> <class> <timestamp> <key fpr>
+       A signature has been created using these parameters.
+           type:  'D' = detached
+                  'C' = cleartext
+                  'S' = standard
+                  (only the first character should be checked)
+           class: 2 hex digits with the signature class
+
+        Note, that TIMESTAMP may either be a number with seconds since
+        epoch or an ISO 8601 string which can be detected by the
+        presence of the letter 'T' inside.
+        
+    KEY_CREATED <type> <fingerprint> [<handle>]
+        A key has been created
+            type: 'B' = primary and subkey
+                  'P' = primary
+                  'S' = subkey
+        The fingerprint is one of the primary key for type B and P and
+        the one of the subkey for S.  Handle is an arbitrary
+        non-whitespace string used to match key parameters from batch
+        key creation run.
+
+    KEY_NOT_CREATED [<handle>]
+        The key from batch run has not been created due to errors.
+
+
+    SESSION_KEY  <algo>:<hexdigits>
+       The session key used to decrypt the message.  This message will
+       only be emitted when the special option --show-session-key
+       is used.  The format is suitable to be passed to the option
+       --override-session-key
+
+    NOTATION_NAME <name> 
+    NOTATION_DATA <string>
+        name and string are %XX escaped; the data may be splitted
+        among several notation_data lines.
+
+    USERID_HINT <long main keyid> <string>
+        Give a hint about the user ID for a certain keyID. 
+
+    POLICY_URL <string>
+        string is %XX escaped
+
+    BEGIN_STREAM
+    END_STREAM
+        Issued by pipemode.
+
+    INV_RECP <reason> <requested_recipient>
+        Issued for each unusable recipient. The reasons codes
+        currently in use are:
+          0 := "No specific reason given".
+          1 := "Not Found"
+          2 := "Ambigious specification"
+          3 := "Wrong key usage"
+          4 := "Key revoked"
+          5 := "Key expired"
+          6 := "No CRL known"
+          7 := "CRL too old"
+          8 := "Policy mismatch"
+          9 := "Not a secret key"
+        10 := "Key not trusted"
+
+        Note that this status is also used for gpgsm's SIGNER command
+        where it relates to signer's of course.
+
+    NO_RECP <reserved>
+        Issued when no recipients are usable.
+
+    ALREADY_SIGNED <long-keyid>
+        Warning: This is experimental and might be removed at any time.
+
+    TRUNCATED <maxno>
+        The output was truncated to MAXNO items.  This status code is issued
+        for certain external requests
+
+    ERROR <error location> <error code> 
+
+        This is a generic error status message, it might be followed
+        by error location specific data. <error token> and
+        <error_location> should not contain a space.  The error code
+        is a either a string commencing with a letter or such string
+        prefix with a numerical error code and an underscore; e.g.:
+        "151011327_EOF"
+
+    ATTRIBUTE <fpr> <octets> <type> <index> <count>
+             <timestamp> <expiredate> <flags>
+       This is one long line issued for each attribute subpacket when
+       an attribute packet is seen during key listing.  <fpr> is the
+       fingerprint of the key. <octets> is the length of the
+       attribute subpacket. <type> is the attribute type
+       (1==image). <index>/<count> indicates that this is the Nth
+       indexed subpacket of count total subpackets in this attribute
+       packet.  <timestamp> and <expiredate> are from the
+       self-signature on the attribute packet.  If the attribute
+       packet does not have a valid self-signature, then the
+       timestamp is 0.  <flags> are a bitwise OR of:
+               0x01 = this attribute packet is a primary uid
+               0x02 = this attribute packet is revoked
+               0x04 = this attribute packet is expired
+
+    CARDCTRL <what> [<serialno>]
+        This is used to control smartcard operations.
+        Defined values for WHAT are:
+           1 = Request insertion of a card.  Serialnumber may be given
+               to request a specific card.
+           2 = Request removal of a card.
+           3 = Card with serialnumber detected
+           4 = No card available.
+
+
+    PLAINTEXT <format> <timestamp>
+        This indicates the format of the plaintext that is about to be
+        written.  The format is a 1 byte hex code that shows the
+        format of the plaintext: 62 ('b') is binary data, 74 ('t') is
+        text data with no character set specified, and 75 ('u') is
+        text data encoded in the UTF-8 character set.  The timestamp
+        is in seconds since the epoch.
+
+    PLAINTEXT_LENGTH <length>
+        This indicates the length of the plaintext that is about to be
+        written.  Note that if the plaintext packet has partial length
+        encoding it is not possible to know the length ahead of time.
+        In that case, this status tag does not appear.
+
+    SIG_SUBPACKET <type> <flags> <len> <data>
+        This indicates that a signature subpacket was seen.  The
+        format is the same as the "spk" record above.
+
+    SC_OP_FAILURE
+        An operation on a smartcard definitely failed.  Currently
+        there is no indication of the actual error code, but
+        application should be prepared to later accept more arguments.
+
+    SC_OP_SUCCESS
+        A smart card operaion succeeded.  This status is only printed
+        for certain operation and is mostly useful to check whether a
+        PIN change really worked.
+
+    BACKUP_KEY_CREATED fingerprint fname
+        A backup key named FNAME has been created for the key wityh
+        KEYID.
+
+
+Format of the "--attribute-fd" output
+=====================================
+
+When --attribute-fd is set, during key listings (--list-keys,
+--list-secret-keys) GnuPG dumps each attribute packet to the file
+descriptor specified.  --attribute-fd is intended for use with
+--status-fd as part of the required information is carried on the
+ATTRIBUTE status tag (see above).
+
+The contents of the attribute data is specified by 2440bis, but for
+convenience, here is the Photo ID format, as it is currently the only
+attribute defined:
+
+   Byte 0-1:  The length of the image header.  Due to a historical
+              accident (i.e. oops!) back in the NAI PGP days, this is
+              a little-endian number.  Currently 16 (0x10 0x00).
+
+   Byte 2:    The image header version.  Currently 0x01.
+
+   Byte 3:    Encoding format.  0x01 == JPEG.
+
+   Byte 4-15: Reserved, and currently unused.
+
+   All other data after this header is raw image (JPEG) data.
+
+
+Format of the "--list-config" output
+====================================
+
+--list-config outputs information about the GnuPG configuration for
+the benefit of frontends or other programs that call GnuPG.  There are
+several list-config items, all colon delimited like the rest of the
+--with-colons output.  The first field is always "cfg" to indicate
+configuration information.  The second field is one of (with
+examples):
+
+version: the third field contains the version of GnuPG.
+
+   cfg:version:1.3.5
+
+pubkey: the third field contains the public key algorithmdcaiphers
+       this version of GnuPG supports, separated by semicolons.  The
+       algorithm numbers are as specified in RFC-2440.
+
+   cfg:pubkey:1;2;3;16;17
+
+cipher: the third field contains the symmetric ciphers this version of
+       GnuPG supports, separated by semicolons.  The cipher numbers
+       are as specified in RFC-2440.
+
+   cfg:cipher:2;3;4;7;8;9;10
+
+digest: the third field contains the digest (hash) algorithms this
+       version of GnuPG supports, separated by semicolons.  The
+       digest numbers are as specified in RFC-2440.
+
+   cfg:digest:1;2;3;8;9;10
+
+compress: the third field contains the compression algorithms this
+         version of GnuPG supports, separated by semicolons.  The
+         algorithm numbers are as specified in RFC-2440.
+
+   cfg:compress:0;1;2;3
+
+group: the third field contains the name of the group, and the fourth
+       field contains the values that the group expands to, separated
+       by semicolons.
+
+For example, a group of:
+   group mynames = paige 0x12345678 joe patti
+
+would result in:
+   cfg:group:mynames:patti;joe;0x12345678;paige
+
+
+Key generation
+==============
+    Key generation shows progress by printing different characters to
+    stderr:
+            "."  Last 10 Miller-Rabin tests failed
+            "+"  Miller-Rabin test succeeded
+            "!"  Reloading the pool with fresh prime numbers
+            "^"  Checking a new value for the generator
+            "<"  Size of one factor decreased
+            ">"  Size of one factor increased
+
+    The prime number for Elgamal is generated this way:
+
+    1) Make a prime number q of 160, 200, 240 bits (depending on the keysize)
+    2) Select the length of the other prime factors to be at least the size
+       of q and calculate the number of prime factors needed
+    3) Make a pool of prime numbers, each of the length determined in step 2
+    4) Get a new permutation out of the pool or continue with step 3
+       if we have tested all permutations.
+    5) Calculate a candidate prime p = 2 * q * p[1] * ... * p[n] + 1
+    6) Check that this prime has the correct length (this may change q if
+       it seems not to be possible to make a prime of the desired length)
+    7) Check whether this is a prime using trial divisions and the
+       Miller-Rabin test.
+    8) Continue with step 4 if we did not find a prime in step 7.
+    9) Find a generator for that prime.
+
+    This algorithm is based on Lim and Lee's suggestion from the
+    Crypto '97 proceedings p. 260.
+
+
+Unattended key generation
+=========================
+This feature allows unattended generation of keys controlled by a
+parameter file.  To use this feature, you use --gen-key together with
+--batch and feed the parameters either from stdin or from a file given
+on the commandline.
+
+The format of this file is as follows:
+  o Text only, line length is limited to about 1000 chars.
+  o You must use UTF-8 encoding to specify non-ascii characters.
+  o Empty lines are ignored.
+  o Leading and trailing spaces are ignored.
+  o A hash sign as the first non white space character indicates a comment line.
+  o Control statements are indicated by a leading percent sign, the
+    arguments are separated by white space from the keyword.
+  o Parameters are specified by a keyword, followed by a colon.  Arguments
+    are separated by white space.
+  o The first parameter must be "Key-Type", control statements
+    may be placed anywhere.
+  o Key generation takes place when either the end of the parameter file
+    is reached, the next "Key-Type" parameter is encountered or at the
+    control statement "%commit"
+  o Control statements:
+    %echo <text>
+       Print <text>.
+    %dry-run
+       Suppress actual key generation (useful for syntax checking).
+    %commit
+       Perform the key generation.  An implicit commit is done
+       at the next "Key-Type" parameter.
+    %pubring <filename>
+    %secring <filename>
+       Do not write the key to the default or commandline given
+       keyring but to <filename>.  This must be given before the first
+       commit to take place, duplicate specification of the same filename
+       is ignored, the last filename before a commit is used.
+       The filename is used until a new filename is used (at commit points)
+       and all keys are written to that file.  If a new filename is given,
+       this file is created (and overwrites an existing one).
+       Both control statements must be given.
+   o The order of the parameters does not matter except for "Key-Type"
+     which must be the first parameter.  The parameters are only for the
+     generated keyblock and parameters from previous key generations are not
+     used. Some syntactically checks may be performed.
+     The currently defined parameters are:
+     Key-Type: <algo-number>|<algo-string>
+       Starts a new parameter block by giving the type of the
+       primary key. The algorithm must be capable of signing.
+       This is a required parameter.
+     Key-Length: <length-in-bits>
+       Length of the key in bits.  Default is 1024.
+     Key-Usage: <usage-list>
+        Space or comma delimited list of key usage, allowed values are
+        "encrypt" and "sign".  This is used to generate the key flags.
+        Please make sure that the algorithm is capable of this usage.
+     Subkey-Type: <algo-number>|<algo-string>
+       This generates a secondary key.  Currently only one subkey
+       can be handled.
+     Subkey-Length: <length-in-bits>
+       Length of the subkey in bits.  Default is 1024.
+     Subkey-Usage: <usage-list>
+        Similar to Key-Usage.
+     Passphrase: <string>
+       If you want to specify a passphrase for the secret key,
+       enter it here.  Default is not to use any passphrase.
+     Name-Real: <string>
+     Name-Comment: <string>
+     Name-Email: <string>
+       The 3 parts of a key. Remember to use UTF-8 here.
+       If you don't give any of them, no user ID is created.
+     Expire-Date: <iso-date>|(<number>[d|w|m|y])
+       Set the expiration date for the key (and the subkey).  It
+       may either be entered in ISO date format (2000-08-15) or as
+       number of days, weeks, month or years. Without a letter days
+       are assumed.
+     Preferences: <string>
+        Set the cipher, hash, and compression preference values for
+       this key.  This expects the same type of string as "setpref"
+       in the --edit menu.
+     Revoker: <algo>:<fpr> [sensitive]
+        Add a designated revoker to the generated key.  Algo is the
+       public key algorithm of the designated revoker (i.e. RSA=1,
+       DSA=17, etc.)  Fpr is the fingerprint of the designated
+       revoker.  The optional "sensitive" flag marks the designated
+       revoker as sensitive information.  Only v4 keys may be
+       designated revokers.
+     Handle: <string>
+        This is an optional parameter only used with the status lines
+        KEY_CREATED and KEY_NOT_CREATED.  STRING may be up to 100
+        characters and should not contauin spaces.  It is useful for
+        batch key generation to associate a key parameter block with a
+        status line.
+
+
+Here is an example:
+$ cat >foo <<EOF
+     %echo Generating a standard key
+     Key-Type: DSA
+     Key-Length: 1024
+     Subkey-Type: ELG-E
+     Subkey-Length: 1024
+     Name-Real: Joe Tester
+     Name-Comment: with stupid passphrase
+     Name-Email: joe@foo.bar
+     Expire-Date: 0
+     Passphrase: abc
+     %pubring foo.pub
+     %secring foo.sec
+     # Do a commit here, so that we can later print "done" :-)
+     %commit
+     %echo done
+EOF
+$ gpg --batch --gen-key foo
+ [...]
+$ gpg --no-default-keyring --secret-keyring ./foo.sec \
+                                 --keyring ./foo.pub --list-secret-keys
+/home/wk/work/gnupg-stable/scratch/foo.sec
+------------------------------------------
+sec  1024D/915A878D 2000-03-09 Joe Tester (with stupid passphrase) <joe@foo.bar>
+ssb  1024g/8F70E2C0 2000-03-09
+
+
+
+Layout of the TrustDB
+=====================
+The TrustDB is built from fixed length records, where the first byte
+describes the record type.  All numeric values are stored in network
+byte order. The length of each record is 40 bytes. The first record of
+the DB is always of type 1 and this is the only record of this type.
+
+FIXME:  The layout changed, document it here.
+
+  Record type 0:
+  --------------
+    Unused record, can be reused for any purpose.
+
+  Record type 1:
+  --------------
+    Version information for this TrustDB.  This is always the first
+    record of the DB and the only one with type 1.
+     1 byte value 1
+     3 bytes 'gpg'  magic value
+     1 byte Version of the TrustDB (2)
+     1 byte marginals needed
+     1 byte completes needed
+     1 byte max_cert_depth
+           The three items are used to check whether the cached
+           validity value from the dir record can be used.
+     1 u32  locked flags [not used]
+     1 u32  timestamp of trustdb creation
+     1 u32  timestamp of last modification which may affect the validity
+           of keys in the trustdb.  This value is checked against the
+           validity timestamp in the dir records.
+     1 u32  timestamp of last validation [currently not used]
+           (Used to keep track of the time, when this TrustDB was checked
+            against the pubring)
+     1 u32  record number of keyhashtable [currently not used]
+     1 u32  first free record
+     1 u32  record number of shadow directory hash table [currently not used]
+           It does not make sense to combine this table with the key table
+           because the keyid is not in every case a part of the fingerprint.
+     1 u32  record number of the trusthashtbale
+
+
+  Record type 2: (directory record)
+  --------------
+    Informations about a public key certificate.
+    These are static values which are never changed without user interaction.
+
+     1 byte value 2
+     1 byte  reserved
+     1 u32   LID     . (This is simply the record number of this record.)
+     1 u32   List of key-records (the first one is the primary key)
+     1 u32   List of uid-records
+     1 u32   cache record
+     1 byte  ownertrust
+     1 byte  dirflag
+     1 byte  maximum validity of all the user ids
+     1 u32   time of last validity check.
+     1 u32   Must check when this time has been reached.
+            (0 = no check required)
+
+
+  Record type 3:  (key record)
+  --------------
+    Informations about a primary public key.
+    (This is mainly used to lookup a trust record)
+
+     1 byte value 3
+     1 byte  reserved
+     1 u32   LID
+     1 u32   next   - next key record
+     7 bytes reserved
+     1 byte  keyflags
+     1 byte  pubkey algorithm
+     1 byte  length of the fingerprint (in bytes)
+     20 bytes fingerprint of the public key
+             (This is the value we use to identify a key)
+
+  Record type 4: (uid record)
+  --------------
+    Informations about a userid
+    We do not store the userid but the hash value of the userid because that
+    is sufficient.
+
+     1 byte value 4
+     1 byte reserved
+     1 u32  LID  points to the directory record.
+     1 u32  next   next userid
+     1 u32  pointer to preference record
+     1 u32  siglist  list of valid signatures
+     1 byte uidflags
+     1 byte validity of the key calculated over this user id
+     20 bytes ripemd160 hash of the username.
+
+
+  Record type 5: (pref record)
+  --------------
+    This record type is not anymore used.
+
+     1 byte value 5
+     1 byte   reserved
+     1 u32  LID; points to the directory record (and not to the uid record!).
+           (or 0 for standard preference record)
+     1 u32  next
+     30 byte preference data
+
+  Record type 6  (sigrec)
+  -------------
+    Used to keep track of key signatures. Self-signatures are not
+    stored.  If a public key is not in the DB, the signature points to
+    a shadow dir record, which in turn has a list of records which
+    might be interested in this key (and the signature record here
+    is one).
+
+     1 byte   value 6
+     1 byte   reserved
+     1 u32    LID          points back to the dir record
+     1 u32    next   next sigrec of this uid or 0 to indicate the
+                    last sigrec.
+     6 times
+       1 u32  Local_id of signatures dir or shadow dir record
+       1 byte Flag: Bit 0 = checked: Bit 1 is valid (we have a real
+                            directory record for this)
+                        1 = valid is set (but may be revoked)
+
+
+
+  Record type 8: (shadow directory record)
+  --------------
+    This record is used to reserve a LID for a public key.  We
+    need this to create the sig records of other keys, even if we
+    do not yet have the public key of the signature.
+    This record (the record number to be more precise) will be reused
+    as the dir record when we import the real public key.
+
+     1 byte value 8
+     1 byte  reserved
+     1 u32   LID      (This is simply the record number of this record.)
+     2 u32   keyid
+     1 byte  pubkey algorithm
+     3 byte reserved
+     1 u32   hintlist  A list of records which have references to
+                       this key.  This is used for fast access to
+                       signature records which are not yet checked.
+                       Note, that this is only a hint and the actual records
+                       may not anymore hold signature records for that key
+                       but that the code cares about this.
+    18 byte reserved
+
+
+
+  Record Type 10 (hash table)
+  --------------
+    Due to the fact that we use fingerprints to lookup keys, we can
+    implement quick access by some simple hash methods, and avoid
+    the overhead of gdbm.  A property of fingerprints is that they can be
+    used directly as hash values.  (They can be considered as strong
+    random numbers.)
+      What we use is a dynamic multilevel architecture, which combines
+    hashtables, record lists, and linked lists.
+
+    This record is a hashtable of 256 entries; a special property
+    is that all these records are stored consecutively to make one
+    big table. The hash value is simple the 1st, 2nd, ... byte of
+    the fingerprint (depending on the indirection level).
+
+    When used to hash shadow directory records, a different table is used
+    and indexed by the keyid.
+
+     1 byte value 10
+     1 byte reserved
+     n u32  recnum; n depends on the record length:
+           n = (reclen-2)/4  which yields 9 for the current record length
+           of 40 bytes.
+
+    the total number of such record which makes up the table is:
+        m = (256+n-1) / n
+    which is 29 for a record length of 40.
+
+    To look up a key we use the first byte of the fingerprint to get
+    the recnum from this hashtable and look up the addressed record:
+       - If this record is another hashtable, we use 2nd byte
+        to index this hash table and so on.
+       - if this record is a hashlist, we walk all entries
+        until we found one a matching one.
+       - if this record is a key record, we compare the
+        fingerprint and to decide whether it is the requested key;
+
+
+  Record type 11 (hash list)
+  --------------
+    see hash table for an explanation.
+    This is also used for other purposes.
+
+    1 byte value 11
+    1 byte reserved
+    1 u32  next         next hash list record
+    n times             n = (reclen-5)/5
+       1 u32  recnum
+
+    For the current record length of 40, n is 7
+
+
+
+  Record type 254 (free record)
+  ---------------
+    All these records form a linked list of unused records.
+     1 byte  value 254
+     1 byte  reserved (0)
+     1 u32   next_free
+
+
+
+Packet Headers
+===============
+
+GNUPG uses PGP 2 packet headers and also understands OpenPGP packet header.
+There is one enhancement used with the old style packet headers:
+
+   CTB bits 10, the "packet-length length bits", have values listed in
+   the following table:
+
+      00 - 1-byte packet-length field
+      01 - 2-byte packet-length field
+      10 - 4-byte packet-length field
+      11 - no packet length supplied, unknown packet length
+
+   As indicated in this table, depending on the packet-length length
+   bits, the remaining 1, 2, 4, or 0 bytes of the packet structure field
+   are a "packet-length field".  The packet-length field is a whole
+   number field.  The value of the packet-length field is defined to be
+   the value of the whole number field.
+
+   A value of 11 is currently used in one place: on compressed data.
+   That is, a compressed data block currently looks like <A3 01 . .  .>,
+   where <A3>, binary 10 1000 11, is an indefinite-length packet. The
+   proper interpretation is "until the end of the enclosing structure",
+   although it should never appear outermost (where the enclosing
+   structure is a file).
+
++  This will be changed with another version, where the new meaning of
++  the value 11 (see below) will also take place.
++
++  A value of 11 for other packets enables a special length encoding,
++  which is used in case, where the length of the following packet can
++  not be determined prior to writing the packet; especially this will
++  be used if large amounts of data are processed in filter mode.
++
++  It works like this: After the CTB (with a length field of 11) a
++  marker field is used, which gives the length of the following datablock.
++  This is a simple 2 byte field (MSB first) containing the amount of data
++  following this field, not including this length field. After this datablock
++  another length field follows, which gives the size of the next datablock.
++  A value of 0 indicates the end of the packet. The maximum size of a
++  data block is limited to 65534, thereby reserving a value of 0xffff for
++  future extensions. These length markers must be inserted into the data
++  stream just before writing the data out.
++
++  This 2 byte field is large enough, because the application must buffer
++  this amount of data to prepend the length marker before writing it out.
++  Data block sizes larger than about 32k doesn't make any sense. Note
++  that this may also be used for compressed data streams, but we must use
++  another packet version to tell the application that it can not assume,
++  that this is the last packet.
+
+
+GNU extensions to the S2K algorithm
+===================================
+S2K mode 101 is used to identify these extensions.
+After the hash algorithm the 3 bytes "GNU" are used to make
+clear that these are extensions for GNU, the next bytes gives the
+GNU protection mode - 1000.  Defined modes are:
+  1001 - do not store the secret part at all
+  1002 - a stub to access smartcards (not used in 1.2.x)
+
+
+Pipemode
+========
+NOTE:  This is deprecated and will be removed in future versions.
+
+This mode can be used to perform multiple operations with one call to
+gpg. It comes handy in cases where you have to verify a lot of
+signatures. Currently we support only detached signatures.  This mode
+is a kludge to avoid running gpg n daemon mode and using Unix Domain
+Sockets to pass the data to it.  There is no easy portable way to do
+this under Windows, so we use plain old pipes which do work well under
+Windows.  Because there is no way to signal multiple EOFs in a pipe we
+have to embed control commands in the data stream: We distinguish
+between a data state and a control state.  Initially the system is in
+data state but it won't accept any data.  Instead it waits for
+transition to control state which is done by sending a single '@'
+character.  While in control state the control command os expected and
+this command is just a single byte after which the system falls back
+to data state (but does not necesary accept data now).  The simplest
+control command is a '@' which just inserts this character into the
+data stream.
+
+Here is the format we use for detached signatures:
+"@<"  - Begin of new stream
+"@B"  - Detached signature follows.
+        This emits a control packet (1,'B')
+<detached_signature>
+"@t"  - Signed text follows. 
+        This emits the control packet (2, 'B')
+<signed_text>
+"@."  - End of operation. The final control packet forces signature
+        verification
+"@>"  - End of stream   
+
+
+
+
+
+
+Other Notes
+===========
+    * For packet version 3 we calculate the keyids this way:
+       RSA     := low 64 bits of n
+       ELGAMAL := build a v3 pubkey packet (with CTB 0x99) and calculate
+                  a rmd160 hash value from it. This is used as the
+                  fingerprint and the low 64 bits are the keyid.
+
+    * Revocation certificates consist only of the signature packet;
+      "import" knows how to handle this.  The rationale behind it is
+      to keep them small.
+
+
+
+
+
+
+
+Keyserver Message Format
+=========================
+
+The keyserver may be contacted by a Unix Domain socket or via TCP.
+
+The format of a request is:
+
+====
+command-tag
+"Content-length:" digits
+CRLF
+=======
+
+Where command-tag is
+
+NOOP
+GET <user-name>
+PUT
+DELETE <user-name>
+
+
+The format of a response is:
+
+======
+"GNUPG/1.0" status-code status-text
+"Content-length:" digits
+CRLF
+============
+followed by <digits> bytes of data
+
+
+Status codes are:
+
+     o 1xx: Informational - Request received, continuing process
+
+     o 2xx: Success - The action was successfully received, understood,
+       and accepted
+
+     o 4xx: Client Error - The request contains bad syntax or cannot be
+       fulfilled
+
+     o 5xx: Server Error - The server failed to fulfill an apparently
+       valid request
+
+
+
+Documentation on HKP (the http keyserver protocol):
+
+A minimalistic HTTP server on port 11371 recognizes a GET for /pks/lookup.
+The standard http URL encoded query parameters are this (always key=value):
+
+- op=index (like pgp -kv), op=vindex (like pgp -kvv) and op=get (like
+  pgp -kxa)
+
+- search=<stringlist>. This is a list of words that must occur in the key.
+  The words are delimited with space, points, @ and so on. The delimiters
+  are not searched for and the order of the words doesn't matter (but see
+  next option).
+
+- exact=on. This switch tells the hkp server to only report exact matching
+  keys back. In this case the order and the "delimiters" are important.
+
+- fingerprint=on. Also reports the fingerprints when used with 'index' or
+  'vindex'
+
+The keyserver also recognizes http-POSTs to /pks/add. Use this to upload
+keys.
+
+
+A better way to do this would be a request like:
+
+   /pks/lookup/<gnupg_formatierte_user_id>?op=<operation>
+
+This can be implemented using Hurd's translator mechanism.
+However, I think the whole key server stuff has to be re-thought;
+I have some ideas and probably create a white paper.
+
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/README b/README
old mode 100755 (executable)
new mode 100644 (file)
diff --git a/misc/poc/README b/misc/poc/README
new file mode 100644 (file)
index 0000000..693db64
--- /dev/null
@@ -0,0 +1 @@
+Proof of concept and initial versions.
diff --git a/misc/poc/firma-0.1 b/misc/poc/firma-0.1
new file mode 100755 (executable)
index 0000000..eab39e6
--- /dev/null
@@ -0,0 +1,53 @@
+#!/bin/bash
+#
+# firma v0.1: simple encrypted mailing list aliases
+# feedback: rhatto@riseup.net | GPL
+#
+# list configuration is passed thru the a config file,
+# where you put PARAMETER=value (whithout spaces)
+#
+# MAIL= path for mail program
+# GPG= path for gnupg binary
+# TMP= where you want the temp files
+# LISTNAME= list email
+# GPGDIR= gpg dir for the lists' keyring
+# PASSWD= passwd for the lists' keyring
+
+# eval the config file
+source $1
+
+GPGCOMMAND="$GPG -q --homedir $GPGDIR"
+GPGLIST="$GPGCOMMAND --list-keys" 
+GPGDECRYPT="$GPGCOMMAND --decrypt"
+GPGENCRYPT="$GPGCOMMAND --always-trust -e -s -a -r" 
+
+rm $TMP $TMP.gpg
+touch $TMP; chmod 600 $TMP;
+touch $TMP.gpg; chmod 600 $TMP.gpg;
+
+# todo: use an array
+while read STDIN; do
+  echo $STDIN >> $TMP
+done
+
+# get the headers
+FROM=$(grep -m 1 ^From: $TMP | cut -f 2 -d :)
+DATE=$(grep -m 1 ^Date: $TMP)
+SUBJECT=$(grep -m 1 ^Subject: $TMP)
+
+# detect the encrypted message
+sed -n '/-----BEGIN PGP MESSAGE-----/,/-----END PGP MESSAGE-----/p' $TMP >> $TMP.gpg
+
+# encrypting and sending for each recipient on the list
+for EMAIL in $($GPGLIST | grep pub | cut -d "<" -f 2 | sed -e 's/>//' | grep @ | grep -v $LISTNAME); do 
+
+  echo "$PASSWD
+  Message from: $FROM
+  $SUBJECT
+  $DATE
+
+  $(echo "$PASSWD" | $GPGDECRYPT $TMP.gpg)" | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $EMAIL 
+
+done
+rm $TMP $TMP.gpg
diff --git a/misc/poc/firma-0.1.5 b/misc/poc/firma-0.1.5
new file mode 100755 (executable)
index 0000000..029a09d
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/bash
+#
+# firma v0.2: simple encrypted mailing list aliases
+# feedback: rhatto@riseup.net | GPL
+#
+# list configuration is passed through a config file,
+# where you put PARAMETER=value (whithout spaces)
+#
+# MAIL= path for mail program
+# GPG= path for gnupg binary
+# TMP= where you want the temp files
+# LISTNAME= list email
+# GPGDIR= gpg dir for the lists' keyring
+# PASSWD= passwd for the lists' keyring
+# FOOTER= message footer
+
+# eval the config file
+source $1
+
+GPGCOMMAND="$GPG -q --homedir $GPGDIR"
+GPGLIST="$GPGCOMMAND --list-keys" 
+GPGDECRYPT="$GPGCOMMAND --decrypt"
+GPGENCRYPT="$GPGCOMMAND --always-trust -e -s -a -r" 
+
+rm $TMP $TMP.gpg
+touch $TMP; chmod 600 $TMP;
+touch $TMP.gpg; chmod 600 $TMP.gpg;
+
+# todo: use an array
+while read STDIN; do
+  echo $STDIN >> $TMP
+done
+
+# get the headers
+FROM=$(grep -m 1 ^From: $TMP | cut -f 2 -d :)
+DATE=$(grep -m 1 ^Date: $TMP)
+SUBJECT=$(grep -m 1 ^Subject: $TMP)
+
+# detect the encrypted message
+sed -n '/-----BEGIN PGP MESSAGE-----/,/-----END PGP MESSAGE-----/p' $TMP >> $TMP.gpg
+
+# encrypting and sending for each recipient on the list
+for EMAIL in $($GPGLIST | grep pub | cut -d "<" -f 2 | sed -e 's/>//' | grep @ | grep -v $LISTNAME); do 
+
+  echo "$PASSWD
+  Message from: $FROM
+  $SUBJECT
+  $DATE
+
+  $(echo "$PASSWD" | $GPGDECRYPT $TMP.gpg)
+
+  ---
+  $FOOTER " | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $EMAIL 
+
+done
+rm $TMP $TMP.gpg
diff --git a/misc/poc/firma-0.1.6 b/misc/poc/firma-0.1.6
new file mode 100755 (executable)
index 0000000..239c9a5
--- /dev/null
@@ -0,0 +1,147 @@
+#!/bin/bash
+#
+# firma v0.2: simple encrypted mailing list aliases
+# feedback: rhatto@riseup.net | GPL
+#
+# list configuration is passed through a config file,
+# where you put PARAMETER=value (whithout spaces)
+#
+# MAIL= path for mail program
+# GPG= path for gnupg binary
+# TMP= where you want the temp files
+# LISTNAME= list email
+# GPGDIR= gpg dir for the lists' keyring
+# PASSWD= passwd for the lists' keyring
+# FOOTER= message footer
+# ALLOWSENDKEY = set to 1 if you want people automatically receive the list
+#                key requesting through listname-request@example.tld
+#                with subject: key
+#
+# design / todo:
+#
+# - list-request:
+#     - key (allow send key)
+#     - help
+#     - subscribe: exchange pubkey
+#     - unsubscribe
+# - strings
+# - check signatures
+# - create list
+# - archive (optional)
+# - logfile (optional)
+# - gpg --no-tty --display-charset --utf8-strings ?
+#
+# sintax: firma -c || firma config-file
+#         -c: create a new list
+#         config-file: parse the email from stdin
+#         with the parameters specified in the
+#         config-file 
+#
+# fix:
+# 
+# - special chars
+# - id's recipient selection
+# 
+
+fuction _refresh_cache { 
+  rm $1 $1.gpg
+  touch $1; chmod 600 $1;
+  touch $1.gpg; chmod 600 $TMP.gpg;
+}
+
+function _process_message {
+  # get the headers
+  FROM=$(grep -m 1 ^From: $1 | cut -f 2 -d :)
+  DATE=$(grep -m 1 ^Date: $1)
+  SUBJECT=$(grep -m 1 ^Subject: $1)
+
+  # detect the encrypted message
+  sed -n '/-----BEGIN PGP MESSAGE-----/,/-----END PGP MESSAGE-----/p' $1 >> $1.gpg
+
+  # encrypting and sending for each recipient on the list
+  for EMAIL in $($GPGLIST | grep pub | cut -d "<" -f 2 | sed -e 's/>//' | grep @ | grep -v $LISTNAME); do 
+
+    echo "$PASSWD
+    Message from: $FROM
+    $SUBJECT
+    $DATE
+
+    $(echo "$PASSWD" | $GPGDECRYPT $1.gpg)
+
+    ---
+    $FOOTER 
+    " | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $EMAIL 
+  done
+}
+
+function _process_request {
+
+  # todo: support subjects like "key   ", etc
+  FROM=$(grep -m 1 ^From: $1 | cut -f 2 -d :)
+  REQUEST=$(grep -m 1 ^Subject: $1)
+  if [[ $REQUEST == "key" ]]; then
+    if [[ $ALLOWSENDKEY == 1 ]]; then  
+      # send key to From: recipient
+    else
+      # dont send the key; return error message
+    fi
+  else if [[ $REQUEST == "subscribe" ]]; then
+    # check if user put its pubkey and
+    # ask the list for subscribe From: recipient
+  else if [[ $REQUEST == "unsubscribe" ]]; then
+    # unsubscribe and advise the list
+  else
+    # error message
+  fi 
+
+}
+
+function _process {
+
+  # eval the config file
+  source $1
+
+  GPGCOMMAND="$GPG -q --homedir $GPGDIR"
+  GPGLIST="$GPGCOMMAND --list-keys" 
+  GPGDECRYPT="$GPGCOMMAND --decrypt"
+  GPGENCRYPT="$GPGCOMMAND --always-trust --hidden-recipient --textmode -e -s -a -r" 
+
+  # clear the cache before read the message
+  _refresh_cache $TMP
+
+  # todo: use an array
+  while read STDIN; do
+    echo $STDIN >> $TMP
+  done 
+
+  # check with action is requested depending on the To: field
+  TO=$(grep -m 1 ^To: $)
+  if [[ $TO == $LISTNAME ]]; then _process_message $TMP;
+  else _process_request $TMP;
+  fi
+
+  # clear after process
+  _refresh_cache $TMP
+
+}
+
+function newlist {
+
+  LISTHOME = 
+  LISTNANE = 
+  ...
+
+  $GPGCOMMAND --gen-key
+
+}
+
+# check sintax
+if [[ $1 = "-c" ]]; then
+  _newlist;
+else if [ -f $1 ];
+  then _process $1;
+else
+  echo sintax: $0 [-c] [config-file];
+fi
+
+rm $TMP $TMP.gpg
diff --git a/misc/poc/firma-0.2 b/misc/poc/firma-0.2
new file mode 100755 (executable)
index 0000000..5cf85d2
--- /dev/null
@@ -0,0 +1,108 @@
+#!/bin/bash
+#
+# firma v0.2: simple encrypted mailing list aliases
+# feedback: rhatto@riseup.net luis@riseup.net | GPL
+#
+# list configuration is passed thru the config file,
+# where you put PARAMETER=value (whithout spaces)
+#
+# MAIL= path for mail program
+# GPG= path for gnupg binary
+# TMP= where you want the temp files
+# LISTNAME= list email
+# LISTADMIN= list administrator email addresses (space separated)
+# GPGDIR= gpg dir for the lists' keyring
+# PASSWD= passwd for the lists' keyring
+
+# eval the config file
+source $1
+
+# declare GPG variables
+GPGCOMMAND="$GPG --quiet --homedir $GPGDIR --batch --no-tty --no-use-agent --no-permission-warning"
+GPGLIST="$GPGCOMMAND --list-keys"
+GPGDECRYPT="$GPGCOMMAND --passphrase-fd 0 --decrypt"
+GPGENCRYPT="$GPGCOMMAND --passphrase-fd 0 --always-trust --encrypt --sign --armor --recipient"
+
+# declare functions
+# discard $GPGDECRYPT STDOUT and get its STDERR instead, for signature checking
+function GPGSTDERR {
+  echo "$PASSWD" | ($GPGDECRYPT --status-fd 2 $TMP.gpg 1> /dev/null) 2>&1 ;
+}
+
+# get list susbscriber addresses
+function SUBSCRIBERS {
+  $GPGLIST | sed -n "/$LISTNAME/d;/pub/p" | grep -o '<.*>' | sed -e 's/[<>]//g' ;
+}
+
+# create the temporary files and restrict their permissions
+rm -f $TMP $TMP.gpg
+touch $TMP; chmod 600 $TMP;
+touch $TMP.gpg; chmod 600 $TMP.gpg;
+
+# todo: use an array
+while read STDIN; do
+  echo $STDIN >> $TMP
+done
+
+# get the message headers
+# todo: find a better place for $FROMADD since its not part of the message headers
+FROM=$(grep -m 1 ^From: $TMP | cut -f 2 -d :)
+FROMADD=$(echo $FROMADD | if grep -q '<' ; then echo $FROMADD | grep -o '<.*>' | sed -e 's/[<>]//g' ; else echo $FROMADD ; fi)
+DATE=$(grep -m 1 ^Date: $TMP)
+SUBJECT=$(grep -m 1 ^Subject: $TMP | cut -f 2 -d :)
+
+# get the encrypted message
+sed -n '/-----BEGIN PGP MESSAGE-----/,/-----END PGP MESSAGE-----/p' $TMP >> $TMP.gpg
+
+# if signature is OK, encrypt and send it for each list subscriber
+# todo: declare a function to decrypt, re-encrypt and send the list messages
+if (GPGSTDERR | grep -q 'GOODSIG') ; then
+
+  for EMAIL in $(SUBSCRIBERS); do 
+
+    echo "$PASSWD
+    Message from: $FROM
+    Subject: $SUBJECT
+    $DATE
+
+    $(GPGSTDERR | grep 'gpg: Signature made')
+    $(GPGSTDERR | grep 'gpg: Good signature from')
+
+$(echo "$PASSWD" | $GPGDECRYPT $TMP.gpg 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $EMAIL
+
+  done
+
+# else, if signature is BAD, email it back to sender and to list admins
+elif (GPGSTDERR | grep -q 'BADSIG') ; then
+
+    echo "$PASSWD
+    Message from: $FROM
+    Subject: [BAD SIGNATURE] $SUBJECT
+    $DATE
+
+    $(GPGSTDERR | grep 'gpg: Signature made')
+    $(GPGSTDERR | grep 'gpg: BAD signature from')
+
+$(echo "$PASSWD" | $GPGDECRYPT $TMP.gpg 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $LISTADMIN $FROMADD | $MAIL -r $LISTNAME $LISTADMIN $FROMADD
+
+# else, probably either the message was not signed or the sender is not subscribed to the list
+# email the message back to sender including a note about this
+# todo: parse STDERR to find out why the signature couldn't be checked and send more specific errors back to sender
+else
+
+    echo "
+    Message from: $FROM
+    Subject: [RETURNED MAIL] $SUBJECT
+    $DATE
+
+    [ It was not possible to process this message. Either or both
+      the message was not encrypted and/or signed, or you are not
+      subscribed to this list.  Contact the list administrator if
+      you have any questions. ]
+
+    -- 
+    firma v0.2" | $MAIL -r $LISTNAME $FROMADD
+
+fi
+rm -f $TMP $TMP.gpg
diff --git a/misc/poc/firma-0.2.1 b/misc/poc/firma-0.2.1
new file mode 100755 (executable)
index 0000000..13ee6da
--- /dev/null
@@ -0,0 +1,133 @@
+#!/bin/bash
+#
+# firma v0.2.1: simple encrypted mailing list aliases
+# feedback: rhatto@riseup.net luis@riseup.net | GPL
+#
+# list configuration is passed thru the config file,
+# where you put PARAMETER=value (whithout spaces)
+#
+# MAIL= path for mail program
+# GPG= path for gnupg binary
+# TMP= where you want the temp files
+# LISTNAME= list email
+# LISTADMIN= list administrator email addresses (space separated)
+# GPGDIR= gpg dir for the lists' keyring
+# PASSWD= passwd for the lists' keyring
+
+# eval the config file
+source $1
+
+# declare GPG variables
+GPGCOMMAND="$GPG --quiet --homedir $GPGDIR --batch --no-tty --no-use-agent --no-permission-warning"
+GPGLIST="$GPGCOMMAND --list-keys --with-colons"
+GPGDECRYPT="$GPGCOMMAND --passphrase-fd 0 --decrypt"
+GPGENCRYPT="$GPGCOMMAND --passphrase-fd 0 --always-trust --encrypt --sign --armor --hidden-recipient"
+
+# check configuration file parameters
+# todo: check if $TMP directory/files exist and if password is at least n characters long
+if [ ! -x $GPG -o ! -f $GPG ]; then
+  echo -e "\n$1: GPG binary ($GPG) could not be found.\n"
+  exit
+elif [ ! -x $MAIL -o ! -f $MAIL ]; then
+  echo -e "\n$1: Mail program ($MAIL) could not be found.\n"
+  exit
+elif [ ! -d $GPGDIR -o ! -f $GPGDIR/pubring.gpg -o ! -f $GPGDIR/secring.gpg ]; then
+  echo -e "\n$1: GPG home directory ($GPGDIR) or the GPG keyrings could not be found.\n"
+  exit
+elif [ -z $($GPGLIST | grep -o "<$LISTNAME>") ]; then
+  echo -e "\n$1: GPG key for list \"$LISTNAME\" could not be found."
+  echo -e "$1: Note that this parameter expects an email address.\n"
+  exit
+else
+  for ADMIN in $LISTADMIN; do {
+    if [ -z $($GPGLIST | grep -o "<$ADMIN>") ]; then
+      echo -e "\n$1: GPG key for list administrator \"$ADMIN\" could not be found."
+      echo -e "$1: Note that this parameter expects one or more email addresses.\n"
+      exit
+    fi; }
+  done
+fi
+
+# declare functions
+# discard $GPGDECRYPT STDOUT and get its STDERR instead, for signature checking
+function GPGSTDERR {
+  echo "$PASSWD" | ($GPGDECRYPT --status-fd 2 $TMP.gpg 1> /dev/null) 2>&1 ;
+}
+
+# get list susbscriber addresses
+function SUBSCRIBERS {
+  $GPGLIST | sed -n "/$LISTNAME/d;/pub/p" | grep -o "<.*>" | sed -e "s/[<>]//g" ;
+}
+
+# create the temporary files and restrict their permissions
+rm -f $TMP $TMP.gpg
+touch $TMP; chmod 600 $TMP;
+touch $TMP.gpg; chmod 600 $TMP.gpg;
+
+# todo: use an array
+while read STDIN; do
+  echo $STDIN >> $TMP
+done
+
+# get the message headers
+# todo: find a better place for $FROMADD since its not part of the message headers
+FROM=$(grep -m 1 "^From:" $TMP | cut -d : -f 2- | sed "s/^ //")
+FROMADD=$(echo $FROM | if grep -q "<" ; then echo $FROM | grep -o "<.*>" | sed -e "s/[<>]//g" ; else echo $FROM ; fi)
+DATE=$(grep -m 1 "^Date:" $TMP)
+SUBJECT=$(grep -m 1 "^Subject:" $TMP | cut -d : -f 2- | sed "s/^ //")
+
+# get the encrypted message
+sed -n "/-----BEGIN PGP MESSAGE-----/,/-----END PGP MESSAGE-----/p" $TMP >> $TMP.gpg
+
+# if signature is Good, encrypt and send it for each list subscriber
+# todo: declare a function to decrypt, re-encrypt and send the list messages
+if (GPGSTDERR | grep -q "GOODSIG") ; then
+
+  for EMAIL in $(SUBSCRIBERS); do 
+
+    echo "$PASSWD
+    Message from: $FROM
+    Subject: $SUBJECT
+    $DATE
+
+    $(GPGSTDERR | grep "gpg: Signature made")
+    $(GPGSTDERR | grep "gpg: Good signature from")
+
+$(echo "$PASSWD" | $GPGDECRYPT $TMP.gpg 2> /dev/null)" | sed -e "s/=20$//" | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $EMAIL
+
+  done
+
+# else, if signature is BAD, email it back to sender and to list admins
+elif (GPGSTDERR | grep -q "BADSIG") ; then
+
+    echo "$PASSWD
+    Message from: $FROM
+    Subject: [BAD SIGNATURE] $SUBJECT
+    $DATE
+
+    $(GPGSTDERR | grep "gpg: Signature made")
+    $(GPGSTDERR | grep "gpg: BAD signature from")
+
+$(echo "$PASSWD" | $GPGDECRYPT $TMP.gpg 2> /dev/null)" | sed -e "s/=20$//" | $GPGENCRYPT $LISTADMIN $FROMADD | $MAIL -r $LISTNAME $LISTADMIN $FROMADD
+
+# else, probably either the message was not signed or the sender is not subscribed to the list
+# email the message back to sender including a note about this
+# todo: parse STDERR to find out why the signature couldn't be checked and send more specific errors back to sender
+else
+
+    echo "
+    Message from: $FROM
+    Subject: [RETURNED MAIL] $SUBJECT
+    $DATE
+
+    [ It was not possible to process this message. Either or both
+      the message was not encrypted and/or signed, or you are not
+      subscribed to this list.  Contact the list administrator if
+      you have any questions. ]
+
+    -- 
+    firma v0.2.1" | $MAIL -r $LISTNAME $FROMADD
+
+fi
+rm -f $TMP $TMP.gpg
diff --git a/misc/poc/firma-0.2.2 b/misc/poc/firma-0.2.2
new file mode 100755 (executable)
index 0000000..f1a8f27
--- /dev/null
@@ -0,0 +1,153 @@
+#!/bin/bash
+#
+# firma v0.2.2: simple encrypted mailing list aliases
+# feedback: rhatto@riseup.net luis@riseup.net | GPL
+#
+# list configuration is passed thru the config file,
+# where you put PARAMETER=value (whithout spaces)
+#
+# MAIL= path for mail program
+# GPG= path for gnupg binary
+# TMP= where you want the temp files
+# LISTNAME= list email
+# LISTADMIN= list administrator email addresses (space separated)
+# GPGDIR= gpg dir for the lists' keyring
+# PASSWD= passwd for the lists' keyring
+
+# if the configuration file exists, disable "sourcepath" and evaluate the parameters
+if [ -f $1 ]; then
+  shopt -u sourcepath && source $1
+else
+  echo -e "\nConfiguration file \"$1\" could not be found.\n"
+  exit
+fi
+
+# declare GPG variables
+GPGCOMMAND="$GPG --quiet --homedir $GPGDIR --batch --no-tty --no-use-agent --no-permission-warning"
+GPGLIST="$GPGCOMMAND --list-keys --with-colons"
+GPGDECRYPT="$GPGCOMMAND --passphrase-fd 0 --decrypt"
+GPGENCRYPT="$GPGCOMMAND --passphrase-fd 0 --always-trust --encrypt --sign --armor --recipient"
+
+# check configuration file parameters
+# todo: check if $TMP directory/files exist
+if [ ! -f $GPG -o ! -x $GPG ]; then
+  echo -e "\n$1: GPG binary ($GPG) could not be found.\n"
+  exit
+elif [ ! -f $MAIL -o ! -x $MAIL ]; then
+  echo -e "\n$1: Mail program ($MAIL) could not be found.\n"
+  exit
+elif [ ! -d $GPGDIR -o ! -f $GPGDIR/pubring.gpg -o ! -f $GPGDIR/secring.gpg ]; then
+  echo -e "\n$1: GPG home directory ($GPGDIR) or the GPG keyrings could not be found.\n"
+  exit
+elif [ -z "$(cat $1 | grep -o ^PASSWD=\'[^\']*\'$)" -o \
+       -z "$(echo -n $PASSWD)" -o \
+       "$(echo -n $PASSWD | wc -m)" -lt "25" -o \
+       -z "$(echo -n $PASSWD | grep -o [[:lower:][:upper:]])" -o \
+       -z "$(echo -n $PASSWD | grep -o [[:digit:]])" -o \
+       "$(echo -n $PASSWD | grep -o [[:punct:]] | wc -l)" -lt "5" ]; then
+  echo -e "\n$1: PASSWD is empty or does not meet the minimum complexity requirements."
+  echo "$1: Please set a new passphrase for the list's private key. Make it at least"
+  echo "$1: 25 characters long (using a combination of letters, numbers and at least"
+  echo "$1: 5 special characters) and enclose it in 'single quotes'. The passphrase"
+  echo -e "$1: itself, though, cannot contain any single quote.\n"
+  exit
+elif [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$LISTNAME\>$)" ]; then
+  echo -e "\n$1: GPG key for list \"$LISTNAME\" could not be found."
+  echo -e "$1: Note that this parameter expects an email address.\n"
+  exit
+else
+  for ADMIN in $LISTADMIN; do {
+    if [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$ADMIN\>$)" ]; then
+      echo -e "\n$1: GPG key for list administrator \"$ADMIN\" could not be found."
+      echo -e "$1: Note that this parameter expects one or more space separated email addresses.\n"
+      exit
+    fi; }
+  done
+fi
+
+# declare functions
+# discard $GPGDECRYPT STDOUT and get its STDERR instead, for signature checking
+function GPGSTDERR {
+  echo $PASSWD | ($GPGDECRYPT --status-fd 2 $TMP.gpg 1> /dev/null) 2>&1 ;
+}
+
+# get list susbscriber addresses
+function SUBSCRIBERS {
+  $GPGLIST | sed -ne "/$LISTNAME/Id" -e '/pub/p' | cut -d : -f 10 | grep -o '<[^<>]*>$' | sed -e 's/[<>]//g' ;
+}
+
+# create the temporary files and restrict their permissions
+rm -f $TMP $TMP.gpg
+touch $TMP && chmod 600 $TMP
+touch $TMP.gpg && chmod 600 $TMP.gpg
+
+# todo: use an array
+while read STDIN; do
+  echo $STDIN >> $TMP
+done
+
+# get the message headers and the sender's email address
+FROM=$(grep -m 1 ^From: $TMP | cut -d : -f 2- | sed -e 's/^ //')
+FROMADD=$(if [ -z "$(echo $FROM | grep '>$')" ] ; then echo $FROM ; else echo $FROM | grep -o '<[^<>]*>$' | sed -e 's/[<>]//g' ; fi)
+DATE=$(grep -m 1 ^Date: $TMP)
+SUBJECT=$(grep -m 1 ^Subject: $TMP | cut -d : -f 2- | sed -e 's/^ //')
+
+# get the encrypted message
+sed -ne '/-----BEGIN PGP MESSAGE-----/,/-----END PGP MESSAGE-----/p' $TMP >> $TMP.gpg
+
+# if signature is Good, encrypt and send it for each list subscriber
+# todo: declare a function to decrypt, re-encrypt and send the list messages
+if (GPGSTDERR | grep -Fq GOODSIG) ; then
+
+  for EMAIL in $(SUBSCRIBERS); do 
+
+    echo "$PASSWD
+    Message from: $FROM
+    Subject: $SUBJECT
+    $DATE
+
+    $(GPGSTDERR | grep -F 'gpg: Signature made')
+    $(GPGSTDERR | grep -F 'gpg: Good signature from')
+
+$(echo $PASSWD | $GPGDECRYPT $TMP.gpg 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $EMAIL
+
+  done
+
+# else, if signature is BAD, email it back to the list admins and to sender
+elif (GPGSTDERR | grep -Fq BADSIG) ; then
+
+  for EMAIL in $(echo $LISTADMIN $FROMADD); do
+
+    echo "$PASSWD
+    Message from: $FROM
+    Subject: [BAD SIGNATURE] $SUBJECT
+    $DATE
+
+    $(GPGSTDERR | grep -F 'gpg: Signature made')
+    $(GPGSTDERR | grep -F 'gpg: BAD signature from')
+
+$(echo $PASSWD | $GPGDECRYPT $TMP.gpg 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $EMAIL
+
+  done
+
+# else, probably either the message was not signed or the sender is not subscribed to the list
+# email the message back to sender including a note about this
+# todo: parse STDERR to find out why the signature couldn't be checked and send more specific errors back to sender
+else
+
+    echo "
+    Message from: $FROM
+    Subject: [RETURNED MAIL] $SUBJECT
+    $DATE
+
+    [ It was not possible to process this message. Either or both
+      the message was not encrypted and/or signed, or you are not
+      subscribed to this list.  Contact the list administrator if
+      you have any questions. ]
+
+    -- 
+    firma v0.2.2" | $MAIL -r $LISTNAME $FROMADD
+
+fi
+rm -f $TMP $TMP.gpg
diff --git a/misc/poc/firma-0.2.3 b/misc/poc/firma-0.2.3
new file mode 100755 (executable)
index 0000000..2864115
--- /dev/null
@@ -0,0 +1,192 @@
+#!/bin/bash
+#
+# firma v0.2.3: encrypted mailing list manager
+# feedback: rhatto@riseup.net luis@riseup.net | GPL
+#
+# list configuration is passed thru the config file,
+# where you put PARAMETER=value (whithout spaces)
+#
+# MAIL= path for mail program
+# GPG= path for gnupg binary
+# TMP= where you want the temp files
+# LISTNAME= list email
+# LISTADMIN= list administrator email addresses (space separated)
+# GPGDIR= gpg dir for the lists' keyring
+# PASSWD= passwd for the lists' keyring
+#
+
+VERSION=0.2.3
+
+function usage {
+  echo usage: $0 firma \<option\> \<config-file\>
+  echo -c: create a new list using config-file
+  echo -p: process a message 
+  echo -a: admin commands
+}
+
+function check_config {
+  # check configuration file parameters
+  # todo: check if $TMP directory/files exist
+  if [ ! -f $GPG -o ! -x $GPG ]; then
+    echo -e "\n$1: GPG binary ($GPG) could not be found.\n"
+    exit 1
+  elif [ ! -f $MAIL -o ! -x $MAIL ]; then
+    echo -e "\n$1: Mail program ($MAIL) could not be found.\n"
+    exit 1
+  elif [ ! -d $GPGDIR -o ! -f $GPGDIR/pubring.gpg -o ! -f $GPGDIR/secring.gpg ]; then
+    echo -e "\n$1: GPG home directory ($GPGDIR) or the GPG keyrings could not be found.\n"
+      exit 1
+  elif [ -z "$(cat $CONFIG | grep -o ^PASSWD=\'[^\']*\'$)" -o \
+         -z "$(echo -n $PASSWD)" -o \
+         "$(echo -n $PASSWD | wc -m)" -lt "25" -o \
+         -z "$(echo -n $PASSWD | grep -o [[:lower:][:upper:]])" -o \
+         -z "$(echo -n $PASSWD | grep -o [[:digit:]])" -o \
+         "$(echo -n $PASSWD | grep -o [[:punct:]] | wc -l)" -lt "5" ]; then
+    echo -e "\n$CONFIG: PASSWD is empty or does not meet the minimum complexity requirements."
+    echo "$1: Please set a new passphrase for the list's private key. Make it at least"
+    echo "$1: 25 characters long (using a combination of letters, numbers and at least"
+    echo "$1: 5 special characters) and enclose it in 'single quotes'. The passphrase"
+    echo -e "$CONFIG: itself, though, cannot contain any single quote.\n"
+    exit 1
+  elif [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$LISTNAME\>$)" ]; then
+    echo -e "\n$CONFIG: GPG key for list \"$LISTNAME\" could not be found."
+    echo -e "$CONFIG: Note that this parameter expects an email address.\n"
+    exit 1
+  else
+    for ADMIN in $LISTADMIN; do {
+      if [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$ADMIN\>$)" ]; then
+        echo -e "\n$CONFIG: GPG key for list administrator \"$ADMIN\" could not be found."
+        echo -e "$CONFIG: Note that this parameter expects one or more space separated email addresses.\n"
+        exit 1
+      fi; }
+    done
+  fi
+}
+
+function GPGSTDERR {
+  # discard $GPGDECRYPT STDOUT and get its STDERR instead, for signature checking
+  echo $PASSWD | ($GPGDECRYPT --status-fd 2 $TMP.gpg 1> /dev/null) 2>&1 ;
+}
+
+function SUBSCRIBERS {
+  # get list susbscriber's addresses
+  $GPGLIST | sed -ne "/$LISTNAME/Id" -e '/pub/p' | cut -d : -f 10 | grep -o '<[^<>]*>$' | sed -e 's/[<>]//g' ;
+}
+
+function process_message {
+  # process a message sent to the list
+
+  # create the temporary files and restrict their permissions
+  rm -f $TMP $TMP.gpg
+  touch $TMP && chmod 600 $TMP
+  touch $TMP.gpg && chmod 600 $TMP.gpg
+  
+  # todo: use an array
+  while read STDIN; do
+    echo $STDIN >> $TMP
+  done
+  
+  # get the message headers and the sender's email address
+  FROM=$(grep -m 1 ^From: $TMP | cut -d : -f 2- | sed -e 's/^ //')
+  FROMADD=$(if [ -z "$(echo $FROM | grep '>$')" ] ; then echo $FROM ; else echo $FROM | grep -o '<[^<>]*>$' | sed -e 's/[<>]//g' ; fi)
+  DATE=$(grep -m 1 ^Date: $TMP)
+  SUBJECT=$(grep -m 1 ^Subject: $TMP | cut -d : -f 2- | sed -e 's/^ //')
+  
+  # get the encrypted message
+  sed -ne '/-----BEGIN PGP MESSAGE-----/,/-----END PGP MESSAGE-----/p' $TMP >> $TMP.gpg
+  
+  # if signature is Good, encrypt and send it for each list subscriber
+  # todo: declare a function to decrypt, re-encrypt and send the list messages
+  if (GPGSTDERR | grep -Fq GOODSIG) ; then
+  
+    for EMAIL in $(SUBSCRIBERS); do 
+  
+      echo "$PASSWD
+    Message from: $FROM
+    Subject: $SUBJECT
+    $DATE
+  
+    $(GPGSTDERR | grep -F 'gpg: Signature made')
+    $(GPGSTDERR | grep -F 'gpg: Good signature from')
+  
+  $(echo $PASSWD | $GPGDECRYPT $TMP.gpg 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $EMAIL
+  
+    done
+  
+  # else, if signature is BAD, email it back to the list admins and to sender
+  elif (GPGSTDERR | grep -Fq BADSIG) ; then
+  
+    for EMAIL in $(echo $LISTADMIN $FROMADD); do
+  
+      echo "$PASSWD
+    Message from: $FROM
+    Subject: [BAD SIGNATURE] $SUBJECT
+    $DATE
+  
+    $(GPGSTDERR | grep -F 'gpg: Signature made')
+    $(GPGSTDERR | grep -F 'gpg: BAD signature from')
+  
+  $(echo $PASSWD | $GPGDECRYPT $TMP.gpg 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $EMAIL
+  
+    done
+  
+  # else, probably either the message was not signed or the sender is not subscribed to the list
+  # email the message back to sender including a note about this
+  # todo: parse STDERR to find out why the signature couldn't be checked and send more specific errors back to sender
+  else
+  
+      echo "
+    Message from: $FROM
+    Subject: [RETURNED MAIL] $SUBJECT
+    $DATE
+  
+    [ It was not possible to process this message. Either or both
+      the message was not encrypted and/or signed, or you are not
+      subscribed to this list.  Contact the list administrator if
+      you have any questions. ]
+    -- 
+    firma v$VERSION" | $MAIL -r $LISTNAME $FROMADD
+  
+  fi
+   
+  rm -f $TMP $TMP.gpg
+  
+}
+
+# main -
+# command line checking
+if [ -z $2 ]; then
+  usage; exit 1
+else
+  CONFIG=$2
+fi
+
+# if the configuration file exists, disable "sourcepath" and evaluate the parameters
+if [ -f $CONFIG ] && [[ $1 != "-c" ]]; then
+  shopt -u sourcepath && source $CONFIG
+else
+  echo -e "\nConfiguration file \"$CONFIG\" could not be found.\n"
+  exit 1
+fi
+
+# declare GPG variables
+GPGCOMMAND="$GPG --quiet --homedir $GPGDIR --batch --no-tty --no-use-agent --no-permission-warning"
+GPGLIST="$GPGCOMMAND --list-keys --with-colons"
+GPGDECRYPT="$GPGCOMMAND --passphrase-fd 0 --decrypt"
+GPGENCRYPT="$GPGCOMMAND --passphrase-fd 0 --always-trust --encrypt --sign --armor --recipient"
+
+# then check the config
+check_config
+
+# command line parsing
+if [[ $1 == "-c" ]]; then
+  newlist 
+elif [[ $1 == "-p" ]]; then
+  process_message
+elif [[ $1 == "-a" ]]; then
+  admin_task
+else
+  usage; exit 1
+fi 
diff --git a/misc/poc/firma-0.2.4 b/misc/poc/firma-0.2.4
new file mode 100755 (executable)
index 0000000..6418782
--- /dev/null
@@ -0,0 +1,211 @@
+#!/bin/bash
+#
+# firma v0.2.4: encrypted mailing list manager
+# feedback: rhatto@riseup.net luis@riseup.net | GPL
+#
+# list configuration is passed thru the config file,
+# where you put PARAMETER=value (whithout spaces)
+#
+# MAIL= path for mail program
+# GPG= path for gnupg binary
+# LISTNAME= list email
+# LISTADMIN= list administrator email addresses (space separated)
+# GPGDIR= gpg dir for the lists' keyring
+# PASSWD= passwd for the lists' keyring
+#
+
+VERSION=0.2.4
+
+function usage {
+  echo usage: $0 firma \<option\> \<config-file\>
+  echo -c: create a new list using config-file
+  echo -p: process a message 
+  echo -a: admin commands
+}
+
+function check_config {
+  # check configuration file parameters
+  if [ ! -f $GPG -o ! -x $GPG ]; then
+    echo -e "\n$1: GPG binary ($GPG) could not be found.\n"
+    exit 1
+  elif [ ! -f $MAIL -o ! -x $MAIL ]; then
+    echo -e "\n$1: Mail program ($MAIL) could not be found.\n"
+    exit 1
+  elif [ ! -d $GPGDIR -o ! -f $GPGDIR/pubring.gpg -o ! -f $GPGDIR/secring.gpg ]; then
+    echo -e "\n$1: GPG home directory ($GPGDIR) or the GPG keyrings could not be found.\n"
+      exit 1
+  elif [ -z "$(cat $CONFIG | grep -o ^PASSWD=\'[^\']*\'$)" -o \
+         -z "$(echo -n $PASSWD)" -o \
+         "$(echo -n $PASSWD | wc -m)" -lt "25" -o \
+         -z "$(echo -n $PASSWD | grep -o [[:lower:][:upper:]])" -o \
+         -z "$(echo -n $PASSWD | grep -o [[:digit:]])" -o \
+         "$(echo -n $PASSWD | grep -o [[:punct:]] | wc -l)" -lt "5" ]; then
+    echo -e "\n$CONFIG: PASSWD is empty or does not meet the minimum complexity requirements."
+    echo "$1: Please set a new passphrase for the list's private key. Make it at least"
+    echo "$1: 25 characters long (using a combination of letters, numbers and at least"
+    echo "$1: 5 special characters) and enclose it in 'single quotes'. The passphrase"
+    echo -e "$CONFIG: itself, though, cannot contain any single quote.\n"
+    exit 1
+  elif [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$LISTNAME\>$)" ]; then
+    echo -e "\n$CONFIG: GPG key for list \"$LISTNAME\" could not be found."
+    echo -e "$CONFIG: Note that this parameter expects an email address.\n"
+    exit 1
+  else
+    for ADMIN in $LISTADMIN; do {
+      if [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$ADMIN\>$)" ]; then
+        echo -e "\n$CONFIG: GPG key for list administrator \"$ADMIN\" could not be found."
+        echo -e "$CONFIG: Note that this parameter expects one or more space separated email addresses.\n"
+        exit 1
+      fi; }
+    done
+  fi
+}
+
+function GPGSTDERR {
+  # discard $GPGDECRYPT STDOUT and get its STDERR instead, for signature checking
+  echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | sed -e 's/^ //' | ($GPGDECRYPT --status-fd 2 1> /dev/null) 2>&1 ;
+}
+
+function SUBSCRIBERS {
+  # get list susbscriber's addresses
+  $GPGLIST | sed -ne "/$LISTNAME/Id" -e '/pub/p' | cut -d : -f 10 | grep -o '<[^<>]*>$' | sed -e 's/[<>]//g' ;
+}
+
+function get_message {
+  n=0;
+  while read STDIN; do
+    MESSAGE[$n]="$STDIN\n"
+    ((++n))
+  done
+}
+
+function get_gpg_message {
+  signal=0; x=0;
+  for ((count=0;count<=n;count++)); do
+    if [[ $signal == "0" ]] && [[ "$(echo "${MESSAGE[$count]}" | grep -v -e "-----BEGIN PGP MESSAGE-----")" == "" ]]; then
+      GPG_MESSAGE[$x]=${MESSAGE[$count]}; ((++x))
+      signal=1
+    elif [[ $signal == "1" ]]; then
+      GPG_MESSAGE[$x]=${MESSAGE[$count]}
+      ((++x))
+      if [[ "$(echo "${MESSAGE[$count]}" | grep -v -e "-----END PGP MESSAGE-----")" == "" ]]; then
+        signal=0
+      fi
+    fi
+  done
+}
+
+function get_headers {
+  # get the message headers and the sender's email address
+  FROM=$(echo -e "${MESSAGE[@]}" | grep -m 1 "From:" | cut -d : -f 2- | sed -e 's/^ //')
+  FROMADD=$(if [ -z "$(echo $FROM | grep '>$')" ] ; then echo $FROM ; else echo $FROM | grep -o '<[^<>]*>$' | sed -e 's/[<>]//
+g' ; fi)
+  DATE=$(echo -e "${MESSAGE[@]}" | grep -m 1 "Date:")
+  SUBJECT=$(echo -e "${MESSAGE[@]}" | grep -m 1 "Subject:" | cut -d : -f 2- | sed -e 's/^ //')
+}
+
+function process_message {
+  # process a message sent to the list
+
+  get_message
+  get_headers 
+  get_gpg_message
+
+  # if signature is Good, encrypt and send it for each list subscriber
+  # todo: declare a function to decrypt, re-encrypt and send the list messages
+  if (GPGSTDERR | grep -Fq GOODSIG) ; then
+  
+    for EMAIL in $(SUBSCRIBERS); do 
+  
+    echo "$PASSWD
+    Message from: $FROM
+    Subject: $SUBJECT
+    $DATE
+  
+    $(GPGSTDERR | grep -F 'gpg: Signature made')
+    $(GPGSTDERR | grep -F 'gpg: Good signature from')
+  
+  $(echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | $GPGDECRYPT 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $EMAIL
+  
+    done
+  
+  # else, if signature is BAD, email it back to the list admins and to sender
+  elif (GPGSTDERR | grep -Fq BADSIG) ; then
+  
+    for EMAIL in $(echo $LISTADMIN $FROMADD); do
+  
+    echo "$PASSWD
+    Message from: $FROM
+    Subject: [BAD SIGNATURE] $SUBJECT
+    $DATE
+  
+    $(GPGSTDERR | grep -F 'gpg: Signature made')
+    $(GPGSTDERR | grep -F 'gpg: BAD signature from')
+  
+  $(echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | $GPGDECRYPT 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $EMAIL | $MAIL -r $LISTNAME $EMAIL
+  
+    done
+  
+  # else, probably either the message was not signed or the sender is not subscribed to the list
+  # email the message back to sender including a note about this
+  # todo: parse STDERR to find out why the signature couldn't be checked and send more specific errors back to sender
+  else
+  
+    echo "
+    Message from: $FROM
+    Subject: [RETURNED MAIL] $SUBJECT
+    $DATE
+  
+    [ It was not possible to process this message. Either or both
+      the message was not encrypted and/or signed, or you are not
+      subscribed to this list.  Contact the list administrator if
+      you have any questions. ]
+    -- 
+    firma v$VERSION" | $MAIL -r $LISTNAME $FROMADD
+  
+  fi
+   
+}
+
+# main -
+# command line checking
+if [ -z $2 ]; then
+  usage; exit 1
+else
+  CONFIG=$2
+fi
+
+# if the configuration file exists, disable "sourcepath" and evaluate the parameters
+if [ -f $CONFIG ] && [[ $1 != "-c" ]]; then
+  shopt -u sourcepath && source $CONFIG
+else
+  echo -e "\nConfiguration file \"$CONFIG\" could not be found.\n"
+  exit 1
+fi
+
+declare -a MESSAGE
+declare -a GPG_MESSAGE
+declare n
+export LANG=en_US
+
+# declare GPG variables
+GPGCOMMAND="$GPG --quiet --homedir $GPGDIR --batch --no-tty --no-use-agent --no-permission-warning"
+GPGLIST="$GPGCOMMAND --list-keys --with-colons"
+GPGDECRYPT="$GPGCOMMAND --passphrase-fd 0 --decrypt"
+GPGENCRYPT="$GPGCOMMAND --passphrase-fd 0 --always-trust --encrypt --sign --armor --recipient"
+
+# then check the config
+check_config
+
+# command line parsing
+if [[ $1 == "-c" ]]; then
+  newlist 
+elif [[ $1 == "-p" ]]; then
+  process_message
+elif [[ $1 == "-a" ]]; then
+  admin_task
+else
+  usage; exit 1
+fi 
diff --git a/misc/poc/firma-0.2.x b/misc/poc/firma-0.2.x
new file mode 100755 (executable)
index 0000000..126f998
--- /dev/null
@@ -0,0 +1,280 @@
+#!/bin/bash
+#
+# firma v0.3: encrypted mailing list manager
+# feedback: rhatto@riseup.net luis@riseup.net | GPL
+#
+# list configuration is passed thru the config file,
+# where you put PARAMETER=value (whithout spaces)
+#
+# MAIL= path for mail program
+# GPG= path for gnupg binary
+# LISTNAME= list email
+# LISTADMIN= list administrator email addresses (space separated)
+# GPGDIR= gpg dir for the lists' keyring
+# PASSWD= passwd for the lists' keyring
+#
+
+FIRMA_LIST_PATH=/usr/local/etc/lists
+VERSION=0.3
+
+# todo:
+# errase all vars before quit the game
+# unset MESSAGE
+# unset GPG_MESSAGE
+# umask ....
+
+function usage {
+  echo usage: $0 firma \<option\> \<config-file\>
+  echo -c: create a new list using config-file
+  echo -p: process a message 
+  echo -r: admin and user requests (mail only)
+  echo -a: admin commands
+}
+
+function check_config {
+  # check configuration file parameters
+  if [ ! -f $GPG -o ! -x $GPG ]; then
+    echo -e "\n$1: GPG binary ($GPG) could not be found.\n"
+    exit 1
+  elif [ ! -f $MAIL -o ! -x $MAIL ]; then
+    echo -e "\n$1: Mail program ($MAIL) could not be found.\n"
+    exit 1
+  elif [ ! -d $GPGDIR -o ! -f $GPGDIR/pubring.gpg -o ! -f $GPGDIR/secring.gpg ]; then
+    echo -e "\n$1: GPG home directory ($GPGDIR) or the GPG keyrings could not be found.\n"
+      exit 1
+  elif [ -z "$(cat $CONFIG | grep -o ^PASSWD=\'[^\']*\'$)" -o \
+         -z "$(echo -n $PASSWD)" -o \
+         "$(echo -n $PASSWD | wc -m)" -lt "25" -o \
+         -z "$(echo -n $PASSWD | grep -o [[:lower:][:upper:]])" -o \
+         -z "$(echo -n $PASSWD | grep -o [[:digit:]])" -o \
+         "$(echo -n $PASSWD | grep -o [[:punct:]] | wc -l)" -lt "5" ]; then
+    echo -e "\n$CONFIG: PASSWD is empty or does not meet the minimum complexity requirements."
+    echo "$1: Please set a new passphrase for the list's private key. Make it at least"
+    echo "$1: 25 characters long (using a combination of letters, numbers and at least"
+    echo "$1: 5 special characters) and enclose it in 'single quotes'. The passphrase"
+    echo -e "$CONFIG: itself, though, cannot contain any single quote.\n"
+    exit 1
+  elif [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$LISTNAME\>$)" ]; then
+    echo -e "\n$CONFIG: GPG key for list \"$LISTNAME\" could not be found."
+    echo -e "$CONFIG: Note that this parameter expects an email address.\n"
+    exit 1
+  else
+    for ADMIN in $LISTADMIN; do {
+      if [ -z "$($GPGLIST | grep ^pub | cut -d : -f 10 | grep -i \<$ADMIN\>$)" ]; then
+        echo -e "\n$CONFIG: GPG key for list administrator \"$ADMIN\" could not be found."
+        echo -e "$CONFIG: Note that this parameter expects one or more space separated email addresses.\n"
+        exit 1
+      fi; }
+    done
+  fi
+}
+
+function GPGSTDERR {
+  # discard $GPGDECRYPT STDOUT and get its STDERR instead, for signature checking
+  echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | sed -e 's/^ //' | ($GPGDECRYPT --status-fd 2 1> /dev/null) 2>&1 ;
+}
+
+function SUBSCRIBERS {
+  # get list susbscriber's addresses
+  $GPGLIST | sed -ne "/$LISTNAME/Id" -e '/pub/p' | cut -d : -f 10 | grep -o '<[^<>]*>$' | sed -e 's/[<>]//g' ;
+}
+
+function get_message {
+  n=0;
+  while read STDIN; do
+    MESSAGE[$n]="$STDIN\n"
+    ((++n))
+  done
+}
+
+function get_gpg_message {
+  signal=0; x=0;
+  for ((count=0;count<=n;count++)); do
+    if [[ $signal == "0" ]] && [[ "$(echo "${MESSAGE[$count]}" | grep -v -e "-----BEGIN PGP MESSAGE-----")" == "" ]]; then
+      GPG_MESSAGE[$x]=${MESSAGE[$count]}; ((++x))
+      signal=1
+    elif [[ $signal == "1" ]]; then
+      GPG_MESSAGE[$x]=${MESSAGE[$count]}
+      ((++x))
+      if [[ "$(echo "${MESSAGE[$count]}" | grep -v -e "-----END PGP MESSAGE-----")" == "" ]]; then
+        signal=0
+      fi
+    fi
+  done
+}
+
+function get_headers {
+  # get the message headers and the sender's email address
+  FROM=$(echo -e "${MESSAGE[@]}" | grep -m 1 "From:" | cut -d : -f 2- | sed -e 's/^ //')
+  FROMADD=$(if [ -z "$(echo $FROM | grep '>$')" ] ; then echo $FROM ; else echo $FROM | grep -o '<[^<>]*>$' | sed -e 's/[<>]//
+g' ; fi)
+  DATE=$(echo -e "${MESSAGE[@]}" | grep -m 1 "Date:")
+  SUBJECT=$(echo -e "${MESSAGE[@]}" | grep -m 1 "Subject:" | cut -d : -f 2- | sed -e 's/^ //')
+}
+
+function message_list {
+# compose and send a message to the list
+# $1: subscriber email
+# sorry no identation :P  
+echo "$PASSWD
+Message from: $FROM
+Subject: $SUBJECT
+$DATE
+  
+$(GPGSTDERR | grep -F 'gpg: Signature made')
+$(GPGSTDERR | grep -F 'gpg: Good signature from')
+  
+$(echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | $GPGDECRYPT 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $1 | $MAIL -r $LISTNAME $1
+}
+
+function message_list_error {
+# compose and send an error message
+# sorry no identation :P  
+echo "$PASSWD
+Message from: $FROM
+Subject: [BAD SIGNATURE] $SUBJECT
+$DATE
+  
+$(GPGSTDERR | grep -F 'gpg: Signature made')
+$(GPGSTDERR | grep -F 'gpg: BAD signature from')
+$(echo -e "$PASSWD\n${GPG_MESSAGE[@]}" | $GPGDECRYPT 2> /dev/null)" | sed -e 's/=20$//' | $GPGENCRYPT $1 | $MAIL -r $LISTNAME $1
+}
+
+function message_list_return {
+# send a bouce message
+# $1: sender email (usually $FROMADD)
+# sorry no identation :P  
+echo "
+Message from: $FROM
+Subject: [RETURNED MAIL] $SUBJECT
+$DATE
+  
+  [ It was not possible to process this message. Either or both
+    the message was not encrypted and/or signed, or you are not
+    subscribed to this list.  Contact the list administrator if
+    you have any questions. ]
+  -- 
+  firma v$VERSION" | $MAIL -r $LISTNAME $1
+}
+
+function process_message {
+  # process a message sent to the list
+
+  get_message
+  get_headers 
+  get_gpg_message
+
+  # if signature is Good, encrypt and send it for each list subscriber
+  # todo: declare a function to decrypt, re-encrypt and send the list messages
+  if (GPGSTDERR | grep -Fq GOODSIG); then
+  
+    for EMAIL in $(SUBSCRIBERS); do 
+      message_list $EMAIL
+    done
+  
+  # else, if signature is BAD, email it back to the list admins and to sender
+  elif (GPGSTDERR | grep -Fq BADSIG) ; then
+  
+    for EMAIL in $(echo $LISTADMIN $FROMADD); do
+      message_list_error $EMAIL
+    done
+  
+  # else, probably either the message was not signed or the sender is not subscribed to the list
+  # email the message back to sender including a note about this
+  # todo: parse STDERR to find out why the signature couldn't be checked and send more specific errors back to sender
+  else
+    message_list_return $FROMADD 
+  fi
+   
+}
+
+function newlist {
+  # create a list if it doesnt already exist
+  if [ ! -d "$CONFIG_PATH" ]; then
+    echo creating folder $CONFIG_PATH...
+    mkdir "$CONFIG_PATH" # || (echo "error creating $CONFIG_PATH: installation aborted"; exit 1)
+    echo "creating list config file and will ask some questions."
+
+    GPGDIR="$CONFIG_PATH"  
+    read -p "path to nail command (eg, /usr/bin/nail): " MAIL
+    read -p "path to gpg binary (eg, /usr/bin/gpg): " GPG
+
+    # if [ ! -x $GPG ]; then 
+
+    read -p "list keyring folder (defaults to $GPGDIR): " GPGDIR
+
+    # todo: please no utf-8 (see DETAILS)
+    read -p "list email (eg, firma@domain.tld): " LISTNAME
+    read -p "list admins emails (space delimited)" LISTADMIN
+    read -p "password for list keyring (use a huge one): " PASSWD 
+
+    # todo: key specs (size, expiry date...)
+
+    echo "creating your config..."
+    touch $CONFIG
+    chown root.root $CONFIG
+    chmod 600 $CONFIG
+    if [ -f $CONFIG ]; then
+      echo -e "MAIL=$MAIL\nGPG=$GPG\nGPGDIR=$GPGDIR\nLISTNAME=$LISTNAME\nLISTADMIN=$LISTADMIN\nPASSWD=$PASSWD" > $CONFIG
+      echo "now generating your keyring..."
+      # re-eval GPGCOMMAND
+      # todo: GPGFLAGS depende de GPGDIR
+      GPGCOMMAND="$GPG $GPGFLAGS"
+      $GPGCOMMAND --gen-key  
+
+    fi
+  else
+    echo error creating $CONFIG_FILE: list already exists
+    exit 1 
+  fi
+}
+
+# main -
+# command line checking
+if [ -z $2 ]; then
+  usage; exit 1
+else
+  CONFIG_FILE="$2"
+  CONFIG_PATH="$FIRMA_LIST_PATH/$2"
+  CONFIG="$CONFIG_PATH/$2.conf"
+fi
+
+# if the configuration file exists, disable "sourcepath" and evaluate the parameters
+if [ -f $CONFIG ] && [[ $1 != "-c" ]]; then
+  shopt -u sourcepath && source $CONFIG
+else
+  echo -e "\nConfiguration file \"$CONFIG\" could not be found.\n"
+  exit 1
+fi
+
+declare -a MESSAGE
+declare -a GPG_MESSAGE
+declare n
+export LANG=en_US
+
+# declare GPG variables
+GPGFLAGS="--quiet --homedir $GPGDIR --batch --no-tty --no-use-agent --no-permission-warning"
+GPGCOMMAND="$GPG $GPGFLAGS"
+GPGLIST="$GPGCOMMAND --list-keys --with-colons"
+GPGDECRYPT="$GPGCOMMAND --passphrase-fd 0 --decrypt"
+GPGENCRYPT="$GPGCOMMAND --passphrase-fd 0 --always-trust --encrypt --sign --armor --recipient"
+
+# then check the config
+check_config
+
+# command line parsing
+if [[ $1 == "-c" ]]; then
+  newlist 
+elif [[ $1 == "-p" ]]; then
+  process_message
+elif [[ $1 == "-a" ]]; then
+  list_admin
+elif [[ $1 == "-r" ]]; then
+  list_request
+else
+  usage; exit 1
+fi 
diff --git a/misc/python/README b/misc/python/README
new file mode 100644 (file)
index 0000000..4f75401
--- /dev/null
@@ -0,0 +1,2 @@
+Initial and broken code. Needs GnuPGInterface available at
+http://py-gnupg.sourceforge.net.
diff --git a/misc/python/firma.py b/misc/python/firma.py
new file mode 100755 (executable)
index 0000000..19f9c9d
--- /dev/null
@@ -0,0 +1,85 @@
+#!/usr/bin/python
+""" Firma - Encrypted Mailing List Manager - Python Version
+
+firma: GnuPG-based encrypted mailing list manager
+Feedback: firma@sarava.org
+
+  Firma is free software; you can redistribute it and/or modify it under the
+  terms of the GNU General Public License as published by the Free Software
+  Foundation; either version 2 of the License, or (at your option) any later
+  version.
+
+  Firma is distributed in the hope that it will be useful, but WITHOUT ANY
+  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+  A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+  Place - Suite 330, Boston, MA 02111-1307, USA
+
+Lets use: http://docs.python.org/lib/module-email.html
+          http://docs.python.org/lib/module-smtplib.html
+          http://py-gnupg.sourceforge.net/
+
+Lets split the work:
+
+ - create list
+   - create folder, set permissions
+   - create config file
+   - create keyring, set permissions again
+ - admin list
+   - parse config file
+   - from command line
+     - parse comand line args
+     - exec admin tasks
+     - display output
+   - from email
+     - decrypt message
+     - parse command line args
+     - exec admin tasks
+     - record output
+     - encrypt and send back output
+ - process message
+   - parse config file
+   - read stdin and store as original message
+   - decrypt message
+   - if encrypted and signed, encrypt again and send to all subscribers
+
+"""
+
+import GnuPGInterface
+
+# first we'll create just a routine that sets up a new gpg keyring
+
+class NewKey(GnuPGInterface.GnuPG):
+       """ Class used to create a new gpg keyring """
+       def __init__(self):
+               GnuPGInterface.GnuPG.__init__(self)
+               self.options.armor = 0
+               self.options.extra_args.append("--gen-key")
+                self.options.meta_interactive = 0
+
+       def __setitem__(self, key, value):
+               if key == "homedir" and value:
+                        # TODO: check if --homedir already is on self.options.extra_args
+                       # TODO: check if the folder referenced by "value" exists
+                       self.options.extra_args.append("--homedir %s" % value)
+               # TODO: else raises an exception?
+
+class DelKey(GnuPGInterface.GnuPG):
+       """ Class used to delete a key from a keyring """
+       def __init__(self):
+               GnuPGInterface.GnuPG.__init__(self)
+
+class RevokeKey(GnuPGInterface.GnuPG):
+       """ Class used to revoke a key """
+       def __init__(self):
+               GnuPGInterface.GnuPG.__init__(self)
+
+# lets start the code
+
+passwd = "senha"
+newkey = NewKey()
+newkey = ["homedir"] = "firma-python/keyring-teste" 
+
+print newkey.options.extra_args
diff --git a/releases/firma-0.1.tar.gz b/releases/firma-0.1.tar.gz
new file mode 100644 (file)
index 0000000..d46768b
Binary files /dev/null and b/releases/firma-0.1.tar.gz differ
diff --git a/releases/firma-0.2.1.tar.gz b/releases/firma-0.2.1.tar.gz
new file mode 100644 (file)
index 0000000..8265862
Binary files /dev/null and b/releases/firma-0.2.1.tar.gz differ
diff --git a/releases/firma-0.2.2.tar.gz b/releases/firma-0.2.2.tar.gz
new file mode 100644 (file)
index 0000000..e653af8
Binary files /dev/null and b/releases/firma-0.2.2.tar.gz differ
diff --git a/releases/firma-0.2.3.tar.gz b/releases/firma-0.2.3.tar.gz
new file mode 100644 (file)
index 0000000..b32a16f
Binary files /dev/null and b/releases/firma-0.2.3.tar.gz differ
diff --git a/releases/firma-0.2.4.tar.gz b/releases/firma-0.2.4.tar.gz
new file mode 100644 (file)
index 0000000..fdcbb09
Binary files /dev/null and b/releases/firma-0.2.4.tar.gz differ
diff --git a/releases/firma-0.2.5.tar.gz b/releases/firma-0.2.5.tar.gz
new file mode 100644 (file)
index 0000000..1fa526b
Binary files /dev/null and b/releases/firma-0.2.5.tar.gz differ
diff --git a/releases/firma-0.2.6.tar.gz b/releases/firma-0.2.6.tar.gz
new file mode 100644 (file)
index 0000000..2a877a6
Binary files /dev/null and b/releases/firma-0.2.6.tar.gz differ
diff --git a/releases/firma-0.2.tar.gz b/releases/firma-0.2.tar.gz
new file mode 100644 (file)
index 0000000..04accb2
Binary files /dev/null and b/releases/firma-0.2.tar.gz differ
diff --git a/releases/firma-0.3pre1.tar.gz b/releases/firma-0.3pre1.tar.gz
new file mode 100644 (file)
index 0000000..6d33cfc
Binary files /dev/null and b/releases/firma-0.3pre1.tar.gz differ
diff --git a/releases/firma-0.3pre2.tar.gz b/releases/firma-0.3pre2.tar.gz
new file mode 100644 (file)
index 0000000..3435161
Binary files /dev/null and b/releases/firma-0.3pre2.tar.gz differ
diff --git a/releases/firma-0.3pre3.tar.gz b/releases/firma-0.3pre3.tar.gz
new file mode 100644 (file)
index 0000000..0d3f607
Binary files /dev/null and b/releases/firma-0.3pre3.tar.gz differ
diff --git a/www/index.html b/www/index.html
new file mode 100644 (file)
index 0000000..b6713cb
--- /dev/null
@@ -0,0 +1,51 @@
+<html><head><title>Firma</title></head>
+
+<body link="gray" alink="gray" vlink="gray" text="black" bgcolor="white">
+
+<pre>
+   ffff  
+  ff    firma -  
+  ffff  encrypted mailing list manager
+  ff    - a firma cai mas nao quebra 
+  ff    
+</pre>
+
+<table>
+<tr>
+
+<td>
+  <font face="monospace">
+  <a href="http://codecoop.org/projects/firma/">Project Page</a><br>
+  <a href="http://codecoop.org/news/?group_id=42">News</a><br>
+  <a href="http://codecoop.org/frs/?group_id=42">Download</a><br>
+  <a href="http://codecoop.org/scm/?group_id=42">CVS Snapshots</a><br>
+  </font>
+</td>
+
+<td>
+<pre>
+ Firma works as a command line and MTA pipe alias tool that receives an
+ email message in its input, grab the encrypted/signed message, re-encrypt
+ and send it to each subscriber.
+
+ In the server you just need the script, a keyring with the list keypair
+ and two config files. When mail arrives, it is redirected by the MTA to the
+ script and it process the message if its properly encrypted and signed.
+ No temporary files are written during a message processing and no default
+ message archive, so no messages -- encrypted or not -- rest on your system
+ in all steps of the process.
+
+ Contact Firma developers using firma at sarava.org, encrypting the message
+ using the public key 0xD68AFEDC available at keyserver.noreply.org.
+</pre>
+</td>
+
+</tr>
+</table>
+
+<font face="monospace">
+Hosted by <a href="http://codecoop.org">CodeCoop</a>.
+</font>
+
+</body>
+</html>