doc/
authorMarcus Brinkmann <mb@g10code.com>
Sun, 27 Apr 2003 20:53:04 +0000 (20:53 +0000)
committerMarcus Brinkmann <mb@g10code.com>
Sun, 27 Apr 2003 20:53:04 +0000 (20:53 +0000)
2003-04-27  Marcus Brinkmann  <marcus@g10code.de>

* gpgme.texi (Creating a Signature): Add info about
GpgmeNewSignature, GpgmeSignResult and gpgme_op_sign_result.
(Crypto Operations): Add GpgmeInvalidUserID.
(Algorithms): New chapter.

gpgme/
2003-04-27  Marcus Brinkmann  <marcus@g10code.de>

* gpgme.h (GpgmePubKeyAlgo, GpgmeHashAlgo, GpgmeInvalidUserID,
GpgmeNewSignature, GpgmeSignResult): New data types.
(gpgme_op_sign_result, gpgme_pubkey_algo_name,
gpgme_hash_algo_name): New prototypes.
* gpgme.c (gpgme_pubkey_algo_name): New function.
(gpgme_hash_algo_name): Likewise.
* ops.h (_gpgme_parse_inv_userid, _gpgme_op_sign_init_result): New
prototype.
(_gpgme_op_sign_status_handler): Fix prototype.
* op-support.c: Include <errno.h> and <string.h>.
(_gpgme_parse_inv_userid): New function.
* sign.c: Include <errno.h> and "gpgme.h", but not <stdio.h>,
<assert.h> and "util.h".
(SKIP_TOKEN_OR_RETURN): Remove macro.
(struct sign_result): Change to op_data_t type and rework it.
(release_sign_result): Rename to ...
(release_op_data): ... this and rewrite it.
(append_xml_info): Remove function.
(gpgme_op_sign_result): New function.
(parse_sig_created): New function.
(_gpgme_sign_status_handler): Change first argument to void *.
Rewrite the function to use the new result structure and functions.
(_gpgme_op_sign_init_result): New function.
(_gpgme_op_sign_start): Rename to ...
(sign_start): ... this.  Call _gpgme_op_sign_init_result.
(gpgme_op_sign_start): Use sign_start instead _gpgme_op_sign_start.
(gpgme_op_sign): Likewise.

NEWS
doc/ChangeLog
doc/gpgme.texi
gpgme/ChangeLog
gpgme/encrypt-sign.c
gpgme/gpgme.c
gpgme/gpgme.h
gpgme/op-support.c
gpgme/ops.h
gpgme/sign.c

diff --git a/NEWS b/NEWS
index b85bb74..177b4d2 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -78,6 +78,10 @@ Noteworthy changes in version 0.4.1 (unreleased)
    GpgmeImportResult and GpgmeImportStatus objects.  Thus, the
    gpgme_op_import_ext variant is deprecated.
 
+ * The new gpgme_op_sign_result function provides detailed information
+   about the result of a signing operation in GpgmeSignResult,
+   GpgmeInvalidUserID and GpgmeNewSignature objects.
+
  * Interface changes relative to the 0.4.0 release:
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 GpgmeIOCb                      CHANGED: Return type from void to GpgmeError.
@@ -108,6 +112,14 @@ gpgme_op_import_ext                DEPRECATED: Use gpgme_op_import_result.
 gpgme_op_import_result         NEW
 GpgmeImportStatus              NEW
 GpgmeImportResult              NEW
+GpgmePubKeyAlgo                        NEW
+GpgmeHashAlgo                  NEW
+GpgmeInvalidUserID             NEW
+GpgmeNewSignature              NEW
+GpgmeSignResult                        NEW
+gpgme_op_sign_result           NEW
+gpgme_pubkey_algo_name         NEW
+gpgme_hash_algo_name           NEW
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Noteworthy changes in version 0.4.0 (2002-12-23)
index 24031a4..0edda75 100644 (file)
@@ -1,5 +1,10 @@
 2003-04-27  Marcus Brinkmann  <marcus@g10code.de>
 
+       * gpgme.texi (Creating a Signature): Add info about
+       GpgmeNewSignature, GpgmeSignResult and gpgme_op_sign_result.
+       (Crypto Operations): Add GpgmeInvalidUserID.
+       (Algorithms): New chapter.
+
        * gpgme.texi (Deleting Keys): Document
        GPGME_Ambiguous_Specification.
        (Error Values): Remove GPGME_Invalid_Type and GPGME_Invalid_Mode.
index 7fdf41e..e1c8c85 100644 (file)
@@ -73,6 +73,7 @@ This is Edition @value{EDITION}, last updated @value{UPDATED}, of
 * Introduction::                  How to use this manual.
 * Preparation::                   What you should do before using the library.
 * Protocols and Engines::         Supported crypto protocols.
+* Algorithms::                    Supported algorithms.
 * Error Handling::                Error numbers and their meanings.
 * Exchanging Data::               Passing data to and from @acronym{GPGME}.
 * Contexts::                      Handling @acronym{GPGME} contexts.
@@ -114,6 +115,11 @@ Protocols and Engines
 * OpenPGP::                       Support for the OpenPGP protocol.
 * Cryptographic Message Syntax::  Support for the CMS.
 
