diff options
Diffstat (limited to '')
| -rw-r--r-- | NEWS | 12 | ||||
| -rw-r--r-- | doc/ChangeLog | 5 | ||||
| -rw-r--r-- | doc/gpgme.texi | 201 | ||||
| -rw-r--r-- | gpgme/ChangeLog | 31 | ||||
| -rw-r--r-- | gpgme/encrypt-sign.c | 4 | ||||
| -rw-r--r-- | gpgme/gpgme.c | 79 | ||||
| -rw-r--r-- | gpgme/gpgme.h | 86 | ||||
| -rw-r--r-- | gpgme/op-support.c | 78 | ||||
| -rw-r--r-- | gpgme/ops.h | 24 | ||||
| -rw-r--r-- | gpgme/sign.c | 331 | 
10 files changed, 700 insertions, 151 deletions
| @@ -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) diff --git a/doc/ChangeLog b/doc/ChangeLog index 24031a4b..0edda75b 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,5 +1,10 @@  2003-04-27  Marcus Brinkmann  <[email protected]> +	* 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. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 7fdf41ee..e1c8c856 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -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 diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 774d9307..8716eda2 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,5 +1,36 @@  2003-04-27  Marcus Brinkmann  <[email protected]> +	* 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. diff --git a/gpgme/encrypt-sign.c b/gpgme/encrypt-sign.c index 68ab115c..3e28773a 100644 --- a/gpgme/encrypt-sign.c +++ b/gpgme/encrypt-sign.c @@ -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) diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c index 41b3b095..72f502a2 100644 --- a/gpgme/gpgme.c +++ b/gpgme/gpgme.c @@ -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; +    } +} diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index 7334bfce..9fa2af01 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -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); + +/* 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); + +  /* 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); + +/* 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.  */ - +  /* 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.  */ + +/* 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); +  /* 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); diff --git a/gpgme/op-support.c b/gpgme/op-support.c index 1d55e387..079bd67e 100644 --- a/gpgme/op-support.c +++ b/gpgme/op-support.c @@ -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;  } + + +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; +} diff --git a/gpgme/ops.h b/gpgme/ops.h index 61ec8d74..7cbb9425 100644 --- a/gpgme/ops.h +++ b/gpgme/ops.h @@ -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 --*/ + +/* 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); + +  /*-- 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, + +/* 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); +  /*-- encrypt.c --*/  GpgmeError _gpgme_encrypt_status_handler (GpgmeCtx ctx, GpgmeStatusCode code,  					  char *args); diff --git a/gpgme/sign.c b/gpgme/sign.c index f416d104..260aa5f7 100644 --- a/gpgme/sign.c +++ b/gpgme/sign.c @@ -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 @@ -21,157 +21,203 @@  #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 + +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) + +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; | 
