1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-11-04 20:38:50 +01:00
gnupg/g10/build-packet.c

1133 lines
28 KiB
C
Raw Normal View History

1997-11-18 15:06:00 +01:00
/* build-packet.c - assemble packets and write them
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
* 2003 Free Software Foundation, Inc.
1997-11-18 15:06:00 +01:00
*
* This file is part of GnuPG.
1997-11-18 15:06:00 +01:00
*
* GnuPG is free software; you can redistribute it and/or modify
1997-11-18 15:06:00 +01:00
* 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.
*
* GnuPG is distributed in the hope that it will be useful,
1997-11-18 15:06:00 +01:00
* 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"
2002-06-29 15:46:34 +02:00
#include "mpi.h"
1997-11-18 15:06:00 +01:00
#include "util.h"
2002-06-29 15:46:34 +02:00
#include "cipher.h"
#include "memory.h"
1997-11-18 15:06:00 +01:00
#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 );
1998-06-29 14:30:57 +02:00
static int do_public_key( IOBUF out, int ctb, PKT_public_key *pk );
static int do_secret_key( IOBUF out, int ctb, PKT_secret_key *pk );
1998-05-03 17:42:08 +02:00
static int do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc );
1997-11-18 15:06:00 +01:00
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 );
1997-12-01 11:33:23 +01:00
static int do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed );
static int do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed );
1997-11-23 16:38:27 +01:00
static int do_compressed( IOBUF out, int ctb, PKT_compressed *cd );
1997-11-24 12:04:11 +01:00
static int do_signature( IOBUF out, int ctb, PKT_signature *sig );
1997-12-02 20:36:53 +01:00
static int do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops );
1997-11-18 15:06:00 +01:00
1998-09-11 07:47:32 +02:00
static int calc_header_length( u32 len, int new_ctb );
1997-11-18 15:06:00 +01:00
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 );
1998-07-29 21:35:05 +02:00
static int write_sign_packet_header( IOBUF out, int ctb, u32 len );
1998-01-16 22:15:24 +01:00
static int write_header2( IOBUF out, int ctb, u32 len, int hdrlen, int blkmode );
static int write_new_header( IOBUF out, int ctb, u32 len, int hdrlen );
1997-11-18 15:06:00 +01:00
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 new_ctb=0, rc=0, ctb;
int pkttype;
1997-11-18 15:06:00 +01:00
if( DBG_PACKET )
log_debug("build_packet() type=%d\n", pkt->pkttype );
assert( pkt->pkt.generic );
switch( (pkttype = pkt->pkttype) ) {
case PKT_OLD_COMMENT: pkttype = pkt->pkttype = PKT_COMMENT; break;
case PKT_PLAINTEXT: new_ctb = pkt->pkt.plaintext->new_ctb; break;
case PKT_ENCRYPTED:
case PKT_ENCRYPTED_MDC: new_ctb = pkt->pkt.encrypted->new_ctb; break;
case PKT_COMPRESSED:new_ctb = pkt->pkt.compressed->new_ctb; break;
case PKT_USER_ID:
2002-06-29 15:46:34 +02:00
if( pkt->pkt.user_id->attrib_data )
pkttype = PKT_ATTRIBUTE;
break;
default: break;
}
if( new_ctb || pkttype > 15 ) /* new format */
ctb = 0xc0 | (pkttype & 0x3f);
1998-01-16 22:15:24 +01:00
else
ctb = 0x80 | ((pkttype & 15)<<2);
switch( pkttype ) {
2002-06-29 15:46:34 +02:00
case PKT_ATTRIBUTE:
1997-11-18 15:06:00 +01:00
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;
1998-06-29 14:30:57 +02:00
case PKT_PUBLIC_SUBKEY:
case PKT_PUBLIC_KEY:
rc = do_public_key( out, ctb, pkt->pkt.public_key );
1997-11-18 15:06:00 +01:00
break;
1998-06-29 14:30:57 +02:00
case PKT_SECRET_SUBKEY:
case PKT_SECRET_KEY:
rc = do_secret_key( out, ctb, pkt->pkt.secret_key );
1997-11-18 15:06:00 +01:00
break;
1998-05-03 17:42:08 +02:00
case PKT_SYMKEY_ENC:
rc = do_symkey_enc( out, ctb, pkt->pkt.symkey_enc );
break;
1997-11-18 15:06:00 +01:00
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;
1997-12-01 11:33:23 +01:00
case PKT_ENCRYPTED:
rc = do_encrypted( out, ctb, pkt->pkt.encrypted );
1997-11-18 15:06:00 +01:00
break;
case PKT_ENCRYPTED_MDC:
rc = do_encrypted_mdc( out, ctb, pkt->pkt.encrypted );
break;
1997-12-01 11:33:23 +01:00
case PKT_COMPRESSED:
1997-11-23 16:38:27 +01:00
rc = do_compressed( out, ctb, pkt->pkt.compressed );
break;
1997-11-18 15:06:00 +01:00
case PKT_SIGNATURE:
1997-11-24 12:04:11 +01:00
rc = do_signature( out, ctb, pkt->pkt.signature );
break;
1997-12-02 20:36:53 +01:00
case PKT_ONEPASS_SIG:
rc = do_onepass_sig( out, ctb, pkt->pkt.onepass_sig );
break;
1997-11-18 15:06:00 +01:00
case PKT_RING_TRUST:
2002-06-29 15:46:34 +02:00
break; /* ignore it (keyring.c does write it directly)*/
case PKT_MDC: /* we write it directly, so we should never see it here. */
1997-11-18 15:06:00 +01:00
default:
1998-05-03 21:35:33 +02:00
log_bug("invalid packet type in build_packet()\n");
1997-11-18 15:06:00 +01:00
break;
}
return rc;
}
/****************
* calculate the length of a packet described by PKT
*/
u32
calc_packet_length( PACKET *pkt )
{
u32 n=0;
1998-09-11 07:47:32 +02:00
int new_ctb = 0;
1997-11-18 15:06:00 +01:00
assert( pkt->pkt.generic );
switch( pkt->pkttype ) {
case PKT_PLAINTEXT:
n = calc_plaintext( pkt->pkt.plaintext );
1998-09-11 07:47:32 +02:00
new_ctb = pkt->pkt.plaintext->new_ctb;
1997-11-18 15:06:00 +01:00
break;
2002-06-29 15:46:34 +02:00
case PKT_ATTRIBUTE:
1997-11-18 15:06:00 +01:00
case PKT_USER_ID:
case PKT_COMMENT:
1998-06-29 14:30:57 +02:00
case PKT_PUBLIC_KEY:
case PKT_SECRET_KEY:
1998-05-03 17:42:08 +02:00
case PKT_SYMKEY_ENC:
1997-11-18 15:06:00 +01:00
case PKT_PUBKEY_ENC:
1997-12-01 11:33:23 +01:00
case PKT_ENCRYPTED:
1997-11-18 15:06:00 +01:00
case PKT_SIGNATURE:
1997-12-02 20:36:53 +01:00
case PKT_ONEPASS_SIG:
1997-11-18 15:06:00 +01:00
case PKT_RING_TRUST:
1997-12-01 11:33:23 +01:00
case PKT_COMPRESSED:
1997-11-18 15:06:00 +01:00
default:
log_bug("invalid packet type in calc_packet_length()");
break;
}
1998-09-11 07:47:32 +02:00
n += calc_header_length(n, new_ctb);
1997-11-18 15:06:00 +01:00
return n;
}
static void
write_fake_data( IOBUF out, MPI a )
{
if( a ) {
unsigned int i;
void *p;
p = mpi_get_opaque( a, &i );
iobuf_write( out, p, i );
}
}
1997-11-18 15:06:00 +01:00
static int
do_comment( IOBUF out, int ctb, PKT_comment *rem )
{
2002-06-29 15:46:34 +02:00
if( opt.sk_comments ) {
1998-01-24 17:32:27 +01:00
write_header(out, ctb, rem->len);
if( iobuf_write( out, rem->data, rem->len ) )
2002-06-29 15:46:34 +02:00
return G10ERR_WRITE_FILE;
1998-01-24 17:32:27 +01:00
}
1997-11-18 15:06:00 +01:00
return 0;
}
static int
do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
{
2002-06-29 15:46:34 +02:00
if( uid->attrib_data ) {
write_header(out, ctb, uid->attrib_len);
if( iobuf_write( out, uid->attrib_data, uid->attrib_len ) )
return G10ERR_WRITE_FILE;
}
else {
write_header(out, ctb, uid->len);
if( iobuf_write( out, uid->name, uid->len ) )
2002-06-29 15:46:34 +02:00
return G10ERR_WRITE_FILE;
}
1997-11-18 15:06:00 +01:00
return 0;
}
static int
1998-06-29 14:30:57 +02:00
do_public_key( IOBUF out, int ctb, PKT_public_key *pk )
1997-11-18 15:06:00 +01:00
{
int rc = 0;
1998-06-13 08:59:14 +02:00
int n, i;
1997-11-18 15:06:00 +01:00
IOBUF a = iobuf_temp();
1998-06-29 14:30:57 +02:00
if( !pk->version )
1998-01-16 22:15:24 +01:00
iobuf_put( a, 3 );
else
1998-06-29 14:30:57 +02:00
iobuf_put( a, pk->version );
write_32(a, pk->timestamp );
1998-10-16 18:00:17 +02:00
if( pk->version < 4 ) {
u16 ndays;
if( pk->expiredate )
ndays = (u16)((pk->expiredate - pk->timestamp) / 86400L);
else
ndays = 0;
1998-10-18 17:21:22 +02:00
write_16(a, ndays );
1998-10-16 18:00:17 +02:00
}
1998-06-29 14:30:57 +02:00
iobuf_put(a, pk->pubkey_algo );
n = pubkey_get_npkey( pk->pubkey_algo );
if( !n )
write_fake_data( a, pk->pkey[0] );
1998-06-13 08:59:14 +02:00
for(i=0; i < n; i++ )
1998-06-29 14:30:57 +02:00
mpi_write(a, pk->pkey[i] );
1997-11-18 15:06:00 +01:00
1998-06-29 14:30:57 +02:00
write_header2(out, ctb, iobuf_get_temp_length(a), pk->hdrbytes, 1 );
1997-11-18 15:06:00 +01:00
if( iobuf_write_temp( out, a ) )
2002-06-29 15:46:34 +02:00
rc = G10ERR_WRITE_FILE;
1997-11-18 15:06:00 +01:00
iobuf_close(a);
return rc;
}
1997-12-09 13:46:23 +01:00
1997-11-18 15:06:00 +01:00
static int
1998-06-29 14:30:57 +02:00
do_secret_key( IOBUF out, int ctb, PKT_secret_key *sk )
1997-11-18 15:06:00 +01:00
{
int rc = 0;
1998-06-13 08:59:14 +02:00
int i, nskey, npkey;
2002-06-29 15:46:34 +02:00
IOBUF a = iobuf_temp(); /* build in a self-enlarging buffer */
1997-11-18 15:06:00 +01:00
2002-06-29 15:46:34 +02:00
/* Write the version number - if none is specified, use 3 */
1998-06-29 14:30:57 +02:00
if( !sk->version )
1998-01-16 22:15:24 +01:00
iobuf_put( a, 3 );
else
1998-06-29 14:30:57 +02:00
iobuf_put( a, sk->version );
write_32(a, sk->timestamp );
2002-06-29 15:46:34 +02:00
/* v3 needs the expiration time */
1998-10-16 18:00:17 +02:00
if( sk->version < 4 ) {
u16 ndays;
if( sk->expiredate )
ndays = (u16)((sk->expiredate - sk->timestamp) / 86400L);
else
ndays = 0;
2002-06-29 15:46:34 +02:00
write_16(a, ndays);
1998-10-16 18:00:17 +02:00
}
2002-06-29 15:46:34 +02:00
1998-06-29 14:30:57 +02:00
iobuf_put(a, sk->pubkey_algo );
2002-06-29 15:46:34 +02:00
/* get number of secret and public parameters. They are held in
one array first the public ones, then the secret ones */
1998-06-29 14:30:57 +02:00
nskey = pubkey_get_nskey( sk->pubkey_algo );
npkey = pubkey_get_npkey( sk->pubkey_algo );
2002-06-29 15:46:34 +02:00
/* If we don't have any public parameters - which is the case if
we don't know the algorithm used - the parameters are stored as
one blob in a faked (opaque) MPI */
1998-07-06 12:23:57 +02:00
if( !npkey ) {
write_fake_data( a, sk->skey[0] );
goto leave;
}
1998-06-13 08:59:14 +02:00
assert( npkey < nskey );
2002-06-29 15:46:34 +02:00
/* Writing the public parameters is easy */
1998-06-13 08:59:14 +02:00
for(i=0; i < npkey; i++ )
1998-06-29 14:30:57 +02:00
mpi_write(a, sk->skey[i] );
2002-06-29 15:46:34 +02:00
/* build the header for protected (encrypted) secret parameters */
1998-06-29 14:30:57 +02:00
if( sk->is_protected ) {
1998-08-11 19:29:34 +02:00
if( is_RSA(sk->pubkey_algo) && sk->version < 4
&& !sk->protect.s2k.mode ) {
2002-06-29 15:46:34 +02:00
/* the simple rfc1991 (v3) way */
1998-06-29 14:30:57 +02:00
iobuf_put(a, sk->protect.algo );
iobuf_write(a, sk->protect.iv, sk->protect.ivlen );
1997-11-24 23:24:04 +01:00
}
1998-06-13 08:59:14 +02:00
else {
2002-06-29 15:46:34 +02:00
/* OpenPGP protection according to rfc2440 */
iobuf_put(a, sk->protect.sha1chk? 0xfe : 0xff );
1998-06-29 14:30:57 +02:00
iobuf_put(a, sk->protect.algo );
if( sk->protect.s2k.mode >= 1000 ) {
2002-06-29 15:46:34 +02:00
/* These modes are not possible in OpenPGP, we use them
to implement our extensions, 101 can be seen as a
2002-06-29 15:46:34 +02:00
private/experimental extension (this is not
specified in rfc2440 but the same scheme is used
for all other algorithm identifiers) */
iobuf_put(a, 101 );
iobuf_put(a, sk->protect.s2k.hash_algo );
iobuf_write(a, "GNU", 3 );
iobuf_put(a, sk->protect.s2k.mode - 1000 );
}
else {
iobuf_put(a, sk->protect.s2k.mode );
iobuf_put(a, sk->protect.s2k.hash_algo );
}
1998-06-29 14:30:57 +02:00
if( sk->protect.s2k.mode == 1
1998-08-05 18:51:59 +02:00
|| sk->protect.s2k.mode == 3 )
1998-06-29 14:30:57 +02:00
iobuf_write(a, sk->protect.s2k.salt, 8 );
1998-08-05 18:51:59 +02:00
if( sk->protect.s2k.mode == 3 )
2002-06-29 15:46:34 +02:00
iobuf_put(a, sk->protect.s2k.count );
/* For out special modes 1001, 1002 we do not need an IV */
if( sk->protect.s2k.mode != 1001
&& sk->protect.s2k.mode != 1002 )
iobuf_write(a, sk->protect.iv, sk->protect.ivlen );
1998-05-05 22:34:20 +02:00
}
1997-11-18 15:06:00 +01:00
}
1998-06-13 08:59:14 +02:00
else
iobuf_put(a, 0 );
2002-06-29 15:46:34 +02:00
if( sk->protect.s2k.mode == 1001 )
2002-06-29 15:46:34 +02:00
; /* GnuPG extension - don't write a secret key at all */
else if( sk->protect.s2k.mode == 1002 )
{ /* GnuPG extension - divert to OpenPGP smartcard. */
iobuf_put(a, sk->protect.ivlen ); /* length of the serial
number or 0 for no serial
number. */
/* The serial number gets stored in the IV field. */
iobuf_write(a, sk->protect.iv, sk->protect.ivlen);
}
else if( sk->is_protected && sk->version >= 4 ) {
2002-06-29 15:46:34 +02:00
/* The secret key is protected - write it out as it is */
1998-08-08 21:27:00 +02:00
byte *p;
unsigned int ndata;
2002-06-29 15:46:34 +02:00
assert( mpi_is_opaque( sk->skey[npkey] ) );
p = mpi_get_opaque( sk->skey[npkey], &ndata );
iobuf_write(a, p, ndata );
1998-08-05 18:51:59 +02:00
}
else if( sk->is_protected ) {
/* The secret key is protected te old v4 way. */
for( ; i < nskey; i++ ) {
byte *p;
unsigned int ndata;
assert (mpi_is_opaque (sk->skey[i]));
p = mpi_get_opaque (sk->skey[i], &ndata);
iobuf_write (a, p, ndata);
}
write_16(a, sk->csum );
}
1998-08-05 18:51:59 +02:00
else {
/* non-protected key */
1998-08-05 18:51:59 +02:00
for( ; i < nskey; i++ )
mpi_write(a, sk->skey[i] );
1998-08-05 18:51:59 +02:00
write_16(a, sk->csum );
}
1997-11-18 15:06:00 +01:00
leave:
2002-06-29 15:46:34 +02:00
/* Build the header of the packet - which we must do after writing all
the other stuff, so that we know the length of the packet */
1998-06-29 14:30:57 +02:00
write_header2(out, ctb, iobuf_get_temp_length(a), sk->hdrbytes, 1 );
2002-06-29 15:46:34 +02:00
/* And finally write it out the real stream */
1997-11-18 15:06:00 +01:00
if( iobuf_write_temp( out, a ) )
2002-06-29 15:46:34 +02:00
rc = G10ERR_WRITE_FILE;
1997-11-18 15:06:00 +01:00
2002-06-29 15:46:34 +02:00
iobuf_close(a); /* close the remporary buffer */
1997-11-18 15:06:00 +01:00
return rc;
}
1998-05-03 17:42:08 +02:00
static int
do_symkey_enc( IOBUF out, int ctb, PKT_symkey_enc *enc )
{
int rc = 0;
IOBUF a = iobuf_temp();
assert( enc->version == 4 );
switch( enc->s2k.mode ) {
1998-08-05 18:51:59 +02:00
case 0: case 1: case 3: break;
1998-05-03 17:42:08 +02:00
default: log_bug("do_symkey_enc: s2k=%d\n", enc->s2k.mode );
}
iobuf_put( a, enc->version );
iobuf_put( a, enc->cipher_algo );
iobuf_put( a, enc->s2k.mode );
iobuf_put( a, enc->s2k.hash_algo );
1998-08-05 18:51:59 +02:00
if( enc->s2k.mode == 1 || enc->s2k.mode == 3 ) {
1998-05-03 17:42:08 +02:00
iobuf_write(a, enc->s2k.salt, 8 );
1998-08-05 18:51:59 +02:00
if( enc->s2k.mode == 3 )
iobuf_put(a, enc->s2k.count);
1998-05-03 17:42:08 +02:00
}
if( enc->seskeylen )
iobuf_write(a, enc->seskey, enc->seskeylen );
write_header(out, ctb, iobuf_get_temp_length(a) );
if( iobuf_write_temp( out, a ) )
2002-06-29 15:46:34 +02:00
rc = G10ERR_WRITE_FILE;
1998-05-03 17:42:08 +02:00
iobuf_close(a);
return rc;
}
1997-11-18 15:06:00 +01:00
static int
do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
{
int rc = 0;
1998-06-13 08:59:14 +02:00
int n, i;
1997-11-18 15:06:00 +01:00
IOBUF a = iobuf_temp();
write_version( a, ctb );
1998-09-11 07:47:32 +02:00
if( enc->throw_keyid ) {
write_32(a, 0 ); /* don't tell Eve who can decrypt the message */
write_32(a, 0 );
}
else {
write_32(a, enc->keyid[0] );
write_32(a, enc->keyid[1] );
}
1997-11-18 15:06:00 +01:00
iobuf_put(a,enc->pubkey_algo );
1998-06-13 08:59:14 +02:00
n = pubkey_get_nenc( enc->pubkey_algo );
if( !n )
write_fake_data( a, enc->data[0] );
1998-06-13 08:59:14 +02:00
for(i=0; i < n; i++ )
mpi_write(a, enc->data[i] );
1997-11-18 15:06:00 +01:00
write_header(out, ctb, iobuf_get_temp_length(a) );
if( iobuf_write_temp( out, a ) )
2002-06-29 15:46:34 +02:00
rc = G10ERR_WRITE_FILE;
1997-11-18 15:06:00 +01:00
iobuf_close(a);
return rc;
}
1997-11-24 12:04:11 +01:00
1997-11-18 15:06:00 +01:00
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 )
{
1998-05-04 20:49:26 +02:00
int i, rc = 0;
1997-11-18 15:06:00 +01:00
u32 n;
byte buf[1000]; /* this buffer has the plaintext! */
1998-05-04 20:49:26 +02:00
int nbytes;
1997-11-18 15:06:00 +01:00
/* Truncate namelen to the maximum 255 characters. This does mean
that a function that calls build_packet with an illegal literal
packet will get it back legalized. */
if(pt->namelen>255)
pt->namelen=255;
1997-11-18 15:06:00 +01:00
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 ) )
2002-06-29 15:46:34 +02:00
rc = G10ERR_WRITE_FILE;
1997-11-18 15:06:00 +01:00
n = 0;
1998-05-04 20:49:26 +02:00
while( (nbytes=iobuf_read(pt->buf, buf, 1000)) != -1 ) {
if( iobuf_write(out, buf, nbytes) == -1 ) {
2002-06-29 15:46:34 +02:00
rc = G10ERR_WRITE_FILE;
1997-11-18 15:06:00 +01:00
break;
}
1998-05-04 20:49:26 +02:00
n += nbytes;
1997-11-18 15:06:00 +01:00
}
wipememory(buf,1000); /* burn the buffer */
1997-11-18 15:06:00 +01:00
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
1997-12-01 11:33:23 +01:00
do_encrypted( IOBUF out, int ctb, PKT_encrypted *ed )
1997-11-18 15:06:00 +01:00
{
int rc = 0;
u32 n;
2002-06-29 15:46:34 +02:00
n = ed->len ? (ed->len + ed->extralen) : 0;
1997-11-18 15:06:00 +01:00
write_header(out, ctb, n );
/* This is all. The caller has to write the real data */
return rc;
}
static int
do_encrypted_mdc( IOBUF out, int ctb, PKT_encrypted *ed )
{
int rc = 0;
u32 n;
assert( ed->mdc_method );
/* Take version number and the following MDC packet in account. */
n = ed->len ? (ed->len + ed->extralen + 1 + 22) : 0;
write_header(out, ctb, n );
iobuf_put(out, 1 ); /* version */
/* This is all. The caller has to write the real data */
return rc;
}
1997-11-23 16:38:27 +01:00
static int
do_compressed( IOBUF out, int ctb, PKT_compressed *cd )
{
int rc = 0;
/* We must use the old convention and don't use blockmode for tyhe
sake of PGP 2 compatibility. However if the new_ctb flag was
set, CTB is already formatted as new style and write_header2
does create a partial length encoding using new the new
style. */
1998-01-16 22:15:24 +01:00
write_header2(out, ctb, 0, 0, 0 );
1997-11-23 16:38:27 +01:00
iobuf_put(out, cd->algorithm );
/* This is all. The caller has to write the real data */
return rc;
}
1997-11-18 15:06:00 +01:00
1998-05-13 19:53:36 +02:00
/****************
2002-06-29 15:46:34 +02:00
* Delete all subpackets of type REQTYPE and return a bool whether a packet
* was deleted.
1998-05-13 19:53:36 +02:00
*/
2002-06-29 15:46:34 +02:00
int
delete_sig_subpkt (subpktarea_t *area, sigsubpkttype_t reqtype )
1998-05-13 19:53:36 +02:00
{
int buflen;
sigsubpkttype_t type;
2002-06-29 15:46:34 +02:00
byte *buffer, *bufstart;
1998-05-13 19:53:36 +02:00
size_t n;
2002-06-29 15:46:34 +02:00
size_t unused = 0;
int okay = 0;
1998-05-13 19:53:36 +02:00
2002-06-29 15:46:34 +02:00
if( !area )
return 0;
buflen = area->len;
buffer = area->data;
1998-05-13 19:53:36 +02:00
for(;;) {
2002-06-29 15:46:34 +02:00
if( !buflen ) {
okay = 1;
break;
}
1998-05-13 19:53:36 +02:00
bufstart = buffer;
n = *buffer++; buflen--;
if( n == 255 ) {
if( buflen < 4 )
break;
n = (buffer[0] << 24) | (buffer[1] << 16)
2002-06-29 15:46:34 +02:00
| (buffer[2] << 8) | buffer[3];
1998-05-13 19:53:36 +02:00
buffer += 4;
buflen -= 4;
}
else if( n >= 192 ) {
if( buflen < 2 )
break;
n = (( n - 192 ) << 8) + *buffer + 192;
buffer++;
1998-05-13 19:53:36 +02:00
buflen--;
}
if( buflen < n )
break;
2002-06-29 15:46:34 +02:00
1998-05-13 19:53:36 +02:00
type = *buffer & 0x7f;
if( type == reqtype ) {
buffer++;
2002-06-29 15:46:34 +02:00
buflen--;
1998-05-13 19:53:36 +02:00
n--;
if( n > buflen )
break;
2002-06-29 15:46:34 +02:00
buffer += n; /* point to next subpkt */
buflen -= n;
memmove (bufstart, buffer, buflen); /* shift */
unused += buffer - bufstart;
buffer = bufstart;
1998-05-13 19:53:36 +02:00
}
2002-06-29 15:46:34 +02:00
else {
buffer += n; buflen -=n;
}
1998-05-13 19:53:36 +02:00
}
2002-06-29 15:46:34 +02:00
if (!okay)
log_error ("delete_subpkt: buffer shorter than subpacket\n");
assert (unused <= area->len);
area->len -= unused;
return !!unused;
1998-05-13 19:53:36 +02:00
}
/****************
2002-06-29 15:46:34 +02:00
* Create or update a signature subpacket for SIG of TYPE. This
* functions knows where to put the data (hashed or unhashed). The
* function may move data from the unhashed part to the hashed one.
* Note: All pointers into sig->[un]hashed (e.g. returned by
* parse_sig_subpkt) are not valid after a call to this function. The
* data to put into the subpaket should be in a buffer with a length
* of buflen.
1998-05-13 19:53:36 +02:00
*/
void
2002-06-29 15:46:34 +02:00
build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
1998-05-13 19:53:36 +02:00
const byte *buffer, size_t buflen )
{
2002-06-29 15:46:34 +02:00
byte *p;
int critical, hashed;
subpktarea_t *oldarea, *newarea;
size_t nlen, n, n0;
1998-05-13 19:53:36 +02:00
critical = (type & SIGSUBPKT_FLAG_CRITICAL);
type &= ~SIGSUBPKT_FLAG_CRITICAL;
2002-06-29 15:46:34 +02:00
/* Sanity check buffer sizes */
if(parse_one_sig_subpkt(buffer,buflen,type)<0)
BUG();
switch(type)
{
case SIGSUBPKT_NOTATION:
case SIGSUBPKT_POLICY:
case SIGSUBPKT_REV_KEY:
/* we do allow multiple subpackets */
break;
default:
/* we don't allow multiple subpackets */
delete_sig_subpkt(sig->hashed,type);
delete_sig_subpkt(sig->unhashed,type);
break;
}
/* Any special magic that needs to be done for this type so the
packet doesn't need to be reparsed? */
switch(type)
{
case SIGSUBPKT_NOTATION:
sig->flags.notation=1;
break;
case SIGSUBPKT_POLICY:
sig->flags.policy_url=1;
break;
case SIGSUBPKT_PREF_KS:
sig->flags.pref_ks=1;
break;
2002-06-29 15:46:34 +02:00
case SIGSUBPKT_EXPORTABLE:
if(buffer[0])
sig->flags.exportable=1;
else
sig->flags.exportable=0;
break;
case SIGSUBPKT_REVOCABLE:
if(buffer[0])
sig->flags.revocable=1;
else
sig->flags.revocable=0;
break;
case SIGSUBPKT_TRUST:
sig->trust_depth=buffer[0];
sig->trust_value=buffer[1];
break;
case SIGSUBPKT_REGEXP:
sig->trust_regexp=buffer;
break;
/* This should never happen since we don't currently allow
creating such a subpacket, but just in case... */
case SIGSUBPKT_SIG_EXPIRE:
if(buffer_to_u32(buffer)+sig->timestamp<=make_timestamp())
sig->flags.expired=1;
else
sig->flags.expired=0;
break;
2002-06-29 15:46:34 +02:00
default:
break;
}
1998-05-13 19:53:36 +02:00
if( (buflen+1) >= 8384 )
2002-06-29 15:46:34 +02:00
nlen = 5; /* write 5 byte length header */
else if( (buflen+1) >= 192 )
2002-06-29 15:46:34 +02:00
nlen = 2; /* write 2 byte length header */
else
2002-06-29 15:46:34 +02:00
nlen = 1; /* just a 1 byte length header */
1998-05-13 19:53:36 +02:00
switch( type ) {
/* The issuer being unhashed is a historical oddity. It
should work equally as well hashed. Of course, if even an
unhashed issuer is tampered with, it makes it awfully hard
to verify the sig... */
case SIGSUBPKT_ISSUER:
2002-06-29 15:46:34 +02:00
hashed = 0;
break;
default:
hashed = 1;
break;
1998-05-13 19:53:36 +02:00
}
if( critical )
type |= SIGSUBPKT_FLAG_CRITICAL;
2002-06-29 15:46:34 +02:00
oldarea = hashed? sig->hashed : sig->unhashed;
/* Calculate new size of the area and allocate */
n0 = oldarea? oldarea->len : 0;
n = n0 + nlen + 1 + buflen; /* length, type, buffer */
if (oldarea && n <= oldarea->size) { /* fits into the unused space */
newarea = oldarea;
/*log_debug ("updating area for type %d\n", type );*/
}
else if (oldarea) {
newarea = m_realloc (oldarea, sizeof (*newarea) + n - 1);
newarea->size = n;
/*log_debug ("reallocating area for type %d\n", type );*/
}
else {
2002-06-29 15:46:34 +02:00
newarea = m_alloc (sizeof (*newarea) + n - 1);
newarea->size = n;
/*log_debug ("allocating area for type %d\n", type );*/
}
2002-06-29 15:46:34 +02:00
newarea->len = n;
p = newarea->data + n0;
if (nlen == 5) {
*p++ = 255;
*p++ = (buflen+1) >> 24;
*p++ = (buflen+1) >> 16;
*p++ = (buflen+1) >> 8;
*p++ = (buflen+1);
*p++ = type;
memcpy (p, buffer, buflen);
}
else if (nlen == 2) {
*p++ = (buflen+1-192) / 256 + 192;
*p++ = (buflen+1-192) % 256;
*p++ = type;
memcpy (p, buffer, buflen);
1998-05-13 19:53:36 +02:00
}
else {
2002-06-29 15:46:34 +02:00
*p++ = buflen+1;
*p++ = type;
memcpy (p, buffer, buflen);
1998-05-13 19:53:36 +02:00
}
2002-06-29 15:46:34 +02:00
if (hashed)
sig->hashed = newarea;
else
sig->unhashed = newarea;
1998-05-13 19:53:36 +02:00
}
/****************
* Put all the required stuff from SIG into subpackets of sig.
2002-06-29 15:46:34 +02:00
* Hmmm, should we delete those subpackets which are in a wrong area?
1998-05-13 19:53:36 +02:00
*/
void
build_sig_subpkt_from_sig( PKT_signature *sig )
{
u32 u;
byte buf[8];
u = sig->keyid[0];
buf[0] = (u >> 24) & 0xff;
buf[1] = (u >> 16) & 0xff;
buf[2] = (u >> 8) & 0xff;
buf[3] = u & 0xff;
u = sig->keyid[1];
buf[4] = (u >> 24) & 0xff;
buf[5] = (u >> 16) & 0xff;
buf[6] = (u >> 8) & 0xff;
buf[7] = u & 0xff;
build_sig_subpkt( sig, SIGSUBPKT_ISSUER, buf, 8 );
u = sig->timestamp;
buf[0] = (u >> 24) & 0xff;
buf[1] = (u >> 16) & 0xff;
buf[2] = (u >> 8) & 0xff;
buf[3] = u & 0xff;
build_sig_subpkt( sig, SIGSUBPKT_SIG_CREATED, buf, 4 );
2002-06-29 15:46:34 +02:00
if(sig->expiredate)
{
if(sig->expiredate>sig->timestamp)
u=sig->expiredate-sig->timestamp;
else
u=0;
2002-06-29 15:46:34 +02:00
buf[0] = (u >> 24) & 0xff;
buf[1] = (u >> 16) & 0xff;
buf[2] = (u >> 8) & 0xff;
buf[3] = u & 0xff;
/* Mark this CRITICAL, so if any implementation doesn't
understand sigs that can expire, it'll just disregard this
sig altogether. */
build_sig_subpkt( sig, SIGSUBPKT_SIG_EXPIRE | SIGSUBPKT_FLAG_CRITICAL,
buf, 4 );
}
1998-05-13 19:53:36 +02:00
}
2002-06-29 15:46:34 +02:00
void
build_attribute_subpkt(PKT_user_id *uid,byte type,
const void *buf,u32 buflen,
const void *header,u32 headerlen)
2002-06-29 15:46:34 +02:00
{
byte *attrib;
int idx;
if(1+headerlen+buflen>8383)
idx=5;
else if(1+headerlen+buflen>191)
idx=2;
else
idx=1;
/* realloc uid->attrib_data to the right size */
uid->attrib_data=m_realloc(uid->attrib_data,
uid->attrib_len+idx+1+headerlen+buflen);
attrib=&uid->attrib_data[uid->attrib_len];
if(idx==5)
{
attrib[0]=255;
attrib[1]=(1+headerlen+buflen) >> 24;
attrib[2]=(1+headerlen+buflen) >> 16;
attrib[3]=(1+headerlen+buflen) >> 8;
attrib[4]=1+headerlen+buflen;
}
else if(idx==2)
{
attrib[0]=(1+headerlen+buflen-192) / 256 + 192;
attrib[1]=(1+headerlen+buflen-192) % 256;
}
else
attrib[0]=1+headerlen+buflen; /* Good luck finding a JPEG this small! */
attrib[idx++]=type;
/* Tack on our data at the end */
if(headerlen>0)
memcpy(&attrib[idx],header,headerlen);
2002-06-29 15:46:34 +02:00
memcpy(&attrib[idx+headerlen],buf,buflen);
uid->attrib_len+=idx+headerlen+buflen;
}
1998-05-13 19:53:36 +02:00
1997-11-24 12:04:11 +01:00
static int
do_signature( IOBUF out, int ctb, PKT_signature *sig )
{
int rc = 0;
1998-06-13 08:59:14 +02:00
int n, i;
1997-11-24 12:04:11 +01:00
IOBUF a = iobuf_temp();
1998-03-09 22:44:06 +01:00
if( !sig->version )
iobuf_put( a, 3 );
else
iobuf_put( a, sig->version );
if( sig->version < 4 )
iobuf_put(a, 5 ); /* constant */
1997-11-24 12:04:11 +01:00
iobuf_put(a, sig->sig_class );
1998-03-09 22:44:06 +01:00
if( sig->version < 4 ) {
write_32(a, sig->timestamp );
write_32(a, sig->keyid[0] );
write_32(a, sig->keyid[1] );
}
1997-11-24 12:04:11 +01:00
iobuf_put(a, sig->pubkey_algo );
1998-03-09 22:44:06 +01:00
iobuf_put(a, sig->digest_algo );
if( sig->version >= 4 ) {
size_t nn;
1998-05-13 19:53:36 +02:00
/* timestamp and keyid must have been packed into the
* subpackets prior to the call of this function, because
* these subpackets are hashed */
2002-06-29 15:46:34 +02:00
nn = sig->hashed? sig->hashed->len : 0;
write_16(a, nn);
if( nn )
2002-06-29 15:46:34 +02:00
iobuf_write( a, sig->hashed->data, nn );
nn = sig->unhashed? sig->unhashed->len : 0;
write_16(a, nn);
if( nn )
2002-06-29 15:46:34 +02:00
iobuf_write( a, sig->unhashed->data, nn );
1998-03-09 22:44:06 +01:00
}
iobuf_put(a, sig->digest_start[0] );
iobuf_put(a, sig->digest_start[1] );
n = pubkey_get_nsig( sig->pubkey_algo );
if( !n )
write_fake_data( a, sig->data[0] );
1998-06-13 08:59:14 +02:00
for(i=0; i < n; i++ )
mpi_write(a, sig->data[i] );
1997-11-24 12:04:11 +01:00
1998-07-29 21:35:05 +02:00
if( is_RSA(sig->pubkey_algo) && sig->version < 4 )
write_sign_packet_header(out, ctb, iobuf_get_temp_length(a) );
else
write_header(out, ctb, iobuf_get_temp_length(a) );
1997-11-24 12:04:11 +01:00
if( iobuf_write_temp( out, a ) )
2002-06-29 15:46:34 +02:00
rc = G10ERR_WRITE_FILE;
1997-11-24 12:04:11 +01:00
iobuf_close(a);
return rc;
}
1997-11-18 15:06:00 +01:00
1997-12-02 20:36:53 +01:00
static int
do_onepass_sig( IOBUF out, int ctb, PKT_onepass_sig *ops )
{
int rc = 0;
IOBUF a = iobuf_temp();
write_version( a, ctb );
iobuf_put(a, ops->sig_class );
iobuf_put(a, ops->digest_algo );
iobuf_put(a, ops->pubkey_algo );
write_32(a, ops->keyid[0] );
write_32(a, ops->keyid[1] );
iobuf_put(a, ops->last );
write_header(out, ctb, iobuf_get_temp_length(a) );
if( iobuf_write_temp( out, a ) )
2002-06-29 15:46:34 +02:00
rc = G10ERR_WRITE_FILE;
1997-12-02 20:36:53 +01:00
iobuf_close(a);
return rc;
}
1997-11-18 15:06:00 +01:00
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
1998-09-11 07:47:32 +02:00
calc_header_length( u32 len, int new_ctb )
1997-11-18 15:06:00 +01:00
{
if( !len )
return 1; /* only the ctb */
1998-09-11 07:47:32 +02:00
if( new_ctb ) {
if( len < 192 )
return 2;
if( len < 8384 )
return 3;
else
return 6;
}
if( len < 256 )
1997-11-18 15:06:00 +01:00
return 2;
1998-09-11 07:47:32 +02:00
if( len < 65536 )
1997-11-18 15:06:00 +01:00
return 3;
1998-09-11 07:47:32 +02:00
return 5;
1997-11-18 15:06:00 +01:00
}
/****************
* Write the CTB and the packet length
*/
static int
write_header( IOBUF out, int ctb, u32 len )
1997-11-23 16:38:27 +01:00
{
1998-01-16 22:15:24 +01:00
return write_header2( out, ctb, len, 0, 1 );
1997-11-23 16:38:27 +01:00
}
1998-07-29 21:35:05 +02:00
static int
write_sign_packet_header( IOBUF out, int ctb, u32 len )
{
/* work around a bug in the pgp read function for signature packets,
* which are not correctly coded and silently assume at some
* point 2 byte length headers.*/
iobuf_put(out, 0x89 );
iobuf_put(out, len >> 8 );
return iobuf_put(out, len ) == -1 ? -1:0;
}
1998-01-16 22:15:24 +01:00
/****************
* if HDRLEN is > 0, try to build a header of this length.
1998-04-14 19:51:16 +02:00
* we need this, so that we can hash packets without reading them again.
1998-01-16 22:15:24 +01:00
*/
1997-11-23 16:38:27 +01:00
static int
1998-01-16 22:15:24 +01:00
write_header2( IOBUF out, int ctb, u32 len, int hdrlen, int blkmode )
1997-11-18 15:06:00 +01:00
{
1998-01-16 22:15:24 +01:00
if( ctb & 0x40 )
return write_new_header( out, ctb, len, hdrlen );
if( hdrlen ) {
if( !len )
ctb |= 3;
else if( hdrlen == 2 && len < 256 )
;
else if( hdrlen == 3 && len < 65536 )
ctb |= 1;
else
ctb |= 2;
}
else {
if( !len )
ctb |= 3;
else if( len < 256 )
;
else if( len < 65536 )
ctb |= 1;
else
ctb |= 2;
}
1997-11-18 15:06:00 +01:00
if( iobuf_put(out, ctb ) )
return -1;
if( !len ) {
1997-11-23 16:38:27 +01:00
if( blkmode )
iobuf_set_block_mode(out, 8196 );
1997-11-18 15:06:00 +01:00
}
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;
}
1998-01-16 22:15:24 +01:00
static int
write_new_header( IOBUF out, int ctb, u32 len, int hdrlen )
{
if( hdrlen )
log_bug("can't cope with hdrlen yet\n");
if( iobuf_put(out, ctb ) )
return -1;
if( !len ) {
iobuf_set_partial_block_mode(out, 512 );
1998-01-16 22:15:24 +01:00
}
else {
if( len < 192 ) {
if( iobuf_put(out, len ) )
return -1;
}
else if( len < 8384 ) {
len -= 192;
if( iobuf_put( out, (len / 256) + 192) )
return -1;
if( iobuf_put( out, (len % 256) ) )
return -1;
}
1998-05-13 19:53:36 +02:00
else {
if( iobuf_put( out, 0xff ) )
return -1;
if( iobuf_put( out, (len >> 24)&0xff ) )
return -1;
if( iobuf_put( out, (len >> 16)&0xff ) )
return -1;
if( iobuf_put( out, (len >> 8)&0xff ) )
return -1;
if( iobuf_put( out, len & 0xff ) )
return -1;
}
1998-01-16 22:15:24 +01:00
}
return 0;
}
1997-11-18 15:06:00 +01:00
static int
write_version( IOBUF out, int ctb )
{
if( iobuf_put( out, 3 ) )
return -1;
return 0;
}