+Algorithms
+
+* Public Key Algorithms::         A list of all public key algorithms.
+* Hash Algorithms::               A list of all hash algorithms.
+
 Error Handling
 
 * Error Values::                  A list of all error values used.
@@ -728,6 +734,110 @@ GnuPG.
 The @acronym{CMS} protocol is specified by @code{GPGME_PROTOCOL_CMS}.
 
 
+@node Algorithms
+@chapter Algorithms
+@cindex algorithms
+
+The crypto backends support a variety of algorithms used in public key
+cryptography.  The following sections list the identifiers used to
+denote such an algorithm.
+
+@menu
+* Public Key Algorithms::         A list of all public key algorithms.
+* Hash Algorithms::               A list of all hash algorithms.
+@end menu
+
+
+@node Public Key Algorithms
+@section Public Key Algorithms
+@cindex algorithms, public key
+@cindex public key algorithms
+
+Public key algorithms are used for encryption, decryption, signing and
+verification of signatures.
+
+@deftp {Data type} {enum GpgmePubKeyAlgo}
+@tindex GpgmePubKeyAlgo
+The @code{GpgmePubKeyAlgo} type specifies the set of all public key
+algorithms that are supported by @acronym{GPGME}.  Possible values
+are:
+
+@table @code
+@item GPGME_PK_RSA
+This value indicates the RSA (Rivest, Shamir, Adleman) algorithm.
+
+@item GPGME_PK_RSA_E
+Deprecated.  This value indicates the RSA (Rivest, Shamir, Adleman)
+algorithm for encryption and decryption only.
+
+@item GPGME_PK_RSA_S
+Deprecated.  This value indicates the RSA (Rivest, Shamir, Adleman)
+algorithm for signing and verification only.
+
+@item GPGME_PK_DSA
+This value indicates DSA, the Digital Signature Algorithm.
+
+@item GPGME_PK_ELG
+This value indicates ElGamal.
+
+@item GPGME_PK_ELG_E
+This value also indicates ElGamal and is used specifically in GnuPG.
+@end table
+@end deftp
+
+@deftypefun {const char *} gpgme_pubkey_algo_name (@w{GpgmePubKeyAlgo @var{algo}})
+The function @code{gpgme_pubkey_algo_name} returns a pointer to a
+statically allocated string containing a description of the public key
+algorithm @var{algo}.  This string can be used to output the name of
+the public key algorithm to the user.
+
+If @var{algo} is not a valid public key algorithm, @code{NULL} is
+returned.
+@end deftypefun
+
+
+@node Hash Algorithms
+@section Hash Algorithms
+@cindex algorithms, hash
+@cindex algorithms, message digest
+@cindex hash algorithms
+@cindex message digest algorithms
+
+Hash (message digest) algorithms are used to compress a long message
+to make it suitable for public key cryptography.
+
+@deftp {Data type} {enum GpgmeHashAlgo}
+@tindex GpgmeHashAlgo
+The @code{GpgmeHashAlgo} type specifies the set of all hash algorithms
+that are supported by @acronym{GPGME}.  Possible values are:
+
+@table @code
+@item GPGME_MD_MD5
+@item GPGME_MD_SHA1
+@item GPGME_MD_RMD160
+@item GPGME_MD_MD2
+@item GPGME_MD_TIGER
+@item GPGME_MD_HAVAL
+@item GPGME_MD_SHA256
+@item GPGME_MD_SHA384
+@item GPGME_MD_SHA512
+@item GPGME_MD_MD4
+@item GPGME_MD_CRC32
+@item GPGME_MD_CRC32_RFC1510
+@item GPGME_MD_CRC24_RFC2440
+@end table
+@end deftp
+
+@deftypefun {const char *} gpgme_hash_algo_name (@w{GpgmeHashAlgo @var{algo}})
+The function @code{gpgme_hash_algo_name} returns a pointer to a
+statically allocated string containing a description of the hash
+algorithm @var{algo}.  This string can be used to output the name of
+the hash algorithm to the user.
+
+If @var{algo} is not a valid hash algorithm, @code{NULL} is returned.
+@end deftypefun
+
+
 @node Error Handling
 @chapter Error Handling
 @cindex error handling
@@ -2308,6 +2418,9 @@ The function @code{gpgme_op_import} adds the keys in the data buffer
 The format of @var{keydata} can be @var{ASCII} armored, for example,
 but the details are specific to the crypto engine.
 
+After the operation completed successfully, the result can be
+retrieved with @code{gpgme_op_import_result}.
+
 The function returns @code{GPGME_No_Error} if the import was completed
 successfully, @code{GPGME_Invalid_Value} if @var{keydata} if @var{ctx}
 or @var{keydata} is not a valid pointer, and @code{GPGME_No_Data} if
@@ -2333,7 +2446,8 @@ import.  The structure contains the following members:
 
 @table @code
 @item GpgmeImportStatus next
-This is a pointer to the next status object in the list.
+This is a pointer to the next status structure in the linked list, or
+@code{NULL} if this is the last element.
 
 @item char *fpr
 This is the fingerprint of the key that was considered.
@@ -2592,10 +2706,34 @@ The function @code{gpgme_trust_item_release} destroys a
 @code{GpgmeTrustItem} object and releases all associated resources.
 @end deftypefun
 
