root/openpgpsdk/trunk/src/signature.c

Revision 166 (checked in by rachel, 8 years ago)

Doxygen markup added to all functions used by current example programs.
Functions defined in groups for better documentation layout

Line 
1 /** \file
2  */
3
4 #include "signature.h"
5 #include "crypto.h"
6 #include "memory.h"
7 #include "build.h"
8 #include "create.h"
9 #include <assert.h>
10 #include <string.h>
11
12 static unsigned char prefix_md5[]={ 0x30,0x20,0x30,0x0C,0x06,0x08,0x2A,0x86,
13                                     0x48,0x86,0xF7,0x0D,0x02,0x05,0x05,0x00,
14                                     0x04,0x10 };
15
16 static unsigned char prefix_sha1[]={ 0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0E,
17                                      0x03,0x02,0x1A,0x05,0x00,0x04,0x14 };
18
19 // XXX: both this and verify would be clearer if the signature were
20 // treated as an MPI.
21 static void rsa_sign(ops_hash_t *hash,const ops_rsa_public_key_t *rsa,
22                      const ops_rsa_secret_key_t *srsa,
23                      ops_create_options_t *opt)
24     {
25     unsigned char hashbuf[8192];
26     unsigned char sigbuf[8192];
27     unsigned keysize;
28     unsigned hashsize;
29     unsigned n;
30     unsigned t;
31     BIGNUM *bn;
32
33     // XXX: we assume hash is sha-1 for now
34     hashsize=20+sizeof prefix_sha1;
35
36     keysize=(BN_num_bits(rsa->n)+7)/8;
37     assert(keysize <= sizeof hashbuf);
38     assert(10+hashsize <= keysize);
39
40     hashbuf[0]=1;
41     for(n=1 ; n < keysize-hashsize-1 ; ++n)
42         hashbuf[n]=0xff;
43     hashbuf[n++]=0;
44
45     memcpy(&hashbuf[n],prefix_sha1,sizeof prefix_sha1);
46     n+=sizeof prefix_sha1;
47
48     t=hash->finish(hash,&hashbuf[n]);
49     assert(t == 20);
50
51     ops_write(&hashbuf[n],2,opt);
52
53     n+=t;
54     assert(n == keysize);
55
56     t=ops_rsa_private_encrypt(sigbuf,hashbuf,keysize,srsa,rsa);
57     bn=BN_bin2bn(sigbuf,t,NULL);
58     ops_write_mpi(bn,opt);
59     BN_free(bn);
60     }
61
62 static ops_boolean_t rsa_verify(ops_hash_algorithm_t type,
63                                 const unsigned char *hash,size_t hash_length,
64                                 const ops_rsa_signature_t *sig,
65                                 const ops_rsa_public_key_t *rsa)
66     {
67     unsigned char sigbuf[8192];
68     unsigned char hashbuf[8192];
69     int n;
70     int keysize;
71     unsigned char *prefix;
72     int plen;
73
74     keysize=(BN_num_bits(rsa->n)+7)/8;
75     // RSA key can't be bigger than 65535 bits, so...
76     assert(keysize <= sizeof hashbuf);
77     assert(BN_num_bits(sig->sig) <= 8*sizeof sigbuf);
78     BN_bn2bin(sig->sig,sigbuf);
79
80     n=ops_rsa_public_decrypt(hashbuf,sigbuf,(BN_num_bits(sig->sig)+7)/8,rsa);
81
82     if(n != keysize) // obviously, this includes error returns
83         return ops_false;
84
85     printf(" decrypt=%d ",n);
86     hexdump(hashbuf,n);
87
88     // XXX: why is there a leading 0? The first byte should be 1...
89     // XXX: because the decrypt should use keysize and not sigsize?
90     if(hashbuf[0] != 0 || hashbuf[1] != 1)
91         return ops_false;
92
93     switch(type)
94         {
95     case OPS_HASH_MD5: prefix=prefix_md5; plen=sizeof prefix_md5; break;
96     case OPS_HASH_SHA1: prefix=prefix_sha1; plen=sizeof prefix_sha1; break;
97     default: assert(0); break;
98         }
99
100     if(keysize-plen-hash_length < 10)
101         return ops_false;
102
103     for(n=2 ; n < keysize-plen-hash_length-1 ; ++n)
104         if(hashbuf[n] != 0xff)
105             return ops_false;
106
107     if(hashbuf[n++] != 0)
108         return ops_false;
109
110     if(memcmp(&hashbuf[n],prefix,plen)
111        || memcmp(&hashbuf[n+plen],hash,hash_length))
112         return ops_false;
113
114     return ops_true;
115     }
116
117 static void hash_add_key(ops_hash_t *hash,const ops_public_key_t *key)
118     {
119     ops_memory_t mem;
120
121     memset(&mem,'\0',sizeof mem);
122     ops_build_public_key(&mem,key,ops_false);
123
124     hash_add_int(hash,0x99,1);
125     hash_add_int(hash,mem.length,2);
126     hash->add(hash,mem.buf,mem.length);
127
128     ops_memory_release(&mem);
129     }
130
131 static void init_signature(ops_hash_t *hash,const ops_signature_t *sig,
132                            const ops_public_key_t *key)
133     {
134     switch(sig->hash_algorithm)
135         {
136     case OPS_HASH_MD5:
137         ops_hash_md5(hash);
138         break;
139
140     case OPS_HASH_SHA1:
141         ops_hash_sha1(hash);
142         break;
143
144     default:
145         assert(0);
146         }
147
148     hash->init(hash);
149     hash_add_key(hash,key);
150     }
151
152 static void hash_add_trailer(ops_hash_t *hash,const ops_signature_t *sig,
153                              const ops_public_key_t *signer,
154                              const unsigned char *raw_packet)
155     {
156     if(sig->version == OPS_SIG_V4)
157         {
158         hash->add(hash,raw_packet+sig->v4_hashed_data_start,
159                   sig->v4_hashed_data_length);
160         hash_add_int(hash,sig->version,1);
161         hash_add_int(hash,0xff,1);
162         hash_add_int(hash,sig->v4_hashed_data_length,4);
163         }
164     else
165         {
166         hash_add_int(hash,sig->type,1);
167         hash_add_int(hash,sig->creation_time,4);
168         }
169     }
170
171 static ops_boolean_t check_signature(ops_hash_t *hash,
172                                      const ops_signature_t *sig,
173                                      const ops_public_key_t *signer)
174     {
175     int n;
176     ops_boolean_t ret;
177     unsigned char hashout[OPS_MAX_HASH];
178
179     n=hash->finish(hash,hashout);
180     printf(" hash=");
181     //    hashout[0]=0;
182     hexdump(hashout,n);
183
184     switch(sig->key_algorithm)
185         {
186     case OPS_PKA_DSA:
187         ret=ops_dsa_verify(hashout,n,&sig->signature.dsa,&signer->key.dsa);
188         break;
189
190     case OPS_PKA_RSA:
191         ret=rsa_verify(sig->hash_algorithm,hashout,n,&sig->signature.rsa,
192                        &signer->key.rsa);
193         break;
194
195     default:
196         assert(0);
197         }
198
199     return ret;
200     }
201
202 static ops_boolean_t finalise_signature(ops_hash_t *hash,
203                                         const ops_signature_t *sig,
204                                         const ops_public_key_t *signer,
205                                         const unsigned char *raw_packet)
206     {
207     hash_add_trailer(hash,sig,signer,raw_packet);
208     return check_signature(hash,sig,signer);
209     }
210
211 ops_boolean_t
212 ops_check_certification_signature(const ops_public_key_t *key,
213                                   const ops_user_id_t *id,
214                                   const ops_signature_t *sig,
215                                   const ops_public_key_t *signer,
216                                   const unsigned char *raw_packet)
217     {
218     ops_hash_t hash;
219
220     init_signature(&hash,sig,key);
221
222     if(sig->version == OPS_SIG_V4)
223         {
224         hash_add_int(&hash,0xb4,1);
225         hash_add_int(&hash,strlen(id->user_id),4);
226         hash.add(&hash,id->user_id,strlen(id->user_id));
227         }
228     else
229         hash.add(&hash,id->user_id,strlen(id->user_id));
230
231     return finalise_signature(&hash,sig,signer,raw_packet);
232     }
233
234 ops_boolean_t
235 ops_check_subkey_signature(const ops_public_key_t *key,
236                            const ops_public_key_t *subkey,
237                            const ops_signature_t *sig,
238                            const ops_public_key_t *signer,
239                            const unsigned char *raw_packet)
240     {
241     ops_hash_t hash;
242
243     init_signature(&hash,sig,key);
244     hash_add_key(&hash,subkey);
245
246     return finalise_signature(&hash,sig,signer,raw_packet);
247     }
248
249 /**
250  * \ingroup Create
251  *
252  * ops_signature_start() creates a V4 signature with a SHA1 hash.
253  *
254  * \param sig
255  * \param key
256  * \param id
257  * \param type
258  * \todo Expand description.
259  */
260 void ops_signature_start(ops_create_signature_t *sig,
261                          const ops_public_key_t *key,
262                          const ops_user_id_t *id,
263                          ops_sig_type_t type)
264     {
265     // XXX: refactor with check (in several ways - check should probably
266     // use the buffered writer to construct packets (done), and also should
267     // share code for hash calculation)
268     sig->sig.version=OPS_SIG_V4;
269     sig->sig.hash_algorithm=OPS_HASH_SHA1;
270     sig->sig.key_algorithm=key->algorithm;
271     sig->sig.type=type;
272
273     sig->hashed_data_length=-1;
274
275     init_signature(&sig->hash,&sig->sig,key);
276
277     hash_add_int(&sig->hash,0xb4,1);
278     hash_add_int(&sig->hash,strlen(id->user_id),4);
279     sig->hash.add(&sig->hash,id->user_id,strlen(id->user_id));
280
281     // since this has subpackets and stuff, we have to buffer the whole
282     // thing to get counts before writing.
283     ops_memory_init(&sig->mem,100);
284     sig->opt.writer=ops_writer_memory;
285     sig->opt.arg=&sig->mem;
286
287     // write nearly up to the first subpacket
288     ops_write_scalar(sig->sig.version,1,&sig->opt);
289     ops_write_scalar(sig->sig.type,1,&sig->opt);
290     ops_write_scalar(sig->sig.key_algorithm,1,&sig->opt);
291     ops_write_scalar(sig->sig.hash_algorithm,1,&sig->opt);
292
293     // dummy hashed subpacket count
294     sig->hashed_count_offset=sig->mem.length;
295     ops_write_scalar(0,2,&sig->opt);
296     }
297
298 /**
299  * \ingroup Create
300  *
301  * Mark the end of the hashed subpackets in the signature
302  *
303  * \param sig
304  */
305
306 void ops_signature_hashed_subpackets_end(ops_create_signature_t *sig)
307     {
308     sig->hashed_data_length=sig->mem.length-sig->hashed_count_offset-2;
309     ops_memory_place_int(&sig->mem,sig->hashed_count_offset,
310                          sig->hashed_data_length,2);
311     // dummy unhashed subpacket count
312     sig->unhashed_count_offset=sig->mem.length;
313     ops_write_scalar(0,2,&sig->opt);
314     }
315
316 /**
317  * \ingroup Create
318  *
319  * Write out a signature
320  *
321  * \param sig
322  * \param key
323  * \param skey
324  * \param opt
325  *
326  * \todo get a better description of how/when this is used
327  */
328
329 void ops_write_signature(ops_create_signature_t *sig,ops_public_key_t *key,
330                          ops_secret_key_t *skey,ops_create_options_t *opt)
331     {
332     assert(sig->hashed_data_length != -1);
333
334     ops_memory_place_int(&sig->mem,sig->unhashed_count_offset,
335                          sig->mem.length-sig->unhashed_count_offset-2,2);
336
337     // add the packet from version number to end of hashed subpackets
338     sig->hash.add(&sig->hash,sig->mem.buf,sig->unhashed_count_offset);
339     hash_add_int(&sig->hash,sig->sig.version,1);
340     hash_add_int(&sig->hash,0xff,1);
341     hash_add_int(&sig->hash,sig->hashed_data_length,4);
342
343     // XXX: technically, we could figure out how big the signature is
344     // and write it directly to the output instead of via memory.
345     assert(key->algorithm == OPS_PKA_RSA);
346     rsa_sign(&sig->hash,&key->key.rsa,&skey->key.rsa,&sig->opt);
347
348     ops_write_ptag(OPS_PTAG_CT_SIGNATURE,opt);
349     ops_write_length(sig->mem.length,opt);
350     ops_write(sig->mem.buf,sig->mem.length,opt);
351
352     ops_memory_release(&sig->mem);
353     }
354
355 /**
356  * \ingroup Create
357  *
358  * ops_signature_add_creation_time() adds a creation time to the signature.
359  *
360  * \param sig
361  * \param when
362  */
363 void ops_signature_add_creation_time(ops_create_signature_t *sig,time_t when)
364     {
365     ops_write_ss_header(5,OPS_PTAG_SS_CREATION_TIME,&sig->opt);
366     ops_write_scalar(when,4,&sig->opt);
367     }
368
369 /**
370  * \ingroup Create
371  *
372  * Adds issuer's key ID to the signature
373  *
374  * \param sig
375  * \param keyid
376  */
377
378 void ops_signature_add_issuer_key_id(ops_create_signature_t *sig,
379                                      const unsigned char keyid[OPS_KEY_ID_SIZE])
380     {
381     ops_write_ss_header(OPS_KEY_ID_SIZE+1,OPS_PTAG_SS_ISSUER_KEY_ID,&sig->opt);
382     ops_write(keyid,OPS_KEY_ID_SIZE,&sig->opt);
383     }
384
385 /**
386  * \ingroup Create
387  *
388  * Adds primary user ID to the signature
389  *
390  * \param sig
391  * \param keyid
392  */
393 void ops_signature_add_primary_user_id(ops_create_signature_t *sig,
394                                        ops_boolean_t primary)
395     {
396     ops_write_ss_header(2,OPS_PTAG_SS_PRIMARY_USER_ID,&sig->opt);
397     ops_write_scalar(primary,1,&sig->opt);
398     }
Note: See TracBrowser for help on using the browser.