diff --git a/NEWS b/NEWS index b6c166f5..352380c2 100644 --- a/NEWS +++ b/NEWS @@ -86,14 +86,17 @@ Noteworthy changes in version 0.4.1 (unreleased) information about the result of an encryption operation in a GpgmeEncryptResult object. - * The new gpgme_op_encrypt_result function provides detailed - information about the result of an encryption operation in - a GpgmeEncryptResult object. - * The new gpgme_op_decrypt_result function provides detailed information about the result of an encryption operation in a GpgmeDecryptResult object. + * The new gpgme_op_verify_result function provides detailed + information about the result of an verify operation in + a GpgmeVerifyResult object. Because of this, the GPGME_SIG_STAT_* + values, gpgme_get_sig_status, gpgme_get_sig_ulong_attr, + gpgme_get_sig_string_attr and gpgme_get_sig_key are now deprecated, + and gpgme_get_notation is removed. + * Interface changes relative to the 0.4.0 release: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GpgmeIOCb CHANGED: Return type from void to GpgmeError. @@ -136,6 +139,14 @@ GpgmeEncryptResult NEW gpgme_op_encrypt_result NEW GpgmeDecryptResult NEW gpgme_op_decrypt_result NEW +GpgmeVerifyResult NEW +gpgme_op_verify_result NEW +gpgme_get_notation REMOVED: Access verify result directly instead. +gpgme_get_sig_key DEPRECATED: Use gpgme_get_key with fingerprint. +gpgme_get_sig_ulong_attr DEPRECATED: Use verify result directly. +gpgme_get_sig_string_attr DEPRECATED: Use verify result directly. +GPGME_SIG_STAT_* DEPRECATED: Use error value in sig status. +gpgme_get_sig_status DEPRECATED: Use verify result directly. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Noteworthy changes in version 0.4.0 (2002-12-23) diff --git a/TODO b/TODO index 00115147..7937e8ea 100644 --- a/TODO +++ b/TODO @@ -14,6 +14,13 @@ Hey Emacs, this is -*- outline -*- mode! *** GPGME_Busy, GPGME_No_Request *** GPGME_No_Passphrase *** GPGME_Invalid_Recipient, GPGME_No_Recipients +*** GPGME_No_Passphrase +*** gpgme_op_import_ext +*** gpgme_get_sig_key +*** gpgme_get_sig_ulong_attr +*** gpgme_get_sig_string_attr +*** GPGME_SIG_STAT_* +*** gpgme_get_sig_status * Thread support: ** Build thread modules for static linking (which just suck in the diff --git a/doc/ChangeLog b/doc/ChangeLog index 778625e4..653c216b 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,5 +1,8 @@ 2003-04-28 Marcus Brinkmann + * gpgme.texi (Verify): Rewritten to take into account new and + deprecated functions and data types. + * gpgme.texi (Decrypt): Descript gpgme_op_decrypt_result and GpgmeDecryptResult. diff --git a/doc/gpgme.texi b/doc/gpgme.texi index 4e15fa07..a05a0e64 100644 --- a/doc/gpgme.texi +++ b/doc/gpgme.texi @@ -2805,7 +2805,199 @@ next operation is started on the context. @cindex signature, verification @cindex cryptographic operation, verification @cindex cryptographic operation, signature check -@cindex signature, status + +@deftypefun GpgmeError gpgme_op_verify (@w{GpgmeCtx @var{ctx}}, @w{GpgmeData @var{sig}}, @w{GpgmeData @var{signed_text}}, @w{GpgmeData @var{plain}}) +The function @code{gpgme_op_verify} verifies that the signature in the +data object @var{sig} is a valid signature. If @var{sig} is a +detached signature, then the signed text should be provided in +@var{signed_text} and @var{plain} should be a null pointer. +Otherwise, if @var{sig} is a normal (or cleartext) signature, +@var{signed_text} should be a null pointer and @var{plain} should be a +writable data object that will contain the plaintext after successful +verification. + +The results of the individual signature verifications can be retrieved +with @code{gpgme_op_verify_result}. + +The function returns @code{GPGME_No_Error} if the operation could be +completed successfully, @code{GPGME_Invalid_Value} if @var{ctx}, +@var{sig}, @var{plain} or @var{r_stat} is not a valid pointer, +@code{GPGME_No_Data} if @var{sig} does not contain any data to verify, +and passes through any errors that are reported by the crypto engine +support routines. +@end deftypefun + +@deftypefun GpgmeError gpgme_op_verify_start (@w{GpgmeCtx @var{ctx}}, @w{GpgmeData @var{sig}}, @w{GpgmeData @var{signed_text}}, @w{GpgmeData @var{plain}}) +The function @code{gpgme_op_verify_start} initiates a +@code{gpgme_op_verify} operation. It can be completed by calling +@code{gpgme_wait} on the context. @xref{Waiting For Completion}. + +The function returns @code{GPGME_No_Error} if the operation could be +started successfully, @code{GPGME_Invalid_Value} if @var{ctx}, +@var{sig}, @var{plain} or @var{r_stat} is not a valid pointer, and +@code{GPGME_No_Data} if @var{sig} or @var{plain} does not contain any +data to verify. +@end deftypefun + +@deftp {Data type} {GpgmeSigNotation} +This is a pointer to a structure used to store a part of the result of +a @code{gpgme_op_verify} operation. The structure contains the +following members: + +@table @code +@item GpgmeSigNotation next +This is a pointer to the next new signature notation structure in the +linked list, or @code{NULL} if this is the last element. + +@item char *name +The name of the notation field. If this is @code{NULL}, then the +member @code{value} will contain a policy URL. + +@item char *value +The value of the notation field. If @code{name} is @code{NULL}, then +this is a policy URL. +@end table +@end deftp + +@deftp {Data type} {GpgmeSignature} +This is a pointer to a structure used to store a part of the result of +a @code{gpgme_op_verify} operation. The structure contains the +following members: + +@table @code +@item GpgmeSignature 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 unsigned int summary; +This is a bit vector giving a summary of the signature status. It +provides an easy interface to a defined semantic of the signature +status. Checking just one bit is sufficient to see whether a +signature is valid without any restrictions. + +The defined bits are: + @table @code + @item GPGME_SIGSUM_VALID + The signature is fully valid. + + @item GPGME_SIGSUM_GREEN + The signature is good but one might want to display some extra + information. Check the other bits. + + @item GPGME_SIGSUM_RED + The signature is bad. It might be useful to checkother bits and + display moe information, i.e. a revoked certificate might not render a + signature invalid when the message was received prior to the cause for + the revocation. + + @item GPGME_SIGSUM_KEY_REVOKED + The key or at least one certificate has been revoked. + + @item GPGME_SIGSUM_KEY_EXPIRED + The key or one of the certificates has expired. It is probably a good + idea to display the date of the expiration. + + @item GPGME_SIGSUM_SIG_EXPIRED + The signature has expired. + + @item GPGME_SIGSUM_KEY_MISSING + Can't verifydue to a missing key o certificate. + + @item GPGME_SIGSUM_CRL_MISSING + The CRL (or an equivalent mechanism) is not available. + + @item GPGME_SIGSUM_CRL_TOO_OLD + Available CRL is too old. + + @item GPGME_SIGSUM_BAD_POLICY + A policy requirement was not met. + + @item GPGME_SIGSUM_SYS_ERROR + A system error occured. + @end table + +@item char *fpr +This is the fingerprint or key ID of the signature. + +@item GpgmeError status +This is the status of the signature. In particular, the following +status codes are of interest: + + @table @code + @item GPGME_No_Error + This status indicates that the signature is valid. For the combined + result this status means that all signatures are valid. + + @item GPGME_Sig_Expired + This status indicates that the signature is valid but expired. For + the combined result this status means that all signatures are valid + and expired. + + @item GPGME_Key_Expired + This status indicates that the signature is valid but the key used to + verify the signature has expired. For the combined result this status + means that all signatures are valid and all keys are expired. + + @item GPGME_Bad_Signature + This status indicates that the signature is invalid. For the combined + result this status means that all signatures are invalid. + + @item GPGME_No_Public_Key + This status indicates that the signature could not be verified due to + a missing key. For the combined result this status means that all + signatures could not be checked due to missing keys. + + @item GPGME_General_Error + This status indicates that there was some other error which prevented + the signature verification. + @end table + +@item GpgmeSigNotation notations +This is a linked list with the notation data and policy URLs. + +@item unsigned long timestamp +The creation timestamp of this signature. + +@item unsigned long exp_timestamp +The expiration timestamp of this signature, or 0 if the signature does +not expire. + +@item int wrong_key_usage : 1; + +@item GpgmeValidity validity + +@item GpgmeError validity_reason +@end table +@end deftp + +@deftp {Data type} {GpgmeVerifyResult} +This is a pointer to a structure used to store the result of a +@code{gpgme_op_verify} operation. After successfully verifying a +signature, you can retrieve the pointer to the result with +@code{gpgme_op_verify_result}. The structure contains the following +member: + +@table @code +@item GpgmeSignature signatures +A linked list with information about all signatures for which a +verification was attempted. +@end table +@end deftp + +@deftypefun GpgmeSignResult gpgme_op_verify_result (@w{GpgmeCtx @var{ctx}}) +The function @code{gpgme_op_verify_result} returns a +@code{GpgmeVerifyResult} pointer to a structure holding the result of +a @code{gpgme_op_verify} operation. The pointer is only valid if the +last operation on the context was a @code{gpgme_op_verify} or +@code{gpgme_op_verify_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 + + +The following interfaces are deprecated and only provided for backward +compatibility. Don't use them. They will be removed in a future +version of @acronym{GPGME}. @deftp {Data type} {enum GpgmeSigStat} @tindex GpgmeSigStat @@ -2855,188 +3047,183 @@ have a different status. You can get each key's status with @end table @end deftp - -@deftypefun GpgmeError gpgme_op_verify (@w{GpgmeCtx @var{ctx}}, @w{GpgmeData @var{sig}}, @w{GpgmeData @var{signed_text}}, @w{GpgmeData @var{plain}}) -The function @code{gpgme_op_verify} verifies that the signature in the -data object @var{sig} is a valid signature. If @var{sig} is a -detached signature, then the signed text should be provided in -@var{signed_text} and @var{plain} should be a null pointer. -Otherwise, if @var{sig} is a normal (or cleartext) signature, -@var{signed_text} should be a null pointer and @var{plain} should be a -writable data object that will contain the plaintext after successful -verification. - -The results of the individual signature verifications can be retrieved -with @code{gpgme_get_sig_status} and @code{gpgme_get_sig_key}. - -The function returns @code{GPGME_No_Error} if the operation could be -completed successfully, @code{GPGME_Invalid_Value} if @var{ctx}, -@var{sig}, @var{plain} or @var{r_stat} is not a valid pointer, -@code{GPGME_No_Data} if @var{sig} does not contain any data to verify, -and passes through any errors that are reported by the crypto engine -support routines. -@end deftypefun - -@deftypefun GpgmeError gpgme_op_verify_start (@w{GpgmeCtx @var{ctx}}, @w{GpgmeData @var{sig}}, @w{GpgmeData @var{signed_text}}, @w{GpgmeData @var{plain}}) -The function @code{gpgme_op_verify_start} initiates a -@code{gpgme_op_verify} operation. It can be completed by calling -@code{gpgme_wait} on the context. @xref{Waiting For Completion}. - -The function returns @code{GPGME_No_Error} if the operation could be -started successfully, @code{GPGME_Invalid_Value} if @var{ctx}, -@var{sig}, @var{plain} or @var{r_stat} is not a valid pointer, and -@code{GPGME_No_Data} if @var{sig} or @var{plain} does not contain any -data to verify. -@end deftypefun - @deftypefun {const char *} gpgme_get_sig_status (@w{GpgmeCtx @var{ctx}}, @w{int @var{idx}}, @w{GpgmeSigStat *@var{r_stat}}, @w{time_t *@var{r_created}}) -The function @code{gpgme_get_sig_status} receives information about a -signature after the @code{gpgme_op_verify} or -@code{gpgme_op_verify_decrypt} operation. A single detached signature -can contain signatures by more than one key. The @var{idx} specifies -which signature's information should be retrieved, starting from -@var{0}. +The function @code{gpgme_get_sig_status} is equivalent to: + +@example + GpgmeVerifyResult result; + GpgmeSignature sig; -The status of the signature will be returned in @var{r_stat} if it is -not @code{NULL}. The creation time stamp of the signature will be -returned in @var{r_created} if it is not @var{NULL}. + result = gpgme_op_verify_result (ctx); + sig = result->signatures; -The function returns a statically allocated string that contains the -fingerprint of the key which signed the plaintext, or @code{NULL} if -@var{ctx} is not a valid pointer, the operation is still pending, or -no verification could be performed. + while (sig && idx) + @{ + sig = sig->next; + idx--; + @} + if (!sig || idx) + return NULL; + + if (r_stat) + @{ + switch (sig->status) + @{ + case GPGME_No_Error: + *r_stat = GPGME_SIG_STAT_GOOD; + break; + + case GPGME_Bad_Signature: + *r_stat = GPGME_SIG_STAT_BAD; + break; + + case GPGME_No_Public_Key: + *r_stat = GPGME_SIG_STAT_NOKEY; + break; + + case GPGME_No_Data: + *r_stat = GPGME_SIG_STAT_NOSIG; + break; + + case GPGME_Sig_Expired: + *r_stat = GPGME_SIG_STAT_GOOD_EXP; + break; + + case GPGME_Key_Expired: + *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY; + break; + + default: + *r_stat = GPGME_SIG_STAT_ERROR; + break; + @} + @} + if (r_created) + *r_created = sig->timestamp; + return sig->fpr; +@end example @end deftypefun @deftypefun {const char *} gpgme_get_sig_string_attr (@w{GpgmeCtx @var{ctx}}, @w{int @var{idx}}, @w{GpgmeAttr @var{what}}, @w{int @var{whatidx}}) -This function is similar to @code{gpgme_get_sig_status} but may be used -to retrieve more detailed information. @var{ctx} should be the context -used for the last signature verification, @var{idx} is used to enumerate -over all signatures starting with @code{0} and @var{whatidx} should be -@code{0} unless otherwise stated. +The function @code{gpgme_get_sig_string_attr} is equivalent to: + +@example + GpgmeVerifyResult result; + GpgmeSignature sig; -The following values may be used for @var{what}: -@table @code -@item GPGME_ATTR_FPR -Return the fingerprint of the key used to create the signature. + result = gpgme_op_verify_result (ctx); + sig = result->signatures; -@item GPGME_ATTR_ERRTOK -Return a token with a more detailed error description. A @var{whatidx} -of @code{0} returns an error token associated with validity calculation, -a value of @code{1} return an error token related to the certificate -checking. + while (sig && idx) + @{ + sig = sig->next; + idx--; + @} + if (!sig || idx) + return NULL; -@end table + switch (what) + @{ + case GPGME_ATTR_FPR: + return sig->fpr; + + case GPGME_ATTR_ERRTOK: + if (whatidx == 1) + return sig->wrong_key_usage ? "Wrong_Key_Usage" : ""; + else + return ""; + default: + break; + @} + + return NULL; +@end example @end deftypefun @deftypefun {const char *} gpgme_get_sig_ulong_attr (@w{GpgmeCtx @var{ctx}}, @w{int @var{idx}}, @w{GpgmeAttr @var{waht}}, @w{int @var{whatidx}}) -This function is similar to @code{gpgme_get_sig_string_attr} but used -for attributes which can be represented by an @code{unsigned long} data -type. @var{ctx} should be the context used for the last signature -verification, @var{idx} is used to enumerate over all signatures -starting with @code{0} and @var{whatidx} should be @code{0} unless -otherwise stated. +The function @code{gpgme_get_sig_ulong_attr} is equivalent to: + +@example + GpgmeVerifyResult result; + GpgmeSignature sig; -The following values may be used for @var{what}: -@table @code -@item GPGME_ATTR_CREATED -Return the creation time of the signature in seconds since Epoch. This -is the same value as returned by @code{gpgme_get_sig_status}. + result = gpgme_op_verify_result (ctx); + sig = result->signatures; -@item GPGME_ATTR_EXPIRE -Return the expiration time of the signature in seconds since Epoch. + while (sig && idx) + @{ + sig = sig->next; + idx--; + @} + if (!sig || idx) + return 0; -@item GPGME_ATTR_VALIDITY -Returns the validity of the key used to create the signature. This is a -shortcut function which avoids an extra key lookup. The value returned -is one of @code{GPGME_VALIDITY_UNKNOWN}, @code{GPGME_VALIDITY_NEVER}, -@code{GPGME_VALIDITY_MARGINAL} or @code{GPGME_VALIDITY_FULL}. + switch (what) + @{ + case GPGME_ATTR_CREATED: + return sig->timestamp; -@item GPGME_ATTR_SIG_STATUS -This is the same value as returned by @code{gpgme_get_sig_status}. + case GPGME_ATTR_EXPIRE: + return sig->exp_timestamp; -@item GPGME_ATTR_SIG_SUMMARY -This returns a bit vector giving a summary of the signature status. -Itprovides an easy interface to a defined semantic of the signature -status. Checking just one bit is sufficient to see whether a signature -is valid without any restrictions. + case GPGME_ATTR_VALIDITY: + return (unsigned long) sig->validity; -The defined bits are: - @table @code - @item GPGME_SIGSUM_VALID - The signature is fully valid. + case GPGME_ATTR_SIG_STATUS: + switch (sig->status) + @{ + case GPGME_No_Error: + return GPGME_SIG_STAT_GOOD; + + case GPGME_Bad_Signature: + return GPGME_SIG_STAT_BAD; + + case GPGME_No_Public_Key: + return GPGME_SIG_STAT_NOKEY; + + case GPGME_No_Data: + return GPGME_SIG_STAT_NOSIG; + + case GPGME_Sig_Expired: + return GPGME_SIG_STAT_GOOD_EXP; + + case GPGME_Key_Expired: + return GPGME_SIG_STAT_GOOD_EXPKEY; + + default: + return GPGME_SIG_STAT_ERROR; + @} - @item GPGME_SIGSUM_GREEN - The signature is good but one might want to display some extra - information. Check the other bits. + case GPGME_ATTR_SIG_SUMMARY: + return sig->summary; - @item GPGME_SIGSUM_RED - The signature is bad. It might be useful to checkother bits and - display moe information, i.e. a revoked certificate might not render a - signature invalid when the message was received prior to the cause for - the revocation. - - @item GPGME_SIGSUM_KEY_REVOKED - The key or at least one certificate has been revoked. - - @item GPGME_SIGSUM_KEY_EXPIRED - The key or one of the certificates has expired. It is probably a good - idea to display the date of the expiration. - - @item GPGME_SIGSUM_SIG_EXPIRED - The signature has expired. - - @item GPGME_SIGSUM_KEY_MISSING - Can't verifydue to a missing key o certificate. - - @item GPGME_SIGSUM_CRL_MISSING - The CRL (or an equivalent mechanism) is not available. - - @item GPGME_SIGSUM_CRL_TOO_OLD - Available CRL is too old. - - @item GPGME_SIGSUM_BAD_POLICY - A policy requirement was not met. - - @item GPGME_SIGSUM_SYS_ERROR - A system error occured. - - @end table - -@end table + default: + break; + @} + return 0; +@end example @end deftypefun - @deftypefun {const char *} gpgme_get_sig_key (@w{GpgmeCtx @var{ctx}}, @w{int @var{idx}}, @w{GpgmeKey *@var{r_key}}) -The function @code{gpgme_get_sig_status} receives a @code{GpgmeKey} -object for the key which was used to verify the signature after the -@code{gpgme_op_verify} or @code{gpgme_op_verify_decrypt} operation. A -single detached signature can contain signatures by more than one key. -The @var{idx} specifies which signature's information should be -retrieved, starting from @var{0}. The key will have on reference for -the user. +The function @code{gpgme_get_sig_key} is equivalent to: -The function is a convenient way to retrieve the keys belonging to the -fingerprints returned by @code{gpgme_get_sig_status}. +@example + GpgmeVerifyResult result; + GpgmeSignature sig; -The function returns @code{GPGME_No_Error} if the key could be -returned, @code{GPGME_Invalid_Value} if @var{r_key} is not a valid -pointer, @code{GPGME_Invalid_Key} if the fingerprint is not valid, -@code{GPGME_EOF} if @var{idx} is too large, or some other error value -if a problem occurred requesting the key. -@end deftypefun + result = gpgme_op_verify_result (ctx); + sig = result->signatures; -@deftypefun {char *} gpgme_get_notation (@w{GpgmeCtx @var{ctx}}) -The function @code{gpgme_get_notation} can be used to retrieve -notation data from the last signature check in the context @var{ctx}. + while (sig && idx) + @{ + sig = sig->next; + idx--; + @} + if (!sig || idx) + return GPGME_EOF; -If there is notation data available from the last signature check, -this function may be used to return this notation data as a string. -The string is an XML representation of that data embedded in a - container. The user has to release the string with -@code{free}. - -The function returns a string if the notation data is available or -@code{NULL} if there is no such data available. + return gpgme_get_key (ctx, sig->fpr, r_key, 0, 0); +@end example @end deftypefun @@ -3204,7 +3391,7 @@ The hash algorithm used to create this signature. @item unsigned long class The signature class of this signature. -@item long int created +@item long int timestamp The creation timestamp of this signature. @item char *fpr diff --git a/gpgme/ChangeLog b/gpgme/ChangeLog index 720dc7b0..c371ce3f 100644 --- a/gpgme/ChangeLog +++ b/gpgme/ChangeLog @@ -1,5 +1,51 @@ 2003-04-28 Marcus Brinkmann + * gpgme.h (struct _gpgme_sig_notation): New structure. + (GpgmeSigNotation): New type. + (struct _gpgme_signature): New structure. + (GpgmeSignature): New type. + (struct _gpgme_op_verify_result): New structure. + (GpgmeVerifyResult): New type. + (gpgme_op_verify_result): New prototype. + (gpgme_get_notation): Remove prototype. + * ops.h (_gpgme_op_verify_init_result): New prototype. + (_gpgme_verify_status_handler): Change first argument to void *. + * util.h (_gpgme_decode_percent_string, _gpgme_map_gnupg_error): + New prototypes. + * conversion.c (_gpgme_decode_percent_string): New function. + (gnupg_errors): New static global. + (_gpgme_map_gnupg_error): New function. + * gpgme.c (gpgme_release): Don't release CTX->notation. + (gpgme_get_notation): Remove function. + * decrypt-verify.c (_gpgme_op_decrypt_verify_start): Call + _gpgme_op_verify_init_result. + * verify.c: Do not include , and "key.h", but + do include "gpgme.h". + (struct verify_result): Replace with ... + (op_data_t): ... this type. + (release_verify_result): Remove function. + (release_op_data): New function. + (is_token): Remove function. + (skip_token): Remove function. + (copy_token): Remove function. + (gpgme_op_verify_result): New function. + (calc_sig_summary): Rewritten. + (finish_sig): Remove function. + (parse_new_sig): New function. + (parse_valid_sig): New function. + (parse_notation): New function. + (parse_trust): New function. + (parse_error): New function. + (_gpgme_verify_status_handler): Rewritten. Change first argument + to void *. + (_gpgme_op_verify_start): Rework error handling. Call + _gpgme_op_verify_init_result. + (gpgme_op_verify): Do not release or clear CTX->notation. + (gpgme_get_sig_status): Rewritten. + (gpgme_get_sig_string_attr): Likewise. + (gpgme_get_sig_ulong_attr): Likewise. + (gpgme_get_sig_key): Likewise. + * gpgme.h (struct _gpgme_op_decrypt_result): New structure. (GpgmeDecryptResult): New type. (gpgme_op_decrypt_result): New prototype. diff --git a/gpgme/conversion.c b/gpgme/conversion.c index 5b2cb67a..57e2f514 100644 --- a/gpgme/conversion.c +++ b/gpgme/conversion.c @@ -161,6 +161,178 @@ _gpgme_decode_c_string (const char *src, char **destp, int len) return 0; } + +/* Decode the percent escaped string SRC and store the result in the + buffer *DESTP which is LEN bytes long. If LEN is zero, then a + large enough buffer is allocated with malloc and *DESTP is set to + the result. Currently, LEN is only used to specify if allocation + is desired or not, the caller is expected to make sure that *DESTP + is large enough if LEN is not zero. */ +GpgmeError +_gpgme_decode_percent_string (const char *src, char **destp, int len) +{ + char *dest; + + /* Set up the destination buffer. */ + if (len) + { + if (len < strlen (src) + 1) + return GPGME_General_Error; + + dest = *destp; + } + else + { + /* The converted string will never be larger than the original + string. */ + dest = malloc (strlen (src) + 1); + if (!dest) + return GPGME_Out_Of_Core; + + *destp = dest; + } + + /* Convert the string. */ + while (*src) + { + if (*src != '%') + { + *(dest++) = *(src++); + continue; + } + else + { + int val = _gpgme_hextobyte (&src[1]); + + if (val == -1) + { + /* Should not happen. */ + *(dest++) = *(src++); + if (*src) + *(dest++) = *(src++); + if (*src) + *(dest++) = *(src++); + } + else + { + if (!val) + { + /* A binary zero is not representable in a C + string. */ + *(dest++) = '\\'; + *(dest++) = '0'; + } + else + *((unsigned char *) dest++) = val; + src += 3; + } + } + } + *(dest++) = 0; + + return 0; +} + + +static struct +{ + char *name; + GpgmeError err; +} gnupg_errors[] = + { + { "EOF", GPGME_EOF }, + { "No_Error", GPGME_No_Error }, + { "General_Error", GPGME_General_Error }, + { "Out_Of_Core", GPGME_Out_Of_Core }, + { "Invalid_Value", GPGME_Invalid_Value }, + { "IO_Error", GPGME_General_Error }, + { "Resource_Limit", GPGME_General_Error }, + { "Internal_Error", GPGME_General_Error }, + { "Bad_Certificate", GPGME_Invalid_Key }, + { "Bad_Certificate_Chain", GPGME_General_Error }, + { "Missing_Certificate", GPGME_No_Public_Key }, + { "No_Data", GPGME_No_Data }, + { "Bad_Signature", GPGME_Bad_Signature }, + { "Not_Implemented", GPGME_Not_Implemented }, + { "Conflict", GPGME_Conflict }, + { "Bug", GPGME_General_Error }, + { "Read_Error", GPGME_General_Error }, + { "Write_Error", GPGME_General_Error }, + { "Invalid_Line", GPGME_General_Error }, + { "Incomplete_Line", GPGME_General_Error }, + { "Invalid_Response", GPGME_General_Error }, + { "Agent_Error", GPGME_General_Error }, + { "No_Public_Key", GPGME_No_Public_Key }, + { "No_Secret_Key", GPGME_No_Secret_Key }, + { "File_Open_Error", GPGME_General_Error }, + { "File_Create_Error", GPGME_General_Error }, + { "File_Error", GPGME_General_Error }, + { "Not_Supported", GPGME_General_Error }, + { "Invalid_Data", GPGME_General_Error }, + { "Assuan_Server_Fault", GPGME_General_Error }, + { "Assuan_Error", GPGME_General_Error }, + { "Invalid_Session_Key", GPGME_General_Error }, + { "Invalid_Sexp", GPGME_General_Error }, + { "Unsupported_Algorithm", GPGME_Unsupported_Algorithm }, + { "No_PIN_Entry", GPGME_Invalid_Engine }, + { "PIN_Entry_Error", GPGME_Invalid_Engine }, + { "Bad_PIN", GPGME_Bad_Passphrase }, + { "Bad_Passphrase", GPGME_Bad_Passphrase }, + { "Invalid_Name", GPGME_General_Error }, + { "Bad_Public_Key", GPGME_General_Error }, + { "Bad_Secret_Key", GPGME_General_Error }, + { "Bad_Data", GPGME_General_Error }, + { "Invalid_Parameter", GPGME_General_Error }, + { "Tribute_to_D_A", GPGME_General_Error }, + { "No_Dirmngr", GPGME_Invalid_Engine }, + { "Dirmngr_Error", GPGME_General_Error }, + { "Certificate_Revoked", GPGME_Key_Revoked }, + { "No_CRL_Known", GPGME_No_CRL_Known }, + { "CRL_Too_Old", GPGME_CRL_Too_Old }, + { "Line_Too_Long", GPGME_General_Error }, + { "Not_Trusted", GPGME_Key_Not_Trusted }, + { "Canceled", GPGME_Canceled }, + { "Bad_CA_Certificate", GPGME_General_Error }, + { "Certificate_Expired", GPGME_Key_Expired }, + { "Certificate_Too_Young", GPGME_Invalid_Key }, + { "Unsupported_Certificate", GPGME_General_Error }, + { "Unknown_Sexp", GPGME_General_Error }, + { "Unsupported_Protection", GPGME_General_Error }, + { "Corrupted_Protection", GPGME_General_Error }, + { "Ambiguous_Name", GPGME_Ambiguous_Specification }, + { "Card_Error", GPGME_General_Error }, + { "Card_Reset", GPGME_General_Error }, + { "Card_Removed", GPGME_General_Error }, + { "Invalid_Card", GPGME_General_Error }, + { "Card_Not_Present", GPGME_General_Error }, + { "No_PKCS15_App", GPGME_General_Error }, + { "Not_Confirmed", GPGME_General_Error }, + { "Configuration_Error", GPGME_General_Error }, + { "No_Policy_Match", GPGME_Policy_Mismatch }, + { "Invalid_Index", GPGME_General_Error }, + { "Invalid_Id", GPGME_General_Error }, + { "No_Scdaemon", GPGME_Invalid_Engine }, + { "Scdaemon_Error", GPGME_General_Error }, + { "Unsupported_Protocol", GPGME_General_Error }, + { "Bad_PIN_Method", GPGME_General_Error }, + { "Card_Not_Initialized", GPGME_General_Error }, + { "Unsupported_Operation", GPGME_General_Error }, + { "Wrong_Key_Usage", GPGME_Wrong_Key_Usage } + }; + + +GpgmeError +_gpgme_map_gnupg_error (char *err) +{ + int i; + + for (i = 0; i < DIM (gnupg_errors); i++) + if (!strcmp (gnupg_errors[i].name, err)) + return gnupg_errors[i].err; + + return GPGME_General_Error; +} + GpgmeError _gpgme_data_append (GpgmeData dh, const char *buffer, size_t length) diff --git a/gpgme/decrypt-verify.c b/gpgme/decrypt-verify.c index 0a94522a..f365b165 100644 --- a/gpgme/decrypt-verify.c +++ b/gpgme/decrypt-verify.c @@ -48,6 +48,10 @@ _gpgme_op_decrypt_verify_start (GpgmeCtx ctx, int synchronous, if (err) return err; + err = _gpgme_op_verify_init_result (ctx); + if (err) + return err; + if (!cipher) return GPGME_No_Data; if (!plain) diff --git a/gpgme/gpgme.c b/gpgme/gpgme.c index 72f502a2..dbcd406f 100644 --- a/gpgme/gpgme.c +++ b/gpgme/gpgme.c @@ -68,7 +68,6 @@ gpgme_release (GpgmeCtx ctx) _gpgme_fd_table_deinit (&ctx->fdt); _gpgme_release_result (ctx); gpgme_key_release (ctx->tmp_key); - gpgme_data_release (ctx->notation); gpgme_signers_clear (ctx); if (ctx->signers) free (ctx->signers); @@ -94,26 +93,6 @@ _gpgme_release_result (GpgmeCtx ctx) } -/** - * gpgme_get_notation: - * @c: the context - * - * If there is notation data available from the last signature check, - * this function may be used to return this notation data as a string. - * The string is an XML represantaton of that data embedded in a - * %<notation> container. - * - * Return value: An XML string or NULL if no notation data is available. - **/ -char * -gpgme_get_notation (GpgmeCtx ctx) -{ - if (!ctx->notation) - return NULL; - return _gpgme_data_get_as_string (ctx->notation); -} - - /** * gpgme_get_op_info: * @c: the context diff --git a/gpgme/gpgme.h b/gpgme/gpgme.h index 0071f06b..4ee92121 100644 --- a/gpgme/gpgme.h +++ b/gpgme/gpgme.h @@ -188,23 +188,6 @@ typedef enum } GpgmeSigStat; -/* Flags used with the GPGME_ATTR_SIG_SUMMARY. */ -enum - { - GPGME_SIGSUM_VALID = 0x0001, /* The signature is fully valid. */ - GPGME_SIGSUM_GREEN = 0x0002, /* The signature is good. */ - GPGME_SIGSUM_RED = 0x0004, /* The signature is bad. */ - GPGME_SIGSUM_KEY_REVOKED = 0x0010, /* One key has been revoked. */ - GPGME_SIGSUM_KEY_EXPIRED = 0x0020, /* One key has expired. */ - GPGME_SIGSUM_SIG_EXPIRED = 0x0040, /* The signature has expired. */ - GPGME_SIGSUM_KEY_MISSING = 0x0080, /* Can't verify: key missing. */ - GPGME_SIGSUM_CRL_MISSING = 0x0100, /* CRL not available. */ - GPGME_SIGSUM_CRL_TOO_OLD = 0x0200, /* Available CRL is too old. */ - GPGME_SIGSUM_BAD_POLICY = 0x0400, /* A policy was not met. */ - GPGME_SIGSUM_SYS_ERROR = 0x0800 /* A system error occured. */ - }; - - /* The available signature modes. */ typedef enum { @@ -406,9 +389,6 @@ GpgmeError gpgme_new (GpgmeCtx *ctx); /* Release the context CTX. */ void gpgme_release (GpgmeCtx ctx); -/* Retrieve more info about performed signature check. */ -char *gpgme_get_notation (GpgmeCtx ctx); - /* Set the protocol to be used by CTX to PROTO. */ GpgmeError gpgme_set_protocol (GpgmeCtx ctx, GpgmeProtocol proto); @@ -831,7 +811,7 @@ struct _gpgme_new_signature GpgmePubKeyAlgo pubkey_algo; GpgmeHashAlgo hash_algo; unsigned long class; - long int created; + long int timestamp; char *fpr; }; typedef struct _gpgme_new_signature *GpgmeNewSignature; @@ -856,6 +836,75 @@ GpgmeError gpgme_op_sign (GpgmeCtx ctx, GpgmeSigMode mode); +/* Verify. */ +struct _gpgme_sig_notation +{ + struct _gpgme_sig_notation *next; + + /* If NAME is a null pointer, then VALUE contains a policy URL + rather than a notation. */ + char *name; + char *value; +}; +typedef struct _gpgme_sig_notation *GpgmeSigNotation; + +/* Flags used for the SUMMARY field in a GpgmeSignature. */ +enum + { + GPGME_SIGSUM_VALID = 0x0001, /* The signature is fully valid. */ + GPGME_SIGSUM_GREEN = 0x0002, /* The signature is good. */ + GPGME_SIGSUM_RED = 0x0004, /* The signature is bad. */ + GPGME_SIGSUM_KEY_REVOKED = 0x0010, /* One key has been revoked. */ + GPGME_SIGSUM_KEY_EXPIRED = 0x0020, /* One key has expired. */ + GPGME_SIGSUM_SIG_EXPIRED = 0x0040, /* The signature has expired. */ + GPGME_SIGSUM_KEY_MISSING = 0x0080, /* Can't verify: key missing. */ + GPGME_SIGSUM_CRL_MISSING = 0x0100, /* CRL not available. */ + GPGME_SIGSUM_CRL_TOO_OLD = 0x0200, /* Available CRL is too old. */ + GPGME_SIGSUM_BAD_POLICY = 0x0400, /* A policy was not met. */ + GPGME_SIGSUM_SYS_ERROR = 0x0800 /* A system error occured. */ + }; + +struct _gpgme_signature +{ + struct _gpgme_signature *next; + + /* A summary of the signature status. */ + unsigned int summary; + + /* The fingerprint or key ID of the signature. */ + char *fpr; + + /* The status of the signature. */ + GpgmeError status; + + /* Notation data and policy URLs. */ + GpgmeSigNotation notations; + + /* Signature creation time. */ + unsigned long timestamp; + + /* Signature exipration time or 0. */ + unsigned long exp_timestamp; + + int wrong_key_usage : 1; + + /* Internal to GPGME, do not use. */ + int _unused : 31; + + GpgmeValidity validity; + GpgmeError validity_reason; +}; +typedef struct _gpgme_signature *GpgmeSignature; + +struct _gpgme_op_verify_result +{ + GpgmeSignature signatures; +}; +typedef struct _gpgme_op_verify_result *GpgmeVerifyResult; + +/* Retrieve a pointer to the result of the verify operation. */ +GpgmeVerifyResult gpgme_op_verify_result (GpgmeCtx ctx); + /* 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); @@ -863,6 +912,7 @@ GpgmeError gpgme_op_verify (GpgmeCtx ctx, GpgmeData sig, GpgmeData signed_text, GpgmeData plaintext); +/* Import. */ enum { /* The key was new. */ diff --git a/gpgme/ops.h b/gpgme/ops.h index 165a5172..ffc2bdbe 100644 --- a/gpgme/ops.h +++ b/gpgme/ops.h @@ -1,4 +1,4 @@ -/* ops.h - internal operations stuff +/* ops.h - Internal operation support. Copyright (C) 2000 Werner Koch (dd9jn) Copyright (C) 2001, 2002, 2003 g10 Code GmbH @@ -73,8 +73,9 @@ GpgmeError _gpgme_op_reset (GpgmeCtx ctx, int synchronous); GpgmeError _gpgme_parse_inv_userid (char *args, GpgmeInvalidUserID *userid); -/*-- verify.c --*/ -GpgmeError _gpgme_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, +/* From verify.c. */ +GpgmeError _gpgme_op_verify_init_result (GpgmeCtx ctx); +GpgmeError _gpgme_verify_status_handler (void *priv, GpgmeStatusCode code, char *args); diff --git a/gpgme/sign.c b/gpgme/sign.c index 260aa5f7..413865dc 100644 --- a/gpgme/sign.c +++ b/gpgme/sign.c @@ -149,7 +149,7 @@ parse_sig_created (char *args, GpgmeNewSignature *sigp) } args = tail; - sig->created = strtol (args, &tail, 0); + sig->timestamp = strtol (args, &tail, 0); if (errno || args == tail || *tail != ' ') { /* The crypto backend does not behave. */ diff --git a/gpgme/util.h b/gpgme/util.h index 2734115e..70b7de9a 100644 --- a/gpgme/util.h +++ b/gpgme/util.h @@ -74,5 +74,15 @@ int _gpgme_hextobyte (const unsigned char *str); is large enough if LEN is not zero. */ GpgmeError _gpgme_decode_c_string (const char *src, char **destp, int len); +/* Decode the percent escaped string SRC and store the result in the + buffer *DESTP which is LEN bytes long. If LEN is zero, then a + large enough buffer is allocated with malloc and *DESTP is set to + the result. Currently, LEN is only used to specify if allocation + is desired or not, the caller is expected to make sure that *DESTP + is large enough if LEN is not zero. */ +GpgmeError _gpgme_decode_percent_string (const char *src, char **destp, + int len); + +GpgmeError _gpgme_map_gnupg_error (char *err); #endif /* UTIL_H */ diff --git a/gpgme/verify.c b/gpgme/verify.c index 3b63491f..85854cdb 100644 --- a/gpgme/verify.c +++ b/gpgme/verify.c @@ -21,391 +21,520 @@ #if HAVE_CONFIG_H #include #endif -#include #include #include -#include +#include +#include "gpgme.h" #include "util.h" #include "context.h" #include "ops.h" -#include "key.h" - -struct verify_result + +typedef struct { - GpgmeSigStat status; - GpgmeSigStat expstatus; /* Only used by finish_sig. */ - GpgmeData notation; /* We store an XML fragment here. */ - int collecting; /* Private to finish_sig(). */ - int notation_in_data; /* Private to add_notation(). */ - char fpr[41]; /* Fingerprint of a good signature or keyid of - a bad one. */ - ulong timestamp; /* Signature creation time. */ - ulong exptimestamp; /* Signature exipration time or 0. */ - GpgmeValidity validity; - int wrong_key_usage; - char trust_errtok[31]; /* Error token send with the trust status. */ -}; -typedef struct verify_result *VerifyResult; + struct _gpgme_op_verify_result result; + + GpgmeSignature current_sig; +} *op_data_t; static void -release_verify_result (void *hook) +release_op_data (void *hook) { - VerifyResult result = (VerifyResult) hook; + op_data_t opd = (op_data_t) hook; + GpgmeSignature sig = opd->result.signatures; - gpgme_data_release (result->notation); -} - - -/* Check whether STRING starts with TOKEN and return true in this - case. This is case insensitive. If NEXT is not NULL return the - number of bytes to be added to STRING to get to the next token; a - returned value of 0 indicates end of line. */ -static int -is_token (const char *string, const char *token, size_t *next) -{ - size_t n = 0; - - for (;*string && *token && *string == *token; string++, token++, n++) - ; - if (*token || (*string != ' ' && !*string)) - return 0; - if (next) + while (sig) { - for (; *string == ' '; string++, n++) - ; - *next = n; + GpgmeSignature next = sig->next; + GpgmeSigNotation notation = sig->notations; + + while (notation) + { + GpgmeSigNotation next_nota = notation->next; + + if (notation->name) + free (notation->name); + if (notation->value) + free (notation->value); + notation = next_nota; + } + + if (sig->fpr) + free (sig->fpr); + free (sig); + sig = next; } - return 1; } -static int -skip_token (const char *string, size_t *next) + +GpgmeVerifyResult +gpgme_op_verify_result (GpgmeCtx ctx) { - size_t n = 0; + op_data_t opd; + GpgmeError err; - for (;*string && *string != ' '; string++, n++) - ; - for (;*string == ' '; string++, n++) - ; - if (!*string) - return 0; - if (next) - *next = n; - return 1; + err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, (void **) &opd, -1, NULL); + if (err || !opd) + return NULL; + + return &opd->result; } - -static size_t -copy_token (const char *string, char *buffer, size_t length) + +/* Build a summary vector from RESULT. */ +static void +calc_sig_summary (GpgmeSignature sig) { - const char *s = string; - char *p = buffer; - size_t i; + unsigned long sum = 0; - for (i = 1; i < length && *s && *s != ' ' ; i++) - *p++ = *s++; - *p = 0; - /* continue scanning in case the copy was truncated */ - while (*s && *s != ' ') - s++; - return s - string; + if (sig->validity == GPGME_VALIDITY_FULL + || sig->validity == GPGME_VALIDITY_ULTIMATE) + { + if (sig->status == GPGME_No_Error + || sig->status == GPGME_Sig_Expired + || sig->status == GPGME_Key_Expired) + sum |= GPGME_SIGSUM_GREEN; + } + else if (sig->validity == GPGME_VALIDITY_NEVER) + { + if (sig->status == GPGME_No_Error + || sig->status == GPGME_Sig_Expired + || sig->status == GPGME_Key_Expired) + sum |= GPGME_SIGSUM_RED; + } + else if (sig->status == GPGME_Bad_Signature) + sum |= GPGME_SIGSUM_RED; + + /* FIXME: handle the case when key and message are expired. */ + if (sig->status == GPGME_Sig_Expired) + sum |= GPGME_SIGSUM_SIG_EXPIRED; + else if (sig->status == GPGME_Key_Expired) + sum |= GPGME_SIGSUM_KEY_EXPIRED; + else if (sig->status == GPGME_No_Public_Key) + sum |= GPGME_SIGSUM_KEY_MISSING; + else if (sig->status) + sum |= GPGME_SIGSUM_SYS_ERROR; + + if (sig->validity_reason == GPGME_Key_Revoked) + sum |= GPGME_SIGSUM_KEY_REVOKED; + else if (sig->validity_reason == GPGME_No_CRL_Known) + sum |= GPGME_SIGSUM_CRL_MISSING; + else if (sig->validity_reason == GPGME_CRL_Too_Old) + sum |= GPGME_SIGSUM_CRL_TOO_OLD; + else if (sig->validity_reason == GPGME_Policy_Mismatch) + sum |= GPGME_SIGSUM_BAD_POLICY; + else if (sig->validity_reason) + sum |= GPGME_SIGSUM_SYS_ERROR; + + if (sig->wrong_key_usage) + sum |= GPGME_SIGSUM_BAD_POLICY; + + /* Set the valid flag when the signature is unquestionable + valid. */ + if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN)) + sum |= GPGME_SIGSUM_VALID; + + sig->summary = sum; } + - -/* FIXME: Check that we are adding this to the correct signature. */ static GpgmeError -add_notation (VerifyResult result, GpgmeStatusCode code, const char *notation) +parse_new_sig (op_data_t opd, GpgmeStatusCode code, char *args) { - GpgmeData dh = result->notation; + GpgmeSignature sig; + char *end = strchr (args, ' '); - if (!dh) + if (end) { - if (gpgme_data_new (&dh)) + *end = '\0'; + end++; + } + + sig = calloc (1, sizeof (*sig)); + if (!sig) + return GPGME_Out_Of_Core; + if (!opd->result.signatures) + opd->result.signatures = sig; + if (opd->current_sig) + opd->current_sig->next = sig; + opd->current_sig = sig; + + switch (code) + { + case GPGME_STATUS_GOODSIG: + sig->status = GPGME_No_Error; + break; + + case GPGME_STATUS_EXPSIG: + sig->status = GPGME_Sig_Expired; + break; + + case GPGME_STATUS_EXPKEYSIG: + sig->status = GPGME_Key_Expired; + break; + + case GPGME_STATUS_BADSIG: + sig->status = GPGME_Bad_Signature; + break; + + case GPGME_STATUS_ERRSIG: + if (end) + { + int i = 0; + /* The return code is the 6th argument, if it is 9, the + problem is a missing key. */ + while (end && i < 4) + end = strchr (end, ' '); + if (end && end[0] && (!end[1] || !end[1] == ' ')) + { + switch (end[0]) + { + case '4': + sig->status = GPGME_Unsupported_Algorithm; + break; + + case 9: + sig->status = GPGME_No_Public_Key; + break; + + default: + sig->status = GPGME_General_Error; + } + } + } + else + sig->status = GPGME_General_Error; + break; + + default: + return GPGME_General_Error; + } + + if (*args) + { + sig->fpr = strdup (args); + if (!sig->fpr) return GPGME_Out_Of_Core; - result->notation = dh; - _gpgme_data_append_string (dh, " \n"); } - - if (code == GPGME_STATUS_NOTATION_DATA) - { - if (!result->notation_in_data) - _gpgme_data_append_string (dh, " "); - _gpgme_data_append_percentstring_for_xml (dh, notation); - result->notation_in_data = 1; - return 0; - } - - if (result->notation_in_data) - { - _gpgme_data_append_string (dh, "\n"); - result->notation_in_data = 0; - } - - if (code == GPGME_STATUS_NOTATION_NAME) - { - _gpgme_data_append_string (dh, " "); - _gpgme_data_append_percentstring_for_xml (dh, notation); - _gpgme_data_append_string (dh, "\n"); - } - else if (code == GPGME_STATUS_POLICY_URL) - { - _gpgme_data_append_string (dh, " "); - _gpgme_data_append_percentstring_for_xml (dh, notation); - _gpgme_data_append_string (dh, "\n"); - } - else - assert (0); return 0; } -/* Finish a pending signature info collection. */ -static void -finish_sig (VerifyResult result) +static GpgmeError +parse_valid_sig (GpgmeSignature sig, char *args) { - struct ctx_op_data *op_data; + char *end = strchr (args, ' '); - /* We intimately know that gpgme_op_data_lookup appends the data to - the op_data structure. We can use this here to change the type - knowing only the hook value. */ - op_data = (struct ctx_op_data *) ((void *) result - - sizeof (struct ctx_op_data)); - op_data->type = OPDATA_VERIFY; + if (end) + { + *end = '\0'; + end++; + } + + if (!*args) + /* We require at least the fingerprint. */ + return GPGME_General_Error; + + if (sig->fpr) + free (sig->fpr); + sig->fpr = strdup (args); + if (!sig->fpr) + return GPGME_Out_Of_Core; + + end = strchr (end, ' '); + if (end) + { + char *tail; + errno = 0; + sig->timestamp = strtol (end, &tail, 0); + if (errno || end == tail || (*tail && *tail != ' ')) + return GPGME_General_Error; + end = tail; + + sig->exp_timestamp = strtol (end, &tail, 0); + if (errno || end == tail || (*tail && *tail != ' ')) + return GPGME_General_Error; + } + return 0; +} + + +static GpgmeError +parse_notation (GpgmeSignature sig, GpgmeStatusCode code, char *args) +{ + GpgmeError err; + GpgmeSigNotation *lastp = &sig->notations; + GpgmeSigNotation notation = sig->notations; + char *end = strchr (args, ' '); + + if (end) + *end = '\0'; + + if (code == GPGME_STATUS_NOTATION_NAME || code == GPGME_STATUS_POLICY_URL) + { + /* FIXME: We could keep a pointer to the last notation in the list. */ + while (notation && notation->value) + { + lastp = ¬ation->next; + notation = notation->next; + } + + if (notation) + /* There is another notation name without data for the + previous one. The crypto backend misbehaves. */ + return GPGME_General_Error; + + notation = malloc (sizeof (*sig)); + if (!notation) + return GPGME_Out_Of_Core; + notation->next = NULL; + + if (code == GPGME_STATUS_NOTATION_NAME) + { + int len = strlen (args) + 1; + + notation->name = malloc (len); + if (!notation->name) + { + free (notation); + return GPGME_Out_Of_Core; + } + err = _gpgme_decode_percent_string (args, ¬ation->name, len); + if (err) + return err; + + notation->value = NULL; + } + else + { + int len = strlen (args) + 1; + + notation->name = NULL; + notation->value = malloc (len); + if (!notation->value) + { + free (notation); + return GPGME_Out_Of_Core; + } + err = _gpgme_decode_percent_string (args, ¬ation->value, len); + if (err) + return err; + } + *lastp = notation; + } + else if (code == GPGME_STATUS_NOTATION_DATA) + { + int len = strlen (args) + 1; + char *dest; + + /* FIXME: We could keep a pointer to the last notation in the list. */ + while (notation && notation->next) + { + lastp = ¬ation->next; + notation = notation->next; + } + + if (!notation || !notation->name) + /* There is notation data without a previous notation + name. The crypto backend misbehaves. */ + return GPGME_General_Error; + + if (!notation->value) + { + dest = notation->value = malloc (len); + if (!dest) + return GPGME_Out_Of_Core; + } + else + { + int cur_len = strlen (notation->value); + dest = realloc (notation->value, len + strlen (notation->value)); + if (!dest) + return GPGME_Out_Of_Core; + notation->value = dest; + dest += cur_len; + } + + err = _gpgme_decode_percent_string (args, &dest, len); + if (err) + return err; + } + else + return GPGME_General_Error; + return 0; +} + + +static GpgmeError +parse_trust (GpgmeSignature sig, GpgmeStatusCode code, char *args) +{ + char *end = strchr (args, ' '); + + if (end) + *end = '\0'; + + switch (code) + { + case GPGME_STATUS_TRUST_UNDEFINED: + default: + sig->validity = GPGME_VALIDITY_UNKNOWN; + break; + + case GPGME_STATUS_TRUST_NEVER: + sig->validity = GPGME_VALIDITY_NEVER; + break; + + case GPGME_STATUS_TRUST_MARGINAL: + sig->validity = GPGME_VALIDITY_MARGINAL; + break; + + case GPGME_STATUS_TRUST_FULLY: + case GPGME_STATUS_TRUST_ULTIMATE: + sig->validity = GPGME_VALIDITY_FULL; + break; + } + + if (*args) + sig->validity_reason = _gpgme_map_gnupg_error (args); + + return 0; +} + + +static GpgmeError +parse_error (GpgmeSignature sig, char *args) +{ + GpgmeError err; + char *where = strchr (args, ' '); + char *which; + + if (where) + { + *where = '\0'; + which = where + 1; + + where = strchr (which, ' '); + if (where) + *where = '\0'; + + where = args; + } + else + return GPGME_General_Error; + + err = _gpgme_map_gnupg_error (which); + + if (!strcmp (where, "verify.findkey")) + sig->status = err; + else if (!strcmp (where, "verify.keyusage") && err == GPGME_Wrong_Key_Usage) + sig->wrong_key_usage = 1; + + return 0; } GpgmeError -_gpgme_verify_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args) +_gpgme_verify_status_handler (void *priv, GpgmeStatusCode code, char *args) { - VerifyResult result; + GpgmeCtx ctx = (GpgmeCtx) priv; GpgmeError err; - char *p; - size_t n; - int i; + op_data_t opd; + GpgmeSignature sig; - err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY_COLLECTING, (void **) &result, - -1, NULL); + err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, (void **) &opd, -1, NULL); if (err) return err; - if (code == GPGME_STATUS_GOODSIG || code == GPGME_STATUS_EXPSIG - || code == GPGME_STATUS_EXPKEYSIG || code == GPGME_STATUS_BADSIG - || code == GPGME_STATUS_ERRSIG) - { - /* A new signature starts. */ - if (result) - finish_sig (result); - err = _gpgme_op_data_lookup (ctx, OPDATA_VERIFY_COLLECTING, (void **) &result, - sizeof (*result), release_verify_result); - if (err) - return err; - } + sig = opd->current_sig; switch (code) { - case GPGME_STATUS_NODATA: - case GPGME_STATUS_UNEXPECTED: - if (!result) - return GPGME_General_Error; - result->status = GPGME_SIG_STAT_NOSIG; - break; - case GPGME_STATUS_GOODSIG: - if (!result) - return GPGME_General_Error; - result->expstatus = GPGME_SIG_STAT_GOOD; - break; - case GPGME_STATUS_EXPSIG: - if (!result) - return GPGME_General_Error; - result->expstatus = GPGME_SIG_STAT_GOOD_EXP; - break; - case GPGME_STATUS_EXPKEYSIG: - if (!result) - return GPGME_General_Error; - result->expstatus = GPGME_SIG_STAT_GOOD_EXPKEY; - break; + case GPGME_STATUS_BADSIG: + case GPGME_STATUS_ERRSIG: + if (sig) + calc_sig_summary (sig); + return parse_new_sig (opd, code, args); case GPGME_STATUS_VALIDSIG: - if (!result) - return GPGME_General_Error; - result->status = GPGME_SIG_STAT_GOOD; - i = copy_token (args, result->fpr, DIM (result->fpr)); - /* Skip the formatted date. */ - while (args[i] && args[i] == ' ') - i++; - while (args[i] && args[i] != ' ') - i++; - /* And get the timestamp. */ - result->timestamp = strtoul (args + i, &p, 10); - if (args[i]) - result->exptimestamp = strtoul (p, NULL, 10); - break; + return sig ? parse_valid_sig (sig, args) : GPGME_General_Error; - case GPGME_STATUS_BADSIG: - if (!result) + case GPGME_STATUS_NODATA: + case GPGME_STATUS_UNEXPECTED: + if (!sig) return GPGME_General_Error; - result->status = GPGME_SIG_STAT_BAD; - /* Store the keyID in the fpr field. */ - copy_token (args, result->fpr, DIM (result->fpr)); - break; - - case GPGME_STATUS_ERRSIG: - if (!result) - return GPGME_General_Error; - /* The return code is the 6th argument, if it is 9, the problem - is a missing key. Note that this is not emitted by gpgsm */ - for (p = args, i = 0; p && *p && i < 5; i++) - { - p = strchr (p, ' '); - if (p) - while (*p == ' ') - p++; - } - if (p && *(p++) == '9' && (*p == '\0' || *p == ' ')) - result->status = GPGME_SIG_STAT_NOKEY; - else - result->status = GPGME_SIG_STAT_ERROR; - /* Store the keyID in the fpr field. */ - copy_token (args, result->fpr, DIM (result->fpr)); + sig->status = GPGME_No_Data; break; case GPGME_STATUS_NOTATION_NAME: case GPGME_STATUS_NOTATION_DATA: case GPGME_STATUS_POLICY_URL: - if (!result) - return GPGME_General_Error; - err = add_notation (result, code, args); - if (err) - return err; - break; + return sig ? parse_notation (sig, code, args) : GPGME_General_Error; case GPGME_STATUS_TRUST_UNDEFINED: - if (!result) - return GPGME_General_Error; - result->validity = GPGME_VALIDITY_UNKNOWN; - copy_token (args, result->trust_errtok, - DIM(result->trust_errtok)); - break; case GPGME_STATUS_TRUST_NEVER: - if (!result) - return GPGME_General_Error; - result->validity = GPGME_VALIDITY_NEVER; - copy_token (args, result->trust_errtok, - DIM(result->trust_errtok)); - break; case GPGME_STATUS_TRUST_MARGINAL: - if (!result) - return GPGME_General_Error; - if (result->status == GPGME_SIG_STAT_GOOD) - result->validity = GPGME_VALIDITY_MARGINAL; - copy_token (args, result->trust_errtok, - DIM(result->trust_errtok)); - break; case GPGME_STATUS_TRUST_FULLY: case GPGME_STATUS_TRUST_ULTIMATE: - if (!result) - return GPGME_General_Error; - if (result->status == GPGME_SIG_STAT_GOOD) - result->validity = GPGME_VALIDITY_FULL; - break; - - case GPGME_STATUS_END_STREAM: - break; + return sig ? parse_trust (sig, code, args) : GPGME_General_Error; case GPGME_STATUS_ERROR: - if (!result) - return GPGME_General_Error; - /* Generic error, we need this for gpgsm (and maybe for gpg in future) - to get error descriptions. */ - if (is_token (args, "verify.findkey", &n) && n) - { - args += n; - if (is_token (args, "No_Public_Key", NULL)) - result->status = GPGME_SIG_STAT_NOKEY; - else - result->status = GPGME_SIG_STAT_ERROR; - - } - else if (skip_token (args, &n) && n) - { - args += n; - if (is_token (args, "Wrong_Key_Usage", NULL)) - result->wrong_key_usage = 1; - } - break; + return sig ? parse_error (sig, args) : GPGME_General_Error; case GPGME_STATUS_EOF: - if (result) - { - finish_sig (result); - - /* FIXME: Put all notation data into one XML fragment. */ - if (result->notation) - { - GpgmeData dh = result->notation; - - if (result->notation_in_data) - { - _gpgme_data_append_string (dh, "\n"); - result->notation_in_data = 0; - } - _gpgme_data_append_string (dh, "\n"); - ctx->notation = dh; - result->notation = NULL; - } - } + if (sig) + calc_sig_summary (sig); break; - + default: - /* Ignore all other codes. */ break; } return 0; } +GpgmeError +_gpgme_op_verify_init_result (GpgmeCtx ctx) +{ + op_data_t opd; + + return _gpgme_op_data_lookup (ctx, OPDATA_VERIFY, (void **) &opd, + sizeof (*opd), release_op_data); +} + + static GpgmeError -_gpgme_op_verify_start (GpgmeCtx ctx, int synchronous, - GpgmeData sig, GpgmeData signed_text, GpgmeData plaintext) +_gpgme_op_verify_start (GpgmeCtx ctx, int synchronous, GpgmeData sig, + GpgmeData signed_text, GpgmeData plaintext) { - int err = 0; + GpgmeError err; err = _gpgme_op_reset (ctx, synchronous); if (err) - goto leave; + return err; + + err = _gpgme_op_verify_init_result (ctx); + if (err) + return err; _gpgme_engine_set_status_handler (ctx->engine, _gpgme_verify_status_handler, ctx); - /* Check the supplied data. */ if (!sig) - { - err = GPGME_No_Data; - goto leave; - } + return GPGME_No_Data; if (!signed_text && !plaintext) - { - err = GPGME_Invalid_Value; - goto leave; - } - err = _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext); + return GPGME_Invalid_Value; - leave: - if (err) - { - _gpgme_engine_release (ctx->engine); - ctx->engine = NULL; - } - return err; + return _gpgme_engine_op_verify (ctx->engine, sig, signed_text, plaintext); } +/* Decrypt ciphertext CIPHER and make a signature verification within + CTX and store the resulting plaintext in PLAIN. */ GpgmeError gpgme_op_verify_start (GpgmeCtx ctx, GpgmeData sig, GpgmeData signed_text, GpgmeData plaintext) @@ -414,226 +543,166 @@ gpgme_op_verify_start (GpgmeCtx ctx, GpgmeData sig, GpgmeData signed_text, } -/** - * gpgme_op_verify: - * @c: the context - * @sig: the signature data - * @text: the signed text - * - * Perform a signature check on the signature given in @sig. If @text - * is a new and uninitialized data object, it is assumed that @sig - * contains a normal or cleartext signature, and the plaintext is - * returned in @text upon successful verification. - * - * If @text is initialized, it is assumed that @sig is a detached - * signature for the material given in @text. - * - * Return value: 0 on success or an errorcode if something not related to - * the signature itself did go wrong. - **/ +/* Decrypt ciphertext CIPHER and make a signature verification within + CTX and store the resulting plaintext in PLAIN. */ GpgmeError gpgme_op_verify (GpgmeCtx ctx, GpgmeData sig, GpgmeData signed_text, GpgmeData plaintext) { GpgmeError err; - gpgme_data_release (ctx->notation); - ctx->notation = NULL; - err = _gpgme_op_verify_start (ctx, 1, sig, signed_text, plaintext); if (!err) err = _gpgme_wait_one (ctx); return err; } + +/* Compatibility interfaces. */ -/** - * gpgme_get_sig_status: - * @c: Context - * @idx: Index of the signature starting at 0 - * @r_stat: Returns the status - * @r_created: Returns the creation timestamp - * - * Return information about an already verified signatures. - * - * The result of this operation is returned in @r_stat which can take these - * values: - * GPGME_SIG_STAT_NONE: No status - should not happen - * GPGME_SIG_STAT_GOOD: The signature is valid - * GPGME_SIG_STAT_BAD: The signature is not valid - * GPGME_SIG_STAT_NOKEY: The signature could not be checked due to a - * missing key - * GPGME_SIG_STAT_NOSIG: This is not a signature - * GPGME_SIG_STAT_ERROR: Due to some other error the check could not be done. - * GPGME_SIG_STAT_DIFF: There is more than 1 signature and they have not - * the same status. - * GPGME_SIG_STAT_GOOD_EXP: The signature is good but has expired. - * GPGME_SIG_STAT_GOOD_KEYEXP: The signature is good but the key has expired. - * - * - * Return value: The fingerprint or NULL in case of an problem or - * when there are no more signatures. - **/ -const char * -gpgme_get_sig_status (GpgmeCtx ctx, int idx, - GpgmeSigStat *r_stat, time_t *r_created) +/* Get the key used to create signature IDX in CTX and return it in + R_KEY. */ +GpgmeError +gpgme_get_sig_key (GpgmeCtx ctx, int idx, GpgmeKey *r_key) { - struct ctx_op_data *op_data; - VerifyResult result; + GpgmeVerifyResult result; + GpgmeSignature sig; - if (!ctx) - return NULL; /* No results yet or verification error. */ + result = gpgme_op_verify_result (ctx); + sig = result->signatures; - op_data = ctx->op_data; - while (op_data) + while (sig && idx) { - while (op_data && op_data->type != OPDATA_VERIFY) - op_data = op_data->next; - if (idx-- == 0) - break; - op_data = op_data->next; + sig = sig->next; + idx--; } - if (!op_data) - return NULL; /* No more signatures. */ + if (!sig || idx) + return GPGME_EOF; + + return gpgme_get_key (ctx, sig->fpr, r_key, 0, 0); +} + + +/* Retrieve the signature status of signature IDX in CTX after a + successful verify operation in R_STAT (if non-null). The creation + time stamp of the signature is returned in R_CREATED (if non-null). + The function returns a string containing the fingerprint. */ +const char *gpgme_get_sig_status (GpgmeCtx ctx, int idx, + GpgmeSigStat *r_stat, time_t *r_created) +{ + GpgmeVerifyResult result; + GpgmeSignature sig; + + result = gpgme_op_verify_result (ctx); + sig = result->signatures; + + while (sig && idx) + { + sig = sig->next; + idx--; + } + if (!sig || idx) + return NULL; - result = (VerifyResult) op_data->hook; if (r_stat) - *r_stat = result->status; + { + switch (sig->status) + { + case GPGME_No_Error: + *r_stat = GPGME_SIG_STAT_GOOD; + break; + + case GPGME_Bad_Signature: + *r_stat = GPGME_SIG_STAT_BAD; + break; + + case GPGME_No_Public_Key: + *r_stat = GPGME_SIG_STAT_NOKEY; + break; + + case GPGME_No_Data: + *r_stat = GPGME_SIG_STAT_NOSIG; + break; + + case GPGME_Sig_Expired: + *r_stat = GPGME_SIG_STAT_GOOD_EXP; + break; + + case GPGME_Key_Expired: + *r_stat = GPGME_SIG_STAT_GOOD_EXPKEY; + break; + + default: + *r_stat = GPGME_SIG_STAT_ERROR; + break; + } + } if (r_created) - *r_created = result->timestamp; - return result->fpr; + *r_created = sig->timestamp; + return sig->fpr; } -/* Build a summary vector from RESULT. */ -static unsigned long -calc_sig_summary (VerifyResult result) +/* Retrieve certain attributes of a signature. IDX is the index + number of the signature after a successful verify operation. WHAT + is an attribute where GPGME_ATTR_EXPIRE is probably the most useful + one. WHATIDX is to be passed as 0 for most attributes . */ +unsigned long gpgme_get_sig_ulong_attr (GpgmeCtx ctx, int idx, + GpgmeAttr what, int whatidx) { - unsigned long sum = 0; + GpgmeVerifyResult result; + GpgmeSignature sig; - if (result->validity == GPGME_VALIDITY_FULL - || result->validity == GPGME_VALIDITY_ULTIMATE) + result = gpgme_op_verify_result (ctx); + sig = result->signatures; + + while (sig && idx) { - if (result->status == GPGME_SIG_STAT_GOOD - || result->status == GPGME_SIG_STAT_GOOD_EXP - || result->status == GPGME_SIG_STAT_GOOD_EXPKEY) - sum |= GPGME_SIGSUM_GREEN; + sig = sig->next; + idx--; } - else if (result->validity == GPGME_VALIDITY_NEVER) - { - if (result->status == GPGME_SIG_STAT_GOOD - || result->status == GPGME_SIG_STAT_GOOD_EXP - || result->status == GPGME_SIG_STAT_GOOD_EXPKEY) - sum |= GPGME_SIGSUM_RED; - } - else if (result->status == GPGME_SIG_STAT_BAD) - sum |= GPGME_SIGSUM_RED; + if (!sig || idx) + return 0; - /* fixme: handle the case when key and message are expired. */ - if (result->status == GPGME_SIG_STAT_GOOD_EXP) - sum |= GPGME_SIGSUM_SIG_EXPIRED; - else if (result->status == GPGME_SIG_STAT_GOOD_EXPKEY) - sum |= GPGME_SIGSUM_KEY_EXPIRED; - else if (result->status == GPGME_SIG_STAT_NOKEY) - sum |= GPGME_SIGSUM_KEY_MISSING; - else if (result->status == GPGME_SIG_STAT_ERROR) - sum |= GPGME_SIGSUM_SYS_ERROR; - - if ( !strcmp (result->trust_errtok, "Certificate_Revoked")) - sum |= GPGME_SIGSUM_KEY_REVOKED; - else if ( !strcmp (result->trust_errtok, "No_CRL_Known")) - sum |= GPGME_SIGSUM_CRL_MISSING; - else if ( !strcmp (result->trust_errtok, "CRL_Too_Old")) - sum |= GPGME_SIGSUM_CRL_TOO_OLD; - else if ( !strcmp (result->trust_errtok, "No_Policy_Match")) - sum |= GPGME_SIGSUM_BAD_POLICY; - else if (*result->trust_errtok) - sum |= GPGME_SIGSUM_SYS_ERROR; - - if (result->wrong_key_usage) - sum |= GPGME_SIGSUM_BAD_POLICY; - - /* Set the valid flag when the signature is unquestionable - valid. */ - if ((sum & GPGME_SIGSUM_GREEN) && !(sum & ~GPGME_SIGSUM_GREEN)) - sum |= GPGME_SIGSUM_VALID; - - return sum; -} - - -const char * -gpgme_get_sig_string_attr (GpgmeCtx ctx, int idx, GpgmeAttr what, int whatidx) -{ - struct ctx_op_data *op_data; - VerifyResult result; - - if (!ctx) - return NULL; /* No results yet or verification error. */ - - op_data = ctx->op_data; - while (op_data) - { - while (op_data && op_data->type != OPDATA_VERIFY) - op_data = op_data->next; - if (idx-- == 0) - break; - op_data = op_data->next; - } - if (!op_data) - return NULL; /* No more signatures. */ - - result = (VerifyResult) op_data->hook; - switch (what) - { - case GPGME_ATTR_FPR: - return result->fpr; - case GPGME_ATTR_ERRTOK: - if (whatidx == 1) - return result->wrong_key_usage? "Wrong_Key_Usage":""; - else - return result->trust_errtok; - default: - break; - } - return NULL; -} - - -unsigned long -gpgme_get_sig_ulong_attr (GpgmeCtx ctx, int idx, GpgmeAttr what, int reserved) -{ - struct ctx_op_data *op_data; - VerifyResult result; - - if (!ctx) - return 0; /* No results yet or verification error. */ - - op_data = ctx->op_data; - while (op_data) - { - while (op_data && op_data->type != OPDATA_VERIFY) - op_data = op_data->next; - if (idx-- == 0) - break; - op_data = op_data->next; - } - if (!op_data) - return 0; /* No more signatures. */ - - result = (VerifyResult) op_data->hook; switch (what) { case GPGME_ATTR_CREATED: - return result->timestamp; + return sig->timestamp; + case GPGME_ATTR_EXPIRE: - return result->exptimestamp; + return sig->exp_timestamp; + case GPGME_ATTR_VALIDITY: - return (unsigned long) result->validity; + return (unsigned long) sig->validity; + case GPGME_ATTR_SIG_STATUS: - return (unsigned long) result->status; + switch (sig->status) + { + case GPGME_No_Error: + return GPGME_SIG_STAT_GOOD; + + case GPGME_Bad_Signature: + return GPGME_SIG_STAT_BAD; + + case GPGME_No_Public_Key: + return GPGME_SIG_STAT_NOKEY; + + case GPGME_No_Data: + return GPGME_SIG_STAT_NOSIG; + + case GPGME_Sig_Expired: + return GPGME_SIG_STAT_GOOD_EXP; + + case GPGME_Key_Expired: + return GPGME_SIG_STAT_GOOD_EXPKEY; + + default: + return GPGME_SIG_STAT_ERROR; + } + case GPGME_ATTR_SIG_SUMMARY: - return calc_sig_summary (result); + return sig->summary; + default: break; } @@ -641,39 +710,36 @@ gpgme_get_sig_ulong_attr (GpgmeCtx ctx, int idx, GpgmeAttr what, int reserved) } -/** - * gpgme_get_sig_key: - * @c: context - * @idx: Index of the signature starting at 0 - * @r_key: Returns the key object - * - * Return a key object which was used to check the signature. - * - * Return value: An Errorcode or 0 for success. GPGME_EOF is returned to - * indicate that there are no more signatures. - **/ -GpgmeError -gpgme_get_sig_key (GpgmeCtx ctx, int idx, GpgmeKey *r_key) +const char *gpgme_get_sig_string_attr (GpgmeCtx ctx, int idx, + GpgmeAttr what, int whatidx) { - struct ctx_op_data *op_data; - VerifyResult result; + GpgmeVerifyResult result; + GpgmeSignature sig; - if (!ctx || !r_key) - return GPGME_Invalid_Value; + result = gpgme_op_verify_result (ctx); + sig = result->signatures; - op_data = ctx->op_data; - while (op_data) + while (sig && idx) { - while (op_data && op_data->type != OPDATA_VERIFY) - op_data = op_data->next; - if (idx-- == 0) - break; - op_data = op_data->next; + sig = sig->next; + idx--; } - if (!op_data) - return GPGME_EOF; + if (!sig || idx) + return NULL; - result = (VerifyResult) op_data->hook; + switch (what) + { + case GPGME_ATTR_FPR: + return sig->fpr; - return gpgme_get_key (ctx, result->fpr, r_key, 0, 0); + case GPGME_ATTR_ERRTOK: + if (whatidx == 1) + return sig->wrong_key_usage ? "Wrong_Key_Usage" : ""; + else + return ""; + default: + break; + } + + return NULL; } diff --git a/tests/gpg/t-verify.c b/tests/gpg/t-verify.c index 1dcca5db..7b5bc36e 100644 --- a/tests/gpg/t-verify.c +++ b/tests/gpg/t-verify.c @@ -112,6 +112,7 @@ status_string (GpgmeSigStat status) return s; } + static const char * validity_string (GpgmeValidity val) { @@ -132,138 +133,181 @@ validity_string (GpgmeValidity val) static void -print_sig_stat ( GpgmeCtx ctx, GpgmeSigStat status ) +print_sig_stat (GpgmeCtx ctx, GpgmeSigStat status) { - const char *s; - time_t created; - int idx; - GpgmeKey key; + const char *s; + time_t created; + int idx; + GpgmeKey key; - printf ("Verification Status: %s\n", status_string (status)); + printf ("Verification Status: %s\n", status_string (status)); - for(idx=0; (s=gpgme_get_sig_status (ctx, idx, &status, &created)); idx++ ) { - printf ("sig %d: created: %lu expires: %lu status: %s\n", - idx, (unsigned long)created, - gpgme_get_sig_ulong_attr (ctx, idx, GPGME_ATTR_EXPIRE, 0), - status_string(status) ); - printf ("sig %d: fpr/keyid: `%s' validity: %s\n", - idx, s, - validity_string (gpgme_get_sig_ulong_attr - (ctx, idx, GPGME_ATTR_VALIDITY, 0)) ); - if ( !gpgme_get_sig_key (ctx, idx, &key) ) { - char *p = gpgme_key_get_as_xml ( key ); - printf ("sig %d: key object:\n%s\n", idx, p ); - free (p); - gpgme_key_release (key); + for (idx = 0; (s = gpgme_get_sig_status (ctx, idx, &status, &created)); idx++) + { + printf ("sig %d: created: %lu expires: %lu status: %s\n", + idx, (unsigned long) created, + gpgme_get_sig_ulong_attr (ctx, idx, GPGME_ATTR_EXPIRE, 0), + status_string (status)); + printf ("sig %d: fpr/keyid: `%s' validity: %s\n", + idx, s, + validity_string (gpgme_get_sig_ulong_attr + (ctx, idx, GPGME_ATTR_VALIDITY, 0))); + if (!gpgme_get_sig_key (ctx, idx, &key)) + { + char *p = gpgme_key_get_as_xml (key); + printf ("sig %d: key object:\n%s\n", idx, p); + free (p); + gpgme_key_release (key); } } } int -main (int argc, char **argv ) +main (int argc, char *argv[]) { - GpgmeCtx ctx; - GpgmeError err; - GpgmeData sig, text; - GpgmeSigStat status; - char *nota; - int n = 0; - size_t len; - int j; + GpgmeCtx ctx; + GpgmeError err; + GpgmeData sig, text; + GpgmeSigStat status; + GpgmeVerifyResult result; + GpgmeSigNotation notation; + char *nota; + int n = 0; + size_t len; + int j; - err = gpgme_new (&ctx); - fail_if_err (err); + err = gpgme_new (&ctx); + fail_if_err (err); - do { - err = gpgme_data_new_from_mem ( &text, - test_text1, strlen (test_text1), 0 ); - fail_if_err (err); - #if 1 - err = gpgme_data_new_from_mem ( &sig, - test_sig1, strlen (test_sig1), 0 ); - #else - err = gpgme_data_new_from_file ( &sig, "xx1", 1 ); - #endif - fail_if_err (err); + do + { + err = gpgme_data_new_from_mem (&text, + test_text1, strlen (test_text1), 0); + fail_if_err (err); +#if 1 + err = gpgme_data_new_from_mem (&sig, + test_sig1, strlen (test_sig1), 0); +#else + err = gpgme_data_new_from_file (&sig, "xx1", 1); +#endif + fail_if_err (err); - puts ("checking a valid message:\n"); - err = gpgme_op_verify (ctx, sig, text, NULL); - fail_if_err (err); - if (!gpgme_get_sig_status (ctx, 0, &status, NULL)) - { - fprintf (stderr, "%s:%d: No signature\n", __FILE__, __LINE__); - exit (1); - } - print_sig_stat (ctx, status); - if (status != GPGME_SIG_STAT_GOOD) - { - fprintf (stderr, "%s:%d: Wrong sig stat\n", __FILE__, __LINE__); - exit (1); - } + puts ("checking a valid message:\n"); + err = gpgme_op_verify (ctx, sig, text, NULL); + fail_if_err (err); + if (!gpgme_get_sig_status (ctx, 0, &status, NULL)) + { + fprintf (stderr, "%s:%d: No signature\n", __FILE__, __LINE__); + exit (1); + } + print_sig_stat (ctx, status); + if (status != GPGME_SIG_STAT_GOOD) + { + fprintf (stderr, "%s:%d: Wrong sig stat\n", __FILE__, __LINE__); + exit (1); + } - if ((nota = gpgme_get_notation (ctx))) - printf ("---Begin Notation---\n%s---End Notation---\n", nota ); - - puts ("checking a manipulated message:\n"); - gpgme_data_release (text); - err = gpgme_data_new_from_mem (&text, - test_text1f, strlen (test_text1f), 0); - fail_if_err (err); - gpgme_data_rewind (sig); - err = gpgme_op_verify (ctx, sig, text, NULL); - fail_if_err (err); - if (!gpgme_get_sig_status (ctx, 0, &status, NULL)) - { - fprintf (stderr, "%s:%d: No signature\n", __FILE__, __LINE__); - exit (1); - } - print_sig_stat (ctx, status); - if (status != GPGME_SIG_STAT_BAD) - { - fprintf (stderr, "%s:%d: Wrong sig stat\n", __FILE__, __LINE__); - exit (1); - } - if ((nota = gpgme_get_notation (ctx))) - printf ("---Begin Notation---\n%s---End Notation---\n", nota ); - - puts ("checking a normal signature:"); - gpgme_data_release (sig); - gpgme_data_release (text); - err = gpgme_data_new_from_mem (&sig, test_sig2, strlen (test_sig2), 0); - fail_if_err (err); - err = gpgme_data_new (&text); - fail_if_err (err); - err = gpgme_op_verify (ctx, sig, NULL, text); - fail_if_err (err); - if (!gpgme_get_sig_status (ctx, 0, &status, NULL)) - { - fprintf (stderr, "%s:%d: No signature\n", __FILE__, __LINE__); - exit (1); - } - - nota = gpgme_data_release_and_get_mem (text, &len); - for (j = 0; j < len; j++) + result = gpgme_op_verify_result (ctx); + notation = result->signatures->notations; + if (notation) + { + printf ("---Begin Notation---\n"); + while (notation) + { + if (notation->name) + printf ("%s: %s\n", notation->name, notation->value); + else + printf ("Policy URL: %s\n", notation->value); + notation = notation->next; + } + printf ("---End Notation---\n"); + } + + puts ("checking a manipulated message:\n"); + gpgme_data_release (text); + err = gpgme_data_new_from_mem (&text, + test_text1f, strlen (test_text1f), 0); + fail_if_err (err); + gpgme_data_rewind (sig); + err = gpgme_op_verify (ctx, sig, text, NULL); + fail_if_err (err); + if (!gpgme_get_sig_status (ctx, 0, &status, NULL)) + { + fprintf (stderr, "%s:%d: No signature\n", __FILE__, __LINE__); + exit (1); + } + print_sig_stat (ctx, status); + if (status != GPGME_SIG_STAT_BAD) + { + fprintf (stderr, "%s:%d: Wrong sig stat\n", __FILE__, __LINE__); + exit (1); + } + result = gpgme_op_verify_result (ctx); + notation = result->signatures->notations; + if (notation) + { + printf ("---Begin Notation---\n"); + while (notation) + { + if (notation->name) + printf ("%s: %s\n", notation->name, notation->value); + else + printf ("Policy URL: %s\n", notation->value); + notation = notation->next; + } + printf ("---End Notation---\n"); + } + + puts ("checking a normal signature:"); + gpgme_data_release (sig); + gpgme_data_release (text); + err = gpgme_data_new_from_mem (&sig, test_sig2, strlen (test_sig2), 0); + fail_if_err (err); + err = gpgme_data_new (&text); + fail_if_err (err); + err = gpgme_op_verify (ctx, sig, NULL, text); + fail_if_err (err); + if (!gpgme_get_sig_status (ctx, 0, &status, NULL)) + { + fprintf (stderr, "%s:%d: No signature\n", __FILE__, __LINE__); + exit (1); + } + + nota = gpgme_data_release_and_get_mem (text, &len); + for (j = 0; j < len; j++) putchar (nota[j]); - if (strncmp (nota, test_text1, strlen (test_text1))) - { - fprintf (stderr, "%s:%d: Wrong plaintext\n", __FILE__, __LINE__); - exit (1); - } - - print_sig_stat (ctx, status); - if (status != GPGME_SIG_STAT_GOOD) - { - fprintf (stderr, "%s:%d: Wrong sig stat\n", __FILE__, __LINE__); - exit (1); - } + if (strncmp (nota, test_text1, strlen (test_text1))) + { + fprintf (stderr, "%s:%d: Wrong plaintext\n", __FILE__, __LINE__); + exit (1); + } + + print_sig_stat (ctx, status); + if (status != GPGME_SIG_STAT_GOOD) + { + fprintf (stderr, "%s:%d: Wrong sig stat\n", __FILE__, __LINE__); + exit (1); + } + result = gpgme_op_verify_result (ctx); + notation = result->signatures->notations; + if (notation) + { + printf ("---Begin Notation---\n"); + while (notation) + { + if (notation->name) + printf ("%s: %s\n", notation->name, notation->value); + else + printf ("Policy URL: %s\n", notation->value); + notation = notation->next; + } + printf ("---End Notation---\n"); + } + + gpgme_data_release (sig); + } + while (argc > 1 && !strcmp (argv[1], "--loop") && ++n < 20); - if ((nota = gpgme_get_notation (ctx))) - printf ("---Begin Notation---\n%s---End Notation---\n", nota); - - gpgme_data_release (sig); - -} while ( argc > 1 && !strcmp( argv[1], "--loop" ) && ++n < 20 ); - gpgme_release (ctx); - - return 0; + gpgme_release (ctx); + return 0; } diff --git a/tests/gpgsm/t-verify.c b/tests/gpgsm/t-verify.c index 0a48b3cb..282cf2b8 100644 --- a/tests/gpgsm/t-verify.c +++ b/tests/gpgsm/t-verify.c @@ -169,6 +169,8 @@ main (int argc, char **argv ) GpgmeError err; GpgmeData sig, text; GpgmeSigStat status; + GpgmeVerifyResult result; + GpgmeSigNotation notation; char *nota; int n = 0; @@ -194,8 +196,21 @@ main (int argc, char **argv ) } print_sig_stat (ctx, status); - if ( (nota=gpgme_get_notation (ctx)) ) - printf ("---Begin Notation---\n%s---End Notation---\n", nota); + result = gpgme_op_verify_result (ctx); + notation = result->signatures->notations; + if (notation) + { + printf ("---Begin Notation---\n"); + while (notation) + { + if (notation->name) + printf ("%s: %s\n", notation->name, notation->value); + else + printf ("Policy URL: %s\n", notation->value); + notation = notation->next; + } + printf ("---End Notation---\n"); + } puts ("checking a manipulated message:\n"); gpgme_data_release (text); @@ -212,8 +227,21 @@ main (int argc, char **argv ) } print_sig_stat (ctx, status); - if ((nota=gpgme_get_notation (ctx))) - printf ("---Begin Notation---\n%s---End Notation---\n", nota); + result = gpgme_op_verify_result (ctx); + notation = result->signatures->notations; + if (notation) + { + printf ("---Begin Notation---\n"); + while (notation) + { + if (notation->name) + printf ("%s: %s\n", notation->name, notation->value); + else + printf ("Policy URL: %s\n", notation->value); + notation = notation->next; + } + printf ("---End Notation---\n"); + } gpgme_data_release (sig); gpgme_data_release (text);