+
 @node Crypto Operations
 @section Crypto Operations
 @cindex cryptographic operation
 
+Sometimes, the result of a crypto operation returns a list of invalid
+user IDs encountered in processing the request.  The following
+structure is used to hold information about such an user ID.
+
+@deftp {Data type} {GpgmeInvalidUserID}
+This is a pointer to a structure used to store a part of the result of
+a crypto operation which takes user IDs as one input parameter.  The
+structure contains the following members:
+
+@table @code
+@item GpgmeInvalidUserID next
+This is a pointer to the next invalid user ID structure in the linked
+list, or @code{NULL} if this is the last element.
+
+@item char *id
+The invalid user ID encountered.
+
+@item GpgmeError reason
+An error code describing the reason why the user ID was found invalid.
+@end table
+@end deftp
+
+
 @menu
 * Decrypt::                       Decrypting a ciphertext.
 * Verify::                        Verifying a signature.
@@ -2994,8 +3132,8 @@ the data object @var{plain} and returns it in the data object
 @acronym{ASCII} armor and text mode attributes set for the context
 @var{ctx} and the requested signature mode @var{mode}.
 
-More information about the signatures is available with
-@code{gpgme_get_op_info}.  @xref{Detailed Results}.
+After the operation completed successfully, the result can be
+retrieved with @code{gpgme_op_sign_result}.
 
 If an S/MIME signed message is created using the CMS crypto engine,
 the number of certificates to include in the message can be specified
@@ -3020,6 +3158,63 @@ started successfully, and @code{GPGME_Invalid_Value} if @var{ctx},
 @var{plain} or @var{sig} is not a valid pointer.
 @end deftypefun
 
+@deftp {Data type} {GpgmeNewSignature}
+This is a pointer to a structure used to store a part of the result of
+a @code{gpgme_op_sign} operation.  The structure contains the
+following members:
+
+@table @code
+@item GpgmeNewSignature next
+This is a pointer to the next new signature structure in the linked
+list, or @code{NULL} if this is the last element.
+
+@item GpgmeSigMode type
+The type of this signature.
+
+@item GpgmePubKeyAlgo
+The public key algorithm used to create this signature.
+
+@item GpgmeHashAlgo
+The hash algorithm used to create this signature.
+
+@item unsigned long class
+The signature class of this signature.
+
+@item long int created
+The creation timestamp of this signature.
+
+@item char *fpr
+The fingerprint of the key which was used to create this signature.
+@end table
+@end deftp
+
+@deftp {Data type} {GpgmeSignResult}
+This is a pointer to a structure used to store the result of a
+@code{gpgme_op_sign} operation.  After successfully generating a
+signature, you can retrieve the pointer to the result with
+@code{gpgme_op_sign_result}.  The structure contains the following
+members:
+
+@table @code
+@item GpgmeInvalidUserID invalid_signers
+A linked list with information about all invalid user IDs for which a
+signature could not be created.
+
+@item GpgmeNewSignature signatures
+A linked list with information about all signatures created.
+@end table
+@end deftp
+
+@deftypefun GpgmeSignResult gpgme_op_sign_result (@w{GpgmeCtx @var{ctx}})
+The function @code{gpgme_op_sign_result} returns a
+@code{GpgmeSignResult} pointer to a structure holding the result of a
+@code{gpgme_op_sign} operation.  The pointer is only valid if the last
+operation on the context was a @code{gpgme_op_sign} or
+@code{gpgme_op_sign_start} operation, and if this operation finished
+successfully.  The returned pointer is only valid until the next
+operation is started on the context.
+@end deftypefun
+
 
 @node Encrypt
 @subsection Encrypt
index 774d930..8716eda 100644 (file)
@@ -1,5 +1,36 @@
 2003-04-27  Marcus Brinkmann  <marcus@g10code.de>
 
+       * gpgme.h (GpgmePubKeyAlgo, GpgmeHashAlgo, GpgmeInvalidUserID,
+       GpgmeNewSignature, GpgmeSignResult): New data types.
+       (gpgme_op_sign_result, gpgme_pubkey_algo_name,
+       gpgme_hash_algo_name): New prototypes.
+       * gpgme.c (gpgme_pubkey_algo_name): New function.
+       (gpgme_hash_algo_name): Likewise.
+       * ops.h (_gpgme_parse_inv_userid, _gpgme_op_sign_init_result): New
+       prototype.
+       (_gpgme_op_sign_status_handler): Fix prototype.
+       * op-support.c: Include <errno.h> and <string.h>.
+       (_gpgme_parse_inv_userid): New function.
+       * sign.c: Include <errno.h> and "gpgme.h", but not <stdio.h>,
+       <assert.h> and "util.h".
+       (SKIP_TOKEN_OR_RETURN): Remove macro.
+       (struct sign_result): Change to op_data_t type and rework it.
+       (release_sign_result): Rename to ...
+       (release_op_data): ... this and rewrite it.
+       (append_xml_info): Remove function.
+       (gpgme_op_sign_result): New function.
+       (parse_sig_created): New function.
+       (_gpgme_sign_status_handler): Change first argument to void *.
+       Rewrite the function to use the new result structure and functions.
+       (_gpgme_op_sign_init_result): New function.
+       (_gpgme_op_sign_start): Rename to ...
+       (sign_start): ... this.  Call _gpgme_op_sign_init_result.
+       (gpgme_op_sign_start): Use sign_start instead _gpgme_op_sign_start.
+       (gpgme_op_sign): Likewise.
+
+       * encrypt-sign.c (_gpgme_op_encrypt_sign_start): Call
+       _gpgme_op_sign_init_result.
+       
        * delete.c: Include <errno.h> and "gpgme.h", but not "util.h" or
        "key.h".
        (enum delete_problem): Move into function delete_status_handler.
