root/openpgpsdk/trunk/src/advanced/adv_validate.c

Revision 527 (checked in by rachel, 5 years ago)

Changes needed to get V4 cleartext sigs working

Line 
1 #include <openpgpsdk/packet-parse.h>
2 #include <openpgpsdk/packet-show.h>
3 #include <openpgpsdk/keyring.h>
4 #include "keyring_local.h"
5 #include <openpgpsdk/util.h>
6 #include <openpgpsdk/signature.h>
7 #include <openpgpsdk/memory.h>
8 #include <openpgpsdk/validate.h>
9 #include <assert.h>
10 #include <string.h>
11
12 #include <openpgpsdk/final.h>
13
14 static int debug=0;
15
16 static ops_boolean_t check_binary_signature(const unsigned len,
17                                             const unsigned char *data,
18                                             const ops_signature_t *sig,
19                                             const ops_public_key_t *signer __attribute__((unused)))
20     {
21     // Does the signed hash match the given hash?
22
23     int n=0;
24     ops_hash_t hash;
25     unsigned char hashout[OPS_MAX_HASH_SIZE];
26     unsigned char trailer[6];
27     unsigned int hashedlen;
28
29     //common_init_signature(&hash,sig);
30     ops_hash_any(&hash,sig->hash_algorithm);
31     hash.init(&hash);
32     hash.add(&hash,data,len);
33     hash.add(&hash,sig->v4_hashed_data,sig->v4_hashed_data_length);
34
35     trailer[0]=0x04; // version
36     trailer[1]=0xFF;
37     hashedlen=sig->v4_hashed_data_length;
38     trailer[2]=hashedlen >> 24;
39     trailer[3]=hashedlen >> 16;
40     trailer[4]=hashedlen >> 8;
41     trailer[5]=hashedlen;
42     hash.add(&hash,&trailer[0],6);
43
44     n=hash.finish(&hash,hashout);
45
46     //    return ops_false;
47     return ops_check_signature(hashout,n,sig,signer);
48     }
49
50 static int key_data_reader(void *dest,size_t length,ops_error_t **errors,
51                            ops_reader_info_t *rinfo,
52                            ops_parse_cb_info_t *cbinfo)
53     {
54     validate_reader_arg_t *arg=ops_reader_get_arg(rinfo);
55
56     OPS_USED(errors);
57     OPS_USED(cbinfo);
58     if(arg->offset == arg->key->packets[arg->packet].length)
59         {
60         ++arg->packet;
61         arg->offset=0;
62         }
63
64     if(arg->packet == arg->key->npackets)
65         return 0;
66
67     // we should never be asked to cross a packet boundary in a single read
68     assert(arg->key->packets[arg->packet].length >= arg->offset+length);
69
70     memcpy(dest,&arg->key->packets[arg->packet].raw[arg->offset],length);
71     arg->offset+=length;
72
73     return length;
74     }
75
76 /**
77  * \ingroup Callbacks
78  */
79
80 ops_parse_cb_return_t
81 validate_key_cb(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo)
82     {
83     const ops_parser_content_union_t *content=&content_->content;
84     validate_key_cb_arg_t *arg=ops_parse_cb_get_arg(cbinfo);
85     ops_error_t **errors=ops_parse_cb_get_errors(cbinfo);
86     const ops_key_data_t *signer;
87     ops_boolean_t valid=ops_false;
88
89     if (debug)
90         printf("%s\n",ops_show_packet_tag(content_->tag));
91
92     switch(content_->tag)
93         {
94     case OPS_PTAG_CT_PUBLIC_KEY:
95         assert(arg->pkey.version == 0);
96         arg->pkey=content->public_key;
97         return OPS_KEEP_MEMORY;
98
99     case OPS_PTAG_CT_PUBLIC_SUBKEY:
100         if(arg->subkey.version)
101             ops_public_key_free(&arg->subkey);
102         arg->subkey=content->public_key;
103         return OPS_KEEP_MEMORY;
104
105     case OPS_PTAG_CT_USER_ID:
106         printf("user id=%s\n",content->user_id.user_id);
107         if(arg->user_id.user_id)
108             ops_user_id_free(&arg->user_id);
109         arg->user_id=content->user_id;
110         arg->last_seen=ID;
111         return OPS_KEEP_MEMORY;
112
113     case OPS_PTAG_CT_USER_ATTRIBUTE:
114         assert(content->user_attribute.data.len);
115         printf("user attribute, length=%d\n",(int)content->user_attribute.data.len);
116         if(arg->user_attribute.data.len)
117             ops_user_attribute_free(&arg->user_attribute);
118         arg->user_attribute=content->user_attribute;
119         arg->last_seen=ATTRIBUTE;
120         return OPS_KEEP_MEMORY;
121
122     case OPS_PTAG_CT_SIGNATURE_FOOTER:
123         printf("  type=%02x signer_id=",content->signature.type);
124         hexdump(content->signature.signer_id,
125                 sizeof content->signature.signer_id);
126
127         signer=ops_keyring_find_key_by_id(arg->keyring,
128                                            content->signature.signer_id);
129         if(!signer)
130             {
131             printf(" UNKNOWN SIGNER\n");
132             ++arg->result->unknown_signer_count;
133             break;
134             }
135
136         switch(content->signature.type)
137             {
138         case OPS_CERT_GENERIC:
139         case OPS_CERT_PERSONA:
140         case OPS_CERT_CASUAL:
141         case OPS_CERT_POSITIVE:
142         case OPS_SIG_REV_CERT:
143             if(arg->last_seen == ID)
144                 valid=ops_check_user_id_certification_signature(&arg->pkey,
145                                                                 &arg->user_id,
146                                                                 &content->signature,
147                                                                 ops_get_public_key_from_data(signer),
148                                                                 arg->rarg->key->packets[arg->rarg->packet].raw);
149             else
150                 valid=ops_check_user_attribute_certification_signature(&arg->pkey,
151                                                                        &arg->user_attribute,
152                                                                        &content->signature,
153                                                                        ops_get_public_key_from_data(signer),
154                                                                        arg->rarg->key->packets[arg->rarg->packet].raw);
155                
156             break;
157
158         case OPS_SIG_SUBKEY:
159             // XXX: we should also check that the signer is the key we are validating, I think.
160             valid=ops_check_subkey_signature(&arg->pkey,&arg->subkey,
161                     &content->signature,
162                     ops_get_public_key_from_data(signer),
163                     arg->rarg->key->packets[arg->rarg->packet].raw);
164             break;
165
166         case OPS_SIG_DIRECT:
167             valid=ops_check_direct_signature(&arg->pkey,&content->signature,
168                     ops_get_public_key_from_data(signer),
169                     arg->rarg->key->packets[arg->rarg->packet].raw);
170             break;
171
172 #ifdef MOVED
173     case OPS_SIG_TEXT:
174 #endif
175     case OPS_SIG_STANDALONE:
176     case OPS_SIG_PRIMARY:
177     case OPS_SIG_REV_KEY:
178     case OPS_SIG_REV_SUBKEY:
179     case OPS_SIG_TIMESTAMP:
180     case OPS_SIG_3RD_PARTY:
181         OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
182                     "Verification of signature type 0x%02x not yet implemented\n", content->signature.type);
183                     break;
184
185         default:
186             OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
187                     "Unexpected signature type 0x%02x\n", content->signature.type);
188             }
189
190         if(valid)
191             {
192             printf(" validated\n");
193             ++arg->result->valid_count;
194             }
195         else
196             {
197             printf(" BAD SIGNATURE\n");
198             ++arg->result->invalid_count;
199             }
200         break;
201
202         // ignore these
203     case OPS_PARSER_PTAG:
204     case OPS_PTAG_CT_SIGNATURE_HEADER:
205     case OPS_PTAG_CT_SIGNATURE:
206         break;
207
208     default:
209         fprintf(stderr,"unexpected tag=0x%x\n",content_->tag);
210         assert(0);
211         break;
212         }
213     return OPS_RELEASE_MEMORY;
214     }
215
216 ops_parse_cb_return_t
217 validate_data_cb(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo)
218     {
219     const ops_parser_content_union_t *content=&content_->content;
220     validate_data_cb_arg_t *arg=ops_parse_cb_get_arg(cbinfo);
221     ops_error_t **errors=ops_parse_cb_get_errors(cbinfo);
222     const ops_key_data_t *signer;
223     ops_boolean_t valid=ops_false;
224     //    unsigned len=0;
225     //    unsigned char *data=NULL;
226     ops_memory_t* mem=NULL;
227
228     if (debug)
229         printf("%s\n",ops_show_packet_tag(content_->tag));
230
231     switch(content_->tag)
232         {
233     case OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
234         // ignore - this gives us the "Armor Header" line "Hash: SHA1" or similar
235         break;
236
237     case OPS_PTAG_CT_LITERAL_DATA_HEADER:
238         // ignore
239         break;
240
241     case OPS_PTAG_CT_LITERAL_DATA_BODY:
242         arg->data.literal_data_body=content->literal_data_body;
243         arg->use=LITERAL_DATA;
244         return OPS_KEEP_MEMORY;
245         break;
246
247     case OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY:
248         arg->data.signed_cleartext_body=content->signed_cleartext_body;
249         arg->use=SIGNED_CLEARTEXT;
250         return OPS_KEEP_MEMORY;
251         break;
252
253     case OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
254         // this gives us an ops_hash_t struct
255         break;
256
257     case OPS_PTAG_CT_SIGNATURE: // V3 sigs
258         // this gives us a signature struct with all info about hash alg, etc from the packet
259         break;
260
261     case OPS_PTAG_CT_SIGNATURE_FOOTER: // V4 sigs
262         
263         if (debug)
264             {
265             printf("\n*** hashed data:\n");
266             unsigned int zzz=0;
267             for (zzz=0; zzz<content->signature.v4_hashed_data_length; zzz++)
268                 printf("0x%02x ", content->signature.v4_hashed_data[zzz]);
269             printf("\n");
270             printf("  type=%02x signer_id=",content->signature.type);
271             hexdump(content->signature.signer_id,
272                     sizeof content->signature.signer_id);
273             }
274
275         signer=ops_keyring_find_key_by_id(arg->keyring,
276                                           content->signature.signer_id);
277         if(!signer)
278             {
279             OPS_ERROR(errors,OPS_E_V_UNKNOWN_SIGNER,"Unknown Signer");
280             printf(" UNKNOWN SIGNER\n");
281             ++arg->result->unknown_signer_count;
282             break;
283             }
284        
285         mem=ops_memory_new();
286         ops_memory_init(mem,128);
287        
288         switch(content->signature.type)
289             {
290         case OPS_SIG_BINARY:
291         case OPS_SIG_TEXT:
292             switch(arg->use)
293                 {
294             case LITERAL_DATA:
295                 ops_memory_add(mem,
296                                arg->data.literal_data_body.data,
297                                arg->data.literal_data_body.length);
298                 break;
299
300             case SIGNED_CLEARTEXT:
301                 ops_memory_add(mem,
302                                arg->data.signed_cleartext_body.data,
303                                arg->data.signed_cleartext_body.length);
304                 break;
305
306             default:
307                 OPS_ERROR_1(errors,OPS_E_UNIMPLEMENTED,"Unimplemented Sig Use %d", arg->use);
308                 printf(" Unimplemented Sig Use %d\n", arg->use);
309                 break;
310                 }
311
312             valid=check_binary_signature(ops_memory_get_length(mem),
313                                          ops_memory_get_data(mem),
314                                          &content->signature,
315                                          ops_get_public_key_from_data(signer));
316             break;
317
318         OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
319                     "Verification of signature type 0x%02x not yet implemented\n", content->signature.type);
320                     break;
321
322         default:
323             OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
324                     "Unexpected signature type 0x%02x\n", content->signature.type);
325             //      exit(1);
326             }
327     ops_memory_free(mem);
328
329         if(valid)
330             {
331             ++arg->result->valid_count;
332             }
333         else
334             {
335         OPS_ERROR(errors,OPS_E_V_BAD_SIGNATURE,"Bad Signature");
336             printf(" BAD SIGNATURE\n");
337             ++arg->result->invalid_count;
338             }
339         break;
340
341         // ignore these
342     case OPS_PARSER_PTAG:
343     case OPS_PTAG_CT_SIGNATURE_HEADER:
344         //    case OPS_PTAG_CT_SIGNATURE:
345         break;
346
347     default:
348         fprintf(stderr,"unexpected tag=0x%x\n",content_->tag);
349         assert(0);
350         break;
351         }
352     return OPS_RELEASE_MEMORY;
353     }
354
355 static void key_data_destroyer(ops_reader_info_t *rinfo)
356     { free(ops_reader_get_arg(rinfo)); }
357
358 void ops_key_data_reader_set(ops_parse_info_t *pinfo,const ops_key_data_t *key)
359     {
360     validate_reader_arg_t *arg=malloc(sizeof *arg);
361
362     memset(arg,'\0',sizeof *arg);
363
364     arg->key=key;
365     arg->packet=0;
366     arg->offset=0;
367
368     ops_reader_set(pinfo,key_data_reader,key_data_destroyer,arg);
369     }
370
371 /*
372  * Validate all signatures on a single key against the given keyring
373  */
374 static void validate_key_signatures(ops_validate_result_t *result,const ops_key_data_t *key,
375                                     const ops_keyring_t *keyring)
376     {
377     ops_parse_info_t *pinfo;
378     validate_key_cb_arg_t carg;
379
380     memset(&carg,'\0',sizeof carg);
381     carg.result=result;
382
383     pinfo=ops_parse_info_new();
384     //    ops_parse_options(&opt,OPS_PTAG_CT_SIGNATURE,OPS_PARSE_PARSED);
385
386     carg.keyring=keyring;
387
388     ops_parse_cb_set(pinfo,validate_key_cb,&carg);
389     ops_key_data_reader_set(pinfo,key);
390
391     carg.rarg=ops_reader_get_arg_from_pinfo(pinfo);
392
393     ops_parse(pinfo);
394
395     ops_public_key_free(&carg.pkey);
396     if(carg.subkey.version)
397         ops_public_key_free(&carg.subkey);
398     ops_user_id_free(&carg.user_id);
399     ops_user_attribute_free(&carg.user_attribute);
400
401     ops_parse_info_delete(pinfo);
402     }
403
404 void ops_validate_all_signatures(ops_validate_result_t *result,
405                                  const ops_keyring_t *ring)
406     {
407     int n;
408
409     memset(result,'\0',sizeof *result);
410     for(n=0 ; n < ring->nkeys ; ++n)
411         validate_key_signatures(result,&ring->keys[n],ring);
412     }
Note: See TracBrowser for help on using the browser.