1 /* -*- Mode: C; c-file-style: "bsd" -*-
2 * sign.c - Signing routines
3 * Copyright (C) 2006 Free Software Foundation, Inc.
4 * Copyright (C) 2002, 2003 Timo Schulz
6 * This file is part of OpenCDK.
8 * OpenCDK is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * OpenCDK is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with OpenCDK; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
37 static int file_clearsign( cdk_ctx_t
, cdk_strlist_t
,
38 const char *, const char * );
39 static int stream_clearsign( cdk_ctx_t
, cdk_stream_t
,
40 cdk_stream_t
, cdk_strlist_t
);
44 calc_subpkt_size( cdk_pkt_signature_t sig
)
49 _cdk_subpkt_get_array( sig
->hashed
, 1, &nbytes
);
50 sig
->hashed_size
= nbytes
;
53 _cdk_subpkt_get_array( sig
->unhashed
, 1, &nbytes
);
54 sig
->unhashed_size
= nbytes
;
60 _cdk_sig_hash_for( int pkalgo
, int pktver
)
62 if( is_DSA( pkalgo
) )
64 else if( is_RSA( pkalgo
) && pktver
< 4 )
66 return CDK_MD_SHA1
; /* default message digest */
71 _cdk_sig_create( cdk_pkt_pubkey_t pk
, cdk_pkt_signature_t sig
)
81 sig
->version
= pk
->version
;
82 sig
->pubkey_algo
= pk
->pubkey_algo
;
83 sig
->digest_algo
= _cdk_sig_hash_for( pk
->pubkey_algo
, pk
->version
);
84 cdk_pk_get_keyid( pk
, sig
->keyid
);
86 sig
->timestamp
= _cdk_timestamp( );
87 if( sig
->version
== 3 )
90 sig
->hashed
= sig
->unhashed
= NULL
;
92 _cdk_u32tobuf( sig
->keyid
[0], buf
);
93 _cdk_u32tobuf( sig
->keyid
[1], buf
+ 4 );
94 node
= cdk_subpkt_new( 8 );
96 cdk_subpkt_init( node
, CDK_SIGSUBPKT_ISSUER
, buf
, 8 );
99 _cdk_u32tobuf( sig
->timestamp
, buf
);
100 node
= cdk_subpkt_new( 4 );
102 cdk_subpkt_init( node
, CDK_SIGSUBPKT_SIG_CREATED
, buf
, 4 );
106 if( sig
->expiredate
) {
107 u32 u
= sig
->expiredate
- sig
->timestamp
;
108 _cdk_u32tobuf( u
, buf
);
109 node
= cdk_subpkt_new( 4 );
111 cdk_subpkt_init( node
, CDK_SIGSUBPKT_SIG_EXPIRE
, buf
, 4 );
112 cdk_subpkt_add( sig
->hashed
, node
);
115 calc_subpkt_size( sig
);
121 _cdk_sig_complete( cdk_pkt_signature_t sig
, cdk_pkt_seckey_t sk
,
126 if( !sig
|| !sk
|| !md
)
127 return CDK_Inv_Value
;
129 calc_subpkt_size( sig
);
130 _cdk_hash_sig_data( sig
, md
);
132 memcpy( digest
, cdk_md_read( md
, sig
->digest_algo
),
133 cdk_md_get_algo_dlen( sig
->digest_algo
) );
134 return cdk_pk_sign( sk
, sig
, digest
);
139 write_literal( cdk_stream_t inp
, cdk_stream_t out
)
142 cdk_pkt_literal_t pt
;
143 const char * s
= _cdk_stream_get_fname( inp
);
147 return CDK_Inv_Value
;
149 pkt
= cdk_calloc( 1, sizeof *pkt
);
151 return CDK_Out_Of_Core
;
152 cdk_stream_seek( inp
, 0 );
155 pt
= cdk_calloc( 1, sizeof *pt
+ strlen( s
) + 1 );
157 return CDK_Out_Of_Core
;
158 pt
->len
= cdk_stream_get_length( inp
);
160 pt
->timestamp
= _cdk_timestamp( );
161 pt
->namelen
= strlen( s
);
163 strcpy( pt
->name
, s
);
164 pkt
->pkttype
= CDK_PKT_LITERAL
;
165 pkt
->pkt
.literal
= pt
;
166 rc
= cdk_pkt_write( out
, pkt
);
174 write_pubkey_enc_list( cdk_ctx_t hd
, cdk_stream_t out
, cdk_strlist_t remusr
)
180 return CDK_Inv_Value
;
182 rc
= cdk_pklist_build( &pkl
, hd
->db
.pub
, remusr
, PK_USAGE_ENCR
);
186 cdk_dek_free( hd
->dek
);
187 rc
= cdk_dek_new( &hd
->dek
);
189 rc
= cdk_dek_set_cipher( hd
->dek
, cdk_pklist_select_algo( pkl
, 1 ) );
191 rc
= cdk_dek_set_key( hd
->dek
, NULL
, 0 );
193 cdk_dek_set_mdc_flag( hd
->dek
, cdk_pklist_use_mdc( pkl
) );
194 rc
= cdk_pklist_encrypt( pkl
, hd
->dek
, out
);
196 cdk_pklist_release( pkl
);
202 sig_get_version( cdk_ctx_t hd
, cdk_keylist_t kl
)
206 if( hd
&& hd
->opt
.compat
)
209 for( l
= kl
; l
; l
= l
->next
) {
210 if( (l
->type
== CDK_PKT_PUBLIC_KEY
&& l
->key
.pk
->version
== 3)
211 || (l
->type
== CDK_PKT_SECRET_KEY
&& l
->key
.sk
->version
== 3))
220 * @hd: session handle
222 * @out: output stream
223 * @locusr: local user list for signing
224 * @remusr: remote user list for encrypting
225 * @encryptflag: shall the output be encrypted? (1/0)
226 * @sigmode: signature mode
228 * Sign the data from the STREAM @inp.
231 cdk_stream_sign( cdk_ctx_t hd
, cdk_stream_t inp
, cdk_stream_t out
,
232 cdk_strlist_t locusr
, cdk_strlist_t remusr
,
233 int encryptflag
, int sigmode
)
238 int sigver
, digest_algo
;
239 int rc
, detached
= sigmode
== CDK_SIGMODE_DETACHED
;
242 return CDK_Inv_Value
;
243 if( detached
&& encryptflag
)
246 if( sigmode
== CDK_SIGMODE_CLEAR
)
247 return stream_clearsign( hd
, inp
, out
, locusr
);
249 rc
= cdk_sklist_build( &list
, hd
->db
.sec
, hd
, locusr
, 1, PK_USAGE_SIGN
);
254 digest_algo
= _cdk_sig_hash_for( sk
->pubkey_algo
, sk
->version
);
255 if( cdk_handle_control( hd
, CDK_CTLF_GET
, CDK_CTL_FORCE_DIGEST
) )
256 digest_algo
= hd
->digest_algo
;
259 cdk_stream_set_armor_flag( out
, detached
? CDK_ARMOR_SIGNATURE
: 0 );
262 cdk_stream_set_cache( out
, 1 );
263 rc
= write_pubkey_enc_list( hd
, out
, remusr
);
265 cdk_sklist_release( list
);
268 cdk_stream_set_cipher_flag( out
, hd
->dek
, hd
->dek
->use_mdc
);
269 cdk_stream_set_cache( out
, 0 );
272 cdk_stream_set_hash_flag( inp
, digest_algo
);
273 /* kick off the filter */
274 sigver
= sig_get_version( hd
, list
);
275 cdk_stream_read( inp
, NULL
, 0 );
276 mfx
= _cdk_stream_get_opaque( inp
, fHASH
);
277 if( mfx
&& mfx
->md
) {
279 rc
= cdk_sklist_write( list
, out
, mfx
->md
, 0x00, 0x03 );
280 if( !rc
&& !detached
)
281 rc
= write_literal( inp
, out
);
285 rc
= cdk_sklist_write_onepass( list
, out
, 0x00, digest_algo
);
287 rc
= write_literal( inp
, out
);
290 rc
= cdk_sklist_write( list
, out
, mfx
->md
, 0x00, 0x04 );
293 cdk_sklist_release( list
);
300 * @locusr: List of userid which should be used for signing
301 * @remusr: If encrypt is valid, the list of recipients
302 * @file: Name of the input file
303 * @output: Name of the output file
304 * @sigmode: Signature mode
305 * @encryptflag: enable sign and encrypt
310 cdk_file_sign( cdk_ctx_t hd
, cdk_strlist_t locusr
, cdk_strlist_t remusr
,
311 const char * file
, const char * output
,
312 int sigmode
, int encryptflag
)
314 cdk_stream_t inp
= NULL
, out
= NULL
;
317 if( !file
|| !output
)
318 return CDK_Inv_Value
;
319 if( encryptflag
&& !remusr
)
320 return CDK_Inv_Value
;
321 if( (sigmode
!= CDK_SIGMODE_NORMAL
) && encryptflag
)
323 if( !remusr
&& !locusr
)
324 return CDK_Inv_Value
;
325 if( sigmode
== CDK_SIGMODE_CLEAR
)
326 return file_clearsign( hd
, locusr
, file
, output
);
328 rc
= cdk_stream_open( file
, &inp
);
332 if( hd
->opt
.armor
|| encryptflag
)
333 rc
= cdk_stream_new( output
, &out
);
335 rc
= cdk_stream_create( output
, &out
);
337 cdk_stream_close( inp
);
340 rc
= cdk_stream_sign( hd
, inp
, out
, locusr
, remusr
, encryptflag
, sigmode
);
342 cdk_stream_close( inp
);
343 cdk_stream_close( out
);
349 put_hash_line( cdk_stream_t out
, int digest_algo
, int is_v4
)
351 const char * s
= NULL
;
354 cdk_stream_putc( out
, '\n' );
358 switch( digest_algo
) {
359 case CDK_MD_MD2
: s
= "Hash: MD2\n\n"; break;
360 case CDK_MD_MD5
: s
= "Hash: MD5\n\n"; break;
361 case CDK_MD_SHA1
: s
= "Hash: SHA1\n\n"; break;
362 case CDK_MD_RMD160
: s
= "Hash: RIPEMD160\n\n"; break;
363 case CDK_MD_SHA256
: s
= "Hash: SHA256\n\n"; break;
364 default : s
= "Hash: SHA1\n\n"; break;
366 _cdk_stream_puts( out
, s
);
371 _cdk_trim_string( char * s
, int canon
)
373 while( s
&& *s
&&( s
[strlen( s
)-1] == '\t'
374 || s
[strlen( s
)-1] == '\r'
375 || s
[strlen( s
)-1] == '\n'
376 || s
[strlen( s
)-1] == ' '))
377 s
[strlen( s
) -1] = '\0';
384 stream_clearsign( cdk_ctx_t hd
, cdk_stream_t inp
, cdk_stream_t out
,
385 cdk_strlist_t locusr
)
387 cdk_md_hd_t md
= NULL
;
393 int digest_algo
, sigver
;
396 rc
= cdk_sklist_build( &list
, hd
->db
.sec
, hd
, locusr
, 1, PK_USAGE_SIGN
);
401 digest_algo
= _cdk_sig_hash_for( sk
->pubkey_algo
, sk
->version
);
402 md
= cdk_md_open( digest_algo
, 0 );
404 cdk_sklist_release( list
);
405 return CDK_Gcry_Error
;
408 s
= _cdk_armor_get_lineend( );
409 strcpy( buf
, "-----BEGIN PGP SIGNED MESSAGE-----" );
411 _cdk_stream_puts( out
, buf
);
412 put_hash_line( out
, digest_algo
, sk
->version
== 4 );
414 while( !cdk_stream_eof( inp
) ) {
415 nread
= _cdk_stream_gets( inp
, buf
, sizeof buf
-1 );
418 _cdk_trim_string( buf
, 1 );
419 cdk_md_write( md
, buf
, strlen( buf
) );
420 if( buf
[0] == '-' ) {
421 memmove( &buf
[2], buf
, nread
+ 1 );
424 if( strlen( s
) == 1 ) {
425 buf
[strlen( buf
) - 1] = '\0';
426 buf
[strlen( buf
) - 1] = '\n';
428 _cdk_stream_puts( out
, buf
);
430 _cdk_stream_puts( out
, s
);
431 tmp
= cdk_stream_tmp( );
433 rc
= CDK_Out_Of_Core
;
436 cdk_stream_tmp_set_mode( tmp
, 1 );
437 cdk_stream_set_armor_flag( tmp
, CDK_ARMOR_SIGNATURE
);
439 sigver
= sig_get_version( hd
, list
);
440 rc
= cdk_sklist_write( list
, tmp
, md
, 0x01, sigver
);
442 cdk_stream_close( tmp
);
446 rc
= cdk_stream_flush( tmp
);
450 while( !cdk_stream_eof( tmp
) ) {
451 nread
= cdk_stream_read( tmp
, buf
, sizeof buf
-1 );
454 cdk_stream_write( out
, buf
, nread
);
456 cdk_stream_close( tmp
);
460 cdk_sklist_release( list
);
466 file_clearsign( cdk_ctx_t hd
, cdk_strlist_t locusr
,
467 const char * file
, const char * output
)
469 cdk_stream_t inp
= NULL
, out
= NULL
;
472 if( !locusr
|| !file
|| !output
)
473 return CDK_Inv_Value
;
474 if( !hd
->opt
.overwrite
&& _cdk_check_file( output
) )
477 rc
= cdk_stream_open( file
, &inp
);
481 rc
= cdk_stream_create( output
, &out
);
483 cdk_stream_close( inp
);
487 rc
= stream_clearsign( hd
, inp
, out
, locusr
);
489 cdk_stream_close( inp
);
490 cdk_stream_close( out
);