index 68ab115..3e28773 100644 (file)
@@ -51,6 +51,10 @@ _gpgme_op_encrypt_sign_start (GpgmeCtx ctx, int synchronous,
   if (err)
     return err;
 
+  err = _gpgme_op_sign_init_result (ctx);
+  if (err)
+    return err;
+
   if (!plain)
     return GPGME_No_Data;
   if (!cipher)
index 41b3b09..72f502a 100644 (file)
@@ -521,3 +521,82 @@ gpgme_get_io_cbs (GpgmeCtx ctx, struct GpgmeIOCbs *io_cbs)
   if (ctx && io_cbs)
     *io_cbs = ctx->io_cbs;
 }
+
+
+const char *
+gpgme_pubkey_algo_name (GpgmePubKeyAlgo algo)
+{
+  switch (algo)
+    {
+    case GPGME_PK_RSA:
+      return "RSA";
+
+    case GPGME_PK_RSA_E:
+      return "RSA-E";
+
+    case GPGME_PK_RSA_S:
+      return "RSA-S";
+
+    case GPGME_PK_ELG_E:
+      return "ELG-E";
+
+    case GPGME_PK_DSA:
+      return "DSA";
+
+    case GPGME_PK_ELG:
+      return "ELG";
+
+    default:
+      return NULL;
+    }
+}
+
+
+const char *
+gpgme_hash_algo_name (GpgmeHashAlgo algo)
+{
+  switch (algo)
+    {
+    case GPGME_MD_MD5:
+      return "MD5";
+
+    case GPGME_MD_SHA1:
+      return "SHA1";
+
+    case GPGME_MD_RMD160:
+      return "RMD160";
+
+    case GPGME_MD_MD2:
+      return "MD2";
+
+    case GPGME_MD_TIGER:
+      return "TIGER";
+
+    case GPGME_MD_HAVAL:
+      return "HAVAL";
+
+    case GPGME_MD_SHA256:
+      return "SHA256";
+
+    case GPGME_MD_SHA384:
+      return "SHA384";
+
+    case GPGME_MD_SHA512:
+      return "SHA512";
+
+    case GPGME_MD_MD4:
+      return "MD4";
+
+    case GPGME_MD_CRC32:
+      return "CRC32";
+
+    case GPGME_MD_CRC32_RFC1510:
+      return "CRC32-RFC1510";
+
+    case GPGME_MD_CRC24_RFC2440:
+      return "CRC24-RFC2440";
+
+    default:
+      return NULL;
+    }
+}
index 7334bfc..9fa2af0 100644 (file)
@@ -138,6 +138,41 @@ typedef enum
   }
 GpgmeDataEncoding;
 
