Page Menu
Home
GnuPG
Search
Configure Global Search
Log In
Files
F34024065
sign.c
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Size
38 KB
Subscribers
None
sign.c
View Options
/* sign.c - sign data
* 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
<errno.h>
#include
<assert.h>
#include
<unistd.h>
/* need sleep() */
#include
"options.h"
#include
"packet.h"
#include
"errors.h"
#include
"iobuf.h"
#include
"keydb.h"
#include
"memory.h"
#include
"util.h"
#include
"main.h"
#include
"filter.h"
#include
"ttyio.h"
#include
"trustdb.h"
#include
"status.h"
#include
"i18n.h"
#include
"pkglue.h"
#include
"call-agent.h"
#ifdef HAVE_DOSISH_SYSTEM
#define LF "\r\n"
void
__stdcall
Sleep
(
ulong
);
#define sleep(a) Sleep((a)*1000)
#else
#define LF "\n"
#endif
static
int
recipient_digest_algo
=
0
;
/****************
* Create a notation. It is assumed that the stings in STRLIST
* are already checked to contain only printable data and have a valid
* NAME=VALUE format.
*/
static
void
mk_notation_and_policy
(
PKT_signature
*
sig
,
PKT_public_key
*
pk
,
PKT_secret_key
*
sk
)
{
const
char
*
string
;
char
*
s
=
NULL
;
byte
*
buf
;
unsigned
n1
,
n2
;
STRLIST
nd
=
NULL
,
pu
=
NULL
;
struct
expando_args
args
;
memset
(
&
args
,
0
,
sizeof
(
args
));
args
.
pk
=
pk
;
args
.
sk
=
sk
;
/* notation data */
if
(
IS_SIG
(
sig
)
&&
opt
.
sig_notation_data
)
{
if
(
sig
->
version
<
4
)
log_info
(
"can't put notation data into v3 signatures
\n
"
);
else
nd
=
opt
.
sig_notation_data
;
}
else
if
(
IS_CERT
(
sig
)
&&
opt
.
cert_notation_data
)
{
if
(
sig
->
version
<
4
)
log_info
(
"can't put notation data into v3 key signatures
\n
"
);
else
nd
=
opt
.
cert_notation_data
;
}
for
(
;
nd
;
nd
=
nd
->
next
)
{
char
*
expanded
;
string
=
nd
->
d
;
s
=
strchr
(
string
,
'='
);
if
(
!
s
)
BUG
();
/* we have already parsed this */
n1
=
s
-
string
;
s
++
;
expanded
=
pct_expando
(
s
,
&
args
);
if
(
!
expanded
)
{
log_error
(
_
(
"WARNING: unable to %%-expand notation "
"(too large). Using unexpanded.
\n
"
));
expanded
=
xstrdup
(
s
);
}
n2
=
strlen
(
expanded
);
buf
=
xmalloc
(
8
+
n1
+
n2
);
buf
[
0
]
=
0x80
;
/* human readable */
buf
[
1
]
=
buf
[
2
]
=
buf
[
3
]
=
0
;
buf
[
4
]
=
n1
>>
8
;
buf
[
5
]
=
n1
;
buf
[
6
]
=
n2
>>
8
;
buf
[
7
]
=
n2
;
memcpy
(
buf
+
8
,
string
,
n1
);
memcpy
(
buf
+
8
+
n1
,
expanded
,
n2
);
build_sig_subpkt
(
sig
,
SIGSUBPKT_NOTATION
|
((
nd
->
flags
&
1
)
?
SIGSUBPKT_FLAG_CRITICAL
:
0
),
buf
,
8
+
n1
+
n2
);
xfree
(
expanded
);
xfree
(
buf
);
}
if
(
opt
.
list_options
&
LIST_SHOW_NOTATION
)
show_notation
(
sig
,
0
,
0
);
/* set policy URL */
if
(
IS_SIG
(
sig
)
&&
opt
.
sig_policy_url
)
{
if
(
sig
->
version
<
4
)
log_info
(
"can't put a policy URL into v3 signatures
\n
"
);
else
pu
=
opt
.
sig_policy_url
;
}
else
if
(
IS_CERT
(
sig
)
&&
opt
.
cert_policy_url
)
{
if
(
sig
->
version
<
4
)
log_info
(
"can't put a policy URL into v3 key signatures
\n
"
);
else
pu
=
opt
.
cert_policy_url
;
}
for
(;
pu
;
pu
=
pu
->
next
)
{
string
=
pu
->
d
;
s
=
pct_expando
(
string
,
&
args
);
if
(
!
s
)
{
log_error
(
_
(
"WARNING: unable to %%-expand policy url "
"(too large). Using unexpanded.
\n
"
));
s
=
xstrdup
(
string
);
}
build_sig_subpkt
(
sig
,
SIGSUBPKT_POLICY
|
((
pu
->
flags
&
1
)
?
SIGSUBPKT_FLAG_CRITICAL
:
0
),
s
,
strlen
(
s
));
xfree
(
s
);
}
if
(
opt
.
list_options
&
LIST_SHOW_POLICY
)
show_policy_url
(
sig
,
0
,
0
);
}
/*
* Helper to hash a user ID packet.
*/
static
void
hash_uid
(
MD_HANDLE
md
,
int
sigversion
,
const
PKT_user_id
*
uid
)
{
if
(
sigversion
>=
4
)
{
byte
buf
[
5
];
if
(
uid
->
attrib_data
)
{
buf
[
0
]
=
0xd1
;
/* indicates an attribute packet */
buf
[
1
]
=
uid
->
attrib_len
>>
24
;
/* always use 4 length bytes */
buf
[
2
]
=
uid
->
attrib_len
>>
16
;
buf
[
3
]
=
uid
->
attrib_len
>>
8
;
buf
[
4
]
=
uid
->
attrib_len
;
}
else
{
buf
[
0
]
=
0xb4
;
/* indicates a userid packet */
buf
[
1
]
=
uid
->
len
>>
24
;
/* always use 4 length bytes */
buf
[
2
]
=
uid
->
len
>>
16
;
buf
[
3
]
=
uid
->
len
>>
8
;
buf
[
4
]
=
uid
->
len
;
}
gcry_md_write
(
md
,
buf
,
5
);
}
if
(
uid
->
attrib_data
)
gcry_md_write
(
md
,
uid
->
attrib_data
,
uid
->
attrib_len
);
else
gcry_md_write
(
md
,
uid
->
name
,
uid
->
len
);
}
/*
* Helper to hash some parts from the signature
*/
static
void
hash_sigversion_to_magic
(
MD_HANDLE
md
,
const
PKT_signature
*
sig
)
{
if
(
sig
->
version
>=
4
)
gcry_md_putc
(
md
,
sig
->
version
);
gcry_md_putc
(
md
,
sig
->
sig_class
);
if
(
sig
->
version
<
4
)
{
u32
a
=
sig
->
timestamp
;
gcry_md_putc
(
md
,
(
a
>>
24
)
&
0xff
);
gcry_md_putc
(
md
,
(
a
>>
16
)
&
0xff
);
gcry_md_putc
(
md
,
(
a
>>
8
)
&
0xff
);
gcry_md_putc
(
md
,
a
&
0xff
);
}
else
{
byte
buf
[
6
];
size_t
n
;
gcry_md_putc
(
md
,
sig
->
pubkey_algo
);
gcry_md_putc
(
md
,
sig
->
digest_algo
);
if
(
sig
->
hashed
)
{
n
=
sig
->
hashed
->
len
;
gcry_md_putc
(
md
,
(
n
>>
8
)
);
gcry_md_putc
(
md
,
n
);
gcry_md_write
(
md
,
sig
->
hashed
->
data
,
n
);
n
+=
6
;
}
else
{
gcry_md_putc
(
md
,
0
);
/* always hash the length of the subpacket*/
gcry_md_putc
(
md
,
0
);
n
=
6
;
}
/* add some magic */
buf
[
0
]
=
sig
->
version
;
buf
[
1
]
=
0xff
;
buf
[
2
]
=
n
>>
24
;
/* hmmm, n is only 16 bit, so this is always 0 */
buf
[
3
]
=
n
>>
16
;
buf
[
4
]
=
n
>>
8
;
buf
[
5
]
=
n
;
gcry_md_write
(
md
,
buf
,
6
);
}
}
static
int
do_sign
(
PKT_secret_key
*
sk
,
PKT_signature
*
sig
,
MD_HANDLE
md
,
int
digest_algo
)
{
gcry_mpi_t
frame
;
byte
*
dp
;
int
rc
;
if
(
sk
->
timestamp
>
sig
->
timestamp
)
{
ulong
d
=
sk
->
timestamp
-
sig
->
timestamp
;
log_info
(
d
==
1
?
_
(
"key has been created %lu second "
"in future (time warp or clock problem)
\n
"
)
:
_
(
"key has been created %lu seconds "
"in future (time warp or clock problem)
\n
"
),
d
);
if
(
!
opt
.
ignore_time_conflict
)
return
GPG_ERR_TIME_CONFLICT
;
}
print_pubkey_algo_note
(
sk
->
pubkey_algo
);
if
(
!
digest_algo
)
digest_algo
=
gcry_md_get_algo
(
md
);
print_digest_algo_note
(
digest_algo
);
dp
=
gcry_md_read
(
md
,
digest_algo
);
sig
->
digest_algo
=
digest_algo
;
sig
->
digest_start
[
0
]
=
dp
[
0
];
sig
->
digest_start
[
1
]
=
dp
[
1
];
#if 0
if (sk->is_protected && sk->protect.s2k.mode == 1002 && !sk->is_primary)
{ /* Temporary hack to test tey auth command. */
char *rbuf;
size_t rbuflen;
char *snbuf;
char *tmpbuf;
size_t tmp_n;
frame = encode_md_value( sk->pubkey_algo, md,
digest_algo, mpi_get_nbits(sk->skey[0]), 0 );
if (!frame)
return GPG_ERR_GENERAL;
if (gcry_mpi_aprint (GCRYMPI_FMT_USG, (void **)&tmpbuf, &tmp_n, frame ))
BUG ();
for (; tmp_n && *tmpbuf; tmp_n--, tmpbuf++)
;
assert (tmp_n);
tmp_n--;
tmpbuf++;
snbuf = serialno_and_fpr_from_sk (sk->protect.iv, sk->protect.ivlen, sk);
rc = agent_scd_pksign (snbuf, 0,
tmpbuf, tmp_n,
&rbuf, &rbuflen);
xfree (snbuf);
if (!rc)
{
if (gcry_mpi_scan (&sig->data[0], GCRYMPI_FMT_USG,
rbuf, rbuflen, NULL ))
BUG ();
}
}
else
#endif
if
(
sk
->
is_protected
&&
sk
->
protect
.
s2k
.
mode
==
1002
)
{
/* FIXME: Note that we do only support RSA for now. */
char
*
rbuf
;
size_t
rbuflen
;
char
*
snbuf
;
snbuf
=
serialno_and_fpr_from_sk
(
sk
->
protect
.
iv
,
sk
->
protect
.
ivlen
,
sk
);
rc
=
agent_scd_pksign
(
snbuf
,
digest_algo
,
gcry_md_read
(
md
,
digest_algo
),
gcry_md_get_algo_dlen
(
digest_algo
),
&
rbuf
,
&
rbuflen
);
xfree
(
snbuf
);
if
(
!
rc
)
{
if
(
gcry_mpi_scan
(
&
sig
->
data
[
0
],
GCRYMPI_FMT_USG
,
rbuf
,
rbuflen
,
NULL
))
BUG
();
}
}
else
{
frame
=
encode_md_value
(
sk
->
pubkey_algo
,
md
,
digest_algo
,
mpi_get_nbits
(
sk
->
skey
[
0
]),
0
);
if
(
!
frame
)
return
GPG_ERR_GENERAL
;
rc
=
pk_sign
(
sk
->
pubkey_algo
,
sig
->
data
,
frame
,
sk
->
skey
);
gcry_mpi_release
(
frame
);
}
if
(
!
rc
&&
!
opt
.
no_sig_create_check
)
{
/* check that the signature verification worked and nothing is
* fooling us e.g. by a bug in the signature create
* code or by deliberately introduced faults. */
PKT_public_key
*
pk
=
xcalloc
(
1
,
sizeof
*
pk
);
if
(
get_pubkey
(
pk
,
sig
->
keyid
)
)
rc
=
GPG_ERR_NO_PUBKEY
;
else
{
frame
=
encode_md_value
(
pk
->
pubkey_algo
,
md
,
sig
->
digest_algo
,
mpi_get_nbits
(
pk
->
pkey
[
0
]),
0
);
if
(
!
frame
)
rc
=
GPG_ERR_GENERAL
;
else
rc
=
pk_verify
(
pk
->
pubkey_algo
,
frame
,
sig
->
data
,
pk
->
pkey
);
gcry_mpi_release
(
frame
);
}
if
(
rc
)
log_error
(
_
(
"checking created signature failed: %s
\n
"
),
gpg_strerror
(
rc
));
free_public_key
(
pk
);
}
if
(
rc
)
log_error
(
_
(
"signing failed: %s
\n
"
),
gpg_strerror
(
rc
)
);
else
{
if
(
opt
.
verbose
)
{
char
*
ustr
=
get_user_id_string_printable
(
sig
->
keyid
);
log_info
(
_
(
"%s/%s signature from:
\"
%s
\"\n
"
),
gcry_pk_algo_name
(
sk
->
pubkey_algo
),
gcry_md_algo_name
(
sig
->
digest_algo
),
ustr
);
xfree
(
ustr
);
}
}
return
rc
;
}
int
complete_sig
(
PKT_signature
*
sig
,
PKT_secret_key
*
sk
,
MD_HANDLE
md
)
{
int
rc
=
0
;
if
(
!
(
rc
=
check_secret_key
(
sk
,
0
))
)
rc
=
do_sign
(
sk
,
sig
,
md
,
0
);
return
rc
;
}
static
int
hash_for
(
int
pubkey_algo
,
int
packet_version
)
{
if
(
opt
.
def_digest_algo
)
return
opt
.
def_digest_algo
;
else
if
(
recipient_digest_algo
)
return
recipient_digest_algo
;
else
if
(
PGP2
&&
pubkey_algo
==
PUBKEY_ALGO_RSA
&&
packet_version
<
4
)
{
/* Old-style PGP only understands MD5 */
return
DIGEST_ALGO_MD5
;
}
else
if
(
pubkey_algo
==
PUBKEY_ALGO_DSA
)
{
/* We need a 160-bit hash for DSA, so we can't just take the first
in the pref list */
if
(
opt
.
personal_digest_prefs
)
{
prefitem_t
*
prefs
;
for
(
prefs
=
opt
.
personal_digest_prefs
;
prefs
->
type
;
prefs
++
)
if
(
gcry_md_get_algo_dlen
(
prefs
->
value
)
==
20
)
return
prefs
->
value
;
}
return
DIGEST_ALGO_SHA1
;
}
else
if
(
opt
.
personal_digest_prefs
)
{
/* It's not DSA, so we can use whatever the first hash algorithm
is in the pref list */
return
opt
.
personal_digest_prefs
[
0
].
value
;
}
else
return
DEFAULT_DIGEST_ALGO
;
}
static
int
only_old_style
(
SK_LIST
sk_list
)
{
SK_LIST
sk_rover
=
NULL
;
int
old_style
=
0
;
/* if there are only old style capable key we use the old sytle */
for
(
sk_rover
=
sk_list
;
sk_rover
;
sk_rover
=
sk_rover
->
next
)
{
PKT_secret_key
*
sk
=
sk_rover
->
sk
;
if
(
sk
->
pubkey_algo
==
PUBKEY_ALGO_RSA
&&
sk
->
version
<
4
)
old_style
=
1
;
else
return
0
;
}
return
old_style
;
}
static
void
print_status_sig_created
(
PKT_secret_key
*
sk
,
PKT_signature
*
sig
,
int
what
)
{
byte
array
[
MAX_FINGERPRINT_LEN
],
*
p
;
char
buf
[
100
+
MAX_FINGERPRINT_LEN
*
2
];
size_t
i
,
n
;
sprintf
(
buf
,
"%c %d %d %02x %lu "
,
what
,
sig
->
pubkey_algo
,
sig
->
digest_algo
,
sig
->
sig_class
,
(
ulong
)
sig
->
timestamp
);
fingerprint_from_sk
(
sk
,
array
,
&
n
);
p
=
buf
+
strlen
(
buf
);
for
(
i
=
0
;
i
<
n
;
i
++
)
sprintf
(
p
+
2
*
i
,
"%02X"
,
array
[
i
]
);
write_status_text
(
STATUS_SIG_CREATED
,
buf
);
}
/*
* Loop over the secret certificates in SK_LIST and build the one pass
* signature packets. OpenPGP says that the data should be bracket by
* the onepass-sig and signature-packet; so we build these onepass
* packet here in reverse order
*/
static
int
write_onepass_sig_packets
(
SK_LIST
sk_list
,
iobuf_t
out
,
int
sigclass
)
{
int
skcount
;
SK_LIST
sk_rover
;
for
(
skcount
=
0
,
sk_rover
=
sk_list
;
sk_rover
;
sk_rover
=
sk_rover
->
next
)
skcount
++
;
for
(;
skcount
;
skcount
--
)
{
PKT_secret_key
*
sk
;
PKT_onepass_sig
*
ops
;
PACKET
pkt
;
int
i
,
rc
;
for
(
i
=
0
,
sk_rover
=
sk_list
;
sk_rover
;
sk_rover
=
sk_rover
->
next
)
{
if
(
++
i
==
skcount
)
break
;
}
sk
=
sk_rover
->
sk
;
ops
=
xcalloc
(
1
,
sizeof
*
ops
);
ops
->
sig_class
=
sigclass
;
ops
->
digest_algo
=
hash_for
(
sk
->
pubkey_algo
,
sk
->
version
);
ops
->
pubkey_algo
=
sk
->
pubkey_algo
;
keyid_from_sk
(
sk
,
ops
->
keyid
);
ops
->
last
=
(
skcount
==
1
);
init_packet
(
&
pkt
);
pkt
.
pkttype
=
PKT_ONEPASS_SIG
;
pkt
.
pkt
.
onepass_sig
=
ops
;
rc
=
build_packet
(
out
,
&
pkt
);
free_packet
(
&
pkt
);
if
(
rc
)
{
log_error
(
"build onepass_sig packet failed: %s
\n
"
,
gpg_strerror
(
rc
));
return
rc
;
}
}
return
0
;
}
/*
* Helper to write the plaintext (literal data) packet
*/
static
int
write_plaintext_packet
(
iobuf_t
out
,
iobuf_t
inp
,
const
char
*
fname
,
int
ptmode
)
{
PKT_plaintext
*
pt
=
NULL
;
u32
filesize
;
int
rc
=
0
;
if
(
!
opt
.
no_literal
)
{
if
(
fname
||
opt
.
set_filename
)
{
char
*
s
=
make_basename
(
opt
.
set_filename
?
opt
.
set_filename
:
fname
/*, iobuf_get_real_fname(inp)*/
);
pt
=
xmalloc
(
sizeof
*
pt
+
strlen
(
s
)
-
1
);
pt
->
namelen
=
strlen
(
s
);
memcpy
(
pt
->
name
,
s
,
pt
->
namelen
);
xfree
(
s
);
}
else
{
/* no filename */
pt
=
xmalloc
(
sizeof
*
pt
-
1
);
pt
->
namelen
=
0
;
}
}
/* try to calculate the length of the data */
if
(
fname
&&
*
fname
&&
!
(
*
fname
==
'-'
&&
!
fname
[
1
]))
{
if
(
!
(
filesize
=
iobuf_get_filelength
(
inp
))
)
log_info
(
_
(
"WARNING: `%s' is an empty file
\n
"
),
fname
);
/* we can't yet encode the length of very large files,
* so we switch to partial length encoding in this case */
if
(
filesize
>=
IOBUF_FILELENGTH_LIMIT
)
filesize
=
0
;
/* because the text_filter modifies the length of the
* data, it is not possible to know the used length
* without a double read of the file - to avoid that
* we simple use partial length packets.
*/
if
(
ptmode
==
't'
)
filesize
=
0
;
}
else
{
filesize
=
opt
.
set_filesize
?
opt
.
set_filesize
:
0
;
/* stdin */
}
if
(
!
opt
.
no_literal
)
{
PACKET
pkt
;
pt
->
timestamp
=
make_timestamp
();
pt
->
mode
=
ptmode
;
pt
->
len
=
filesize
;
pt
->
new_ctb
=
!
pt
->
len
&&
!
RFC1991
;
pt
->
buf
=
inp
;
init_packet
(
&
pkt
);
pkt
.
pkttype
=
PKT_PLAINTEXT
;
pkt
.
pkt
.
plaintext
=
pt
;
/*cfx.datalen = filesize? calc_packet_length( &pkt ) : 0;*/
if
(
(
rc
=
build_packet
(
out
,
&
pkt
))
)
log_error
(
"build_packet(PLAINTEXT) failed: %s
\n
"
,
gpg_strerror
(
rc
)
);
pt
->
buf
=
NULL
;
}
else
{
byte
copy_buffer
[
4096
];
int
bytes_copied
;
while
((
bytes_copied
=
iobuf_read
(
inp
,
copy_buffer
,
4096
))
!=
-1
)
if
(
(
rc
=
iobuf_write
(
out
,
copy_buffer
,
bytes_copied
)
))
{
log_error
(
"copying input to output failed: %s
\n
"
,
gpg_strerror
(
rc
));
break
;
}
wipememory
(
copy_buffer
,
4096
);
/* burn buffer */
}
/* fixme: it seems that we never freed pt/pkt */
return
rc
;
}
/*
* Write the signatures from the SK_LIST to OUT. HASH must be a non-finalized
* hash which will not be changes here.
*/
static
int
write_signature_packets
(
SK_LIST
sk_list
,
iobuf_t
out
,
MD_HANDLE
hash
,
int
sigclass
,
u32
timestamp
,
u32
duration
,
int
status_letter
)
{
SK_LIST
sk_rover
;
/* loop over the secret certificates */
for
(
sk_rover
=
sk_list
;
sk_rover
;
sk_rover
=
sk_rover
->
next
)
{
PKT_secret_key
*
sk
;
PKT_signature
*
sig
;
MD_HANDLE
md
;
int
rc
;
sk
=
sk_rover
->
sk
;
/* build the signature packet */
sig
=
xcalloc
(
1
,
sizeof
*
sig
);
if
(
opt
.
force_v3_sigs
||
RFC1991
)
sig
->
version
=
3
;
else
if
(
duration
||
opt
.
sig_policy_url
||
opt
.
sig_notation_data
)
sig
->
version
=
4
;
else
sig
->
version
=
sk
->
version
;
keyid_from_sk
(
sk
,
sig
->
keyid
);
sig
->
digest_algo
=
hash_for
(
sk
->
pubkey_algo
,
sk
->
version
);
sig
->
pubkey_algo
=
sk
->
pubkey_algo
;
if
(
timestamp
)
sig
->
timestamp
=
timestamp
;
else
sig
->
timestamp
=
make_timestamp
();
if
(
duration
)
sig
->
expiredate
=
sig
->
timestamp
+
duration
;
sig
->
sig_class
=
sigclass
;
gcry_md_copy
(
&
md
,
hash
);
if
(
sig
->
version
>=
4
)
build_sig_subpkt_from_sig
(
sig
);
mk_notation_and_policy
(
sig
,
NULL
,
sk
);
hash_sigversion_to_magic
(
md
,
sig
);
gcry_md_final
(
md
);
rc
=
do_sign
(
sk
,
sig
,
md
,
hash_for
(
sig
->
pubkey_algo
,
sk
->
version
)
);
gcry_md_close
(
md
);
if
(
!
rc
)
{
/* and write it */
PACKET
pkt
;
init_packet
(
&
pkt
);
pkt
.
pkttype
=
PKT_SIGNATURE
;
pkt
.
pkt
.
signature
=
sig
;
rc
=
build_packet
(
out
,
&
pkt
);
if
(
!
rc
&&
is_status_enabled
())
{
print_status_sig_created
(
sk
,
sig
,
status_letter
);
}
free_packet
(
&
pkt
);
if
(
rc
)
log_error
(
"build signature packet failed: %s
\n
"
,
gpg_strerror
(
rc
)
);
}
if
(
rc
)
return
rc
;;
}
return
0
;
}
/****************
* Sign the files whose names are in FILENAME.
* If DETACHED has the value true,
* make a detached signature. If FILENAMES->d is NULL read from stdin
* and ignore the detached mode. Sign the file with all secret keys
* which can be taken from LOCUSR, if this is NULL, use the default one
* If ENCRYPTFLAG is true, use REMUSER (or ask if it is NULL) to encrypt the
* signed data for these users.
* If OUTFILE is not NULL; this file is used for output and the function
* does not ask for overwrite permission; output is then always
* uncompressed, non-armored and in binary mode.
*/
int
sign_file
(
STRLIST
filenames
,
int
detached
,
STRLIST
locusr
,
int
encryptflag
,
STRLIST
remusr
,
const
char
*
outfile
)
{
const
char
*
fname
;
armor_filter_context_t
afx
;
compress_filter_context_t
zfx
;
md_filter_context_t
mfx
;
text_filter_context_t
tfx
;
progress_filter_context_t
pfx
;
encrypt_filter_context_t
efx
;
iobuf_t
inp
=
NULL
,
out
=
NULL
;
PACKET
pkt
;
int
rc
=
0
;
PK_LIST
pk_list
=
NULL
;
SK_LIST
sk_list
=
NULL
;
SK_LIST
sk_rover
=
NULL
;
int
multifile
=
0
;
u32
duration
=
0
;
memset
(
&
afx
,
0
,
sizeof
afx
);
memset
(
&
zfx
,
0
,
sizeof
zfx
);
memset
(
&
mfx
,
0
,
sizeof
mfx
);
memset
(
&
efx
,
0
,
sizeof
efx
);
init_packet
(
&
pkt
);
if
(
filenames
)
{
fname
=
filenames
->
d
;
multifile
=
!!
filenames
->
next
;
}
else
fname
=
NULL
;
if
(
fname
&&
filenames
->
next
&&
(
!
detached
||
encryptflag
)
)
log_bug
(
"multiple files can only be detached signed"
);
if
(
opt
.
ask_sig_expire
&&
!
opt
.
force_v3_sigs
&&
!
opt
.
batch
&&
!
RFC1991
)
duration
=
ask_expire_interval
(
1
);
if
(
(
rc
=
build_sk_list
(
locusr
,
&
sk_list
,
1
,
PUBKEY_USAGE_SIG
))
)
goto
leave
;
if
(
PGP2
&&
!
only_old_style
(
sk_list
))
{
log_info
(
_
(
"you can only detach-sign with PGP 2.x style keys "
"while in --pgp2 mode
\n
"
));
compliance_failure
();
}
if
(
encryptflag
&&
(
rc
=
build_pk_list
(
remusr
,
&
pk_list
,
PUBKEY_USAGE_ENC
)))
goto
leave
;
/* prepare iobufs */
if
(
multifile
)
/* have list of filenames */
inp
=
NULL
;
/* we do it later */
else
{
if
(
!
(
inp
=
iobuf_open
(
fname
))
)
{
rc
=
gpg_error_from_errno
(
errno
);
log_error
(
"can't open %s: %s
\n
"
,
fname
?
fname
:
"[stdin]"
,
strerror
(
errno
)
);
goto
leave
;
}
handle_progress
(
&
pfx
,
inp
,
fname
);
}
if
(
outfile
)
{
if
(
!
(
out
=
iobuf_create
(
outfile
))
)
{
rc
=
gpg_error_from_errno
(
errno
);
log_error
(
_
(
"can't create %s: %s
\n
"
),
outfile
,
strerror
(
errno
)
);
goto
leave
;
}
else
if
(
opt
.
verbose
)
log_info
(
_
(
"writing to `%s'
\n
"
),
outfile
);
}
else
if
(
(
rc
=
open_outfile
(
fname
,
opt
.
armor
?
1
:
detached
?
2
:
0
,
&
out
)))
goto
leave
;
/* prepare to calculate the MD over the input */
if
(
opt
.
textmode
&&
!
outfile
&&
!
multifile
)
{
memset
(
&
tfx
,
0
,
sizeof
tfx
);
iobuf_push_filter
(
inp
,
text_filter
,
&
tfx
);
}
gcry_md_open
(
&
mfx
.
md
,
0
,
0
);
/* If we're encrypting and signing, it is reasonable to pick the
hash algorithm to use out of the recepient key prefs. */
if
(
pk_list
)
{
if
(
opt
.
def_digest_algo
)
{
if
(
!
opt
.
expert
&&
select_algo_from_prefs
(
pk_list
,
PREFTYPE_HASH
,
opt
.
def_digest_algo
,
NULL
)
!=
opt
.
def_digest_algo
)
log_info
(
_
(
"forcing digest algorithm %s (%d) "
"violates recipient preferences
\n
"
),
gcry_md_algo_name
(
opt
.
def_digest_algo
),
opt
.
def_digest_algo
);
}
else
{
int
hashlen
=
0
,
algo
;
/* Of course, if the recipient asks for something
unreasonable (like a non-160-bit hash for DSA, for
example), then don't do it. Check all sk's - if any
are DSA, then the hash must be 160-bit. In the future
this can be more complex with different hashes for each
sk, but so long as there is only one signing algorithm
with hash restrictions, this is ok. -dms */
for
(
sk_rover
=
sk_list
;
sk_rover
;
sk_rover
=
sk_rover
->
next
)
if
(
sk_rover
->
sk
->
pubkey_algo
==
PUBKEY_ALGO_DSA
)
hashlen
=
20
;
if
((
algo
=
select_algo_from_prefs
(
pk_list
,
PREFTYPE_HASH
,
-1
,
hashlen
?&
hashlen
:
NULL
))
>
0
)
recipient_digest_algo
=
algo
;
}
}
for
(
sk_rover
=
sk_list
;
sk_rover
;
sk_rover
=
sk_rover
->
next
)
{
PKT_secret_key
*
sk
=
sk_rover
->
sk
;
gcry_md_enable
(
mfx
.
md
,
hash_for
(
sk
->
pubkey_algo
,
sk
->
version
));
}
if
(
!
multifile
)
iobuf_push_filter
(
inp
,
md_filter
,
&
mfx
);
if
(
detached
&&
!
encryptflag
&&
!
RFC1991
)
afx
.
what
=
2
;
if
(
opt
.
armor
&&
!
outfile
)
iobuf_push_filter
(
out
,
armor_filter
,
&
afx
);
if
(
encryptflag
)
{
efx
.
pk_list
=
pk_list
;
/* fixme: set efx.cfx.datalen if known */
iobuf_push_filter
(
out
,
encrypt_filter
,
&
efx
);
}
if
(
opt
.
compress
&&
!
outfile
&&
(
!
detached
||
opt
.
compress_sigs
)
)
{
int
compr_algo
=
opt
.
def_compress_algo
;
/* If not forced by user */
if
(
compr_algo
==
-1
)
{
/* If we're not encrypting, then select_algo_from_prefs
will fail and we'll end up with the default. If we are
encrypting, select_algo_from_prefs cannot fail since
there is an assumed preference for uncompressed data.
Still, if it did fail, we'll also end up with the
default. */
if
((
compr_algo
=
select_algo_from_prefs
(
pk_list
,
PREFTYPE_ZIP
,
-1
,
NULL
))
==
-1
)
compr_algo
=
default_compress_algo
();
}
else
if
(
!
opt
.
expert
&&
pk_list
&&
select_algo_from_prefs
(
pk_list
,
PREFTYPE_ZIP
,
compr_algo
,
NULL
)
!=
compr_algo
)
log_info
(
_
(
"forcing compression algorithm %s (%d) "
"violates recipient preferences
\n
"
),
compress_algo_to_string
(
compr_algo
),
compr_algo
);
/* algo 0 means no compression */
if
(
compr_algo
)
{
zfx
.
algo
=
compr_algo
;
iobuf_push_filter
(
out
,
compress_filter
,
&
zfx
);
}
}
/* Write the one-pass signature packets if needed */
if
(
!
detached
&&
!
RFC1991
)
{
rc
=
write_onepass_sig_packets
(
sk_list
,
out
,
opt
.
textmode
&&
!
outfile
?
0x01
:
0x00
);
if
(
rc
)
goto
leave
;
}
/* setup the inner packet */
if
(
detached
)
{
if
(
multifile
)
{
STRLIST
sl
;
if
(
opt
.
verbose
)
log_info
(
_
(
"signing:"
)
);
/* must walk reverse trough this list */
for
(
sl
=
strlist_last
(
filenames
);
sl
;
sl
=
strlist_prev
(
filenames
,
sl
)
)
{
if
(
!
(
inp
=
iobuf_open
(
sl
->
d
))
)
{
rc
=
gpg_error_from_errno
(
errno
);
log_error
(
_
(
"can't open %s: %s
\n
"
),
sl
->
d
,
strerror
(
errno
)
);
goto
leave
;
}
handle_progress
(
&
pfx
,
inp
,
sl
->
d
);
if
(
opt
.
verbose
)
fprintf
(
stderr
,
" `%s'"
,
sl
->
d
);
if
(
opt
.
textmode
)
{
memset
(
&
tfx
,
0
,
sizeof
tfx
);
iobuf_push_filter
(
inp
,
text_filter
,
&
tfx
);
}
iobuf_push_filter
(
inp
,
md_filter
,
&
mfx
);
while
(
iobuf_get
(
inp
)
!=
-1
)
;
iobuf_close
(
inp
);
inp
=
NULL
;
}
if
(
opt
.
verbose
)
putc
(
'\n'
,
stderr
);
}
else
{
/* read, so that the filter can calculate the digest */
while
(
iobuf_get
(
inp
)
!=
-1
)
;
}
}
else
{
rc
=
write_plaintext_packet
(
out
,
inp
,
fname
,
opt
.
textmode
&&
!
outfile
?
't'
:
'b'
);
}
/* catch errors from above */
if
(
rc
)
goto
leave
;
/* write the signatures */
rc
=
write_signature_packets
(
sk_list
,
out
,
mfx
.
md
,
opt
.
textmode
&&
!
outfile
?
0x01
:
0x00
,
0
,
duration
,
detached
?
'D'
:
'S'
);
if
(
rc
)
goto
leave
;
leave
:
if
(
rc
)
iobuf_cancel
(
out
);
else
{
iobuf_close
(
out
);
if
(
encryptflag
)
write_status
(
STATUS_END_ENCRYPTION
);
}
iobuf_close
(
inp
);
gcry_md_close
(
mfx
.
md
);
release_sk_list
(
sk_list
);
release_pk_list
(
pk_list
);
recipient_digest_algo
=
0
;
return
rc
;
}
/****************
* make a clear signature. note that opt.armor is not needed
*/
int
clearsign_file
(
const
char
*
fname
,
STRLIST
locusr
,
const
char
*
outfile
)
{
armor_filter_context_t
afx
;
progress_filter_context_t
pfx
;
MD_HANDLE
textmd
=
NULL
;
iobuf_t
inp
=
NULL
,
out
=
NULL
;
PACKET
pkt
;
int
rc
=
0
;
SK_LIST
sk_list
=
NULL
;
SK_LIST
sk_rover
=
NULL
;
int
old_style
=
RFC1991
;
int
only_md5
=
0
;
u32
duration
=
0
;
memset
(
&
afx
,
0
,
sizeof
afx
);
init_packet
(
&
pkt
);
if
(
opt
.
ask_sig_expire
&&
!
opt
.
force_v3_sigs
&&
!
opt
.
batch
&&
!
RFC1991
)
duration
=
ask_expire_interval
(
1
);
if
(
(
rc
=
build_sk_list
(
locusr
,
&
sk_list
,
1
,
PUBKEY_USAGE_SIG
))
)
goto
leave
;
if
(
!
old_style
&&
!
duration
)
old_style
=
only_old_style
(
sk_list
);
if
(
PGP2
&&
!
only_old_style
(
sk_list
))
{
log_info
(
_
(
"you can only clearsign with PGP 2.x style keys "
"while in --pgp2 mode
\n
"
));
compliance_failure
();
}
/* prepare iobufs */
if
(
!
(
inp
=
iobuf_open
(
fname
))
)
{
rc
=
gpg_error_from_errno
(
errno
);
log_error
(
"can't open %s: %s
\n
"
,
fname
?
fname
:
"[stdin]"
,
strerror
(
errno
)
);
goto
leave
;
}
handle_progress
(
&
pfx
,
inp
,
fname
);
if
(
outfile
)
{
if
(
!
(
out
=
iobuf_create
(
outfile
))
)
{
rc
=
gpg_error_from_errno
(
errno
);
log_error
(
_
(
"can't create %s: %s
\n
"
),
outfile
,
strerror
(
errno
)
);
goto
leave
;
}
else
if
(
opt
.
verbose
)
log_info
(
_
(
"writing to `%s'
\n
"
),
outfile
);
}
else
if
(
(
rc
=
open_outfile
(
fname
,
1
,
&
out
))
)
goto
leave
;
iobuf_writestr
(
out
,
"-----BEGIN PGP SIGNED MESSAGE-----"
LF
);
for
(
sk_rover
=
sk_list
;
sk_rover
;
sk_rover
=
sk_rover
->
next
)
{
PKT_secret_key
*
sk
=
sk_rover
->
sk
;
if
(
hash_for
(
sk
->
pubkey_algo
,
sk
->
version
)
==
DIGEST_ALGO_MD5
)
only_md5
=
1
;
else
{
only_md5
=
0
;
break
;
}
}
if
(
!
(
old_style
&&
only_md5
)
)
{
const
char
*
s
;
int
any
=
0
;
byte
hashs_seen
[
256
];
memset
(
hashs_seen
,
0
,
sizeof
hashs_seen
);
iobuf_writestr
(
out
,
"Hash: "
);
for
(
sk_rover
=
sk_list
;
sk_rover
;
sk_rover
=
sk_rover
->
next
)
{
PKT_secret_key
*
sk
=
sk_rover
->
sk
;
int
i
=
hash_for
(
sk
->
pubkey_algo
,
sk
->
version
);
if
(
!
hashs_seen
[
i
&
0xff
]
)
{
s
=
gcry_md_algo_name
(
i
);
if
(
s
)
{
hashs_seen
[
i
&
0xff
]
=
1
;
if
(
any
)
iobuf_put
(
out
,
','
);
iobuf_writestr
(
out
,
s
);
any
=
1
;
}
}
}
assert
(
any
);
iobuf_writestr
(
out
,
LF
);
}
if
(
opt
.
not_dash_escaped
)
iobuf_writestr
(
out
,
"NotDashEscaped: You need GnuPG to verify this message"
LF
);
iobuf_writestr
(
out
,
LF
);
gcry_md_open
(
&
textmd
,
0
,
0
);
for
(
sk_rover
=
sk_list
;
sk_rover
;
sk_rover
=
sk_rover
->
next
)
{
PKT_secret_key
*
sk
=
sk_rover
->
sk
;
gcry_md_enable
(
textmd
,
hash_for
(
sk
->
pubkey_algo
,
sk
->
version
));
}
if
(
DBG_HASHING
)
gcry_md_start_debug
(
textmd
,
"clearsign"
);
copy_clearsig_text
(
out
,
inp
,
textmd
,
!
opt
.
not_dash_escaped
,
opt
.
escape_from
,
(
old_style
&&
only_md5
)
);
/* fixme: check for read errors */
/* now write the armor */
afx
.
what
=
2
;
iobuf_push_filter
(
out
,
armor_filter
,
&
afx
);
/* write the signatures */
rc
=
write_signature_packets
(
sk_list
,
out
,
textmd
,
0x01
,
0
,
duration
,
'C'
);
if
(
rc
)
goto
leave
;
leave
:
if
(
rc
)
iobuf_cancel
(
out
);
else
iobuf_close
(
out
);
iobuf_close
(
inp
);
gcry_md_close
(
textmd
);
release_sk_list
(
sk_list
);
return
rc
;
}
/*
* Sign and conventionally encrypt the given file.
* FIXME: Far too much code is duplicated - revamp the whole file.
*/
int
sign_symencrypt_file
(
const
char
*
fname
,
STRLIST
locusr
)
{
armor_filter_context_t
afx
;
progress_filter_context_t
pfx
;
compress_filter_context_t
zfx
;
md_filter_context_t
mfx
;
text_filter_context_t
tfx
;
cipher_filter_context_t
cfx
;
iobuf_t
inp
=
NULL
,
out
=
NULL
;
PACKET
pkt
;
STRING2KEY
*
s2k
=
NULL
;
int
rc
=
0
;
SK_LIST
sk_list
=
NULL
;
SK_LIST
sk_rover
=
NULL
;
int
algo
;
u32
duration
=
0
;
memset
(
&
afx
,
0
,
sizeof
afx
);
memset
(
&
zfx
,
0
,
sizeof
zfx
);
memset
(
&
mfx
,
0
,
sizeof
mfx
);
memset
(
&
tfx
,
0
,
sizeof
tfx
);
memset
(
&
cfx
,
0
,
sizeof
cfx
);
init_packet
(
&
pkt
);
if
(
opt
.
ask_sig_expire
&&
!
opt
.
force_v3_sigs
&&
!
opt
.
batch
&&
!
RFC1991
)
duration
=
ask_expire_interval
(
1
);
rc
=
build_sk_list
(
locusr
,
&
sk_list
,
1
,
PUBKEY_USAGE_SIG
);
if
(
rc
)
goto
leave
;
/* prepare iobufs */
inp
=
iobuf_open
(
fname
);
if
(
!
inp
)
{
rc
=
gpg_error_from_errno
(
errno
);
log_error
(
"can't open %s: %s
\n
"
,
fname
?
fname
:
"[stdin]"
,
strerror
(
errno
)
);
goto
leave
;
}
handle_progress
(
&
pfx
,
inp
,
fname
);
/* prepare key */
s2k
=
xcalloc
(
1
,
sizeof
*
s2k
);
s2k
->
mode
=
RFC1991
?
0
:
opt
.
s2k_mode
;
s2k
->
hash_algo
=
opt
.
s2k_digest_algo
;
algo
=
default_cipher_algo
();
if
(
!
opt
.
quiet
||
!
opt
.
batch
)
log_info
(
_
(
"%s encryption will be used
\n
"
),
gcry_cipher_algo_name
(
algo
)
);
cfx
.
dek
=
passphrase_to_dek
(
NULL
,
0
,
algo
,
s2k
,
2
,
NULL
,
NULL
);
if
(
!
cfx
.
dek
||
!
cfx
.
dek
->
keylen
)
{
rc
=
gpg_error
(
GPG_ERR_INV_PASSPHRASE
);
log_error
(
_
(
"error creating passphrase: %s
\n
"
),
gpg_strerror
(
rc
)
);
goto
leave
;
}
/* now create the outfile */
rc
=
open_outfile
(
fname
,
opt
.
armor
?
1
:
0
,
&
out
);
if
(
rc
)
goto
leave
;
/* prepare to calculate the MD over the input */
if
(
opt
.
textmode
)
iobuf_push_filter
(
inp
,
text_filter
,
&
tfx
);
gcry_md_open
(
&
mfx
.
md
,
0
,
0
);
for
(
sk_rover
=
sk_list
;
sk_rover
;
sk_rover
=
sk_rover
->
next
)
{
PKT_secret_key
*
sk
=
sk_rover
->
sk
;
gcry_md_enable
(
mfx
.
md
,
hash_for
(
sk
->
pubkey_algo
,
sk
->
version
));
}
iobuf_push_filter
(
inp
,
md_filter
,
&
mfx
);
/* Push armor output filter */
if
(
opt
.
armor
)
iobuf_push_filter
(
out
,
armor_filter
,
&
afx
);
/* Write the symmetric key packet */
/*(current filters: armor)*/
if
(
!
RFC1991
)
{
PKT_symkey_enc
*
enc
=
xcalloc
(
1
,
sizeof
*
enc
);
enc
->
version
=
4
;
enc
->
cipher_algo
=
cfx
.
dek
->
algo
;
enc
->
s2k
=
*
s2k
;
pkt
.
pkttype
=
PKT_SYMKEY_ENC
;
pkt
.
pkt
.
symkey_enc
=
enc
;
if
(
(
rc
=
build_packet
(
out
,
&
pkt
))
)
log_error
(
"build symkey packet failed: %s
\n
"
,
gpg_strerror
(
rc
)
);
xfree
(
enc
);
}
/* Push the encryption filter */
iobuf_push_filter
(
out
,
cipher_filter
,
&
cfx
);
/* Push the Zip filter */
if
(
opt
.
compress
&&
default_compress_algo
())
{
zfx
.
algo
=
default_compress_algo
();
iobuf_push_filter
(
out
,
compress_filter
,
&
zfx
);
}
/* Write the one-pass signature packets */
/*(current filters: zip - encrypt - armor)*/
if
(
!
RFC1991
)
{
rc
=
write_onepass_sig_packets
(
sk_list
,
out
,
opt
.
textmode
?
0x01
:
0x00
);
if
(
rc
)
goto
leave
;
}
/* Pipe data through all filters; i.e. write the signed stuff */
/*(current filters: zip - encrypt - armor)*/
rc
=
write_plaintext_packet
(
out
,
inp
,
fname
,
opt
.
textmode
?
't'
:
'b'
);
if
(
rc
)
goto
leave
;
/* Write the signatures */
/*(current filters: zip - encrypt - armor)*/
rc
=
write_signature_packets
(
sk_list
,
out
,
mfx
.
md
,
opt
.
textmode
?
0x01
:
0x00
,
0
,
duration
,
'S'
);
if
(
rc
)
goto
leave
;
leave
:
if
(
rc
)
iobuf_cancel
(
out
);
else
{
iobuf_close
(
out
);
write_status
(
STATUS_END_ENCRYPTION
);
}
iobuf_close
(
inp
);
release_sk_list
(
sk_list
);
gcry_md_close
(
mfx
.
md
);
xfree
(
cfx
.
dek
);
xfree
(
s2k
);
return
rc
;
}
/****************
* Create a signature packet for the given public key certificate and
* the user id and return it in ret_sig. User signature class SIGCLASS
* user-id is not used (and may be NULL if sigclass is 0x20) If
* DIGEST_ALGO is 0 the function selects an appropriate one.
* SIGVERSION gives the minimal required signature packet version;
* this is needed so that special properties like local sign are not
* applied (actually: dropped) when a v3 key is used. TIMESTAMP is
* the timestamp to use for the signature. 0 means "now". */
int
make_keysig_packet
(
PKT_signature
**
ret_sig
,
PKT_public_key
*
pk
,
PKT_user_id
*
uid
,
PKT_public_key
*
subpk
,
PKT_secret_key
*
sk
,
int
sigclass
,
int
digest_algo
,
int
sigversion
,
u32
timestamp
,
u32
duration
,
int
(
*
mksubpkt
)(
PKT_signature
*
,
void
*
),
void
*
opaque
)
{
PKT_signature
*
sig
;
int
rc
=
0
;
MD_HANDLE
md
;
assert
(
(
sigclass
>=
0x10
&&
sigclass
<=
0x13
)
||
sigclass
==
0x1F
||
sigclass
==
0x20
||
sigclass
==
0x18
||
sigclass
==
0x30
||
sigclass
==
0x28
);
if
(
opt
.
force_v4_certs
)
sigversion
=
4
;
if
(
sigversion
<
sk
->
version
)
sigversion
=
sk
->
version
;
/* If you are making a signature on a v4 key using your v3 key, it
doesn't make sense to generate a v3 sig. After all, no v3-only
PGP implementation could understand the v4 key in the first
place. Note that this implies that a signature on an attribute
uid is usually going to be v4 as well, since they are not
generally found on v3 keys. */
if
(
sigversion
<
pk
->
version
)
sigversion
=
pk
->
version
;
if
(
!
digest_algo
)
{
/* Basically, this means use SHA1 always unless it's a v3 RSA
key making a v3 cert (use MD5), or the user specified
something (use whatever they said). They still must use a
160-bit hash with DSA, or the signature will fail. Note
that this still allows the caller of make_keysig_packet to
override the user setting if it must. */
if
(
opt
.
cert_digest_algo
)
digest_algo
=
opt
.
cert_digest_algo
;
else
if
((
sk
->
pubkey_algo
==
PUBKEY_ALGO_RSA
||
sk
->
pubkey_algo
==
PUBKEY_ALGO_RSA_S
)
&&
pk
->
version
<
4
&&
sigversion
<
4
)
digest_algo
=
DIGEST_ALGO_MD5
;
else
digest_algo
=
DIGEST_ALGO_SHA1
;
}
gcry_md_open
(
&
md
,
digest_algo
,
0
);
/* hash the public key certificate and the user id */
hash_public_key
(
md
,
pk
);
if
(
sigclass
==
0x18
||
sigclass
==
0x28
)
{
/* subkey binding/revocation*/
hash_public_key
(
md
,
subpk
);
}
else
if
(
sigclass
!=
0x1F
&&
sigclass
!=
0x20
)
{
hash_uid
(
md
,
sigversion
,
uid
);
}
/* and make the signature packet */
sig
=
xcalloc
(
1
,
sizeof
*
sig
);
sig
->
version
=
sigversion
;
sig
->
flags
.
exportable
=
1
;
sig
->
flags
.
revocable
=
1
;
keyid_from_sk
(
sk
,
sig
->
keyid
);
sig
->
pubkey_algo
=
sk
->
pubkey_algo
;
sig
->
digest_algo
=
digest_algo
;
if
(
timestamp
)
sig
->
timestamp
=
timestamp
;
else
sig
->
timestamp
=
make_timestamp
();
if
(
duration
)
sig
->
expiredate
=
sig
->
timestamp
+
duration
;
sig
->
sig_class
=
sigclass
;
if
(
sig
->
version
>=
4
)
build_sig_subpkt_from_sig
(
sig
);
mk_notation_and_policy
(
sig
,
pk
,
sk
);
/* Crucial that the call to mksubpkt comes LAST before the calls
to finalize the sig as that makes it possible for the mksubpkt
function to get a reliable pointer to the subpacket area. */
if
(
sig
->
version
>=
4
&&
mksubpkt
)
rc
=
(
*
mksubpkt
)(
sig
,
opaque
);
if
(
!
rc
)
{
hash_sigversion_to_magic
(
md
,
sig
);
gcry_md_final
(
md
);
rc
=
complete_sig
(
sig
,
sk
,
md
);
}
gcry_md_close
(
md
);
if
(
rc
)
free_seckey_enc
(
sig
);
else
*
ret_sig
=
sig
;
return
rc
;
}
/****************
* Create a new signature packet based on an existing one.
* Only user ID signatures are supported for now.
* TODO: Merge this with make_keysig_packet.
*/
int
update_keysig_packet
(
PKT_signature
**
ret_sig
,
PKT_signature
*
orig_sig
,
PKT_public_key
*
pk
,
PKT_user_id
*
uid
,
PKT_public_key
*
subpk
,
PKT_secret_key
*
sk
,
int
(
*
mksubpkt
)(
PKT_signature
*
,
void
*
),
void
*
opaque
)
{
PKT_signature
*
sig
;
int
rc
=
0
;
MD_HANDLE
md
;
if
((
!
orig_sig
||
!
pk
||
!
sk
)
||
(
orig_sig
->
sig_class
>=
0x10
&&
orig_sig
->
sig_class
<=
0x13
&&
!
uid
)
||
(
orig_sig
->
sig_class
==
0x18
&&
!
subpk
))
return
GPG_ERR_GENERAL
;
gcry_md_open
(
&
md
,
orig_sig
->
digest_algo
,
0
);
/* hash the public key certificate and the user id */
hash_public_key
(
md
,
pk
);
if
(
orig_sig
->
sig_class
==
0x18
)
hash_public_key
(
md
,
subpk
);
else
hash_uid
(
md
,
orig_sig
->
version
,
uid
);
/* create a new signature packet */
sig
=
copy_signature
(
NULL
,
orig_sig
);
/* We need to create a new timestamp so that new sig expiration
calculations are done correctly... */
sig
->
timestamp
=
make_timestamp
();
/* ... but we won't make a timestamp earlier than the existing
one. */
while
(
sig
->
timestamp
<=
orig_sig
->
timestamp
)
{
sleep
(
1
);
sig
->
timestamp
=
make_timestamp
();
}
/* Note that already expired sigs will remain expired (with a
duration of 0) since build-packet.c:build_sig_subpkt_from_sig
detects this case. */
if
(
sig
->
version
>=
4
)
{
/* Put the updated timestamp into the sig. Note that this
will automagically lower any sig expiration dates to
correctly correspond to the differences in the timestamps
(i.e. the duration will shrink). */
build_sig_subpkt_from_sig
(
sig
);
if
(
mksubpkt
)
rc
=
(
*
mksubpkt
)(
sig
,
opaque
);
}
if
(
!
rc
)
{
hash_sigversion_to_magic
(
md
,
sig
);
gcry_md_final
(
md
);
rc
=
complete_sig
(
sig
,
sk
,
md
);
}
gcry_md_close
(
md
);
if
(
rc
)
free_seckey_enc
(
sig
);
else
*
ret_sig
=
sig
;
return
rc
;
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Sat, Nov 29, 7:03 AM (1 d, 12 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
41/86/da995dd27250e2d27fbaa24e96ad
Attached To
rG GnuPG
Event Timeline
Log In to Comment