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.
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)
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.
* 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.
* 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.
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
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
@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.
@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.
@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
@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
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.
if (err)
return err;
+ err = _gpgme_op_sign_init_result (ctx);
+ if (err)
+ return err;
+
if (!plain)
return GPGME_No_Data;
if (!cipher)
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;
+ }
+}
}
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
{
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);
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,
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);
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);
#include <config.h>
#endif
#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
#include "gpgme.h"
#include "context.h"
_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;
+}
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);
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);
-/* 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:
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;
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;
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;