partly added creation of OP partial length headers
[gnupg.git] / g10 / build-packet.c
1 /* build-packet.c - assemble packets and write them
2  *      Copyright (C) 1998 Free Software Foundation, Inc.
3  *
4  * This file is part of GNUPG.
5  *
6  * GNUPG is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GNUPG is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "packet.h"
28 #include "errors.h"
29 #include "iobuf.h"
30 #include "mpi.h"
31 #include "util.h"
32 #include "cipher.h"
33 #include "memory.h"
34 #include "options.h"
35
36
37 static int do_comment( IOBUF out, int ctb, PKT_comment *rem );
38 static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid );
39 static int do_public_key( IOBUF out, int ctb, PKT_public_key *pk );
40 static int do_secret_key( IOBUF out, int ctb, PKT_secret_key *pk );
41 static int do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc );
42 static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc );
43 static u32 calc_plaintext( PKT_plaintext *pt );
44 static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt );
45 static int do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed );
46 static int do_compressed( IOBUF out, int ctb, PKT_compressed *cd );
47 static int do_signature( IOBUF out, int ctb, PKT_signature *sig );
48 static int do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops );
49
50 static int calc_header_length( u32 len );
51 static int write_16(IOBUF inp, u16 a);
52 static int write_32(IOBUF inp, u32 a);
53 static int write_header( IOBUF out, int ctb, u32 len );
54 static int write_header2( IOBUF out, int ctb, u32 len, int hdrlen, int blkmode );
55 static int write_new_header( IOBUF out, int ctb, u32 len, int hdrlen );
56 static int write_version( IOBUF out, int ctb );
57
58 /****************
59  * Build a packet and write it to INP
60  * Returns: 0 := okay
61  *         >0 := error
62  * Note: Caller must free the packet
63  */
64 int
65 build_packet( IOBUF out, PACKET *pkt )
66 {
67     int new_ctb=0, rc=0, ctb;
68
69     if( DBG_PACKET )
70         log_debug("build_packet() type=%d\n", pkt->pkttype );
71     assert( pkt->pkt.generic );
72
73     switch( pkt->pkttype ) {
74       case PKT_OLD_COMMENT: pkt->pkttype = PKT_COMMENT; break;
75       case PKT_PLAINTEXT: new_ctb = pkt->pkt.plaintext->new_ctb; break;
76       case PKT_ENCRYPTED: new_ctb = pkt->pkt.encrypted->new_ctb; break;
77       case PKT_COMPRESSED:new_ctb = pkt->pkt.compressed->new_ctb; break;
78       default: break;
79     }
80
81     if( new_ctb || pkt->pkttype > 15 ) /* new format */
82         ctb = 0xc0 | (pkt->pkttype & 0x3f);
83     else
84         ctb = 0x80 | ((pkt->pkttype & 15)<<2);
85     switch( pkt->pkttype ) {
86       case PKT_USER_ID:
87         rc = do_user_id( out, ctb, pkt->pkt.user_id );
88         break;
89       case PKT_COMMENT:
90         rc = do_comment( out, ctb, pkt->pkt.comment );
91         break;
92       case PKT_PUBLIC_SUBKEY:
93       case PKT_PUBLIC_KEY:
94         rc = do_public_key( out, ctb, pkt->pkt.public_key );
95         break;
96       case PKT_SECRET_SUBKEY:
97       case PKT_SECRET_KEY:
98         rc = do_secret_key( out, ctb, pkt->pkt.secret_key );
99         break;
100       case PKT_SYMKEY_ENC:
101         rc = do_symkey_enc( out, ctb, pkt->pkt.symkey_enc );
102         break;
103       case PKT_PUBKEY_ENC:
104         rc = do_pubkey_enc( out, ctb, pkt->pkt.pubkey_enc );
105         break;
106       case PKT_PLAINTEXT:
107         rc = do_plaintext( out, ctb, pkt->pkt.plaintext );
108         break;
109       case PKT_ENCRYPTED:
110         rc = do_encrypted( out, ctb, pkt->pkt.encrypted );
111         break;
112       case PKT_COMPRESSED:
113         rc = do_compressed( out, ctb, pkt->pkt.compressed );
114         break;
115       case PKT_SIGNATURE:
116         rc = do_signature( out, ctb, pkt->pkt.signature );
117         break;
118       case PKT_ONEPASS_SIG:
119         rc = do_onepass_sig( out, ctb, pkt->pkt.onepass_sig );
120         break;
121       case PKT_RING_TRUST:
122       default:
123         log_bug("invalid packet type in build_packet()\n");
124         break;
125     }
126
127     return rc;
128 }
129
130 /****************
131  * calculate the length of a packet described by PKT
132  */
133 u32
134 calc_packet_length( PACKET *pkt )
135 {
136     u32 n=0;
137
138     assert( pkt->pkt.generic );
139     switch( pkt->pkttype ) {
140       case PKT_PLAINTEXT:
141         n = calc_plaintext( pkt->pkt.plaintext );
142         break;
143       case PKT_USER_ID:
144       case PKT_COMMENT:
145       case PKT_PUBLIC_KEY:
146       case PKT_SECRET_KEY:
147       case PKT_SYMKEY_ENC:
148       case PKT_PUBKEY_ENC:
149       case PKT_ENCRYPTED:
150       case PKT_SIGNATURE:
151       case PKT_ONEPASS_SIG:
152       case PKT_RING_TRUST:
153       case PKT_COMPRESSED:
154       default:
155         log_bug("invalid packet type in calc_packet_length()");
156         break;
157     }
158     n += calc_header_length(n);
159     return n;
160 }
161
162 static void
163 write_fake_data( IOBUF out, MPI a )
164 {
165     byte *s;
166     u16 len;
167
168     if( a ) {
169         s = (byte*)a;
170         len = (s[0] << 8) | s[1];
171         iobuf_write( out, s+2, len );
172     }
173 }
174
175
176 static int
177 do_comment( IOBUF out, int ctb, PKT_comment *rem )
178 {
179     if( !opt.no_comment ) {
180         write_header(out, ctb, rem->len);
181         if( iobuf_write( out, rem->data, rem->len ) )
182             return G10ERR_WRITE_FILE;
183     }
184     return 0;
185 }
186
187 static int
188 do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
189 {
190     write_header(out, ctb, uid->len);
191     if( iobuf_write( out, uid->name, uid->len ) )
192         return G10ERR_WRITE_FILE;
193     return 0;
194 }
195
196 static int
197 do_public_key( IOBUF out, int ctb, PKT_public_key *pk )
198 {
199     int rc = 0;
200     int n, i;
201     IOBUF a = iobuf_temp();
202
203     if( !pk->version )
204         iobuf_put( a, 3 );
205     else
206         iobuf_put( a, pk->version );
207     write_32(a, pk->timestamp );
208     if( pk->version < 4 )
209         write_16(a, pk->valid_days );
210     iobuf_put(a, pk->pubkey_algo );
211     n = pubkey_get_npkey( pk->pubkey_algo );
212     if( !n )
213         write_fake_data( a, pk->pkey[0] );
214     for(i=0; i < n; i++ )
215         mpi_write(a, pk->pkey[i] );
216
217     write_header2(out, ctb, iobuf_get_temp_length(a), pk->hdrbytes, 1 );
218     if( iobuf_write_temp( out, a ) )
219         rc = G10ERR_WRITE_FILE;
220
221     iobuf_close(a);
222     return rc;
223 }
224
225
226 /****************
227  * Make a hash value from the public key certificate
228  */
229 void
230 hash_public_key( MD_HANDLE md, PKT_public_key *pk )
231 {
232     PACKET pkt;
233     int rc = 0;
234     int c;
235     IOBUF a = iobuf_temp();
236   #if 0
237     FILE *fp = fopen("dump.pk", "a");
238     int i=0;
239
240     fprintf(fp, "\nHashing PK (v%d):\n", pk->version);
241   #endif
242
243     /* build the packet */
244     init_packet(&pkt);
245     pkt.pkttype = PKT_PUBLIC_KEY;
246     pkt.pkt.public_key = pk;
247     if( (rc = build_packet( a, &pkt )) )
248         log_fatal("build public_key for hashing failed: %s\n", g10_errstr(rc));
249     while( (c=iobuf_get(a)) != -1 ) {
250       #if 0
251         fprintf( fp," %02x", c );
252         if( (++i == 24) ) {
253             putc('\n', fp);
254             i=0;
255         }
256       #endif
257         md_putc( md, c );
258     }
259   #if 0
260     putc('\n', fp);
261     fclose(fp);
262   #endif
263     iobuf_cancel(a);
264 }
265
266
267 static int
268 do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
269 {
270     int rc = 0;
271     int i, nskey, npkey;
272     IOBUF a = iobuf_temp();
273
274     if( !sk->version )
275         iobuf_put( a, 3 );
276     else
277         iobuf_put( a, sk->version );
278     write_32(a, sk->timestamp );
279     if( sk->version < 4 )
280         write_16(a, sk->valid_days );
281     iobuf_put(a, sk->pubkey_algo );
282     nskey = pubkey_get_nskey( sk->pubkey_algo );
283     npkey = pubkey_get_npkey( sk->pubkey_algo );
284     if( npkey ) {
285         write_fake_data( a, sk->skey[0] );
286         goto leave;
287     }
288     assert( npkey < nskey );
289
290     for(i=0; i < npkey; i++ )
291         mpi_write(a, sk->skey[i] );
292     if( sk->is_protected ) {
293         if( is_RSA(sk->pubkey_algo) && sk->version < 4 ) {
294             iobuf_put(a, sk->protect.algo );
295             iobuf_write(a, sk->protect.iv, 8 );
296         }
297         else {
298             iobuf_put(a, 0xff );
299             iobuf_put(a, sk->protect.algo );
300             iobuf_put(a, sk->protect.s2k.mode );
301             iobuf_put(a, sk->protect.s2k.hash_algo );
302             if( sk->protect.s2k.mode == 1
303                 || sk->protect.s2k.mode == 4 )
304                 iobuf_write(a, sk->protect.s2k.salt, 8 );
305             if( sk->protect.s2k.mode == 4 )
306                 write_32(a, sk->protect.s2k.count );
307             iobuf_write(a, sk->protect.iv, 8 );
308         }
309     }
310     else
311         iobuf_put(a, 0 );
312     for(   ; i < nskey; i++ )
313         mpi_write(a, sk->skey[i] );
314     write_16(a, sk->csum );
315
316   leave:
317     write_header2(out, ctb, iobuf_get_temp_length(a), sk->hdrbytes, 1 );
318     if( iobuf_write_temp( out, a ) )
319         rc = G10ERR_WRITE_FILE;
320
321     iobuf_close(a);
322     return rc;
323 }
324
325 static int
326 do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
327 {
328     int rc = 0;
329     IOBUF a = iobuf_temp();
330
331     assert( enc->version == 4 );
332     switch( enc->s2k.mode ) {
333       case 0: case 1: case 4: break;
334       default: log_bug("do_symkey_enc: s2k=%d\n", enc->s2k.mode );
335     }
336     iobuf_put( a, enc->version );
337     iobuf_put( a, enc->cipher_algo );
338     iobuf_put( a, enc->s2k.mode );
339     iobuf_put( a, enc->s2k.hash_algo );
340     if( enc->s2k.mode == 1 || enc->s2k.mode == 4 ) {
341         iobuf_write(a, enc->s2k.salt, 8 );
342         if( enc->s2k.mode == 4 )
343             write_32(a, enc->s2k.count);
344     }
345     if( enc->seskeylen )
346         iobuf_write(a, enc->seskey, enc->seskeylen );
347
348     write_header(out, ctb, iobuf_get_temp_length(a) );
349     if( iobuf_write_temp( out, a ) )
350         rc = G10ERR_WRITE_FILE;
351
352     iobuf_close(a);
353     return rc;
354 }
355
356
357
358
359 static int
360 do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
361 {
362     int rc = 0;
363     int n, i;
364     IOBUF a = iobuf_temp();
365
366     write_version( a, ctb );
367     write_32(a, enc->keyid[0] );
368     write_32(a, enc->keyid[1] );
369     iobuf_put(a,enc->pubkey_algo );
370     n = pubkey_get_nenc( enc->pubkey_algo );
371     if( !n )
372         write_fake_data( a, enc->data[0] );
373     for(i=0; i < n; i++ )
374         mpi_write(a, enc->data[i] );
375
376     write_header(out, ctb, iobuf_get_temp_length(a) );
377     if( iobuf_write_temp( out, a ) )
378         rc = G10ERR_WRITE_FILE;
379
380     iobuf_close(a);
381     return rc;
382 }
383
384
385
386
387 static u32
388 calc_plaintext( PKT_plaintext *pt )
389 {
390     return pt->len? (1 + 1 + pt->namelen + 4 + pt->len) : 0;
391 }
392
393 static int
394 do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
395 {
396     int i, rc = 0;
397     u32 n;
398     byte buf[1000]; /* FIXME: this buffer has the plaintext! */
399     int nbytes;
400
401     write_header(out, ctb, calc_plaintext( pt ) );
402     iobuf_put(out, pt->mode );
403     iobuf_put(out, pt->namelen );
404     for(i=0; i < pt->namelen; i++ )
405         iobuf_put(out, pt->name[i] );
406     if( write_32(out, pt->timestamp ) )
407         rc = G10ERR_WRITE_FILE;
408
409     n = 0;
410     while( (nbytes=iobuf_read(pt->buf, buf, 1000)) != -1 ) {
411         if( iobuf_write(out, buf, nbytes) == -1 ) {
412             rc = G10ERR_WRITE_FILE;
413             break;
414         }
415         n += nbytes;
416     }
417     memset(buf,0,1000); /* at least burn the buffer */
418     if( !pt->len )
419         iobuf_set_block_mode(out, 0 ); /* write end marker */
420     else if( n != pt->len )
421         log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n",
422                         (ulong)n, (ulong)pt->len );
423
424     return rc;
425 }
426
427
428
429 static int
430 do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed )
431 {
432     int rc = 0;
433     u32 n;
434
435     n = ed->len ? (ed->len + 10) : 0;
436     write_header(out, ctb, n );
437
438     /* This is all. The caller has to write the real data */
439
440     return rc;
441 }
442
443 static int
444 do_compressed( IOBUF out, int ctb, PKT_compressed *cd )
445 {
446     int rc = 0;
447
448     /* we must use the old convention and don't use blockmode */
449     write_header2(out, ctb, 0, 0, 0 );
450     iobuf_put(out, cd->algorithm );
451
452     /* This is all. The caller has to write the real data */
453
454     return rc;
455 }
456
457
458
459 /****************
460  * Find a subpacket of type REQTYPE in BUFFER and a return a pointer
461  * to the first byte of that subpacket data.
462  * And return the length of the packet in RET_N and the number of
463  * header bytes in RET_HLEN (length header and type byte).
464  */
465 byte *
466 find_subpkt( byte *buffer, sigsubpkttype_t reqtype,
467              size_t *ret_hlen, size_t *ret_n )
468 {
469     int buflen;
470     sigsubpkttype_t type;
471     byte *bufstart;
472     size_t n;
473
474     if( !buffer )
475         return NULL;
476     buflen = (*buffer << 8) | buffer[1];
477     buffer += 2;
478     for(;;) {
479         if( !buflen )
480             return NULL; /* end of packets; not found */
481         bufstart = buffer;
482         n = *buffer++; buflen--;
483         if( n == 255 ) {
484             if( buflen < 4 )
485                 break;
486             n = (buffer[0] << 24) | (buffer[1] << 16)
487                                   | (buffer[2] << 8) | buffer[3];
488             buffer += 4;
489             buflen -= 4;
490         }
491         else if( n >= 192 ) {
492             if( buflen < 2 )
493                 break;
494             n = (( n - 192 ) << 8) + *buffer + 192;
495             buflen--;
496         }
497         if( buflen < n )
498             break;
499         type = *buffer & 0x7f;
500         if( type == reqtype ) {
501             buffer++;
502             n--;
503             if( n > buflen )
504                 break;
505             if( ret_hlen )
506                 *ret_hlen = buffer - bufstart;
507             if( ret_n )
508                 *ret_n = n;
509             return buffer;
510         }
511         buffer += n; buflen -=n;
512     }
513
514     log_error("find_subpkt: buffer shorter than subpacket\n");
515     return NULL;
516 }
517
518
519 /****************
520  * Create or update a signature subpacket for SIG of TYPE.
521  * This functions know, where to put the data (hashed or unhashed).
522  * The function may move data from the unhased part to the hashed one.
523  * Note: All pointers into sig->[un]hashed are not valid after a call
524  * to this function.  The data to but into the subpaket should be
525  * in buffer with a length of buflen.
526  */
527 void
528 build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
529                   const byte *buffer, size_t buflen )
530 {
531
532     byte *data;
533     size_t hlen, dlen;
534     int found, hashed, realloced;
535     size_t n, n0;
536
537     if( (data = find_subpkt( sig->hashed_data, type, &hlen, &dlen )) )
538         found = 1;
539     else if( (data = find_subpkt( sig->unhashed_data, type, &hlen, &dlen )))
540         found = 2;
541     else
542         found = 0;
543
544     if( found )
545         log_bug("build_sig_packet: update nyi\n");
546     if( buflen+1 >= 192 )
547         log_bug("build_sig_packet: long subpackets are nyi\n");
548
549     switch( type ) {
550       case SIGSUBPKT_SIG_CREATED:
551       case SIGSUBPKT_PRIV_ADD_SIG:
552       case SIGSUBPKT_PREF_SYM:
553       case SIGSUBPKT_PREF_HASH:
554       case SIGSUBPKT_PREF_COMPR:
555       case SIGSUBPKT_KS_FLAGS:
556       case SIGSUBPKT_KEY_EXPIRE:
557                hashed = 1; break;
558       default: hashed = 0; break;
559     }
560
561     if( hashed ) {
562         n0 = sig->hashed_data ? ((*sig->hashed_data << 8)
563                                     | sig->hashed_data[1]) : 0;
564         n = n0 + 1 + 1 + buflen; /* length, type, buffer */
565         realloced = !!sig->hashed_data;
566         data = sig->hashed_data ? m_realloc( sig->hashed_data, n+2 )
567                                 : m_alloc( n+2 );
568     }
569     else {
570         n0 = sig->unhashed_data ? ((*sig->unhashed_data << 8)
571                                       | sig->unhashed_data[1]) : 0;
572         n = n0 + 1 + 1 + buflen; /* length, type, buffer */
573         realloced = !!sig->unhashed_data;
574         data = sig->unhashed_data ? m_realloc( sig->unhashed_data, n+2 )
575                                   : m_alloc( n+2 );
576     }
577
578     data[0] = (n >> 8) & 0xff;
579     data[1] = n & 0xff;
580     data[n0+2] = buflen+1;
581     data[n0+3] = type;
582     memcpy(data+n0+4, buffer, buflen );
583
584     if( hashed ) {
585         if( !realloced )
586             m_free(sig->hashed_data);
587         sig->hashed_data = data;
588     }
589     else {
590         if( !realloced )
591             m_free(sig->unhashed_data);
592         sig->unhashed_data = data;
593     }
594 }
595
596
597 /****************
598  * Put all the required stuff from SIG into subpackets of sig.
599  */
600 void
601 build_sig_subpkt_from_sig( PKT_signature *sig )
602 {
603     u32  u;
604     byte buf[8];
605
606     u = sig->keyid[0];
607     buf[0] = (u >> 24) & 0xff;
608     buf[1] = (u >> 16) & 0xff;
609     buf[2] = (u >>  8) & 0xff;
610     buf[3] = u & 0xff;
611     u = sig->keyid[1];
612     buf[4] = (u >> 24) & 0xff;
613     buf[5] = (u >> 16) & 0xff;
614     buf[6] = (u >>  8) & 0xff;
615     buf[7] = u & 0xff;
616     build_sig_subpkt( sig, SIGSUBPKT_ISSUER, buf, 8 );
617
618     u = sig->timestamp;
619     buf[0] = (u >> 24) & 0xff;
620     buf[1] = (u >> 16) & 0xff;
621     buf[2] = (u >>  8) & 0xff;
622     buf[3] = u & 0xff;
623     build_sig_subpkt( sig, SIGSUBPKT_SIG_CREATED, buf, 4 );
624 }
625
626
627 static int
628 do_signature( IOBUF out, int ctb, PKT_signature *sig )
629 {
630     int rc = 0;
631     int n, i;
632     IOBUF a = iobuf_temp();
633
634     if( !sig->version )
635         iobuf_put( a, 3 );
636     else
637         iobuf_put( a, sig->version );
638     if( sig->version < 4 )
639         iobuf_put(a, 5 ); /* constant */
640     iobuf_put(a, sig->sig_class );
641     if( sig->version < 4 ) {
642         write_32(a, sig->timestamp );
643         write_32(a, sig->keyid[0] );
644         write_32(a, sig->keyid[1] );
645     }
646     iobuf_put(a, sig->pubkey_algo );
647     iobuf_put(a, sig->digest_algo );
648     if( sig->version >= 4 ) {
649         size_t n;
650         /* timestamp and keyid must have been packed into the
651          * subpackets prior to the call of this function, because
652          * these subpackets are hashed */
653         n = sig->hashed_data?((sig->hashed_data[0]<<8)
654                               |sig->hashed_data[1])   :0;
655         write_16(a, n);
656         if( n )
657             iobuf_write( a, sig->hashed_data+2, n );
658         n = sig->unhashed_data?((sig->unhashed_data[0]<<8)
659                                 |sig->unhashed_data[1])   :0;
660         write_16(a, n);
661         if( n )
662             iobuf_write( a, sig->unhashed_data+2, n );
663     }
664     iobuf_put(a, sig->digest_start[0] );
665     iobuf_put(a, sig->digest_start[1] );
666     n = pubkey_get_nsig( sig->pubkey_algo );
667     if( !n )
668         write_fake_data( a, sig->data[0] );
669     for(i=0; i < n; i++ )
670         mpi_write(a, sig->data[i] );
671
672     write_header(out, ctb, iobuf_get_temp_length(a) );
673     if( iobuf_write_temp( out, a ) )
674         rc = G10ERR_WRITE_FILE;
675
676     iobuf_close(a);
677     return rc;
678 }
679
680
681 static int
682 do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops )
683 {
684     int rc = 0;
685     IOBUF a = iobuf_temp();
686
687     write_version( a, ctb );
688     iobuf_put(a, ops->sig_class );
689     iobuf_put(a, ops->digest_algo );
690     iobuf_put(a, ops->pubkey_algo );
691     write_32(a, ops->keyid[0] );
692     write_32(a, ops->keyid[1] );
693     iobuf_put(a, ops->last );
694
695     write_header(out, ctb, iobuf_get_temp_length(a) );
696     if( iobuf_write_temp( out, a ) )
697         rc = G10ERR_WRITE_FILE;
698
699     iobuf_close(a);
700     return rc;
701 }
702
703
704 static int
705 write_16(IOBUF out, u16 a)
706 {
707     iobuf_put(out, a>>8);
708     if( iobuf_put(out,a) )
709         return -1;
710     return 0;
711 }
712
713 static int
714 write_32(IOBUF out, u32 a)
715 {
716     iobuf_put(out, a>> 24);
717     iobuf_put(out, a>> 16);
718     iobuf_put(out, a>> 8);
719     if( iobuf_put(out, a) )
720         return -1;
721     return 0;
722 }
723
724
725 /****************
726  * calculate the length of a header
727  */
728 static int
729 calc_header_length( u32 len )
730 {
731     if( !len )
732         return 1; /* only the ctb */
733     else if( len < 256 )
734         return 2;
735     else if( len < 65536 )
736         return 3;
737     else
738         return 5;
739 }
740
741 /****************
742  * Write the CTB and the packet length
743  */
744 static int
745 write_header( IOBUF out, int ctb, u32 len )
746 {
747     return write_header2( out, ctb, len, 0, 1 );
748 }
749
750 /****************
751  * if HDRLEN is > 0, try to build a header of this length.
752  * we need this, so that we can hash packets without reading them again.
753  */
754 static int
755 write_header2( IOBUF out, int ctb, u32 len, int hdrlen, int blkmode )
756 {
757     if( ctb & 0x40 )
758         return write_new_header( out, ctb, len, hdrlen );
759
760     if( hdrlen ) {
761         if( !len )
762             ctb |= 3;
763         else if( hdrlen == 2 && len < 256 )
764             ;
765         else if( hdrlen == 3 && len < 65536 )
766             ctb |= 1;
767         else
768             ctb |= 2;
769     }
770     else {
771         if( !len )
772             ctb |= 3;
773         else if( len < 256 )
774             ;
775         else if( len < 65536 )
776             ctb |= 1;
777         else
778             ctb |= 2;
779     }
780     if( iobuf_put(out, ctb ) )
781         return -1;
782     if( !len ) {
783         if( blkmode )
784             iobuf_set_block_mode(out, 8196 );
785     }
786     else {
787         if( ctb & 2 ) {
788             iobuf_put(out, len >> 24 );
789             iobuf_put(out, len >> 16 );
790         }
791         if( ctb & 3 )
792             iobuf_put(out, len >> 8 );
793         if( iobuf_put(out, len ) )
794             return -1;
795     }
796     return 0;
797 }
798
799
800 static int
801 write_new_header( IOBUF out, int ctb, u32 len, int hdrlen )
802 {
803     if( hdrlen )
804         log_bug("can't cope with hdrlen yet\n");
805
806     if( iobuf_put(out, ctb ) )
807         return -1;
808     if( !len ) {
809         iobuf_set_partial_block_mode(out, 512 );
810     }
811     else {
812         if( len < 192 ) {
813             if( iobuf_put(out, len ) )
814                 return -1;
815         }
816         else if( len < 8384 ) {
817             len -= 192;
818             if( iobuf_put( out, (len / 256) + 192) )
819                 return -1;
820             if( iobuf_put( out, (len % 256) )  )
821                 return -1;
822         }
823         else {
824             if( iobuf_put( out, 0xff ) )
825                 return -1;
826             if( iobuf_put( out, (len >> 24)&0xff ) )
827                 return -1;
828             if( iobuf_put( out, (len >> 16)&0xff ) )
829                 return -1;
830             if( iobuf_put( out, (len >> 8)&0xff )  )
831                 return -1;
832             if( iobuf_put( out, len & 0xff ) )
833                 return -1;
834         }
835     }
836     return 0;
837 }
838
839 static int
840 write_version( IOBUF out, int ctb )
841 {
842     if( iobuf_put( out, 3 ) )
843         return -1;
844     return 0;
845 }
846