+
+/* Public key algorithms from libgcrypt.  */
+typedef enum
+  {
+    GPGME_PK_RSA   = 1,
+    GPGME_PK_RSA_E = 2,
+    GPGME_PK_RSA_S = 3,
+    GPGME_PK_ELG_E = 16,
+    GPGME_PK_DSA   = 17,
+    GPGME_PK_ELG   = 20
+  }
+GpgmePubKeyAlgo;
+
+
+/* Hash algorithms from libgcrypt.  */
+typedef enum
+  {
+    GPGME_MD_NONE          = 0,  
+    GPGME_MD_MD5           = 1,
+    GPGME_MD_SHA1          = 2,
+    GPGME_MD_RMD160        = 3,
+    GPGME_MD_MD2           = 5,
+    GPGME_MD_TIGER         = 6,   /* TIGER/192. */
+    GPGME_MD_HAVAL         = 7,   /* HAVAL, 5 pass, 160 bit. */
+    GPGME_MD_SHA256        = 8,
+    GPGME_MD_SHA384        = 9,
+    GPGME_MD_SHA512        = 10,
+    GPGME_MD_MD4           = 301,
+    GPGME_MD_CRC32        = 302,
+    GPGME_MD_CRC32_RFC1510 = 303,
+    GPGME_MD_CRC24_RFC2440 = 304
+  }
+GpgmeHashAlgo;
+
+
 /* The possible signature stati.  */
 typedef enum
   {
@@ -426,6 +461,16 @@ void gpgme_set_progress_cb (GpgmeCtx c, GpgmeProgressCb cb, void *hook_value);
 void gpgme_get_progress_cb (GpgmeCtx ctx, GpgmeProgressCb *cb,
                            void **hook_value);
 
+\f
+/* Return a statically allocated string with the name of the public
+   key algorithm ALGO, or NULL if that name is not known.  */
+const char *gpgme_pubkey_algo_name (GpgmePubKeyAlgo algo);
+
+/* Return a statically allocated string with the name of the hash
+   algorithm ALGO, or NULL if that name is not known.  */
+const char *gpgme_hash_algo_name (GpgmeHashAlgo algo);
+
+\f
 /* Delete all signers from CTX.  */
 void gpgme_signers_clear (GpgmeCtx ctx);
 
@@ -710,10 +755,18 @@ const char *gpgme_trust_item_get_string_attr (GpgmeTrustItem item,
    attribute appears more than once in the key.  */
 int gpgme_trust_item_get_int_attr (GpgmeTrustItem item, GpgmeAttr what,
                                   const void *reserved, int idx);
+\f
+/* Crypto Operations.  */
 
+struct _gpgme_invalid_user_id
+{
+  struct _gpgme_invalid_user_id *next;
+  char *id;
+  GpgmeError reason;
+};
+typedef struct _gpgme_invalid_user_id *GpgmeInvalidUserID;
 
-/* Crypto operation function.  */
-
+\f
 /* Encrypt plaintext PLAIN within CTX for the recipients RECP and
    store the resulting ciphertext in CIPHER.  */
 GpgmeError gpgme_op_encrypt_start (GpgmeCtx ctx,
@@ -747,8 +800,32 @@ GpgmeError gpgme_op_decrypt_verify_start (GpgmeCtx ctx,
 GpgmeError gpgme_op_decrypt_verify (GpgmeCtx ctx,
                                    GpgmeData cipher, GpgmeData plain);
 
-/* Sign the plaintext PLAIN and store the signature in SIG.  Only
-   detached signatures are supported for now.  */
+\f
+/* Signing.  */
+struct _gpgme_new_signature
+{
+  struct _gpgme_new_signature *next;
+  GpgmeSigMode type;
+  GpgmePubKeyAlgo pubkey_algo;
+  GpgmeHashAlgo hash_algo;
+  unsigned long class;
+  long int created;
+  char *fpr;
+};
+typedef struct _gpgme_new_signature *GpgmeNewSignature;
+
+struct _gpgme_op_sign_result
+{
+  /* The list of invalid signers.  */
+  GpgmeInvalidUserID invalid_signers;
+  GpgmeNewSignature signatures;
+};
+typedef struct _gpgme_op_sign_result *GpgmeSignResult;
+
+/* Retrieve a pointer to the result of the signing operation.  */
+GpgmeSignResult gpgme_op_sign_result (GpgmeCtx ctx);
+
+/* Sign the plaintext PLAIN and store the signature in SIG.  */
 GpgmeError gpgme_op_sign_start (GpgmeCtx ctx,
                                GpgmeData plain, GpgmeData sig,
                                GpgmeSigMode mode);
@@ -756,6 +833,7 @@ GpgmeError gpgme_op_sign (GpgmeCtx ctx,
                          GpgmeData plain, GpgmeData sig,
                          GpgmeSigMode mode);
 
+\f
 /* Verify within CTX that SIG is a valid signature for TEXT.  */
 GpgmeError gpgme_op_verify_start (GpgmeCtx ctx, GpgmeData sig,
                                  GpgmeData signed_text, GpgmeData plaintext);
index 1d55e38..079bd67 100644 (file)
@@ -21,6 +21,8 @@
 #include <config.h>
 #endif
 #include <stdlib.h>
+#include <errno.h>
+#include <string.h>
 
 #include "gpgme.h"
 #include "context.h"
@@ -105,3 +107,79 @@ _gpgme_op_reset (GpgmeCtx ctx, int type)
   _gpgme_engine_set_io_cbs (ctx->engine, &io_cbs);
   return err;
 }
+
+\f
+GpgmeError
+_gpgme_parse_inv_userid (char *args, GpgmeInvalidUserID *userid)
+{
+  GpgmeInvalidUserID inv_userid;
+  char *tail;
+  long int reason;
+
+  inv_userid = malloc (sizeof (*inv_userid));
+  if (!inv_userid)
+    return GPGME_Out_Of_Core;
+  inv_userid->next = NULL;
+  errno = 0;
+  reason = strtol (args, &tail, 0);
+  if (errno || args == tail || *tail != ' ')
+    {
+      /* The crypto backend does not behave.  */
+      free (inv_userid);
+      return GPGME_General_Error;
+    }
+
+  switch (reason)
+    {
+    default:
+    case 0:
+      inv_userid->reason = GPGME_Unknown_Reason;
+
+    case 1:
+      inv_userid->reason = GPGME_Not_Found;
+
+    case 2:
+      inv_userid->reason = GPGME_Ambiguous_Specification;
+
+    case 3:
+      inv_userid->reason = GPGME_Wrong_Key_Usage;
+
+    case 4:
+      inv_userid->reason = GPGME_Key_Revoked;
+
+    case 5:
+      inv_userid->reason = GPGME_Key_Expired;
+
+    case 6:
+      inv_userid->reason = GPGME_No_CRL_Known;
+
+    case 7:
+      inv_userid->reason = GPGME_CRL_Too_Old;
+
+    case 8:
+      inv_userid->reason = GPGME_Policy_Mismatch;
+
+    case 9:
+      inv_userid->reason = GPGME_No_Secret_Key;
+
+    case 10:
+      inv_userid->reason = GPGME_Key_Not_Trusted;
+    }
+
+  while (*tail == ' ')
+    tail++;
+  if (*tail)
+    {
+      inv_userid->id = strdup (tail);
+      if (!inv_userid->id)
+       {
+         free (inv_userid);
+         return GPGME_Out_Of_Core;
+       }
+    }
+  else
+    inv_userid->id = NULL;
+
+  *userid = inv_userid;
+  return 0;
+}
index 61ec8d7..7cbb942 100644 (file)
@@ -57,12 +57,22 @@ GpgmeError _gpgme_data_outbound_handler (void *opaque, int fd);
 GpgmeError _gpgme_key_new ( GpgmeKey *r_key );
 GpgmeError _gpgme_key_new_secret ( GpgmeKey *r_key );
 
-/*-- op-support.c --*/
+\f
+/* From op-support.c.  */
+
+/* Find or create the op data object of type TYPE.  */
 GpgmeError _gpgme_op_data_lookup (GpgmeCtx ctx, ctx_op_data_type type,
                                  void **hook, int size,
                                  void (*cleanup) (void *));
+
+/* Prepare a new operation on CTX.  */
 GpgmeError _gpgme_op_reset (GpgmeCtx ctx, int synchronous);
 
+/* Parse the invalid user ID status line in ARGS and return the result
+   in USERID.  */
+GpgmeError _gpgme_parse_inv_userid (char *args, GpgmeInvalidUserID *userid);
+
+\f
 /*-- verify.c --*/
 GpgmeError _gpgme_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code,
                                         char *args);
@@ -74,10 +84,18 @@ GpgmeError _gpgme_decrypt_start (GpgmeCtx ctx, int synchronous,
                                 GpgmeData ciph, GpgmeData plain,
                                 void *status_handler);
 
-/*-- sign.c --*/
-GpgmeError _gpgme_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code,
+\f
+/* From sign.c.  */
+
+/* Create an initial op data object for signing.  Needs to be called
+   once before calling _gpgme_sign_status_handler.  */
+GpgmeError _gpgme_op_sign_init_result (GpgmeCtx ctx);
+
+/* Process a status line for signing operations.  */
+GpgmeError _gpgme_sign_status_handler (void *priv, GpgmeStatusCode code,
                                       char *args);
 
+\f
 /*-- encrypt.c --*/
 GpgmeError _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code,
                                          char *args);
index f416d10..260aa5f 100644 (file)
@@ -1,4 +1,4 @@
-/* sign.c -  signing functions
+/* sign.c - Signing function.
    Copyright (C) 2000 Werner Koch (dd9jn)
    Copyright (C) 2001, 2002, 2003 g10 Code GmbH
 
 #if HAVE_CONFIG_H
 #include <config.h>
 #endif
-#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
+#include <errno.h>
 
-#include "util.h"
+#include "gpgme.h"
 #include "context.h"
 #include "ops.h"
 
-#define SKIP_TOKEN_OR_RETURN(a) do { \
-    while (*(a) && *(a) != ' ') (a)++; \
-    while (*(a) == ' ') (a)++; \
-    if (!*(a)) \
-        return; /* oops */ \
-} while (0)
-
-struct sign_result
+\f
+typedef struct
 {
-  int okay;
-  GpgmeData xmlinfo;
-};
-typedef struct sign_result *SignResult;
+  struct _gpgme_op_sign_result result;
+
+  /* A pointer to the next pointer of the last invalid signer in
+     the list.  This makes appending new invalid signers painless
+     while preserving the order.  */
+  GpgmeInvalidUserID *last_signer_p;
+
+  /* Likewise for signature information.  */
+  GpgmeNewSignature *last_sig_p;
+} *op_data_t;
 
 
 static void
