Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F18825888
verify.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
25 KB
Subscribers
None
verify.c
View Options
/* verify.c - Signature verification.
Copyright (C) 2000 Werner Koch (dd9jn)
Copyright (C) 2001, 2002, 2003, 2004, 2005 g10 Code GmbH
This file is part of GPGME.
GPGME is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.
GPGME is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#if HAVE_CONFIG_H
#include
<config.h>
#endif
#include
<stdlib.h>
#include
<string.h>
#include
<errno.h>
#include
<assert.h>
#include
"gpgme.h"
#include
"debug.h"
#include
"util.h"
#include
"context.h"
#include
"ops.h"
typedef
struct
{
struct
_gpgme_op_verify_result
result
;
gpgme_signature_t
current_sig
;
int
did_prepare_new_sig
;
int
only_newsig_seen
;
int
plaintext_seen
;
}
*
op_data_t
;
static
void
release_op_data
(
void
*
hook
)
{
op_data_t
opd
=
(
op_data_t
)
hook
;
gpgme_signature_t
sig
=
opd
->
result
.
signatures
;
while
(
sig
)
{
gpgme_signature_t
next
=
sig
->
next
;
gpgme_sig_notation_t
notation
=
sig
->
notations
;
while
(
notation
)
{
gpgme_sig_notation_t
next_nota
=
notation
->
next
;
_gpgme_sig_notation_free
(
notation
);
notation
=
next_nota
;
}
if
(
sig
->
fpr
)
free
(
sig
->
fpr
);
if
(
sig
->
pka_address
)
free
(
sig
->
pka_address
);
free
(
sig
);
sig
=
next
;
}
if
(
opd
->
result
.
file_name
)
free
(
opd
->
result
.
file_name
);
}
gpgme_verify_result_t
gpgme_op_verify_result
(
gpgme_ctx_t
ctx
)
{
void
*
hook
;
op_data_t
opd
;
gpgme_error_t
err
;
gpgme_signature_t
sig
;
TRACE_BEG
(
DEBUG_CTX
,
"gpgme_op_verify_result"
,
ctx
);
err
=
_gpgme_op_data_lookup
(
ctx
,
OPDATA_VERIFY
,
&
hook
,
-1
,
NULL
);
opd
=
hook
;
if
(
err
||
!
opd
)
{
TRACE_SUC0
(
"result=(null)"
);
return
NULL
;
}
/* It is possible that we saw a new signature only followed by an
ERROR line for that. In particular a missing X.509 key triggers
this. In this case it is surprising that the summary field has
not been updated. We fix it here by explicitly looking for this
case. The real fix would be to have GPGME emit ERRSIG. */
for
(
sig
=
opd
->
result
.
signatures
;
sig
;
sig
=
sig
->
next
)
{
if
(
!
sig
->
summary
)
{
switch
(
gpg_err_code
(
sig
->
status
))
{
case
GPG_ERR_KEY_EXPIRED
:
sig
->
summary
|=
GPGME_SIGSUM_KEY_EXPIRED
;
break
;
case
GPG_ERR_NO_PUBKEY
:
sig
->
summary
|=
GPGME_SIGSUM_KEY_MISSING
;
break
;
default
:
break
;
}
}
}
/* Now for some tracing stuff. */
if
(
_gpgme_debug_trace
())
{
int
i
;
for
(
sig
=
opd
->
result
.
signatures
,
i
=
0
;
sig
;
sig
=
sig
->
next
,
i
++
)
{
TRACE_LOG4
(
"sig[%i] = fpr %s, summary 0x%x, status %s"
,
i
,
sig
->
fpr
,
sig
->
summary
,
gpg_strerror
(
sig
->
status
));
TRACE_LOG6
(
"sig[%i] = timestamps 0x%x/0x%x flags:%s%s%s"
,
i
,
sig
->
timestamp
,
sig
->
exp_timestamp
,
sig
->
wrong_key_usage
?
"wrong key usage"
:
""
,
sig
->
pka_trust
==
1
?
"pka bad"
:
(
sig
->
pka_trust
==
2
?
"pka_okay"
:
"pka RFU"
),
sig
->
chain_model
?
"chain model"
:
""
);
TRACE_LOG5
(
"sig[%i] = validity 0x%x (%s), algos %s/%s"
,
i
,
sig
->
validity
,
gpg_strerror
(
sig
->
validity_reason
),
gpgme_pubkey_algo_name
(
sig
->
pubkey_algo
),
gpgme_hash_algo_name
(
sig
->
hash_algo
));
if
(
sig
->
pka_address
)
{
TRACE_LOG2
(
"sig[%i] = PKA address %s"
,
i
,
sig
->
pka_address
);
}
if
(
sig
->
notations
)
{
TRACE_LOG1
(
"sig[%i] = has notations (not shown)"
,
i
);
}
}
}
TRACE_SUC1
(
"result=%p"
,
&
opd
->
result
);
return
&
opd
->
result
;
}
/* Build a summary vector from RESULT. */
static
void
calc_sig_summary
(
gpgme_signature_t
sig
)
{
unsigned
long
sum
=
0
;
/* Calculate the red/green flag. */
if
(
sig
->
validity
==
GPGME_VALIDITY_FULL
||
sig
->
validity
==
GPGME_VALIDITY_ULTIMATE
)
{
if
(
gpg_err_code
(
sig
->
status
)
==
GPG_ERR_NO_ERROR
||
gpg_err_code
(
sig
->
status
)
==
GPG_ERR_SIG_EXPIRED
||
gpg_err_code
(
sig
->
status
)
==
GPG_ERR_KEY_EXPIRED
)
sum
|=
GPGME_SIGSUM_GREEN
;
}
else
if
(
sig
->
validity
==
GPGME_VALIDITY_NEVER
)
{
if
(
gpg_err_code
(
sig
->
status
)
==
GPG_ERR_NO_ERROR
||
gpg_err_code
(
sig
->
status
)
==
GPG_ERR_SIG_EXPIRED
||
gpg_err_code
(
sig
->
status
)
==
GPG_ERR_KEY_EXPIRED
)
sum
|=
GPGME_SIGSUM_RED
;
}
else
if
(
gpg_err_code
(
sig
->
status
)
==
GPG_ERR_BAD_SIGNATURE
)
sum
|=
GPGME_SIGSUM_RED
;
/* FIXME: handle the case when key and message are expired. */
switch
(
gpg_err_code
(
sig
->
status
))
{
case
GPG_ERR_SIG_EXPIRED
:
sum
|=
GPGME_SIGSUM_SIG_EXPIRED
;
break
;
case
GPG_ERR_KEY_EXPIRED
:
sum
|=
GPGME_SIGSUM_KEY_EXPIRED
;
break
;
case
GPG_ERR_NO_PUBKEY
:
sum
|=
GPGME_SIGSUM_KEY_MISSING
;
break
;
case
GPG_ERR_BAD_SIGNATURE
:
case
GPG_ERR_NO_ERROR
:
break
;
default
:
sum
|=
GPGME_SIGSUM_SYS_ERROR
;
break
;
}
/* Now look at the certain reason codes. */
switch
(
gpg_err_code
(
sig
->
validity_reason
))
{
case
GPG_ERR_CRL_TOO_OLD
:
if
(
sig
->
validity
==
GPGME_VALIDITY_UNKNOWN
)
sum
|=
GPGME_SIGSUM_CRL_TOO_OLD
;
break
;
case
GPG_ERR_CERT_REVOKED
:
sum
|=
GPGME_SIGSUM_KEY_REVOKED
;
break
;
default
:
break
;
}
/* Check other flags. */
if
(
sig
->
wrong_key_usage
)
sum
|=
GPGME_SIGSUM_BAD_POLICY
;
/* Set the valid flag when the signature is unquestionable
valid. (The test is identical to if(sum == GPGME_SIGSUM_GREEN)). */
if
((
sum
&
GPGME_SIGSUM_GREEN
)
&&
!
(
sum
&
~
GPGME_SIGSUM_GREEN
))
sum
|=
GPGME_SIGSUM_VALID
;
sig
->
summary
=
sum
;
}
static
gpgme_error_t
prepare_new_sig
(
op_data_t
opd
)
{
gpgme_signature_t
sig
;
if
(
opd
->
only_newsig_seen
&&
opd
->
current_sig
)
{
/* We have only seen the NEWSIG status and nothing else - we
better skip this signature therefore and reuse it for the
next possible signature. */
sig
=
opd
->
current_sig
;
memset
(
sig
,
0
,
sizeof
*
sig
);
assert
(
opd
->
result
.
signatures
==
sig
);
}
else
{
sig
=
calloc
(
1
,
sizeof
(
*
sig
));
if
(
!
sig
)
return
gpg_error_from_syserror
();
if
(
!
opd
->
result
.
signatures
)
opd
->
result
.
signatures
=
sig
;
if
(
opd
->
current_sig
)
opd
->
current_sig
->
next
=
sig
;
opd
->
current_sig
=
sig
;
}
opd
->
did_prepare_new_sig
=
1
;
opd
->
only_newsig_seen
=
0
;
return
0
;
}
static
gpgme_error_t
parse_new_sig
(
op_data_t
opd
,
gpgme_status_code_t
code
,
char
*
args
,
gpgme_protocol_t
protocol
)
{
gpgme_signature_t
sig
;
char
*
end
=
strchr
(
args
,
' '
);
char
*
tail
;
if
(
end
)
{
*
end
=
'\0'
;
end
++
;
}
if
(
!
opd
->
did_prepare_new_sig
)
{
gpg_error_t
err
;
err
=
prepare_new_sig
(
opd
);
if
(
err
)
return
err
;
}
assert
(
opd
->
did_prepare_new_sig
);
opd
->
did_prepare_new_sig
=
0
;
assert
(
opd
->
current_sig
);
sig
=
opd
->
current_sig
;
/* FIXME: We should set the source of the state. */
switch
(
code
)
{
case
GPGME_STATUS_GOODSIG
:
sig
->
status
=
gpg_error
(
GPG_ERR_NO_ERROR
);
break
;
case
GPGME_STATUS_EXPSIG
:
sig
->
status
=
gpg_error
(
GPG_ERR_SIG_EXPIRED
);
break
;
case
GPGME_STATUS_EXPKEYSIG
:
sig
->
status
=
gpg_error
(
GPG_ERR_KEY_EXPIRED
);
break
;
case
GPGME_STATUS_BADSIG
:
sig
->
status
=
gpg_error
(
GPG_ERR_BAD_SIGNATURE
);
break
;
case
GPGME_STATUS_REVKEYSIG
:
sig
->
status
=
gpg_error
(
GPG_ERR_CERT_REVOKED
);
break
;
case
GPGME_STATUS_ERRSIG
:
/* Parse the pubkey algo. */
if
(
!
end
)
goto
parse_err_sig_fail
;
gpg_err_set_errno
(
0
);
sig
->
pubkey_algo
=
_gpgme_map_pk_algo
(
strtol
(
end
,
&
tail
,
0
),
protocol
);
if
(
errno
||
end
==
tail
||
*
tail
!=
' '
)
goto
parse_err_sig_fail
;
end
=
tail
;
while
(
*
end
==
' '
)
end
++
;
/* Parse the hash algo. */
if
(
!*
end
)
goto
parse_err_sig_fail
;
gpg_err_set_errno
(
0
);
sig
->
hash_algo
=
strtol
(
end
,
&
tail
,
0
);
if
(
errno
||
end
==
tail
||
*
tail
!=
' '
)
goto
parse_err_sig_fail
;
end
=
tail
;
while
(
*
end
==
' '
)
end
++
;
/* Skip the sig class. */
end
=
strchr
(
end
,
' '
);
if
(
!
end
)
goto
parse_err_sig_fail
;
while
(
*
end
==
' '
)
end
++
;
/* Parse the timestamp. */
sig
->
timestamp
=
_gpgme_parse_timestamp
(
end
,
&
tail
);
if
(
sig
->
timestamp
==
-1
||
end
==
tail
||
(
*
tail
&&
*
tail
!=
' '
))
return
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
end
=
tail
;
while
(
*
end
==
' '
)
end
++
;
/* Parse the return code. */
if
(
end
[
0
]
&&
(
!
end
[
1
]
||
end
[
1
]
==
' '
))
{
switch
(
end
[
0
])
{
case
'4'
:
sig
->
status
=
gpg_error
(
GPG_ERR_UNSUPPORTED_ALGORITHM
);
break
;
case
'9'
:
sig
->
status
=
gpg_error
(
GPG_ERR_NO_PUBKEY
);
break
;
default
:
sig
->
status
=
gpg_error
(
GPG_ERR_GENERAL
);
}
}
else
goto
parse_err_sig_fail
;
goto
parse_err_sig_ok
;
parse_err_sig_fail
:
sig
->
status
=
gpg_error
(
GPG_ERR_GENERAL
);
parse_err_sig_ok
:
break
;
default
:
return
gpg_error
(
GPG_ERR_GENERAL
);
}
if
(
*
args
)
{
sig
->
fpr
=
strdup
(
args
);
if
(
!
sig
->
fpr
)
return
gpg_error_from_syserror
();
}
return
0
;
}
static
gpgme_error_t
parse_valid_sig
(
gpgme_signature_t
sig
,
char
*
args
,
gpgme_protocol_t
protocol
)
{
char
*
end
=
strchr
(
args
,
' '
);
if
(
end
)
{
*
end
=
'\0'
;
end
++
;
}
if
(
!*
args
)
/* We require at least the fingerprint. */
return
gpg_error
(
GPG_ERR_GENERAL
);
if
(
sig
->
fpr
)
free
(
sig
->
fpr
);
sig
->
fpr
=
strdup
(
args
);
if
(
!
sig
->
fpr
)
return
gpg_error_from_syserror
();
/* Skip the creation date. */
end
=
strchr
(
end
,
' '
);
if
(
end
)
{
char
*
tail
;
sig
->
timestamp
=
_gpgme_parse_timestamp
(
end
,
&
tail
);
if
(
sig
->
timestamp
==
-1
||
end
==
tail
||
(
*
tail
&&
*
tail
!=
' '
))
return
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
end
=
tail
;
sig
->
exp_timestamp
=
_gpgme_parse_timestamp
(
end
,
&
tail
);
if
(
sig
->
exp_timestamp
==
-1
||
end
==
tail
||
(
*
tail
&&
*
tail
!=
' '
))
return
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
end
=
tail
;
while
(
*
end
==
' '
)
end
++
;
/* Skip the signature version. */
end
=
strchr
(
end
,
' '
);
if
(
end
)
{
while
(
*
end
==
' '
)
end
++
;
/* Skip the reserved field. */
end
=
strchr
(
end
,
' '
);
if
(
end
)
{
/* Parse the pubkey algo. */
gpg_err_set_errno
(
0
);
sig
->
pubkey_algo
=
_gpgme_map_pk_algo
(
strtol
(
end
,
&
tail
,
0
),
protocol
);
if
(
errno
||
end
==
tail
||
*
tail
!=
' '
)
return
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
end
=
tail
;
while
(
*
end
==
' '
)
end
++
;
if
(
*
end
)
{
/* Parse the hash algo. */
gpg_err_set_errno
(
0
);
sig
->
hash_algo
=
strtol
(
end
,
&
tail
,
0
);
if
(
errno
||
end
==
tail
||
*
tail
!=
' '
)
return
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
end
=
tail
;
}
}
}
}
return
0
;
}
static
gpgme_error_t
parse_notation
(
gpgme_signature_t
sig
,
gpgme_status_code_t
code
,
char
*
args
)
{
gpgme_error_t
err
;
gpgme_sig_notation_t
*
lastp
=
&
sig
->
notations
;
gpgme_sig_notation_t
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
=
&
notation
->
next
;
notation
=
notation
->
next
;
}
if
(
notation
)
/* There is another notation name without data for the
previous one. The crypto backend misbehaves. */
return
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
err
=
_gpgme_sig_notation_create
(
&
notation
,
NULL
,
0
,
NULL
,
0
,
0
);
if
(
err
)
return
err
;
if
(
code
==
GPGME_STATUS_NOTATION_NAME
)
{
err
=
_gpgme_decode_percent_string
(
args
,
&
notation
->
name
,
0
,
0
);
if
(
err
)
{
_gpgme_sig_notation_free
(
notation
);
return
err
;
}
notation
->
name_len
=
strlen
(
notation
->
name
);
/* FIXME: For now we fake the human-readable flag. The
critical flag can not be reported as it is not
provided. */
notation
->
flags
=
GPGME_SIG_NOTATION_HUMAN_READABLE
;
notation
->
human_readable
=
1
;
}
else
{
/* This is a policy URL. */
err
=
_gpgme_decode_percent_string
(
args
,
&
notation
->
value
,
0
,
0
);
if
(
err
)
{
_gpgme_sig_notation_free
(
notation
);
return
err
;
}
notation
->
value_len
=
strlen
(
notation
->
value
);
}
*
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
=
&
notation
->
next
;
notation
=
notation
->
next
;
}
if
(
!
notation
||
!
notation
->
name
)
/* There is notation data without a previous notation
name. The crypto backend misbehaves. */
return
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
if
(
!
notation
->
value
)
{
dest
=
notation
->
value
=
malloc
(
len
);
if
(
!
dest
)
return
gpg_error_from_syserror
();
}
else
{
int
cur_len
=
strlen
(
notation
->
value
);
dest
=
realloc
(
notation
->
value
,
len
+
strlen
(
notation
->
value
));
if
(
!
dest
)
return
gpg_error_from_syserror
();
notation
->
value
=
dest
;
dest
+=
cur_len
;
}
err
=
_gpgme_decode_percent_string
(
args
,
&
dest
,
len
,
0
);
if
(
err
)
return
err
;
notation
->
value_len
+=
strlen
(
dest
);
}
else
return
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
return
0
;
}
static
gpgme_error_t
parse_trust
(
gpgme_signature_t
sig
,
gpgme_status_code_t
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
;
}
sig
->
validity_reason
=
0
;
sig
->
chain_model
=
0
;
if
(
*
args
)
{
sig
->
validity_reason
=
atoi
(
args
);
while
(
*
args
&&
*
args
!=
' '
)
args
++
;
if
(
*
args
)
{
while
(
*
args
==
' '
)
args
++
;
if
(
!
strncmp
(
args
,
"chain"
,
2
)
&&
(
args
[
2
]
==
' '
||
!
args
[
2
]))
sig
->
chain_model
=
1
;
}
}
return
0
;
}
/* Parse an error status line and if SET_STATUS is true update the
result status as appropriate. With SET_STATUS being false, only
check for an error. */
static
gpgme_error_t
parse_error
(
gpgme_signature_t
sig
,
char
*
args
,
int
set_status
)
{
gpgme_error_t
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
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
err
=
atoi
(
which
);
if
(
!
strcmp
(
where
,
"proc_pkt.plaintext"
)
&&
gpg_err_code
(
err
)
==
GPG_ERR_BAD_DATA
)
{
/* This indicates a double plaintext. The only solid way to
handle this is by failing the oepration. */
return
gpg_error
(
GPG_ERR_BAD_DATA
);
}
else
if
(
!
set_status
)
;
else
if
(
!
strcmp
(
where
,
"verify.findkey"
))
sig
->
status
=
err
;
else
if
(
!
strcmp
(
where
,
"verify.keyusage"
)
&&
gpg_err_code
(
err
)
==
GPG_ERR_WRONG_KEY_USAGE
)
sig
->
wrong_key_usage
=
1
;
return
0
;
}
gpgme_error_t
_gpgme_verify_status_handler
(
void
*
priv
,
gpgme_status_code_t
code
,
char
*
args
)
{
gpgme_ctx_t
ctx
=
(
gpgme_ctx_t
)
priv
;
gpgme_error_t
err
;
void
*
hook
;
op_data_t
opd
;
gpgme_signature_t
sig
;
char
*
end
;
err
=
_gpgme_op_data_lookup
(
ctx
,
OPDATA_VERIFY
,
&
hook
,
-1
,
NULL
);
opd
=
hook
;
if
(
err
)
return
err
;
sig
=
opd
->
current_sig
;
switch
(
code
)
{
case
GPGME_STATUS_NEWSIG
:
if
(
sig
)
calc_sig_summary
(
sig
);
err
=
prepare_new_sig
(
opd
);
opd
->
only_newsig_seen
=
1
;
return
err
;
case
GPGME_STATUS_GOODSIG
:
case
GPGME_STATUS_EXPSIG
:
case
GPGME_STATUS_EXPKEYSIG
:
case
GPGME_STATUS_BADSIG
:
case
GPGME_STATUS_ERRSIG
:
case
GPGME_STATUS_REVKEYSIG
:
if
(
sig
&&
!
opd
->
did_prepare_new_sig
)
calc_sig_summary
(
sig
);
opd
->
only_newsig_seen
=
0
;
return
parse_new_sig
(
opd
,
code
,
args
,
ctx
->
protocol
);
case
GPGME_STATUS_VALIDSIG
:
opd
->
only_newsig_seen
=
0
;
return
sig
?
parse_valid_sig
(
sig
,
args
,
ctx
->
protocol
)
:
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
case
GPGME_STATUS_NODATA
:
opd
->
only_newsig_seen
=
0
;
if
(
!
sig
)
return
gpg_error
(
GPG_ERR_NO_DATA
);
sig
->
status
=
gpg_error
(
GPG_ERR_NO_DATA
);
break
;
case
GPGME_STATUS_UNEXPECTED
:
opd
->
only_newsig_seen
=
0
;
if
(
!
sig
)
return
gpg_error
(
GPG_ERR_GENERAL
);
sig
->
status
=
gpg_error
(
GPG_ERR_NO_DATA
);
break
;
case
GPGME_STATUS_NOTATION_NAME
:
case
GPGME_STATUS_NOTATION_DATA
:
case
GPGME_STATUS_POLICY_URL
:
opd
->
only_newsig_seen
=
0
;
return
sig
?
parse_notation
(
sig
,
code
,
args
)
:
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
case
GPGME_STATUS_TRUST_UNDEFINED
:
case
GPGME_STATUS_TRUST_NEVER
:
case
GPGME_STATUS_TRUST_MARGINAL
:
case
GPGME_STATUS_TRUST_FULLY
:
case
GPGME_STATUS_TRUST_ULTIMATE
:
opd
->
only_newsig_seen
=
0
;
return
sig
?
parse_trust
(
sig
,
code
,
args
)
:
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
case
GPGME_STATUS_PKA_TRUST_BAD
:
case
GPGME_STATUS_PKA_TRUST_GOOD
:
opd
->
only_newsig_seen
=
0
;
/* Check that we only get one of these status codes per
signature; if not the crypto backend misbehaves. */
if
(
!
sig
||
sig
->
pka_trust
||
sig
->
pka_address
)
return
trace_gpg_error
(
GPG_ERR_INV_ENGINE
);
sig
->
pka_trust
=
code
==
GPGME_STATUS_PKA_TRUST_GOOD
?
2
:
1
;
end
=
strchr
(
args
,
' '
);
if
(
end
)
*
end
=
0
;
sig
->
pka_address
=
strdup
(
args
);
break
;
case
GPGME_STATUS_ERROR
:
opd
->
only_newsig_seen
=
0
;
/* Some error stati are informational, so we don't return an
error code if we are not ready to process this status. */
return
parse_error
(
sig
,
args
,
!!
sig
);
case
GPGME_STATUS_EOF
:
if
(
sig
&&
!
opd
->
did_prepare_new_sig
)
calc_sig_summary
(
sig
);
if
(
opd
->
only_newsig_seen
&&
sig
)
{
gpgme_signature_t
sig2
;
/* The last signature has no valid information - remove it
from the list. */
assert
(
!
sig
->
next
);
if
(
sig
==
opd
->
result
.
signatures
)
opd
->
result
.
signatures
=
NULL
;
else
{
for
(
sig2
=
opd
->
result
.
signatures
;
sig2
;
sig2
=
sig2
->
next
)
if
(
sig2
->
next
==
sig
)
{
sig2
->
next
=
NULL
;
break
;
}
}
/* Note that there is no need to release the members of SIG
because we won't be here if they have been set. */
free
(
sig
);
opd
->
current_sig
=
NULL
;
}
opd
->
only_newsig_seen
=
0
;
break
;
case
GPGME_STATUS_PLAINTEXT
:
if
(
++
opd
->
plaintext_seen
>
1
)
return
gpg_error
(
GPG_ERR_BAD_DATA
);
err
=
_gpgme_parse_plaintext
(
args
,
&
opd
->
result
.
file_name
);
if
(
err
)
return
err
;
default
:
break
;
}
return
0
;
}
static
gpgme_error_t
verify_status_handler
(
void
*
priv
,
gpgme_status_code_t
code
,
char
*
args
)
{
gpgme_error_t
err
;
err
=
_gpgme_progress_status_handler
(
priv
,
code
,
args
);
if
(
!
err
)
err
=
_gpgme_verify_status_handler
(
priv
,
code
,
args
);
return
err
;
}
gpgme_error_t
_gpgme_op_verify_init_result
(
gpgme_ctx_t
ctx
)
{
void
*
hook
;
op_data_t
opd
;
return
_gpgme_op_data_lookup
(
ctx
,
OPDATA_VERIFY
,
&
hook
,
sizeof
(
*
opd
),
release_op_data
);
}
static
gpgme_error_t
verify_start
(
gpgme_ctx_t
ctx
,
int
synchronous
,
gpgme_data_t
sig
,
gpgme_data_t
signed_text
,
gpgme_data_t
plaintext
)
{
gpgme_error_t
err
;
err
=
_gpgme_op_reset
(
ctx
,
synchronous
);
if
(
err
)
return
err
;
err
=
_gpgme_op_verify_init_result
(
ctx
);
if
(
err
)
return
err
;
_gpgme_engine_set_status_handler
(
ctx
->
engine
,
verify_status_handler
,
ctx
);
if
(
!
sig
)
return
gpg_error
(
GPG_ERR_NO_DATA
);
if
(
!
signed_text
&&
!
plaintext
)
return
gpg_error
(
GPG_ERR_INV_VALUE
);
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. */
gpgme_error_t
gpgme_op_verify_start
(
gpgme_ctx_t
ctx
,
gpgme_data_t
sig
,
gpgme_data_t
signed_text
,
gpgme_data_t
plaintext
)
{
gpg_error_t
err
;
TRACE_BEG3
(
DEBUG_CTX
,
"gpgme_op_verify_start"
,
ctx
,
"sig=%p, signed_text=%p, plaintext=%p"
,
sig
,
signed_text
,
plaintext
);
if
(
!
ctx
)
return
TRACE_ERR
(
gpg_error
(
GPG_ERR_INV_VALUE
));
err
=
verify_start
(
ctx
,
0
,
sig
,
signed_text
,
plaintext
);
return
TRACE_ERR
(
err
);
}
/* Decrypt ciphertext CIPHER and make a signature verification within
CTX and store the resulting plaintext in PLAIN. */
gpgme_error_t
gpgme_op_verify
(
gpgme_ctx_t
ctx
,
gpgme_data_t
sig
,
gpgme_data_t
signed_text
,
gpgme_data_t
plaintext
)
{
gpgme_error_t
err
;
TRACE_BEG3
(
DEBUG_CTX
,
"gpgme_op_verify"
,
ctx
,
"sig=%p, signed_text=%p, plaintext=%p"
,
sig
,
signed_text
,
plaintext
);
if
(
!
ctx
)
return
TRACE_ERR
(
gpg_error
(
GPG_ERR_INV_VALUE
));
err
=
verify_start
(
ctx
,
1
,
sig
,
signed_text
,
plaintext
);
if
(
!
err
)
err
=
_gpgme_wait_one
(
ctx
);
return
TRACE_ERR
(
err
);
}
/* Compatibility interfaces. */
/* Get the key used to create signature IDX in CTX and return it in
R_KEY. */
gpgme_error_t
gpgme_get_sig_key
(
gpgme_ctx_t
ctx
,
int
idx
,
gpgme_key_t
*
r_key
)
{
gpgme_verify_result_t
result
;
gpgme_signature_t
sig
;
if
(
!
ctx
)
return
gpg_error
(
GPG_ERR_INV_VALUE
);
result
=
gpgme_op_verify_result
(
ctx
);
sig
=
result
->
signatures
;
while
(
sig
&&
idx
)
{
sig
=
sig
->
next
;
idx
--
;
}
if
(
!
sig
||
idx
)
return
gpg_error
(
GPG_ERR_EOF
);
return
gpgme_get_key
(
ctx
,
sig
->
fpr
,
r_key
,
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
(
gpgme_ctx_t
ctx
,
int
idx
,
_gpgme_sig_stat_t
*
r_stat
,
time_t
*
r_created
)
{
gpgme_verify_result_t
result
;
gpgme_signature_t
sig
;
result
=
gpgme_op_verify_result
(
ctx
);
sig
=
result
->
signatures
;
while
(
sig
&&
idx
)
{
sig
=
sig
->
next
;
idx
--
;
}
if
(
!
sig
||
idx
)
return
NULL
;
if
(
r_stat
)
{
switch
(
gpg_err_code
(
sig
->
status
))
{
case
GPG_ERR_NO_ERROR
:
*
r_stat
=
GPGME_SIG_STAT_GOOD
;
break
;
case
GPG_ERR_BAD_SIGNATURE
:
*
r_stat
=
GPGME_SIG_STAT_BAD
;
break
;
case
GPG_ERR_NO_PUBKEY
:
*
r_stat
=
GPGME_SIG_STAT_NOKEY
;
break
;
case
GPG_ERR_NO_DATA
:
*
r_stat
=
GPGME_SIG_STAT_NOSIG
;
break
;
case
GPG_ERR_SIG_EXPIRED
:
*
r_stat
=
GPGME_SIG_STAT_GOOD_EXP
;
break
;
case
GPG_ERR_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
;
}
/* 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
(
gpgme_ctx_t
ctx
,
int
idx
,
_gpgme_attr_t
what
,
int
whatidx
)
{
gpgme_verify_result_t
result
;
gpgme_signature_t
sig
;
result
=
gpgme_op_verify_result
(
ctx
);
sig
=
result
->
signatures
;
while
(
sig
&&
idx
)
{
sig
=
sig
->
next
;
idx
--
;
}
if
(
!
sig
||
idx
)
return
0
;
switch
(
what
)
{
case
GPGME_ATTR_CREATED
:
return
sig
->
timestamp
;
case
GPGME_ATTR_EXPIRE
:
return
sig
->
exp_timestamp
;
case
GPGME_ATTR_VALIDITY
:
return
(
unsigned
long
)
sig
->
validity
;
case
GPGME_ATTR_SIG_STATUS
:
switch
(
gpg_err_code
(
sig
->
status
))
{
case
GPG_ERR_NO_ERROR
:
return
GPGME_SIG_STAT_GOOD
;
case
GPG_ERR_BAD_SIGNATURE
:
return
GPGME_SIG_STAT_BAD
;
case
GPG_ERR_NO_PUBKEY
:
return
GPGME_SIG_STAT_NOKEY
;
case
GPG_ERR_NO_DATA
:
return
GPGME_SIG_STAT_NOSIG
;
case
GPG_ERR_SIG_EXPIRED
:
return
GPGME_SIG_STAT_GOOD_EXP
;
case
GPG_ERR_KEY_EXPIRED
:
return
GPGME_SIG_STAT_GOOD_EXPKEY
;
default
:
return
GPGME_SIG_STAT_ERROR
;
}
case
GPGME_ATTR_SIG_SUMMARY
:
return
sig
->
summary
;
default
:
break
;
}
return
0
;
}
const
char
*
gpgme_get_sig_string_attr
(
gpgme_ctx_t
ctx
,
int
idx
,
_gpgme_attr_t
what
,
int
whatidx
)
{
gpgme_verify_result_t
result
;
gpgme_signature_t
sig
;
result
=
gpgme_op_verify_result
(
ctx
);
sig
=
result
->
signatures
;
while
(
sig
&&
idx
)
{
sig
=
sig
->
next
;
idx
--
;
}
if
(
!
sig
||
idx
)
return
NULL
;
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
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Mon, Dec 23, 3:33 PM (23 h, 50 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
aa/da/74949efce36d4be65f8a9ad3e0b8
Attached To
rM GPGME
Event Timeline
Log In to Comment