root/openpgpsdk/trunk/src/create.c

Revision 371 (checked in by ben, 7 years ago)

Make sure dmalloc happens last.

Line 
1 /** \file
2  */
3
4 #include <openpgpsdk/create.h>
5 #include <openpgpsdk/util.h>
6 #include <string.h>
7 #include <assert.h>
8 #include <unistd.h>
9
10 #include <openpgpsdk/final.h>
11
12 struct ops_writer_info
13     {
14     ops_writer_t *writer;
15     ops_writer_finaliser_t *finaliser;
16     ops_writer_destroyer_t *destroyer;
17     void *arg;
18     ops_writer_info_t *next;
19     };
20
21 /**
22  * \ingroup Create
23  * This struct contains the required information about how to write
24  */
25 struct ops_create_info
26     {
27     ops_writer_info_t winfo;
28     ops_error_t *errors;        /*!< an error stack */
29     };
30
31 /*
32  * return true if OK, otherwise false
33  */
34 static ops_boolean_t base_write(const void *src,unsigned length,
35                                 ops_create_info_t *info)
36     {
37     return info->winfo.writer(src,length,&info->errors,&info->winfo);
38     }
39
40 /**
41  * \ingroup Create
42  *
43  * \param src
44  * \param length
45  * \param info
46  * \return 1 if OK, otherwise 0
47  */
48
49 ops_boolean_t ops_write(const void *src,unsigned length,
50                         ops_create_info_t *info)
51     {
52     return base_write(src,length,info);
53     }
54
55 /**
56  * \ingroup Create
57  * \param n
58  * \param length
59  * \param info
60  * \return ops_true if OK, otherwise ops_false
61  */
62
63 ops_boolean_t ops_write_scalar(unsigned n,unsigned length,
64                                ops_create_info_t *info)
65     {
66     while(length-- > 0)
67         {
68         unsigned char c[1];
69
70         c[0]=n >> (length*8);
71         if(!base_write(c,1,info))
72             return ops_false;
73         }
74     return ops_true;
75     }
76
77 /**
78  * \ingroup Create
79  * \param bn
80  * \param info
81  * \return 1 if OK, otherwise 0
82  * \todo This statement about the return value is true based on the assumption
83  *      that ops_true=1. Tidy this assumption up.
84  */
85
86 ops_boolean_t ops_write_mpi(const BIGNUM *bn,ops_create_info_t *info)
87     {
88     unsigned char buf[8192];
89     int bits=BN_num_bits(bn);
90
91     assert(bits <= 65535);
92     BN_bn2bin(bn,buf);
93     return ops_write_scalar(bits,2,info)
94         && ops_write(buf,(bits+7)/8,info);
95     }
96
97 /**
98  * \ingroup Create
99  * \param tag
100  * \param info
101  * \return 1 if OK, otherwise 0
102  */
103
104 ops_boolean_t ops_write_ptag(ops_content_tag_t tag,ops_create_info_t *info)
105     {
106     unsigned char c[1];
107
108     c[0]=tag|OPS_PTAG_ALWAYS_SET|OPS_PTAG_NEW_FORMAT;
109
110     return base_write(c,1,info);
111     }
112
113 /**
114  * \ingroup Create
115  * \param length
116  * \param info
117  * \return 1 if OK, otherwise 0
118  */
119
120 ops_boolean_t ops_write_length(unsigned length,ops_create_info_t *info)
121     {
122     unsigned char c[2];
123
124     if(length < 192)
125         {
126         c[0]=length;
127         return base_write(c,1,info);
128         }
129     else if(length < 8384)
130         {
131         c[0]=((length-192) >> 8)+192;
132         c[1]=(length-192)%256;
133         return base_write(c,2,info);
134         }
135     return ops_write_scalar(0xff,1,info) && ops_write_scalar(length,4,info);
136     }
137
138 /**
139  * \ingroup Create
140  * \param length
141  * \param type
142  * \param info
143  * \return 1 if OK, otherwise 0
144  */
145
146 ops_boolean_t ops_write_ss_header(unsigned length,ops_content_tag_t type,
147                                   ops_create_info_t *info)
148     {
149     return ops_write_length(length,info)
150         && ops_write_scalar(type-OPS_PTAG_SIGNATURE_SUBPACKET_BASE,1,info);
151     }
152
153 /* XXX: the general idea of _fast_ is that it doesn't copy stuff
154  * the safe (i.e. non _fast_) version will, and so will also need to
155  * be freed. */
156
157 /**
158  * \ingroup Create
159  *
160  * ops_fast_create_user_id() sets id->user_id to the given user_id.
161  * This is fast because it is only copying a char*. However, if user_id
162  * is changed or freed in the future, this could have injurious results.
163  * \param id
164  * \param user_id
165  */
166
167 void ops_fast_create_user_id(ops_user_id_t *id,unsigned char *user_id)
168     {
169     id->user_id=user_id;
170     }
171
172 /**
173  * \ingroup Create
174  *
175  * Writes a User Id from the information held in id and info
176  *
177  * \param id
178  * \param info
179  * \return Return value from ops_write() unless call to ops_write_ptag() or ops_write_length() failed before it was called, in which case returns 0
180  * \todo tidy up that return value description!
181  */
182 ops_boolean_t ops_write_struct_user_id(ops_user_id_t *id,
183                                        ops_create_info_t *info)
184     {
185     return ops_write_ptag(OPS_PTAG_CT_USER_ID,info)
186         && ops_write_length(strlen((char *)id->user_id),info)
187         && ops_write(id->user_id,strlen((char *)id->user_id),info);
188     }
189
190 /**
191  * \ingroup Create
192  *
193  * Write User Id
194  *
195  * \param user_id
196  * \param info
197  *
198  * \return return value from ops_write_struct_user_id()
199  * \todo better descr of return value
200  */
201 ops_boolean_t ops_write_user_id(const unsigned char *user_id,ops_create_info_t *info)
202     {
203     ops_user_id_t id;
204
205     id.user_id=(unsigned char *)user_id;
206     return ops_write_struct_user_id(&id,info);
207     }
208
209 static unsigned mpi_length(const BIGNUM *bn)
210     {
211     return 2+(BN_num_bits(bn)+7)/8;
212     }
213
214 static unsigned public_key_length(const ops_public_key_t *key)
215     {
216     switch(key->algorithm)
217         {
218     case OPS_PKA_RSA:
219         return mpi_length(key->key.rsa.n)+mpi_length(key->key.rsa.e);
220
221     default:
222         assert(!"unknown key algorithm");
223         }
224     /* not reached */
225     return 0;
226     }
227
228 static unsigned secret_key_length(const ops_secret_key_t *key)
229     {
230     int l;
231
232     switch(key->public_key.algorithm)
233         {
234     case OPS_PKA_RSA:
235         l=mpi_length(key->key.rsa.d)+mpi_length(key->key.rsa.p)
236             +mpi_length(key->key.rsa.q)+mpi_length(key->key.rsa.u);
237         break;
238
239     default:
240         assert(!"unknown key algorithm");
241         }
242
243     return l+public_key_length(&key->public_key);
244     }
245
246 /**
247  * \ingroup Create
248  * \param key
249  * \param time
250  * \param n
251  * \param e
252 */
253 void ops_fast_create_rsa_public_key(ops_public_key_t *key,time_t time,
254                                     BIGNUM *n,BIGNUM *e)
255     {
256     key->version=4;
257     key->creation_time=time;
258     key->algorithm=OPS_PKA_RSA;
259     key->key.rsa.n=n;
260     key->key.rsa.e=e;
261     }
262
263 /* Note that we support v3 keys here because they're needed for
264  * for verification - the writer doesn't allow them, though */
265 static ops_boolean_t write_public_key_body(const ops_public_key_t *key,
266                                            ops_create_info_t *info)
267     {
268     if(!(ops_write_scalar(key->version,1,info)
269          && ops_write_scalar(key->creation_time,4,info)))
270         return ops_false;
271
272     if(key->version != 4 && !ops_write_scalar(key->days_valid,2,info))
273         return ops_false;
274
275     if(!ops_write_scalar(key->algorithm,1,info))
276         return ops_false;
277
278     switch(key->algorithm)
279         {
280     case OPS_PKA_DSA:
281         return ops_write_mpi(key->key.dsa.p,info)
282             && ops_write_mpi(key->key.dsa.q,info)
283             && ops_write_mpi(key->key.dsa.g,info)
284             && ops_write_mpi(key->key.dsa.y,info);
285
286     case OPS_PKA_RSA:
287     case OPS_PKA_RSA_ENCRYPT_ONLY:
288     case OPS_PKA_RSA_SIGN_ONLY:
289         return ops_write_mpi(key->key.rsa.n,info)
290             && ops_write_mpi(key->key.rsa.e,info);
291
292     case OPS_PKA_ELGAMAL:
293         return ops_write_mpi(key->key.elgamal.p,info)
294             && ops_write_mpi(key->key.elgamal.g,info)
295             && ops_write_mpi(key->key.elgamal.y,info);
296
297     default:
298         assert(0);
299         break;
300         }
301
302     /* not reached */
303     return ops_false;
304     }
305
306 static void push_secret_key_checksum_writer(ops_create_info_t *info)
307     {
308     OPS_USED(info);
309     // XXX: push a SHA-1 checksum writer (and change s2k to 254).
310     }
311
312 static ops_boolean_t pop_secret_key_checksum_writer(ops_create_info_t *info)
313     {
314     // XXX: actually write a SHA-1 checksum, but for now, dummy...
315     return ops_write_scalar(0,2,info);
316     }
317
318
319 /* Note that we support v3 keys here because they're needed for
320  * for verification - the writer doesn't allow them, though */
321 static ops_boolean_t write_secret_key_body(const ops_secret_key_t *key,
322                                            ops_create_info_t *info)
323     {
324     if(!write_public_key_body(&key->public_key,info))
325         return ops_false;
326
327     if(!ops_write_scalar(key->s2k_usage,1,info))
328         return ops_false;
329    
330     // XXX: for now, no secret key encryption, so s2k == 0
331     assert(key->s2k_usage == OPS_S2KU_NONE);
332
333     push_secret_key_checksum_writer(info);
334
335     switch(key->public_key.algorithm)
336         {
337         //    case OPS_PKA_DSA:
338         //      return ops_write_mpi(key->key.dsa.x,info);
339
340     case OPS_PKA_RSA:
341     case OPS_PKA_RSA_ENCRYPT_ONLY:
342     case OPS_PKA_RSA_SIGN_ONLY:
343         if(!ops_write_mpi(key->key.rsa.d,info)
344            || !ops_write_mpi(key->key.rsa.p,info)
345            || !ops_write_mpi(key->key.rsa.q,info)
346            || !ops_write_mpi(key->key.rsa.u,info))
347             return ops_false;
348         break;
349
350         //    case OPS_PKA_ELGAMAL:
351         //      return ops_write_mpi(key->key.elgamal.x,info);
352
353     default:
354         assert(0);
355         break;
356         }
357
358     return pop_secret_key_checksum_writer(info);
359     }
360
361
362 /**
363  * \ingroup Create
364  *
365  * Writes a Public Key from the information held in "key" and "info"
366  *
367  * \param key
368  * \param info
369  * \return Return value from write_public_key_body() unless call to ops_write_ptag() or ops_write_length() failed before it was called, in which case returns 0
370  * \todo tidy up that return value description!
371  */
372 ops_boolean_t ops_write_struct_public_key(const ops_public_key_t *key,
373                                           ops_create_info_t *info)
374     {
375     assert(key->version == 4);
376
377     return ops_write_ptag(OPS_PTAG_CT_PUBLIC_KEY,info)
378         && ops_write_length(1+4+1+public_key_length(key),info)
379         && write_public_key_body(key,info);
380     }
381
382 /**
383  * \ingroup Create
384  *
385  * Writes one RSA public key.
386  *
387  * The parameters for the public key are provided by "time", "n" and "e".
388  *
389  * This function expects "info" to specify a "writer" function to be used, for the
390  * actual output.
391  *
392  * \sa See Detailed Description for usage.
393  *
394  * \param time Creation time
395  * \param n RSA public modulus
396  * \param e RSA public encryption exponent
397  * \param info Writer setup
398  *
399  * \return result from ops_write_struct_public_key()
400  *
401  * \todo get better definition of return values
402  */
403
404 ops_boolean_t ops_write_rsa_public_key(time_t time,const BIGNUM *n,
405                                        const BIGNUM *e,
406                                        ops_create_info_t *info)
407     {
408     ops_public_key_t key;
409
410     ops_fast_create_rsa_public_key(&key,time,DECONST(BIGNUM,n),
411                                    DECONST(BIGNUM,e));
412     return ops_write_struct_public_key(&key,info);
413     }
414
415 /**
416  * \ingroup Create
417  * \param out
418  * \param key
419  * \param make_packet
420  */
421
422 void ops_build_public_key(ops_memory_t *out,const ops_public_key_t *key,
423                           ops_boolean_t make_packet)
424     {
425     ops_create_info_t *info;
426
427     info=ops_create_info_new();
428
429     ops_memory_init(out,128);
430     ops_writer_set_memory(info,out);
431
432     write_public_key_body(key,info);
433
434     if(make_packet)
435         ops_memory_make_packet(out,OPS_PTAG_CT_PUBLIC_KEY);
436
437     ops_create_info_delete(info);
438     }
439
440 /**
441  * \ingroup Create
442  *
443  * Create an RSA secret key structure. If a parameter is marked as
444  * [OPTIONAL], then it can be omitted and will be calculated from
445  * other parameters - or, in the case of e, will default to 0x10001.
446  *
447  * Parameters are _not_ copied, so will be freed if the structure is
448  * freed.
449  *
450  * \param key The key structure to be initialised.
451  * \param e The RSA parameter d (=e^-1 mod (p-1)(q-1)) [OPTIONAL]
452  * \param p The RSA parameter p
453  * \param q The RSA parameter q (q > p)
454  * \param u The RSA parameter u (=p^-1 mod q) [OPTIONAL]
455  * \param n The RSA public parameter n (=p*q) [OPTIONAL]
456  * \param e The RSA public parameter e */
457
458 void ops_fast_create_rsa_secret_key(ops_secret_key_t *key,time_t time,
459                                     BIGNUM *d,BIGNUM *p,BIGNUM *q,BIGNUM *u,
460                                     BIGNUM *n,BIGNUM *e)
461     {
462     ops_fast_create_rsa_public_key(&key->public_key,time,n,e);
463
464     // XXX: calculate optionals
465     key->key.rsa.d=d;
466     key->key.rsa.p=p;
467     key->key.rsa.q=q;
468     key->key.rsa.u=u;
469
470     key->s2k_usage=OPS_S2KU_NONE;
471
472     // XXX: sanity check and add errors...
473     }
474
475 /**
476  * \ingroup Create
477  *
478  * Writes a secret key.
479  *
480  * \param key The secret key
481  * \param info
482  * \return success
483  */
484 ops_boolean_t ops_write_struct_secret_key(const ops_secret_key_t *key,
485                                           ops_create_info_t *info)
486     {
487     assert(key->public_key.version == 4);
488
489     return ops_write_ptag(OPS_PTAG_CT_SECRET_KEY,info)
490         && ops_write_length(1+4+1+1+secret_key_length(key)+2,info)
491         && write_secret_key_body(key,info);
492     }
493
494 /**
495  * \ingroup Create
496  *
497  * Create a new ops_create_info_t structure.
498  *
499  * \return the new structure.
500  */
501 ops_create_info_t *ops_create_info_new(void)
502     { return ops_mallocz(sizeof(ops_create_info_t)); }
503
504 /* Note that we finalise from the top down, so we don't use writers below
505  * that have already been finalised
506  */
507 static ops_boolean_t writer_info_finalise(ops_error_t **errors,
508                                           ops_writer_info_t *winfo)
509     {
510     ops_boolean_t ret=ops_true;
511
512     if(winfo->finaliser)
513         {
514         ret=winfo->finaliser(errors,winfo);
515         winfo->finaliser=NULL;
516         }
517     if(winfo->next && !writer_info_finalise(errors,winfo->next))
518         {
519         winfo->finaliser=NULL;
520         return ops_false;
521         }
522     return ret;
523     }
524
525 static void writer_info_delete(ops_writer_info_t *winfo)
526     {
527     // we should have finalised before deleting
528     assert(!winfo->finaliser);
529     if(winfo->next)
530         {
531         writer_info_delete(winfo->next);
532         free(winfo->next);
533         winfo->next=NULL;
534         }
535     if(winfo->destroyer)
536         {
537         winfo->destroyer(winfo);
538         winfo->destroyer=NULL;
539         }
540     winfo->writer=NULL;
541     }
542
543 /**
544  * \ingroup Create
545  *
546  * Delete an ops_create_info_t structure. If a writer is active, then
547  * that is also deleted.
548  *
549  * \param info the structure to be deleted.
550  */
551 void ops_create_info_delete(ops_create_info_t *info)
552     {
553     writer_info_delete(&info->winfo);
554     free(info);
555     }
556
557 typedef struct
558     {
559     int fd;
560     } writer_fd_arg_t;
561
562 static ops_boolean_t fd_writer(const unsigned char *src,unsigned length,
563                                ops_error_t **errors,
564                                ops_writer_info_t *winfo)
565     {
566     writer_fd_arg_t *arg=ops_writer_get_arg(winfo);
567     int n=write(arg->fd,src,length);
568
569     if(n == -1)
570         {
571         OPS_SYSTEM_ERROR_1(errors,OPS_E_W_WRITE_FAILED,"write",
572                            "file descriptor %d",arg->fd);
573         return ops_false;
574         }
575
576     if((unsigned)n != length)
577         {
578         OPS_ERROR_1(errors,OPS_E_W_WRITE_TOO_SHORT,
579                     "file descriptor %d",arg->fd);
580         return ops_false;
581         }
582
583     return ops_true;
584     }
585
586 static void fd_destroyer(ops_writer_info_t *winfo)
587     {
588     free(ops_writer_get_arg(winfo));
589     }
590
591 /**
592  * \ingroup Create
593  *
594  * Set the writer in info to be a stock writer that writes to a file
595  * descriptor. If another writer has already been set, then that is
596  * first destroyed.
597  *
598  * \param info The info structure
599  * \param fd The file descriptor
600  *
601  */
602
603 void ops_writer_set_fd(ops_create_info_t *info,int fd)
604     {
605     writer_fd_arg_t *arg=malloc(sizeof *arg);
606
607     arg->fd=fd;
608     ops_writer_set(info,fd_writer,NULL,fd_destroyer,arg);
609     }
610
611 /**
612  * \ingroup Create
613  *
614  * Set a writer in info. There should not be another writer set.
615  *
616  * \param info The info structure
617  * \param writer The writer
618  * \param destroyer The destroyer
619  * \param arg The argument for the writer and destroyer
620  */
621 void ops_writer_set(ops_create_info_t *info,
622                     ops_writer_t *writer,
623                     ops_writer_finaliser_t *finaliser,
624                     ops_writer_destroyer_t *destroyer,
625                     void *arg)
626     {
627     assert(!info->winfo.writer);
628     info->winfo.writer=writer;
629     info->winfo.finaliser=finaliser;
630     info->winfo.destroyer=destroyer;
631     info->winfo.arg=arg;
632     }
633
634 /**
635  * \ingroup Create
636  *
637  * Push a writer in info. There must already be another writer set.
638  *
639  * \param info The info structure
640  * \param writer The writer
641  * \param destroyer The destroyer
642  * \param arg The argument for the writer and destroyer
643  */
644 void ops_writer_push(ops_create_info_t *info,
645                      ops_writer_t *writer,
646                      ops_writer_finaliser_t *finaliser,
647                      ops_writer_destroyer_t *destroyer,
648                      void *arg)
649     {
650     ops_writer_info_t *copy=ops_mallocz(sizeof *copy);
651
652     assert(info->winfo.writer);
653     *copy=info->winfo;
654     info->winfo.next=copy;
655
656     info->winfo.writer=writer;
657     info->winfo.finaliser=finaliser;
658     info->winfo.destroyer=destroyer;
659     info->winfo.arg=arg;
660     }
661
662 void ops_writer_pop(ops_create_info_t *info)
663     {
664     ops_writer_info_t *next;
665
666     // Make sure the finaliser has been called.
667     assert(!info->winfo.finaliser);
668     // Makew sure this is a stacked writer
669     assert(info->winfo.next);
670     if(info->winfo.destroyer)
671         info->winfo.destroyer(&info->winfo);
672
673     next=info->winfo.next;
674     info->winfo=*next;
675
676     free(next);
677     }
678
679 /**
680  * \ingroup Create
681  *
682  * Close the writer currently set in info.
683  *
684  * \param info The info structure
685  */
686 ops_boolean_t ops_writer_close(ops_create_info_t *info)
687     {
688     ops_boolean_t ret=writer_info_finalise(&info->errors,&info->winfo);
689
690     writer_info_delete(&info->winfo);
691
692     return ret;
693     }
694
695 /**
696  * \ingroup Create
697  *
698  * Get the arg supplied to ops_create_info_set_writer().
699  *
700  * \param winfo The writer_info structure
701  * \return The arg
702  */
703 void *ops_writer_get_arg(ops_writer_info_t *winfo)
704     { return winfo->arg; }
705
706 /**
707  * \ingroup Create
708  *
709  * Write to the next writer down in the stack.
710  *
711  * \param src The data to write.
712  * \param length The length of src.
713  * \param flags The writer flags.
714  * \param errors A place to store errors.
715  * \param info The writer_info structure.
716  * \return Success - if ops_false, then errors should contain the error.
717  */
718 ops_boolean_t ops_stacked_write(const void *src,unsigned length,
719                                 ops_error_t **errors,ops_writer_info_t *winfo)
720     {
721     return winfo->next->writer(src,length,errors,winfo->next);
722     }
723
724 /**
725  * \ingroup Create
726  *
727  * Free the arg. Many writers just have a malloc()ed lump of storage, this
728  * function releases it.
729  *
730  * \param winfo the info structure.
731  */
732 void ops_writer_generic_destroyer(ops_writer_info_t *winfo)
733     { free(ops_writer_get_arg(winfo)); }
734
735 /**
736  * \ingroup Create
737  *
738  * A writer that just writes to the next one down. Useful for when you
739  * want to insert just a finaliser into the stack.
740  */
741 ops_boolean_t ops_writer_passthrough(const unsigned char *src,
742                                      unsigned length,
743                                      ops_error_t **errors,
744                                      ops_writer_info_t *winfo)
745     { return ops_stacked_write(src,length,errors,winfo); }
Note: See TracBrowser for help on using the browser.