-release_sign_result (void *hook)
+release_op_data (void *hook)
 {
-  SignResult result = (SignResult) hook;
+  op_data_t opd = (op_data_t) hook;
+  GpgmeInvalidUserID invalid_signer = opd->result.invalid_signers;
+  GpgmeNewSignature sig = opd->result.signatures;
 
-  gpgme_data_release (result->xmlinfo);
+  while (invalid_signer)
+    {
+      GpgmeInvalidUserID next = invalid_signer->next;
+      free (invalid_signer->id);
+      free (invalid_signer);
+      invalid_signer = next;
+    }
+
+  while (sig)
+    {
+      GpgmeNewSignature next = sig->next;
+      free (sig->fpr);
+      free (sig);
+      sig = next;
+    }
 }
 
-/* Parse the args and save the information 
-   <type> <pubkey algo> <hash algo> <class> <timestamp> <key fpr>
-   in an XML structure.  With args of NULL the xml structure is
-   closed.  */
-static void
-append_xml_siginfo (GpgmeData *rdh, char *args)
+
+GpgmeSignResult
+gpgme_op_sign_result (GpgmeCtx ctx)
 {
-  GpgmeData dh;
-  char helpbuf[100];
-  int i;
-  char *s;
-  unsigned long ul;
+  op_data_t opd;
+  GpgmeError err;
+
+  err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, (void **) &opd, -1, NULL);
+  if (err || !opd)
+    return NULL;
+
+  return &opd->result;
+}
 
