aboutsummaryrefslogtreecommitdiffstats
path: root/g10/build-packet.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/build-packet.c')
-rw-r--r--g10/build-packet.c386
1 files changed, 386 insertions, 0 deletions
diff --git a/g10/build-packet.c b/g10/build-packet.c
new file mode 100644
index 000000000..b6e1b6fd4
--- /dev/null
+++ b/g10/build-packet.c
@@ -0,0 +1,386 @@
+/* build-packet.c - assemble packets and write them
+ * Copyright (c) 1997 by Werner Koch (dd9jn)
+ *
+ * This file is part of G10.
+ *
+ * G10 is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * G10 is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "packet.h"
+#include "errors.h"
+#include "iobuf.h"
+#include "mpi.h"
+#include "util.h"
+#include "cipher.h"
+#include "memory.h"
+#include "options.h"
+
+
+static int do_comment( IOBUF out, int ctb, PKT_comment *rem );
+static int do_user_id( IOBUF out, int ctb, PKT_user_id *uid );
+static int do_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pk );
+static int do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *pk );
+static int do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc );
+static u32 calc_plaintext( PKT_plaintext *pt );
+static int do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt );
+static int do_encr_data( IOBUF out, int ctb, PKT_encr_data *ed );
+
+static int calc_header_length( u32 len );
+static int write_16(IOBUF inp, u16 a);
+static int write_32(IOBUF inp, u32 a);
+static int write_header( IOBUF out, int ctb, u32 len );
+static int write_version( IOBUF out, int ctb );
+
+/****************
+ * Build a packet and write it to INP
+ * Returns: 0 := okay
+ * >0 := error
+ * Note: Caller must free the packet
+ */
+int
+build_packet( IOBUF out, PACKET *pkt )
+{
+ int rc=0, ctb;
+
+ if( DBG_PACKET )
+ log_debug("build_packet() type=%d\n", pkt->pkttype );
+ assert( pkt->pkt.generic );
+ ctb = 0x80 | ((pkt->pkttype & 15)<<2);
+ switch( pkt->pkttype ) {
+ case PKT_USER_ID:
+ rc = do_user_id( out, ctb, pkt->pkt.user_id );
+ break;
+ case PKT_COMMENT:
+ rc = do_comment( out, ctb, pkt->pkt.comment );
+ break;
+ case PKT_PUBKEY_CERT:
+ rc = do_pubkey_cert( out, ctb, pkt->pkt.pubkey_cert );
+ break;
+ case PKT_SECKEY_CERT:
+ rc = do_seckey_cert( out, ctb, pkt->pkt.seckey_cert );
+ break;
+ case PKT_PUBKEY_ENC:
+ rc = do_pubkey_enc( out, ctb, pkt->pkt.pubkey_enc );
+ break;
+ case PKT_PLAINTEXT:
+ rc = do_plaintext( out, ctb, pkt->pkt.plaintext );
+ break;
+ case PKT_ENCR_DATA:
+ rc = do_encr_data( out, ctb, pkt->pkt.encr_data );
+ break;
+ case PKT_SIGNATURE:
+ case PKT_RING_TRUST:
+ case PKT_COMPR_DATA:
+ default:
+ log_bug("invalid packet type in build_packet()");
+ break;
+ }
+
+ return rc;
+}
+
+/****************
+ * calculate the length of a packet described by PKT
+ */
+u32
+calc_packet_length( PACKET *pkt )
+{
+ u32 n=0;
+
+ assert( pkt->pkt.generic );
+ switch( pkt->pkttype ) {
+ case PKT_PLAINTEXT:
+ n = calc_plaintext( pkt->pkt.plaintext );
+ break;
+ case PKT_USER_ID:
+ case PKT_COMMENT:
+ case PKT_PUBKEY_CERT:
+ case PKT_SECKEY_CERT:
+ case PKT_PUBKEY_ENC:
+ case PKT_ENCR_DATA:
+ case PKT_SIGNATURE:
+ case PKT_RING_TRUST:
+ case PKT_COMPR_DATA:
+ default:
+ log_bug("invalid packet type in calc_packet_length()");
+ break;
+ }
+ n += calc_header_length(n);
+ return n;
+}
+
+
+static int
+do_comment( IOBUF out, int ctb, PKT_comment *rem )
+{
+ write_header(out, ctb, rem->len);
+ if( iobuf_write( out, rem->data, rem->len ) )
+ return G10ERR_WRITE_FILE;
+ return 0;
+}
+
+static int
+do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
+{
+ write_header(out, ctb, uid->len);
+ if( iobuf_write( out, uid->name, uid->len ) )
+ return G10ERR_WRITE_FILE;
+ return 0;
+}
+
+static int
+do_pubkey_cert( IOBUF out, int ctb, PKT_pubkey_cert *pkc )
+{
+ int rc = 0;
+ IOBUF a = iobuf_temp();
+
+ write_version( a, ctb );
+ write_32(a, pkc->timestamp );
+ write_16(a, pkc->valid_days );
+ iobuf_put(a, pkc->pubkey_algo );
+ if( pkc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_encode(a, pkc->d.rsa.rsa_n );
+ mpi_encode(a, pkc->d.rsa.rsa_e );
+ }
+ else {
+ rc = G10ERR_PUBKEY_ALGO;
+ goto leave;
+ }
+
+ write_header(out, ctb, iobuf_get_temp_length(a) );
+ if( iobuf_write_temp( out, a ) )
+ rc = G10ERR_WRITE_FILE;
+
+ leave:
+ iobuf_close(a);
+ return rc;
+}
+
+static int
+do_seckey_cert( IOBUF out, int ctb, PKT_seckey_cert *skc )
+{
+ int rc = 0;
+ IOBUF a = iobuf_temp();
+
+ write_version( a, ctb );
+ write_32(a, skc->timestamp );
+ write_16(a, skc->valid_days );
+ iobuf_put(a, skc->pubkey_algo );
+ if( skc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_encode(a, skc->d.rsa.rsa_n );
+ mpi_encode(a, skc->d.rsa.rsa_e );
+ iobuf_put(a, skc->d.rsa.protect_algo );
+ skc->d.rsa.calc_csum = 0;
+ if( skc->d.rsa.protect_algo ) {
+ assert( skc->d.rsa.is_protected == 1 );
+ assert( skc->d.rsa.protect_algo == CIPHER_ALGO_BLOWFISH );
+ iobuf_write(a, skc->d.rsa.protect.blowfish.iv, 8 );
+
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum );
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum );
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum );
+ mpi_write_csum(a, (byte*)skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum );
+ }
+ else { /* Not protected: You fool you! */
+ assert( !skc->d.rsa.is_protected );
+ mpi_encode_csum(a, skc->d.rsa.rsa_d, &skc->d.rsa.calc_csum );
+ mpi_encode_csum(a, skc->d.rsa.rsa_p, &skc->d.rsa.calc_csum );
+ mpi_encode_csum(a, skc->d.rsa.rsa_q, &skc->d.rsa.calc_csum );
+ mpi_encode_csum(a, skc->d.rsa.rsa_u, &skc->d.rsa.calc_csum );
+ }
+
+ write_16(a, skc->d.rsa.calc_csum );
+ }
+ else {
+ rc = G10ERR_PUBKEY_ALGO;
+ goto leave;
+ }
+
+ write_header(out, ctb, iobuf_get_temp_length(a) );
+ if( iobuf_write_temp( out, a ) )
+ rc = G10ERR_WRITE_FILE;
+
+ leave:
+ iobuf_close(a);
+ return rc;
+}
+
+static int
+do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
+{
+ int rc = 0;
+ IOBUF a = iobuf_temp();
+
+ write_version( a, ctb );
+ write_32(a, enc->keyid[0] );
+ write_32(a, enc->keyid[1] );
+ iobuf_put(a,enc->pubkey_algo );
+ if( enc->pubkey_algo == PUBKEY_ALGO_RSA ) {
+ mpi_encode(a, enc->d.rsa.rsa_integer );
+ }
+ else {
+ rc = G10ERR_PUBKEY_ALGO;
+ goto leave;
+ }
+
+ write_header(out, ctb, iobuf_get_temp_length(a) );
+ if( iobuf_write_temp( out, a ) )
+ rc = G10ERR_WRITE_FILE;
+
+ leave:
+ iobuf_close(a);
+ return rc;
+}
+
+
+static u32
+calc_plaintext( PKT_plaintext *pt )
+{
+ return pt->len? (1 + 1 + pt->namelen + 4 + pt->len) : 0;
+}
+
+static int
+do_plaintext( IOBUF out, int ctb, PKT_plaintext *pt )
+{
+ int c, i, rc = 0;
+ u32 n;
+
+ write_header(out, ctb, calc_plaintext( pt ) );
+ iobuf_put(out, pt->mode );
+ iobuf_put(out, pt->namelen );
+ for(i=0; i < pt->namelen; i++ )
+ iobuf_put(out, pt->name[i] );
+ if( write_32(out, pt->timestamp ) )
+ rc = G10ERR_WRITE_FILE;
+
+ n = 0;
+ while( (c=iobuf_get(pt->buf)) != -1 ) {
+ if( iobuf_put(out, c) ) {
+ rc = G10ERR_WRITE_FILE;
+ break;
+ }
+ n++;
+ }
+ if( !pt->len )
+ iobuf_set_block_mode(out, 0 ); /* write end marker */
+ else if( n != pt->len )
+ log_error("do_plaintext(): wrote %lu bytes but expected %lu bytes\n",
+ (ulong)n, (ulong)pt->len );
+
+ return rc;
+}
+
+
+
+static int
+do_encr_data( IOBUF out, int ctb, PKT_encr_data *ed )
+{
+ int rc = 0;
+ u32 n;
+
+ n = ed->len ? (ed->len + 10) : 0;
+ write_header(out, ctb, n );
+
+ /* This is all. The caller has to write the real data */
+
+ return rc;
+}
+
+
+
+
+static int
+write_16(IOBUF out, u16 a)
+{
+ iobuf_put(out, a>>8);
+ if( iobuf_put(out,a) )
+ return -1;
+ return 0;
+}
+
+static int
+write_32(IOBUF out, u32 a)
+{
+ iobuf_put(out, a>> 24);
+ iobuf_put(out, a>> 16);
+ iobuf_put(out, a>> 8);
+ if( iobuf_put(out, a) )
+ return -1;
+ return 0;
+}
+
+
+/****************
+ * calculate the length of a header
+ */
+static int
+calc_header_length( u32 len )
+{
+ if( !len )
+ return 1; /* only the ctb */
+ else if( len < 256 )
+ return 2;
+ else if( len < 65536 )
+ return 3;
+ else
+ return 5;
+}
+
+/****************
+ * Write the CTB and the packet length
+ */
+static int
+write_header( IOBUF out, int ctb, u32 len )
+{
+ if( !len )
+ ctb |= 3;
+ else if( len < 256 )
+ ;
+ else if( len < 65536 )
+ ctb |= 1;
+ else
+ ctb |= 2;
+ if( iobuf_put(out, ctb ) )
+ return -1;
+ if( !len ) {
+ iobuf_set_block_mode(out, 5 /*8196*/ );
+ }
+ else {
+ if( ctb & 2 ) {
+ iobuf_put(out, len >> 24 );
+ iobuf_put(out, len >> 16 );
+ }
+ if( ctb & 3 )
+ iobuf_put(out, len >> 8 );
+ if( iobuf_put(out, len ) )
+ return -1;
+ }
+ return 0;
+}
+
+static int
+write_version( IOBUF out, int ctb )
+{
+ if( iobuf_put( out, 3 ) )
+ return -1;
+ return 0;
+}
+