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.
This commit is contained in:
Marcus Brinkmann 2003-04-27 20:53:04 +00:00
parent e254482818
commit 2971894b27
10 changed files with 715 additions and 166 deletions

12
NEWS
View File

@ -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)

View 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.

View 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

View 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.

View 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)

View 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;
}
}

View 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);
/* 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);

View 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;
}
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;
}

View 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 --*/
/* 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);

View 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
@ -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;
if (!*rdh)
{
if (gpgme_data_new (rdh))
{
return; /* fixme: We are ignoring out-of-core */
}
dh = *rdh;
_gpgme_data_append_string (dh, "<GnupgOperationInfo>\n");
}
else
{
dh = *rdh;
_gpgme_data_append_string (dh, " </signature>\n");
}
if (!args)
{
/* Just close the XML containter. */
_gpgme_data_append_string (dh, "</GnupgOperationInfo>\n");
return;
}
_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)
{
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;
}
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");
}
GpgmeError
_gpgme_sign_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
{
SignResult result;
op_data_t opd;
GpgmeError err;
err = _gpgme_passphrase_status_handler (ctx, code, args);
err = _gpgme_op_data_lookup (ctx, OPDATA_SIGN, (void **) &opd, -1, NULL);
if (err || !opd)
return NULL;
return &opd->result;
}
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)
{
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;
}
args++;
if (*args != ' ')
{
free (sig);
return GPGME_General_Error;
}
errno = 0;
sig->pubkey_algo = strtol (args, &tail, 0);
if (errno || args == tail || *tail != ' ')
{
/* The crypto backend does not behave. */
free (sig);
return GPGME_General_Error;
}
args = tail;
sig->hash_algo = strtol (args, &tail, 0);
if (errno || args == tail || *tail != ' ')
{
/* The crypto backend does not behave. */
free (sig);
return GPGME_General_Error;
}
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 (void *priv, GpgmeStatusCode code, char *args)
{
GpgmeCtx ctx = (GpgmeCtx) priv;
GpgmeError err;
op_data_t opd;
err = _gpgme_passphrase_status_handler (priv, code, args);
if (err)
return err;
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_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_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_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;