-  if (!*rdh)
+\f
+static GpgmeError
+parse_sig_created (char *args, GpgmeNewSignature *sigp)
+{
+  GpgmeNewSignature sig;
+  char *tail;
+
+  sig = malloc (sizeof (*sig));
+  if (!sig)
+    return GPGME_Out_Of_Core;
+
+  sig->next = NULL;
+  switch (*args)
     {
-      if (gpgme_data_new (rdh))
-       {
-         return; /* fixme: We are ignoring out-of-core */
-        }
-      dh = *rdh;
-      _gpgme_data_append_string (dh, "<GnupgOperationInfo>\n");
+    case 'S':
+      sig->type = GPGME_SIG_MODE_NORMAL;
+      break;
+
+    case 'D':
+      sig->type = GPGME_SIG_MODE_DETACH;
+      break;
+
+    case 'C':
+      sig->type = GPGME_SIG_MODE_CLEAR;
+      break;
+
+    default:
+      /* The backend engine is not behaving.  */
+      free (sig);
+      return GPGME_General_Error;
     }
-  else
+
+  args++;
+  if (*args != ' ')
     {
-      dh = *rdh;
-      _gpgme_data_append_string (dh, "  </signature>\n");
+      free (sig);
+      return GPGME_General_Error;
     }
 
-  if (!args)
+  errno = 0;
+  sig->pubkey_algo = strtol (args, &tail, 0);
+  if (errno || args == tail || *tail != ' ')
     {
-      /* Just close the XML containter.  */
-      _gpgme_data_append_string (dh, "</GnupgOperationInfo>\n");
-      return;
+      /* The crypto backend does not behave.  */
+      free (sig);
+      return GPGME_General_Error;
     }
+  args = tail;
 
-  _gpgme_data_append_string (dh, "  <signature>\n");
-    
-  _gpgme_data_append_string (dh,
-                            *args == 'D' ? "    <detached/>\n" :
-                            *args == 'C' ? "    <cleartext/>\n" :
-                            *args == 'S' ? "    <standard/>\n" : "");
-  SKIP_TOKEN_OR_RETURN (args);
-
-  sprintf (helpbuf, "    <algo>%d</algo>\n", atoi (args));
-  _gpgme_data_append_string (dh, helpbuf);
-  SKIP_TOKEN_OR_RETURN (args);
-
-  i = atoi (args);
-  sprintf (helpbuf, "    <hashalgo>%d</hashalgo>\n", atoi (args));
-  _gpgme_data_append_string (dh, helpbuf);
-  switch (i)
+  sig->hash_algo = strtol (args, &tail, 0);
+  if (errno || args == tail || *tail != ' ')
     {
-    case  1: s = "pgp-md5"; break;
-    case  2: s = "pgp-sha1"; break;
-    case  3: s = "pgp-ripemd160"; break;
-    case  5: s = "pgp-md2"; break;
-    case  6: s = "pgp-tiger192"; break;
-    case  7: s = "pgp-haval-5-160"; break;
-    case  8: s = "pgp-sha256"; break;
-    case  9: s = "pgp-sha384"; break;
-    case 10: s = "pgp-sha512"; break;
-    default: s = "pgp-unknown"; break;
+      /* The crypto backend does not behave.  */
+      free (sig);
+      return GPGME_General_Error;
     }
-  sprintf (helpbuf, "    <micalg>%s</micalg>\n", s);
-  _gpgme_data_append_string (dh,helpbuf);
-  SKIP_TOKEN_OR_RETURN (args);
-    
-  sprintf (helpbuf, "    <sigclass>%.2s</sigclass>\n", args);
-  _gpgme_data_append_string (dh, helpbuf);
-  SKIP_TOKEN_OR_RETURN (args);
-
-  ul = strtoul (args, NULL, 10);
-  sprintf (helpbuf, "    <created>%lu</created>\n", ul);
-  _gpgme_data_append_string (dh, helpbuf);
-  SKIP_TOKEN_OR_RETURN (args);
-
-  /* Count the length of the finperprint.  */
-  for (i = 0; args[i] && args[i] != ' '; i++)
-    ;
-  _gpgme_data_append_string (dh, "    <fpr>");
-  _gpgme_data_append (dh, args, i);
-  _gpgme_data_append_string (dh, "</fpr>\n");
+  args = tail;
+
+  sig->class = strtol (args, &tail, 0);
+  if (errno || args == tail || *tail != ' ')
+    {
+      /* The crypto backend does not behave.  */
+      free (sig);
+      return GPGME_General_Error;
+    }
+  args = tail;
+
+  sig->created = strtol (args, &tail, 0);
+  if (errno || args == tail || *tail != ' ')
+    {
+      /* The crypto backend does not behave.  */
+      free (sig);
+      return GPGME_General_Error;
+    }
+  args = tail;
+  while (*args == ' ')
+    args++;
+
+  if (!*args)
+    {
+      /* The crypto backend does not behave.  */
+      free (sig);
+      return GPGME_General_Error;
+    }
+
+  tail = strchr (args, ' ');
+  if (tail)
+    *tail = '\0';
+
+  sig->fpr = strdup (args);
+  if (!sig->fpr)
+    {
+      free (sig);
+      return GPGME_Out_Of_Core;
+    }
+  *sigp = sig;
+  return 0;
 }
 
+
 GpgmeError
