Output armor works, RSA keygen works.
[gnupg.git] / g10 / build-packet.c
1 /* build-packet.c - assemble packets and write them
2  *      Copyright (c) 1997 by Werner Koch (dd9jn)
3  *
4  * This file is part of G10.
5  *
6  * G10 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  * G10 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_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pk );
40 static int do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *pk );
41 static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc );
42 static u32 calc_plaintext( PKT_plaintext *pt );
43 static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt );
44 static int do_encr_data( IOBUF out, int ctb, PKT_encr_data *ed );
45
46 static int calc_header_length( u32 len );
47 static int write_16(IOBUF inp, u16 a);
48 static int write_32(IOBUF inp, u32 a);
49 static int write_header( IOBUF out, int ctb, u32 len );
50 static int write_version( IOBUF out, int ctb );
51
52 /****************
53  * Build a packet and write it to INP
54  * Returns: 0 := okay
55  *         >0 := error
56  * Note: Caller must free the packet
57  */
58 int
59 build_packet( IOBUF out, PACKET *pkt )
60 {
61     int rc=0, ctb;
62
63     if( DBG_PACKET )
64         log_debug("build_packet() type=%d\n", pkt->pkttype );
65     assert( pkt->pkt.generic );
66     ctb = 0x80 | ((pkt->pkttype & 15)<<2);
67     switch( pkt->pkttype ) {
68       case PKT_USER_ID:
69         rc = do_user_id( out, ctb, pkt->pkt.user_id );
70         break;
71       case PKT_COMMENT:
72         rc = do_comment( out, ctb, pkt->pkt.comment );
73         break;
74       case PKT_PUBKEY_CERT:
75         rc = do_pubkey_cert( out, ctb, pkt->pkt.pubkey_cert );
76         break;
77       case PKT_SECKEY_CERT:
78         rc = do_seckey_cert( out, ctb, pkt->pkt.seckey_cert );
79         break;
80       case PKT_PUBKEY_ENC:
81         rc = do_pubkey_enc( out, ctb, pkt->pkt.pubkey_enc );
82         break;
83       case PKT_PLAINTEXT:
84         rc = do_plaintext( out, ctb, pkt->pkt.plaintext );
85         break;
86       case PKT_ENCR_DATA:
87         rc = do_encr_data( out, ctb, pkt->pkt.encr_data );
88         break;
89       case PKT_SIGNATURE:
90       case PKT_RING_TRUST:
91       case PKT_COMPR_DATA:
92       default:
93         log_bug("invalid packet type in build_packet()");
94         break;
95     }
96
97     return rc;
98 }
99
100 /****************
101  * calculate the length of a packet described by PKT
102  */
103 u32
104 calc_packet_length( PACKET *pkt )
105 {
106     u32 n=0;
107
108     assert( pkt->pkt.generic );
109     switch( pkt->pkttype ) {
110       case PKT_PLAINTEXT:
111         n = calc_plaintext( pkt->pkt.plaintext );
112         break;
113       case PKT_USER_ID:
114       case PKT_COMMENT:
115       case PKT_PUBKEY_CERT:
116       case PKT_SECKEY_CERT:
117       case PKT_PUBKEY_ENC:
118       case PKT_ENCR_DATA:
119       case PKT_SIGNATURE:
120       case PKT_RING_TRUST:
121       case PKT_COMPR_DATA:
122       default:
123         log_bug("invalid packet type in calc_packet_length()");
124         break;
125     }
126     n += calc_header_length(n);
127     return n;
128 }
129
130
131 static int
132 do_comment( IOBUF out, int ctb, PKT_comment *rem )
133 {
134     write_header(out, ctb, rem->len);
135     if( iobuf_write( out, rem->data, rem->len ) )
136         return G10ERR_WRITE_FILE;
137     return 0;
138 }
139
140 static int
141 do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
142 {
143     write_header(out, ctb, uid->len);
144     if( iobuf_write( out, uid->name, uid->len ) )
145         return G10ERR_WRITE_FILE;
146     return 0;
147 }
148
149 static int
150 do_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pkc )
151 {
152     int rc = 0;
153     IOBUF a = iobuf_temp();
154
155     write_version( a, ctb );
156     write_32(a, pkc->timestamp );
157     write_16(a, pkc->valid_days );
158     iobuf_put(a, pkc->pubkey_algo );
159     if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
160         mpi_encode(a, pkc->d.rsa.rsa_n );
161         mpi_encode(a, pkc->d.rsa.rsa_e );
162     }
163     else {
164         rc = G10ERR_PUBKEY_ALGO;
165         goto leave;
166     }
167
168     write_header(out, ctb, iobuf_get_temp_length(a) );
169     if( iobuf_write_temp( out, a ) )
170         rc = G10ERR_WRITE_FILE;
171
172   leave:
173     iobuf_close(a);
174     return rc;
175 }
176
177 static int
178 do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *skc )
179 {
180     int rc = 0;
181     IOBUF a = iobuf_temp();
182
183     write_version( a, ctb );
184     write_32(a, skc->timestamp );
185     write_16(a, skc->valid_days );
186     iobuf_put(a, skc->pubkey_algo );
187     if( skc->pubkey_algo == PUBKEY_ALGO_RSA ) {
188         mpi_encode(a, skc->d.rsa.rsa_n );
189         mpi_encode(a, skc->d.rsa.rsa_e );
190         iobuf_put(a, skc->d.rsa.protect_algo );
191         skc->d.rsa.calc_csum = 0;
192         if( skc->d.rsa.protect_algo ) {
193             assert( skc->d.rsa.is_protected == 1 );
194             assert( skc->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH );
195             iobuf_write(a, skc->d.rsa.protect.blowfish.iv, 8 );
196
197             mpi_write_csum(a, (byte*)skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum );
198             mpi_write_csum(a, (byte*)skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum );
199             mpi_write_csum(a, (byte*)skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum );
200             mpi_write_csum(a, (byte*)skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum );
201         }
202         else {  /* Not protected: You fool you! */
203             assert( !skc->d.rsa.is_protected );
204             mpi_encode_csum(a, skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum );
205             mpi_encode_csum(a, skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum );
206             mpi_encode_csum(a, skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum );
207             mpi_encode_csum(a, skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum );
208         }
209
210         write_16(a, skc->d.rsa.calc_csum );
211     }
212     else {
213         rc = G10ERR_PUBKEY_ALGO;
214         goto leave;
215     }
216
217     write_header(out, ctb, iobuf_get_temp_length(a) );
218     if( iobuf_write_temp( out, a ) )
219         rc = G10ERR_WRITE_FILE;
220
221   leave:
222     iobuf_close(a);
223     return rc;
224 }
225
226 static int
227 do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
228 {
229     int rc = 0;
230     IOBUF a = iobuf_temp();
231
232     write_version( a, ctb );
233     write_32(a, enc->keyid[0] );
234     write_32(a, enc->keyid[1] );
235     iobuf_put(a,enc->pubkey_algo );
236     if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) {
237         mpi_encode(a, enc->d.rsa.rsa_integer );
238     }
239     else {
240         rc = G10ERR_PUBKEY_ALGO;
241         goto leave;
242     }
243
244     write_header(out, ctb, iobuf_get_temp_length(a) );
245     if( iobuf_write_temp( out, a ) )
246         rc = G10ERR_WRITE_FILE;
247
248   leave:
249     iobuf_close(a);
250     return rc;
251 }
252
253
254 static u32
255 calc_plaintext( PKT_plaintext *pt )
256 {
257     return pt->len? (1 + 1 + pt->namelen + 4 + pt->len) : 0;
258 }
259
260 static int
261 do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
262 {
263     int c, i, rc = 0;
264     u32 n;
265
266     write_header(out, ctb, calc_plaintext( pt ) );
267     iobuf_put(out, pt->mode );
268     iobuf_put(out, pt->namelen );
269     for(i=0; i < pt->namelen; i++ )
270         iobuf_put(out, pt->name[i] );
271     if( write_32(out, pt->timestamp ) )
272         rc = G10ERR_WRITE_FILE;
273
274     n = 0;
275     while( (c=iobuf_get(pt->buf)) != -1 ) {
276         if( iobuf_put(out, c) ) {
277             rc = G10ERR_WRITE_FILE;
278             break;
279         }
280         n++;
281     }
282     if( !pt->len )
283         iobuf_set_block_mode(out, 0 ); /* write end marker */
284     else if( n != pt->len )
285         log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n",
286                         (ulong)n, (ulong)pt->len );
287
288     return rc;
289 }
290
291
292
293 static int
294 do_encr_data( IOBUF out, int ctb, PKT_encr_data *ed )
295 {
296     int rc = 0;
297     u32 n;
298
299     n = ed->len ? (ed->len + 10) : 0;
300     write_header(out, ctb, n );
301
302     /* This is all. The caller has to write the real data */
303
304     return rc;
305 }
306
307
308
309
310 static int
311 write_16(IOBUF out, u16 a)
312 {
313     iobuf_put(out, a>>8);
314     if( iobuf_put(out,a) )
315         return -1;
316     return 0;
317 }
318
319 static int
320 write_32(IOBUF out, u32 a)
321 {
322     iobuf_put(out, a>> 24);
323     iobuf_put(out, a>> 16);
324     iobuf_put(out, a>> 8);
325     if( iobuf_put(out, a) )
326         return -1;
327     return 0;
328 }
329
330
331 /****************
332  * calculate the length of a header
333  */
334 static int
335 calc_header_length( u32 len )
336 {
337     if( !len )
338         return 1; /* only the ctb */
339     else if( len < 256 )
340         return 2;
341     else if( len < 65536 )
342         return 3;
343     else
344         return 5;
345 }
346
347 /****************
348  * Write the CTB and the packet length
349  */
350 static int
351 write_header( IOBUF out, int ctb, u32 len )
352 {
353     if( !len )
354         ctb |= 3;
355     else if( len < 256 )
356         ;
357     else if( len < 65536 )
358         ctb |= 1;
359     else
360         ctb |= 2;
361     if( iobuf_put(out, ctb ) )
362         return -1;
363     if( !len ) {
364         iobuf_set_block_mode(out, 8196 );
365     }
366     else {
367         if( ctb & 2 ) {
368             iobuf_put(out, len >> 24 );
369             iobuf_put(out, len >> 16 );
370         }
371         if( ctb & 3 )
372             iobuf_put(out, len >> 8 );
373         if( iobuf_put(out, len ) )
374             return -1;
375     }
376     return 0;
377 }
378
379 static int
380 write_version( IOBUF out, int ctb )
381 {
382     if( iobuf_put( out, 3 ) )
383         return -1;
384     return 0;
385 }
386