1 /* sig-check.c - Check signatures
2 * Copyright (C) 1998-2012 Free Software Foundation, Inc.
6 * This file is part of OpenCDK.
8 * The OpenCDK library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public License
10 * as published by the Free Software Foundation; either version 3 of
11 * the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>
33 /* Hash all multi precision integers of the key PK with the given
34 message digest context MD. */
36 hash_mpibuf (cdk_pubkey_t pk
, digest_hd_st
* md
, int usefpr
)
38 byte buf
[MAX_MPI_BYTES
]; /* FIXME: do not use hardcoded length. */
43 /* We have to differ between two modes for v3 keys. To form the
44 fingerprint, we hash the MPI values without the length prefix.
45 But if we calculate the hash for verifying/signing we use all data. */
46 npkey
= cdk_pk_get_npkey (pk
->pubkey_algo
);
47 for (i
= 0; i
< npkey
; i
++)
49 nbytes
= MAX_MPI_BYTES
;
50 err
= _gnutls_mpi_print_pgp (pk
->mpi
[i
], buf
, &nbytes
);
55 return map_gnutls_error (err
);
58 if (!usefpr
|| pk
->version
== 4)
59 _gnutls_hash (md
, buf
, nbytes
);
60 else /* without the prefix. */
61 _gnutls_hash (md
, buf
+ 2, nbytes
- 2);
67 /* Hash an entire public key PK with the given message digest context
68 MD. The @usefpr param is only valid for version 3 keys because of
69 the different way to calculate the fingerprint. */
71 _cdk_hash_pubkey (cdk_pubkey_t pk
, digest_hd_st
* md
, int usefpr
)
79 if (usefpr
&& pk
->version
< 4 && is_RSA (pk
->pubkey_algo
))
80 return hash_mpibuf (pk
, md
, 1);
82 /* The version 4 public key packet does not have the 2 octets for
83 the expiration date. */
84 n
= pk
->version
< 4 ? 8 : 6;
85 npkey
= cdk_pk_get_npkey (pk
->pubkey_algo
);
86 for (i
= 0; i
< npkey
; i
++)
87 n
= n
+ (_gnutls_mpi_get_nbits (pk
->mpi
[i
]) + 7) / 8 + 2;
93 buf
[i
++] = pk
->version
;
94 buf
[i
++] = pk
->timestamp
>> 24;
95 buf
[i
++] = pk
->timestamp
>> 16;
96 buf
[i
++] = pk
->timestamp
>> 8;
97 buf
[i
++] = pk
->timestamp
>> 0;
103 /* Convert the expiration date into days. */
105 a
= (u16
) ((pk
->expiredate
- pk
->timestamp
) / 86400L);
109 buf
[i
++] = pk
->pubkey_algo
;
110 _gnutls_hash (md
, buf
, i
);
111 return hash_mpibuf (pk
, md
, 0);
115 /* Hash the user ID @uid with the given message digest @md.
116 Use openpgp mode if @is_v4 is 1. */
118 _cdk_hash_userid (cdk_pkt_userid_t uid
, int is_v4
, digest_hd_st
* md
)
125 return CDK_Inv_Value
;
129 _gnutls_hash (md
, (byte
*) uid
->name
, uid
->len
);
133 dlen
= uid
->attrib_img
? uid
->attrib_len
: uid
->len
;
134 data
= uid
->attrib_img
? uid
->attrib_img
: (byte
*) uid
->name
;
135 buf
[0] = uid
->attrib_img
? 0xD1 : 0xB4;
140 _gnutls_hash (md
, buf
, 5);
141 _gnutls_hash (md
, data
, dlen
);
146 /* Hash all parts of the signature which are needed to derive
147 the correct message digest to verify the sig. */
149 _cdk_hash_sig_data (cdk_pkt_signature_t sig
, digest_hd_st
* md
)
155 return CDK_Inv_Value
;
157 if (sig
->version
== 4)
158 _gnutls_hash (md
, &sig
->version
, 1);
160 _gnutls_hash (md
, &sig
->sig_class
, 1);
161 if (sig
->version
< 4)
163 buf
[0] = sig
->timestamp
>> 24;
164 buf
[1] = sig
->timestamp
>> 16;
165 buf
[2] = sig
->timestamp
>> 8;
166 buf
[3] = sig
->timestamp
>> 0;
167 _gnutls_hash (md
, buf
, 4);
173 tmp
= _cdk_pub_algo_to_pgp (sig
->pubkey_algo
);
174 _gnutls_hash (md
, &tmp
, 1);
175 tmp
= _gnutls_hash_algo_to_pgp (sig
->digest_algo
);
176 _gnutls_hash (md
, &tmp
, 1);
177 if (sig
->hashed
!= NULL
)
179 byte
*p
= _cdk_subpkt_get_array (sig
->hashed
, 0, &n
);
183 _gnutls_hash (md
, buf
, 2);
184 _gnutls_hash (md
, p
, n
);
186 sig
->hashed_size
= n
;
187 n
= sig
->hashed_size
+ 6;
192 _gnutls_hash (md
, &tmp
, 1);
193 _gnutls_hash (md
, &tmp
, 1);
196 _gnutls_hash (md
, &sig
->version
, 1);
198 _gnutls_hash (md
, &tmp
, 1);
203 _gnutls_hash (md
, buf
, 4);
209 /* Cache the signature result and store it inside the sig. */
211 cache_sig_result (cdk_pkt_signature_t sig
, int res
)
213 sig
->flags
.checked
= 0;
214 sig
->flags
.valid
= 0;
217 sig
->flags
.checked
= 1;
218 sig
->flags
.valid
= 1;
220 else if (res
== CDK_Bad_Sig
)
222 sig
->flags
.checked
= 1;
223 sig
->flags
.valid
= 0;
228 /* Check the given signature @sig with the public key @pk.
229 Use the digest handle @digest. */
231 _cdk_sig_check (cdk_pubkey_t pk
, cdk_pkt_signature_t sig
,
232 digest_hd_st
* digest
, int *r_expired
)
235 byte md
[MAX_DIGEST_LEN
];
236 time_t cur_time
= (u32
) gnutls_time (NULL
);
238 if (!pk
|| !sig
|| !digest
)
241 return CDK_Inv_Value
;
244 if (sig
->flags
.checked
)
245 return sig
->flags
.valid
? 0 : CDK_Bad_Sig
;
246 if (!KEY_CAN_SIGN (pk
->pubkey_algo
))
248 if (pk
->timestamp
> sig
->timestamp
|| pk
->timestamp
> cur_time
)
249 return CDK_Time_Conflict
;
251 if (r_expired
&& pk
->expiredate
252 && (pk
->expiredate
+ pk
->timestamp
) > cur_time
)
255 _cdk_hash_sig_data (sig
, digest
);
256 _gnutls_hash_output (digest
, md
);
258 if (md
[0] != sig
->digest_start
[0] || md
[1] != sig
->digest_start
[1])
261 return CDK_Chksum_Error
;
264 rc
= cdk_pk_verify (pk
, sig
, md
);
265 cache_sig_result (sig
, rc
);
270 /* Check the given key signature.
271 @knode is the key node and @snode the signature node. */
273 _cdk_pk_check_sig (cdk_keydb_hd_t keydb
,
274 cdk_kbnode_t knode
, cdk_kbnode_t snode
, int *is_selfsig
,
280 cdk_pkt_signature_t sig
;
285 if (!knode
|| !snode
)
288 return CDK_Inv_Value
;
293 if ((knode
->pkt
->pkttype
!= CDK_PKT_PUBLIC_KEY
&&
294 knode
->pkt
->pkttype
!= CDK_PKT_PUBLIC_SUBKEY
) ||
295 snode
->pkt
->pkttype
!= CDK_PKT_SIGNATURE
)
298 return CDK_Inv_Value
;
300 pk
= knode
->pkt
->pkt
.public_key
;
301 sig
= snode
->pkt
->pkt
.signature
;
303 err
= _gnutls_hash_init (&md
, sig
->digest_algo
);
307 return map_gnutls_error (err
);
311 if (sig
->sig_class
== 0x20)
312 { /* key revocation */
313 cdk_kbnode_hash (knode
, &md
, 0, 0, 0);
314 rc
= _cdk_sig_check (pk
, sig
, &md
, &is_expired
);
316 else if (sig
->sig_class
== 0x28)
317 { /* subkey revocation */
318 node
= cdk_kbnode_find_prev (knode
, snode
, CDK_PKT_PUBLIC_SUBKEY
);
320 { /* no subkey for subkey revocation packet */
322 rc
= CDK_Error_No_Key
;
325 cdk_kbnode_hash (knode
, &md
, 0, 0, 0);
326 cdk_kbnode_hash (node
, &md
, 0, 0, 0);
327 rc
= _cdk_sig_check (pk
, sig
, &md
, &is_expired
);
329 else if (sig
->sig_class
== 0x18 || sig
->sig_class
== 0x19)
330 { /* primary/secondary key binding */
331 node
= cdk_kbnode_find_prev (knode
, snode
, CDK_PKT_PUBLIC_SUBKEY
);
333 { /* no subkey for subkey binding packet */
335 rc
= CDK_Error_No_Key
;
338 cdk_kbnode_hash (knode
, &md
, 0, 0, 0);
339 cdk_kbnode_hash (node
, &md
, 0, 0, 0);
340 rc
= _cdk_sig_check (pk
, sig
, &md
, &is_expired
);
342 else if (sig
->sig_class
== 0x1F)
343 { /* direct key signature */
344 cdk_kbnode_hash (knode
, &md
, 0, 0, 0);
345 rc
= _cdk_sig_check (pk
, sig
, &md
, &is_expired
);
348 { /* all other classes */
349 cdk_pkt_userid_t uid
;
350 node
= cdk_kbnode_find_prev (knode
, snode
, CDK_PKT_USER_ID
);
352 { /* no user ID for key signature packet */
354 rc
= CDK_Error_No_Key
;
358 uid
= node
->pkt
->pkt
.user_id
;
361 *ret_uid
= uid
->name
;
363 cdk_kbnode_hash (knode
, &md
, 0, 0, 0);
364 cdk_kbnode_hash (node
, &md
, sig
->version
== 4, 0, 0);
366 if (pk
->keyid
[0] == sig
->keyid
[0] && pk
->keyid
[1] == sig
->keyid
[1])
368 rc
= _cdk_sig_check (pk
, sig
, &md
, &is_expired
);
372 else if (keydb
!= NULL
)
375 rc
= cdk_keydb_get_pk (keydb
, sig
->keyid
, &sig_pk
);
377 rc
= _cdk_sig_check (sig_pk
, sig
, &md
, &is_expired
);
378 cdk_pk_release (sig_pk
);
382 _gnutls_hash_deinit (&md
, NULL
);
390 struct verify_uid
*next
;
394 uid_list_add_sig (struct verify_uid
**list
, const char *uid
,
399 *list
= cdk_calloc (1, sizeof (struct verify_uid
));
401 return CDK_Out_Of_Core
;
409 struct verify_uid
*p
, *prev_p
= NULL
;
416 if (strcmp (uid
, p
->name
) == 0)
426 { /* not found add to the last */
427 prev_p
->next
= cdk_calloc (1, sizeof (struct verify_uid
));
428 if (prev_p
->next
== NULL
)
429 return CDK_Out_Of_Core
;
430 prev_p
->next
->name
= uid
;
432 prev_p
->next
->nsigs
++;
435 { /* found... increase sigs */
445 uid_list_free (struct verify_uid
*list
)
447 struct verify_uid
*p
, *p1
;
458 /* returns non (0) if all UIDs in the list have at least one
459 * signature. If the list is empty or no signatures are present
460 * a (0) value is returned.
463 uid_list_all_signed (struct verify_uid
*list
)
465 struct verify_uid
*p
;
479 return 1; /* all signed */
484 * @key: the public key
485 * @hd: an optinal key database handle
486 * @r_status: variable to store the status of the key
488 * Check all signatures. When no key is available for checking, the
489 * sigstat is marked as 'NOKEY'. The @r_status contains the key flags
490 * which are or-ed or (0) when there are no flags.
493 cdk_pk_check_sigs (cdk_kbnode_t key
, cdk_keydb_hd_t keydb
, int *r_status
)
495 cdk_pkt_signature_t sig
;
499 int key_status
, is_selfsig
= 0;
500 struct verify_uid
*uid_list
= NULL
;
503 if (!key
|| !r_status
)
506 return CDK_Inv_Value
;
510 node
= cdk_kbnode_find (key
, CDK_PKT_PUBLIC_KEY
);
514 return CDK_Error_No_Key
;
518 /* Continue with the signature check but adjust the
519 key status flags accordingly. */
520 if (node
->pkt
->pkt
.public_key
->is_revoked
)
521 key_status
|= CDK_KEY_REVOKED
;
522 if (node
->pkt
->pkt
.public_key
->has_expired
)
523 key_status
|= CDK_KEY_EXPIRED
;
526 keyid
= cdk_pk_get_keyid (node
->pkt
->pkt
.public_key
, NULL
);
527 for (node
= key
; node
; node
= node
->next
)
529 if (node
->pkt
->pkttype
!= CDK_PKT_SIGNATURE
)
531 sig
= node
->pkt
->pkt
.signature
;
532 rc
= _cdk_pk_check_sig (keydb
, key
, node
, &is_selfsig
, &uid_name
);
534 if (rc
&& rc
!= CDK_Error_No_Key
)
536 /* It might be possible that a single signature has been
537 corrupted, thus we do not consider it a problem when
538 one ore more signatures are bad. But at least the self
539 signature has to be valid. */
542 key_status
|= CDK_KEY_INVALID
;
547 _cdk_log_debug ("signature %s: signer %08X keyid %08X\n",
548 rc
== CDK_Bad_Sig
? "BAD" : "good",
549 (unsigned int) sig
->keyid
[1], (unsigned int) keyid
);
551 if (IS_UID_SIG (sig
) && uid_name
!= NULL
)
553 /* add every uid in the uid list. Only consider valid:
554 * - verification was ok
558 uid_list_add_sig (&uid_list
, uid_name
,
559 (rc
== CDK_Success
&& is_selfsig
== 0) ? 1 : 0);
560 if (rc
!= CDK_Success
)
569 if (uid_list_all_signed (uid_list
) == 0)
570 key_status
|= CDK_KEY_NOSIGNER
;
571 *r_status
= key_status
;
572 if (rc
== CDK_Error_No_Key
)
576 uid_list_free (uid_list
);
582 * cdk_pk_check_self_sig:
584 * @r_status: output the status of the key.
586 * A convenient function to make sure the key is valid.
587 * Valid means the self signature is ok.
590 cdk_pk_check_self_sig (cdk_kbnode_t key
, int *r_status
)
592 cdk_pkt_signature_t sig
;
595 u32 keyid
[2], sigid
[2];
596 int is_selfsig
, sig_ok
;
597 cdk_kbnode_t p
, ctx
= NULL
;
600 if (!key
|| !r_status
)
601 return CDK_Inv_Value
;
603 cdk_pk_get_keyid (key
->pkt
->pkt
.public_key
, keyid
);
605 while ((p
= cdk_kbnode_walk (key
, &ctx
, 0)))
607 pkt
= cdk_kbnode_get_packet (p
);
608 if (pkt
->pkttype
!= CDK_PKT_PUBLIC_SUBKEY
609 && pkt
->pkttype
!= CDK_PKT_PUBLIC_KEY
)
612 /* FIXME: we should set expire/revoke here also but callers
613 expect CDK_KEY_VALID=0 if the key is okay. */
615 for (node
= p
; node
; node
= node
->next
)
617 if (node
->pkt
->pkttype
!= CDK_PKT_SIGNATURE
)
619 sig
= node
->pkt
->pkt
.signature
;
621 cdk_sig_get_keyid (sig
, sigid
);
622 if (sigid
[0] != keyid
[0] || sigid
[1] != keyid
[1])
624 /* FIXME: Now we check all self signatures. */
625 rc
= _cdk_pk_check_sig (NULL
, p
, node
, &is_selfsig
, NULL
);
628 *r_status
= CDK_KEY_INVALID
;
631 else /* For each valid self sig we increase this counter. */
635 /* A key without a self signature is not valid. At least one
636 * signature for the given key has to be found.
640 *r_status
= CDK_KEY_INVALID
;
641 return CDK_General_Error
;
645 /* No flags indicate a valid key. */
646 *r_status
= CDK_KEY_VALID
;