-_gpgme_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
+_gpgme_sign_status_handler (void *priv, GpgmeStatusCode code, char *args)
 {
-  SignResult result;
+  GpgmeCtx ctx = (GpgmeCtx) priv;
   GpgmeError err;
+  op_data_t opd;
+
+  err = _gpgme_passphrase_status_handler (priv, code, args);
+  if (err)
+    return err;
 
-  err = _gpgme_passphrase_status_handler (ctx, code, args);
+  err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, (void **) &opd, -1, NULL);
   if (err)
     return err;
 
   switch (code)
     {
-    case GPGME_STATUS_EOF:
-      err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, (void **) &result,
-                                  -1, NULL);
-      if (!err)
-       {
-         if (result && result->okay)
-           {
-             append_xml_siginfo (&result->xmlinfo, NULL);
-             _gpgme_set_op_info (ctx, result->xmlinfo);
-             result->xmlinfo = NULL;
-           }
-         else if (!result || !result->okay)
-           /* FIXME: choose a better error code?  */
-           err = GPGME_No_Data;
-       }
+    case GPGME_STATUS_SIG_CREATED:
+      err = parse_sig_created (args, opd->last_sig_p);
+      if (err)
+       return err;
+
+      opd->last_sig_p = &(*opd->last_sig_p)->next;
+      break;
+
+    case GPGME_STATUS_INV_RECP:
+      err = _gpgme_parse_inv_userid (args, opd->last_signer_p);
+      if (err)
+       return err;
+
+      opd->last_signer_p = &(*opd->last_signer_p)->next;
       break;
 
-    case GPGME_STATUS_SIG_CREATED: 
-      /* FIXME: We have no error return for multiple signatures.  */
-      err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, (void **) &result,
-                                  sizeof (*result), release_sign_result);
-      append_xml_siginfo (&result->xmlinfo, args);
-      result->okay = 1;
+    case GPGME_STATUS_EOF:
+      if (opd->result.invalid_signers)
+       return GPGME_Invalid_UserID;
       break;
 
     default:
@@ -180,10 +226,26 @@ _gpgme_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
   return err;
 }
 
+
+GpgmeError
+_gpgme_op_sign_init_result (GpgmeCtx ctx)
+{
+  GpgmeError err;
+  op_data_t opd;
+
+  err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, (void **) &opd,
+                              sizeof (*opd), release_op_data);
+  if (err)
+    return err;
+  opd->last_signer_p = &opd->result.invalid_signers;
+  opd->last_sig_p = &opd->result.signatures;
+  return 0;
+}
+
+
 static GpgmeError
-_gpgme_op_sign_start (GpgmeCtx ctx, int synchronous,
-                     GpgmeData plain, GpgmeData sig,
-                     GpgmeSigMode mode)
+sign_start (GpgmeCtx ctx, int synchronous, GpgmeData plain, GpgmeData sig,
+           GpgmeSigMode mode)
 {
   GpgmeError err;
 
@@ -191,6 +253,10 @@ _gpgme_op_sign_start (GpgmeCtx ctx, int synchronous,
   if (err)
     return err;
 
+  err = _gpgme_op_sign_init_result (ctx);
+  if (err)
+    return err;
+
   if (mode != GPGME_SIG_MODE_NORMAL && mode != GPGME_SIG_MODE_DETACH
       && mode != GPGME_SIG_MODE_CLEAR)
     return GPGME_Invalid_Value;
@@ -217,38 +283,21 @@ _gpgme_op_sign_start (GpgmeCtx ctx, int synchronous,
                                ctx /* FIXME */);
 }
 
+
+/* Sign the plaintext PLAIN and store the signature in SIG.  */
 GpgmeError
-gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData in, GpgmeData out,
+gpgme_op_sign_start (GpgmeCtx ctx, GpgmeData plain, GpgmeData sig,
                     GpgmeSigMode mode)
 {
-  return _gpgme_op_sign_start (ctx, 0, in, out, mode);
+  return sign_start (ctx, 0, plain, sig, mode);
 }
 
-/**
- * gpgme_op_sign:
- * @ctx: The context
- * @in: Data to be signed
- * @out: Detached signature
- * @mode: Signature creation mode
- * 
- * Create a detached signature for @in and write it to @out.
- * The data will be signed using either the default key or the ones
- * defined through @ctx.
- * The defined modes for signature create are:
- * <literal>
- * GPGME_SIG_MODE_NORMAL (or 0) 
- * GPGME_SIG_MODE_DETACH
- * GPGME_SIG_MODE_CLEAR
- * </literal>
- * Note that the settings done by gpgme_set_armor() and gpgme_set_textmode()
- * are ignore for @mode GPGME_SIG_MODE_CLEAR.
- * 
- * Return value: 0 on success or an error code.
- **/
+
+/* Sign the plaintext PLAIN and store the signature in SIG.  */
 GpgmeError
-gpgme_op_sign (GpgmeCtx ctx, GpgmeData in, GpgmeData out, GpgmeSigMode mode)
+gpgme_op_sign (GpgmeCtx ctx, GpgmeData plain, GpgmeData sig, GpgmeSigMode mode)
 {
-  GpgmeError err = _gpgme_op_sign_start (ctx, 1, in, out, mode);
+  GpgmeError err = sign_start (ctx, 1, plain, sig, mode);
   if (!err)
     err = _gpgme_wait_one (ctx);
   return err;