1 /* build-packet.c - assemble packets and write them
2 * Copyright (c) 1997 by Werner Koch (dd9jn)
4 * This file is part of G10.
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.
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.
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
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 );
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 );
53 * Build a packet and write it to INP
56 * Note: Caller must free the packet
59 build_packet( IOBUF out, PACKET *pkt )
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 ) {
69 rc = do_user_id( out, ctb, pkt->pkt.user_id );
72 rc = do_comment( out, ctb, pkt->pkt.comment );
75 rc = do_pubkey_cert( out, ctb, pkt->pkt.pubkey_cert );
78 rc = do_seckey_cert( out, ctb, pkt->pkt.seckey_cert );
81 rc = do_pubkey_enc( out, ctb, pkt->pkt.pubkey_enc );
84 rc = do_plaintext( out, ctb, pkt->pkt.plaintext );
87 rc = do_encr_data( out, ctb, pkt->pkt.encr_data );
93 log_bug("invalid packet type in build_packet()");
101 * calculate the length of a packet described by PKT
104 calc_packet_length( PACKET *pkt )
108 assert( pkt->pkt.generic );
109 switch( pkt->pkttype ) {
111 n = calc_plaintext( pkt->pkt.plaintext );
115 case PKT_PUBKEY_CERT:
116 case PKT_SECKEY_CERT:
123 log_bug("invalid packet type in calc_packet_length()");
126 n += calc_header_length(n);
132 do_comment( IOBUF out, int ctb, PKT_comment *rem )
134 write_header(out, ctb, rem->len);
135 if( iobuf_write( out, rem->data, rem->len ) )
136 return G10ERR_WRITE_FILE;
141 do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
143 write_header(out, ctb, uid->len);
144 if( iobuf_write( out, uid->name, uid->len ) )
145 return G10ERR_WRITE_FILE;
150 do_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pkc )
153 IOBUF a = iobuf_temp();
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 );
164 rc = G10ERR_PUBKEY_ALGO;
168 write_header(out, ctb, iobuf_get_temp_length(a) );
169 if( iobuf_write_temp( out, a ) )
170 rc = G10ERR_WRITE_FILE;
178 do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *skc )
181 IOBUF a = iobuf_temp();
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 );
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 );
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 );
210 write_16(a, skc->d.rsa.calc_csum );
213 rc = G10ERR_PUBKEY_ALGO;
217 write_header(out, ctb, iobuf_get_temp_length(a) );
218 if( iobuf_write_temp( out, a ) )
219 rc = G10ERR_WRITE_FILE;
227 do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
230 IOBUF a = iobuf_temp();
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 );
240 rc = G10ERR_PUBKEY_ALGO;
244 write_header(out, ctb, iobuf_get_temp_length(a) );
245 if( iobuf_write_temp( out, a ) )
246 rc = G10ERR_WRITE_FILE;
255 calc_plaintext( PKT_plaintext *pt )
257 return pt->len? (1 + 1 + pt->namelen + 4 + pt->len) : 0;
261 do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
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;
275 while( (c=iobuf_get(pt->buf)) != -1 ) {
276 if( iobuf_put(out, c) ) {
277 rc = G10ERR_WRITE_FILE;
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 );
294 do_encr_data( IOBUF out, int ctb, PKT_encr_data *ed )
299 n = ed->len ? (ed->len + 10) : 0;
300 write_header(out, ctb, n );
302 /* This is all. The caller has to write the real data */
311 write_16(IOBUF out, u16 a)
313 iobuf_put(out, a>>8);
314 if( iobuf_put(out,a) )
320 write_32(IOBUF out, u32 a)
322 iobuf_put(out, a>> 24);
323 iobuf_put(out, a>> 16);
324 iobuf_put(out, a>> 8);
325 if( iobuf_put(out, a) )
332 * calculate the length of a header
335 calc_header_length( u32 len )
338 return 1; /* only the ctb */
341 else if( len < 65536 )
348 * Write the CTB and the packet length
351 write_header( IOBUF out, int ctb, u32 len )
357 else if( len < 65536 )
361 if( iobuf_put(out, ctb ) )
364 iobuf_set_block_mode(out, 8196 );
368 iobuf_put(out, len >> 24 );
369 iobuf_put(out, len >> 16 );
372 iobuf_put(out, len >> 8 );
373 if( iobuf_put(out, len ) )
380 write_version( IOBUF out, int ctb )
382 if( iobuf_put( out, 3 ) )