Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F36623731
build-packet.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
29 KB
Subscribers
None
build-packet.c
View Options
/* build-packet.c - assemble packets and write them
* Copyright (C) 1998, 1999, 2000, 2001, 2002,
* 2003 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
* GnuPG 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.
*
* GnuPG 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
"gpg.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_t
out
,
int
ctb
,
PKT_comment
*
rem
);
static
int
do_user_id
(
iobuf_t
out
,
int
ctb
,
PKT_user_id
*
uid
);
static
int
do_public_key
(
iobuf_t
out
,
int
ctb
,
PKT_public_key
*
pk
);
static
int
do_secret_key
(
iobuf_t
out
,
int
ctb
,
PKT_secret_key
*
pk
);
static
int
do_symkey_enc
(
iobuf_t
out
,
int
ctb
,
PKT_symkey_enc
*
enc
);
static
int
do_pubkey_enc
(
iobuf_t
out
,
int
ctb
,
PKT_pubkey_enc
*
enc
);
static
u32
calc_plaintext
(
PKT_plaintext
*
pt
);
static
int
do_plaintext
(
iobuf_t
out
,
int
ctb
,
PKT_plaintext
*
pt
);
static
int
do_encrypted
(
iobuf_t
out
,
int
ctb
,
PKT_encrypted
*
ed
);
static
int
do_encrypted_mdc
(
iobuf_t
out
,
int
ctb
,
PKT_encrypted
*
ed
);
static
int
do_compressed
(
iobuf_t
out
,
int
ctb
,
PKT_compressed
*
cd
);
static
int
do_signature
(
iobuf_t
out
,
int
ctb
,
PKT_signature
*
sig
);
static
int
do_onepass_sig
(
iobuf_t
out
,
int
ctb
,
PKT_onepass_sig
*
ops
);
static
int
calc_header_length
(
u32
len
,
int
new_ctb
);
static
int
write_16
(
iobuf_t
inp
,
u16
a
);
static
int
write_32
(
iobuf_t
inp
,
u32
a
);
static
int
write_header
(
iobuf_t
out
,
int
ctb
,
u32
len
);
static
int
write_sign_packet_header
(
iobuf_t
out
,
int
ctb
,
u32
len
);
static
int
write_header2
(
iobuf_t
out
,
int
ctb
,
u32
len
,
int
hdrlen
,
int
blkmode
);
static
int
write_new_header
(
iobuf_t
out
,
int
ctb
,
u32
len
,
int
hdrlen
);
static
int
write_version
(
iobuf_t
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_t
out
,
PACKET
*
pkt
)
{
int
new_ctb
=
0
,
rc
=
0
,
ctb
;
int
pkttype
;
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
:
if
(
pkt
->
pkt
.
user_id
->
attrib_data
)
pkttype
=
PKT_ATTRIBUTE
;
break
;
default
:
break
;
}
if
(
new_ctb
||
pkttype
>
15
)
/* new format */
ctb
=
0xc0
|
(
pkttype
&
0x3f
);
else
ctb
=
0x80
|
((
pkttype
&
15
)
<<
2
);
switch
(
pkttype
)
{
case
PKT_ATTRIBUTE
:
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_PUBLIC_SUBKEY
:
case
PKT_PUBLIC_KEY
:
rc
=
do_public_key
(
out
,
ctb
,
pkt
->
pkt
.
public_key
);
break
;
case
PKT_SECRET_SUBKEY
:
case
PKT_SECRET_KEY
:
rc
=
do_secret_key
(
out
,
ctb
,
pkt
->
pkt
.
secret_key
);
break
;
case
PKT_SYMKEY_ENC
:
rc
=
do_symkey_enc
(
out
,
ctb
,
pkt
->
pkt
.
symkey_enc
);
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_ENCRYPTED
:
rc
=
do_encrypted
(
out
,
ctb
,
pkt
->
pkt
.
encrypted
);
break
;
case
PKT_ENCRYPTED_MDC
:
rc
=
do_encrypted_mdc
(
out
,
ctb
,
pkt
->
pkt
.
encrypted
);
break
;
case
PKT_COMPRESSED
:
rc
=
do_compressed
(
out
,
ctb
,
pkt
->
pkt
.
compressed
);
break
;
case
PKT_SIGNATURE
:
rc
=
do_signature
(
out
,
ctb
,
pkt
->
pkt
.
signature
);
break
;
case
PKT_ONEPASS_SIG
:
rc
=
do_onepass_sig
(
out
,
ctb
,
pkt
->
pkt
.
onepass_sig
);
break
;
case
PKT_RING_TRUST
:
break
;
/* ignore it (keyring.c does write it directly)*/
case
PKT_MDC
:
/* we write it directly, so we should never see it here. */
default
:
log_bug
(
"invalid packet type in build_packet()
\n
"
);
break
;
}
return
rc
;
}
/****************
* calculate the length of a packet described by PKT
*/
u32
calc_packet_length
(
PACKET
*
pkt
)
{
u32
n
=
0
;
int
new_ctb
=
0
;
assert
(
pkt
->
pkt
.
generic
);
switch
(
pkt
->
pkttype
)
{
case
PKT_PLAINTEXT
:
n
=
calc_plaintext
(
pkt
->
pkt
.
plaintext
);
new_ctb
=
pkt
->
pkt
.
plaintext
->
new_ctb
;
break
;
case
PKT_ATTRIBUTE
:
case
PKT_USER_ID
:
case
PKT_COMMENT
:
case
PKT_PUBLIC_KEY
:
case
PKT_SECRET_KEY
:
case
PKT_SYMKEY_ENC
:
case
PKT_PUBKEY_ENC
:
case
PKT_ENCRYPTED
:
case
PKT_SIGNATURE
:
case
PKT_ONEPASS_SIG
:
case
PKT_RING_TRUST
:
case
PKT_COMPRESSED
:
default
:
log_bug
(
"invalid packet type in calc_packet_length()"
);
break
;
}
n
+=
calc_header_length
(
n
,
new_ctb
);
return
n
;
}
static
void
write_fake_data
(
iobuf_t
out
,
gcry_mpi_t
a
)
{
if
(
a
)
{
unsigned
int
n
;
void
*
p
;
assert
(
gcry_mpi_get_flag
(
a
,
GCRYMPI_FLAG_OPAQUE
));
p
=
gcry_mpi_get_opaque
(
a
,
&
n
);
iobuf_write
(
out
,
p
,
(
n
+
7
)
/
8
);
}
}
static
int
do_comment
(
iobuf_t
out
,
int
ctb
,
PKT_comment
*
rem
)
{
int
rc
=
0
;
if
(
opt
.
sk_comments
)
{
write_header
(
out
,
ctb
,
rem
->
len
);
rc
=
iobuf_write
(
out
,
rem
->
data
,
rem
->
len
);
}
return
rc
;
}
static
int
do_user_id
(
iobuf_t
out
,
int
ctb
,
PKT_user_id
*
uid
)
{
int
rc
;
if
(
uid
->
attrib_data
)
{
write_header
(
out
,
ctb
,
uid
->
attrib_len
);
rc
=
iobuf_write
(
out
,
uid
->
attrib_data
,
uid
->
attrib_len
);
}
else
{
write_header
(
out
,
ctb
,
uid
->
len
);
rc
=
iobuf_write
(
out
,
uid
->
name
,
uid
->
len
);
}
return
rc
;
}
static
int
do_public_key
(
iobuf_t
out
,
int
ctb
,
PKT_public_key
*
pk
)
{
int
rc
=
0
;
int
n
,
i
;
iobuf_t
a
=
iobuf_temp
();
if
(
!
pk
->
version
)
iobuf_put
(
a
,
3
);
else
iobuf_put
(
a
,
pk
->
version
);
write_32
(
a
,
pk
->
timestamp
);
if
(
pk
->
version
<
4
)
{
u16
ndays
;
if
(
pk
->
expiredate
)
ndays
=
(
u16
)((
pk
->
expiredate
-
pk
->
timestamp
)
/
86400L
);
else
ndays
=
0
;
write_16
(
a
,
ndays
);
}
iobuf_put
(
a
,
pk
->
pubkey_algo
);
n
=
pubkey_get_npkey
(
pk
->
pubkey_algo
);
if
(
!
n
)
write_fake_data
(
a
,
pk
->
pkey
[
0
]
);
for
(
i
=
0
;
i
<
n
;
i
++
)
mpi_write
(
a
,
pk
->
pkey
[
i
]
);
write_header2
(
out
,
ctb
,
iobuf_get_temp_length
(
a
),
pk
->
hdrbytes
,
1
);
rc
=
iobuf_write_temp
(
out
,
a
);
iobuf_close
(
a
);
return
rc
;
}
/****************
* Make a hash value from the public key certificate
*/
void
hash_public_key
(
MD_HANDLE
md
,
PKT_public_key
*
pk
)
{
PACKET
pkt
;
int
rc
=
0
;
int
ctb
;
ulong
pktlen
;
int
c
;
iobuf_t
a
=
iobuf_temp
();
#if 0
FILE *fp = fopen("dump.pk", "a");
int i=0;
fprintf(fp, "\nHashing PK (v%d):\n", pk->version);
#endif
/* build the packet */
init_packet
(
&
pkt
);
pkt
.
pkttype
=
PKT_PUBLIC_KEY
;
pkt
.
pkt
.
public_key
=
pk
;
if
(
(
rc
=
build_packet
(
a
,
&
pkt
))
)
log_fatal
(
"build public_key for hashing failed: %s
\n
"
,
gpg_strerror
(
rc
));
if
(
!
(
pk
->
version
==
3
&&
pk
->
pubkey_algo
==
16
)
)
{
/* skip the constructed header but don't do this for our very old
* v3 ElG keys */
ctb
=
iobuf_get_noeof
(
a
);
pktlen
=
0
;
if
(
(
ctb
&
0x40
)
)
{
c
=
iobuf_get_noeof
(
a
);
if
(
c
<
192
)
pktlen
=
c
;
else
if
(
c
<
224
)
{
pktlen
=
(
c
-
192
)
*
256
;
c
=
iobuf_get_noeof
(
a
);
pktlen
+=
c
+
192
;
}
else
if
(
c
==
255
)
{
pktlen
=
iobuf_get_noeof
(
a
)
<<
24
;
pktlen
|=
iobuf_get_noeof
(
a
)
<<
16
;
pktlen
|=
iobuf_get_noeof
(
a
)
<<
8
;
pktlen
|=
iobuf_get_noeof
(
a
);
}
}
else
{
int
lenbytes
=
((
ctb
&
3
)
==
3
)
?
0
:
(
1
<<
(
ctb
&
3
));
for
(
;
lenbytes
;
lenbytes
--
)
{
pktlen
<<=
8
;
pktlen
|=
iobuf_get_noeof
(
a
);
}
}
/* hash a header */
gcry_md_putc
(
md
,
0x99
);
pktlen
&=
0xffff
;
/* can't handle longer packets */
gcry_md_putc
(
md
,
pktlen
>>
8
);
gcry_md_putc
(
md
,
pktlen
&
0xff
);
}
/* hash the packet body */
while
(
(
c
=
iobuf_get
(
a
))
!=
-1
)
{
#if 0
fprintf( fp," %02x", c );
if( (++i == 24) ) {
putc('\n', fp);
i=0;
}
#endif
gcry_md_putc
(
md
,
c
);
}
#if 0
putc('\n', fp);
fclose(fp);
#endif
iobuf_cancel
(
a
);
}
static
int
do_secret_key
(
iobuf_t
out
,
int
ctb
,
PKT_secret_key
*
sk
)
{
int
rc
=
0
;
int
i
,
nskey
,
npkey
;
iobuf_t
a
=
iobuf_temp
();
/* build in a self-enlarging buffer */
/* Write the version number - if none is specified, use 3 */
if
(
!
sk
->
version
)
iobuf_put
(
a
,
3
);
else
iobuf_put
(
a
,
sk
->
version
);
write_32
(
a
,
sk
->
timestamp
);
/* v3 needs the expiration time */
if
(
sk
->
version
<
4
)
{
u16
ndays
;
if
(
sk
->
expiredate
)
ndays
=
(
u16
)((
sk
->
expiredate
-
sk
->
timestamp
)
/
86400L
);
else
ndays
=
0
;
write_16
(
a
,
ndays
);
}
iobuf_put
(
a
,
sk
->
pubkey_algo
);
/* get number of secret and public parameters. They are held in
one array first the public ones, then the secret ones */
nskey
=
pubkey_get_nskey
(
sk
->
pubkey_algo
);
npkey
=
pubkey_get_npkey
(
sk
->
pubkey_algo
);
/* 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) gcry_mpi_t */
if
(
!
npkey
)
{
write_fake_data
(
a
,
sk
->
skey
[
0
]
);
goto
leave
;
}
assert
(
npkey
<
nskey
);
/* Writing the public parameters is easy */
for
(
i
=
0
;
i
<
npkey
;
i
++
)
mpi_write
(
a
,
sk
->
skey
[
i
]
);
/* build the header for protected (encrypted) secret parameters */
if
(
sk
->
is_protected
)
{
if
(
is_RSA
(
sk
->
pubkey_algo
)
&&
sk
->
version
<
4
&&
!
sk
->
protect
.
s2k
.
mode
)
{
/* the simple rfc1991 (v3) way */
iobuf_put
(
a
,
sk
->
protect
.
algo
);
iobuf_write
(
a
,
sk
->
protect
.
iv
,
sk
->
protect
.
ivlen
);
}
else
{
/* OpenPGP protection according to rfc2440 */
iobuf_put
(
a
,
sk
->
protect
.
sha1chk
?
0xfe
:
0xff
);
iobuf_put
(
a
,
sk
->
protect
.
algo
);
if
(
sk
->
protect
.
s2k
.
mode
>=
1000
)
{
/* These modes are not possible in OpenPGP, we use them
to implement our extensions, 101 can be seen as a
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
);
}
if
(
sk
->
protect
.
s2k
.
mode
==
1
||
sk
->
protect
.
s2k
.
mode
==
3
)
iobuf_write
(
a
,
sk
->
protect
.
s2k
.
salt
,
8
);
if
(
sk
->
protect
.
s2k
.
mode
==
3
)
iobuf_put
(
a
,
sk
->
protect
.
s2k
.
count
);
/* For our special modes 1001 and 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
);
}
}
else
iobuf_put
(
a
,
0
);
if
(
sk
->
protect
.
s2k
.
mode
==
1001
)
;
/* 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
)
{
/* The secret key is protected - write it out as it is */
byte
*
p
;
assert
(
gcry_mpi_get_flag
(
sk
->
skey
[
npkey
],
GCRYMPI_FLAG_OPAQUE
)
);
p
=
gcry_mpi_get_opaque
(
sk
->
skey
[
npkey
],
&
i
);
iobuf_write
(
a
,
p
,
(
i
+
7
)
/
8
);
}
else
if
(
sk
->
is_protected
)
{
/* The secret key is protected the old v4 way. */
for
(
;
i
<
nskey
;
i
++
)
{
byte
*
p
;
size_t
n
;
assert
(
gcry_mpi_get_flag
(
sk
->
skey
[
i
],
GCRYMPI_FLAG_OPAQUE
));
p
=
gcry_mpi_get_opaque
(
sk
->
skey
[
i
],
&
n
);
iobuf_write
(
a
,
p
,
(
n
+
7
)
/
8
);
}
write_16
(
a
,
sk
->
csum
);
}
else
{
/* non-protected key */
for
(
;
i
<
nskey
;
i
++
)
mpi_write
(
a
,
sk
->
skey
[
i
]
);
write_16
(
a
,
sk
->
csum
);
}
leave
:
/* 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 */
write_header2
(
out
,
ctb
,
iobuf_get_temp_length
(
a
),
sk
->
hdrbytes
,
1
);
/* And finally write it out the real stream */
rc
=
iobuf_write_temp
(
out
,
a
);
iobuf_close
(
a
);
/* close the remporary buffer */
return
rc
;
}
static
int
do_symkey_enc
(
iobuf_t
out
,
int
ctb
,
PKT_symkey_enc
*
enc
)
{
int
rc
=
0
;
iobuf_t
a
=
iobuf_temp
();
assert
(
enc
->
version
==
4
);
switch
(
enc
->
s2k
.
mode
)
{
case
0
:
case
1
:
case
3
:
break
;
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
);
if
(
enc
->
s2k
.
mode
==
1
||
enc
->
s2k
.
mode
==
3
)
{
iobuf_write
(
a
,
enc
->
s2k
.
salt
,
8
);
if
(
enc
->
s2k
.
mode
==
3
)
iobuf_put
(
a
,
enc
->
s2k
.
count
);
}
if
(
enc
->
seskeylen
)
iobuf_write
(
a
,
enc
->
seskey
,
enc
->
seskeylen
);
write_header
(
out
,
ctb
,
iobuf_get_temp_length
(
a
)
);
rc
=
iobuf_write_temp
(
out
,
a
);
iobuf_close
(
a
);
return
rc
;
}
static
int
do_pubkey_enc
(
iobuf_t
out
,
int
ctb
,
PKT_pubkey_enc
*
enc
)
{
int
rc
=
0
;
int
n
,
i
;
iobuf_t
a
=
iobuf_temp
();
write_version
(
a
,
ctb
);
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
]
);
}
iobuf_put
(
a
,
enc
->
pubkey_algo
);
n
=
pubkey_get_nenc
(
enc
->
pubkey_algo
);
if
(
!
n
)
write_fake_data
(
a
,
enc
->
data
[
0
]
);
for
(
i
=
0
;
i
<
n
;
i
++
)
mpi_write
(
a
,
enc
->
data
[
i
]
);
write_header
(
out
,
ctb
,
iobuf_get_temp_length
(
a
)
);
rc
=
iobuf_write_temp
(
out
,
a
);
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_t
out
,
int
ctb
,
PKT_plaintext
*
pt
)
{
int
i
,
rc
=
0
;
u32
n
;
byte
buf
[
1000
];
/* this buffer has the plaintext! */
int
nbytes
;
/* 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
;
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
]
);
rc
=
write_32
(
out
,
pt
->
timestamp
);
n
=
0
;
while
(
(
nbytes
=
iobuf_read
(
pt
->
buf
,
buf
,
1000
))
!=
-1
)
{
rc
=
iobuf_write
(
out
,
buf
,
nbytes
);
if
(
rc
)
break
;
n
+=
nbytes
;
}
wipememory
(
buf
,
1000
);
/* burn the buffer */
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_encrypted
(
iobuf_t
out
,
int
ctb
,
PKT_encrypted
*
ed
)
{
int
rc
=
0
;
u32
n
;
n
=
ed
->
len
?
(
ed
->
len
+
ed
->
extralen
)
:
0
;
write_header
(
out
,
ctb
,
n
);
/* This is all. The caller has to write the real data */
return
rc
;
}
static
int
do_encrypted_mdc
(
iobuf_t
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
;
}
static
int
do_compressed
(
iobuf_t
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. */
write_header2
(
out
,
ctb
,
0
,
0
,
0
);
iobuf_put
(
out
,
cd
->
algorithm
);
/* This is all. The caller has to write the real data */
return
rc
;
}
/****************
* Delete all subpackets of type REQTYPE and return a bool whether a packet
* was deleted.
*/
int
delete_sig_subpkt
(
subpktarea_t
*
area
,
sigsubpkttype_t
reqtype
)
{
int
buflen
;
sigsubpkttype_t
type
;
byte
*
buffer
,
*
bufstart
;
size_t
n
;
size_t
unused
=
0
;
int
okay
=
0
;
if
(
!
area
)
return
0
;
buflen
=
area
->
len
;
buffer
=
area
->
data
;
for
(;;)
{
if
(
!
buflen
)
{
okay
=
1
;
break
;
}
bufstart
=
buffer
;
n
=
*
buffer
++
;
buflen
--
;
if
(
n
==
255
)
{
if
(
buflen
<
4
)
break
;
n
=
(
buffer
[
0
]
<<
24
)
|
(
buffer
[
1
]
<<
16
)
|
(
buffer
[
2
]
<<
8
)
|
buffer
[
3
];
buffer
+=
4
;
buflen
-=
4
;
}
else
if
(
n
>=
192
)
{
if
(
buflen
<
2
)
break
;
n
=
((
n
-
192
)
<<
8
)
+
*
buffer
+
192
;
buffer
++
;
buflen
--
;
}
if
(
buflen
<
n
)
break
;
type
=
*
buffer
&
0x7f
;
if
(
type
==
reqtype
)
{
buffer
++
;
buflen
--
;
n
--
;
if
(
n
>
buflen
)
break
;
buffer
+=
n
;
/* point to next subpkt */
buflen
-=
n
;
memmove
(
bufstart
,
buffer
,
buflen
);
/* shift */
unused
+=
buffer
-
bufstart
;
buffer
=
bufstart
;
}
else
{
buffer
+=
n
;
buflen
-=
n
;
}
}
if
(
!
okay
)
log_error
(
"delete_subpkt: buffer shorter than subpacket
\n
"
);
assert
(
unused
<=
area
->
len
);
area
->
len
-=
unused
;
return
!!
unused
;
}
/****************
* 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.
*/
void
build_sig_subpkt
(
PKT_signature
*
sig
,
sigsubpkttype_t
type
,
const
byte
*
buffer
,
size_t
buflen
)
{
byte
*
p
;
int
critical
,
hashed
;
subpktarea_t
*
oldarea
,
*
newarea
;
size_t
nlen
,
n
,
n0
;
critical
=
(
type
&
SIGSUBPKT_FLAG_CRITICAL
);
type
&=
~
SIGSUBPKT_FLAG_CRITICAL
;
/* 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
;
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
;
default
:
break
;
}
if
(
(
buflen
+
1
)
>=
8384
)
nlen
=
5
;
/* write 5 byte length header */
else
if
(
(
buflen
+
1
)
>=
192
)
nlen
=
2
;
/* write 2 byte length header */
else
nlen
=
1
;
/* just a 1 byte length header */
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
:
hashed
=
0
;
break
;
default
:
hashed
=
1
;
break
;
}
if
(
critical
)
type
|=
SIGSUBPKT_FLAG_CRITICAL
;
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
=
xrealloc
(
oldarea
,
sizeof
(
*
newarea
)
+
n
-
1
);
newarea
->
size
=
n
;
/*log_debug ("reallocating area for type %d\n", type );*/
}
else
{
newarea
=
xmalloc
(
sizeof
(
*
newarea
)
+
n
-
1
);
newarea
->
size
=
n
;
/*log_debug ("allocating area for type %d\n", type );*/
}
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
);
}
else
{
*
p
++
=
buflen
+
1
;
*
p
++
=
type
;
memcpy
(
p
,
buffer
,
buflen
);
}
if
(
hashed
)
sig
->
hashed
=
newarea
;
else
sig
->
unhashed
=
newarea
;
}
/****************
* Put all the required stuff from SIG into subpackets of sig.
* Hmmm, should we delete those subpackets which are in a wrong area?
*/
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
);
if
(
sig
->
expiredate
)
{
if
(
sig
->
expiredate
>
sig
->
timestamp
)
u
=
sig
->
expiredate
-
sig
->
timestamp
;
else
u
=
0
;
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
);
}
}
void
build_attribute_subpkt
(
PKT_user_id
*
uid
,
byte
type
,
const
void
*
buf
,
u32
buflen
,
const
void
*
header
,
u32
headerlen
)
{
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
=
xrealloc
(
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
);
memcpy
(
&
attrib
[
idx
+
headerlen
],
buf
,
buflen
);
uid
->
attrib_len
+=
idx
+
headerlen
+
buflen
;
}
static
int
do_signature
(
iobuf_t
out
,
int
ctb
,
PKT_signature
*
sig
)
{
int
rc
=
0
;
int
n
,
i
;
iobuf_t
a
=
iobuf_temp
();
if
(
!
sig
->
version
)
iobuf_put
(
a
,
3
);
else
iobuf_put
(
a
,
sig
->
version
);
if
(
sig
->
version
<
4
)
iobuf_put
(
a
,
5
);
/* constant */
iobuf_put
(
a
,
sig
->
sig_class
);
if
(
sig
->
version
<
4
)
{
write_32
(
a
,
sig
->
timestamp
);
write_32
(
a
,
sig
->
keyid
[
0
]
);
write_32
(
a
,
sig
->
keyid
[
1
]
);
}
iobuf_put
(
a
,
sig
->
pubkey_algo
);
iobuf_put
(
a
,
sig
->
digest_algo
);
if
(
sig
->
version
>=
4
)
{
size_t
nn
;
/* timestamp and keyid must have been packed into the
* subpackets prior to the call of this function, because
* these subpackets are hashed */
nn
=
sig
->
hashed
?
sig
->
hashed
->
len
:
0
;
write_16
(
a
,
nn
);
if
(
nn
)
iobuf_write
(
a
,
sig
->
hashed
->
data
,
nn
);
nn
=
sig
->
unhashed
?
sig
->
unhashed
->
len
:
0
;
write_16
(
a
,
nn
);
if
(
nn
)
iobuf_write
(
a
,
sig
->
unhashed
->
data
,
nn
);
}
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
]
);
for
(
i
=
0
;
i
<
n
;
i
++
)
mpi_write
(
a
,
sig
->
data
[
i
]
);
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
)
);
rc
=
iobuf_write_temp
(
out
,
a
);
iobuf_close
(
a
);
return
rc
;
}
static
int
do_onepass_sig
(
iobuf_t
out
,
int
ctb
,
PKT_onepass_sig
*
ops
)
{
int
rc
=
0
;
iobuf_t
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
)
);
rc
=
iobuf_write_temp
(
out
,
a
);
iobuf_close
(
a
);
return
rc
;
}
static
int
write_16
(
iobuf_t
out
,
u16
a
)
{
iobuf_put
(
out
,
a
>>
8
);
return
iobuf_put
(
out
,
a
);
}
static
int
write_32
(
iobuf_t
out
,
u32
a
)
{
iobuf_put
(
out
,
a
>>
24
);
iobuf_put
(
out
,
a
>>
16
);
iobuf_put
(
out
,
a
>>
8
);
return
iobuf_put
(
out
,
a
);
}
/****************
* calculate the length of a header
*/
static
int
calc_header_length
(
u32
len
,
int
new_ctb
)
{
if
(
!
len
)
return
1
;
/* only the ctb */
if
(
new_ctb
)
{
if
(
len
<
192
)
return
2
;
if
(
len
<
8384
)
return
3
;
else
return
6
;
}
if
(
len
<
256
)
return
2
;
if
(
len
<
65536
)
return
3
;
return
5
;
}
/****************
* Write the CTB and the packet length
*/
static
int
write_header
(
iobuf_t
out
,
int
ctb
,
u32
len
)
{
return
write_header2
(
out
,
ctb
,
len
,
0
,
1
);
}
static
int
write_sign_packet_header
(
iobuf_t
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
;
}
/****************
* if HDRLEN is > 0, try to build a header of this length.
* we need this, so that we can hash packets without reading them again.
*/
static
int
write_header2
(
iobuf_t
out
,
int
ctb
,
u32
len
,
int
hdrlen
,
int
blkmode
)
{
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
;
}
if
(
iobuf_put
(
out
,
ctb
)
)
return
-1
;
if
(
!
len
)
{
if
(
blkmode
)
iobuf_set_block_mode
(
out
,
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_new_header
(
iobuf_t
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
);
}
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
;
}
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
;
}
}
return
0
;
}
static
int
write_version
(
iobuf_t
out
,
int
ctb
)
{
if
(
iobuf_put
(
out
,
3
)
)
return
-1
;
return
0
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Thu, Feb 26, 6:58 PM (1 d, 18 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
f6/c8/0b56d1c63c3a5bca9f7e64371630
Attached To
rG GnuPG
Event Timeline
Log In to Comment