xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/signature.c (revision c8da0e5fefd3800856b306200a18b2315c7fbb9f)
1 /*-
2  * Copyright (c) 2009 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Alistair Crooks (agc@NetBSD.org)
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 /*
30  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31  * All rights reserved.
32  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33  * their moral rights under the UK Copyright Design and Patents Act 1988 to
34  * be recorded as the authors of this copyright work.
35  *
36  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37  * use this file except in compliance with the License.
38  *
39  * You may obtain a copy of the License at
40  *     http://www.apache.org/licenses/LICENSE-2.0
41  *
42  * Unless required by applicable law or agreed to in writing, software
43  * distributed under the License is distributed on an "AS IS" BASIS,
44  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45  *
46  * See the License for the specific language governing permissions and
47  * limitations under the License.
48  */
49 
50 /** \file
51  */
52 #include "config.h"
53 
54 #ifdef HAVE_FCNTL_H
55 #include <fcntl.h>
56 #endif
57 
58 #include <string.h>
59 
60 #ifdef HAVE_UNISTD_H
61 #include <unistd.h>
62 #endif
63 
64 #ifdef HAVE_OPENSSL_DSA_H
65 #include <openssl/dsa.h>
66 #endif
67 
68 #include "signature.h"
69 #include "crypto.h"
70 #include "create.h"
71 #include "netpgpsdk.h"
72 #include "readerwriter.h"
73 #include "loccreate.h"
74 #include "validate.h"
75 #include "netpgpdefs.h"
76 
77 #define MAXBUF 1024		/* <! Standard buffer size to use */
78 
79 /** \ingroup Core_Create
80  * needed for signature creation
81  */
82 struct __ops_create_sig {
83 	__ops_hash_t		 hash;
84 	__ops_sig_t		 sig;
85 	__ops_memory_t		*mem;
86 	__ops_createinfo_t	*info;/* !< how to do the writing */
87 	unsigned		 hashed_count_offset;
88 	unsigned		 hashed_data_length;
89 	unsigned 		 unhashed_count_offset;
90 };
91 
92 /**
93    \ingroup Core_Signature
94    Creates new __ops_create_sig_t
95    \return new __ops_create_sig_t
96    \note It is the caller's responsibility to call __ops_create_sig_delete()
97    \sa __ops_create_sig_delete()
98 */
99 __ops_create_sig_t *
100 __ops_create_sig_new(void)
101 {
102 	return calloc(1, sizeof(__ops_create_sig_t));
103 }
104 
105 /**
106    \ingroup Core_Signature
107    Free signature and memory associated with it
108    \param sig struct to free
109    \sa __ops_create_sig_new()
110 */
111 void
112 __ops_create_sig_delete(__ops_create_sig_t *sig)
113 {
114 	__ops_createinfo_delete(sig->info);
115 	sig->info = NULL;
116 	free(sig);
117 }
118 
119 static unsigned char prefix_md5[] = {
120 	0x30, 0x20, 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86,
121 	0xF7, 0x0D, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10
122 };
123 
124 static unsigned char prefix_sha1[] = {
125 	0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0E, 0x03, 0x02,
126 	0x1A, 0x05, 0x00, 0x04, 0x14
127 };
128 
129 static unsigned char prefix_sha256[] = {
130 	0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
131 	0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
132 };
133 
134 
135 /* XXX: both this and verify would be clearer if the signature were */
136 /* treated as an MPI. */
137 static int
138 rsa_sign(__ops_hash_t *hash,
139 	const __ops_rsa_pubkey_t *pubrsa,
140 	const __ops_rsa_seckey_t *secrsa,
141 	__ops_createinfo_t *opt)
142 {
143 	unsigned char   hashbuf[NETPGP_BUFSIZ];
144 	unsigned char   sigbuf[NETPGP_BUFSIZ];
145 	unsigned        hashsize;
146 	unsigned        keysize;
147 	unsigned        n;
148 	unsigned        t;
149 	BIGNUM         *bn;
150 
151 	if (strcmp(hash->name, "SHA1") == 0) {
152 		hashsize = OPS_SHA1_HASH_SIZE + sizeof(prefix_sha1);
153 	} else {
154 		hashsize = OPS_SHA256_HASH_SIZE + sizeof(prefix_sha256);
155 	}
156 	keysize = (BN_num_bits(pubrsa->n) + 7) / 8;
157 	if (keysize > sizeof(hashbuf)) {
158 		(void) fprintf(stderr, "rsa_sign: keysize too big\n");
159 		return 0;
160 	}
161 	if (10 + hashsize > keysize) {
162 		(void) fprintf(stderr, "rsa_sign: hashsize too big\n");
163 		return 0;
164 	}
165 
166 	hashbuf[0] = 0;
167 	hashbuf[1] = 1;
168 	if (__ops_get_debug_level(__FILE__)) {
169 		printf("rsa_sign: PS is %d\n", keysize - hashsize - 1 - 2);
170 	}
171 	for (n = 2; n < keysize - hashsize - 1; ++n) {
172 		hashbuf[n] = 0xff;
173 	}
174 	hashbuf[n++] = 0;
175 
176 	if (strcmp(hash->name, "SHA1") == 0) {
177 		(void) memcpy(&hashbuf[n], prefix_sha1, sizeof(prefix_sha1));
178 		n += sizeof(prefix_sha1);
179 		t = hash->finish(hash, &hashbuf[n]);
180 		if (t != OPS_SHA1_HASH_SIZE) {
181 			(void) fprintf(stderr, "rsa_sign: short SHA1 hash\n");
182 			return 0;
183 		}
184 	} else {
185 		(void) memcpy(&hashbuf[n], prefix_sha256,
186 				sizeof(prefix_sha256));
187 		n += sizeof(prefix_sha256);
188 		t = hash->finish(hash, &hashbuf[n]);
189 		if (t != OPS_SHA256_HASH_SIZE) {
190 			(void) fprintf(stderr, "rsa_sign: short SHA256 hash\n");
191 			return 0;
192 		}
193 	}
194 
195 	__ops_write(&hashbuf[n], 2, opt);
196 
197 	n += t;
198 	if (n != keysize) {
199 		(void) fprintf(stderr, "rsa_sign: n != keysize\n");
200 		return 0;
201 	}
202 
203 	t = __ops_rsa_private_encrypt(sigbuf, hashbuf, keysize, secrsa, pubrsa);
204 	bn = BN_bin2bn(sigbuf, (int)t, NULL);
205 	__ops_write_mpi(bn, opt);
206 	BN_free(bn);
207 	return 1;
208 }
209 
210 static int
211 dsa_sign(__ops_hash_t * hash,
212 	 const __ops_dsa_pubkey_t *dsa,
213 	 const __ops_dsa_seckey_t *sdsa,
214 	 __ops_createinfo_t *cinfo)
215 {
216 	unsigned char   hashbuf[NETPGP_BUFSIZ];
217 	unsigned        hashsize;
218 	unsigned        t;
219 	DSA_SIG        *dsasig;
220 
221 	/* hashsize must be "equal in size to the number of bits of q,  */
222 	/* the group generated by the DSA key's generator value */
223 	/* 160/8 = 20 */
224 
225 	hashsize = 20;
226 
227 	/* finalise hash */
228 	t = hash->finish(hash, &hashbuf[0]);
229 	if (t != 20) {
230 		(void) fprintf(stderr, "dsa_sign: hashfinish not 20\n");
231 		return 0;
232 	}
233 
234 	__ops_write(&hashbuf[0], 2, cinfo);
235 
236 	/* write signature to buf */
237 	dsasig = __ops_dsa_sign(hashbuf, hashsize, sdsa, dsa);
238 
239 	/* convert and write the sig out to memory */
240 	__ops_write_mpi(dsasig->r, cinfo);
241 	__ops_write_mpi(dsasig->s, cinfo);
242 	DSA_SIG_free(dsasig);
243 	return 1;
244 }
245 
246 static bool
247 rsa_verify(__ops_hash_alg_t type,
248 	   const unsigned char *hash,
249 	   size_t hash_length,
250 	   const __ops_rsa_sig_t *sig,
251 	   const __ops_rsa_pubkey_t *pubrsa)
252 {
253 	const unsigned char	*prefix;
254 	unsigned char   	 sigbuf[NETPGP_BUFSIZ];
255 	unsigned char   	 hashbuf_from_sig[NETPGP_BUFSIZ];
256 	unsigned        	 n;
257 	unsigned        	 keysize;
258 	unsigned		 plen;
259 	unsigned		 debug_len_decrypted;
260 
261 	plen = 0;
262 	prefix = (const unsigned char *) "";
263 	keysize = BN_num_bytes(pubrsa->n);
264 	/* RSA key can't be bigger than 65535 bits, so... */
265 	if (keysize > sizeof(hashbuf_from_sig)) {
266 		(void) fprintf(stderr, "rsa_verify: keysize too big\n");
267 		return false;
268 	}
269 	if ((unsigned) BN_num_bits(sig->sig) > 8 * sizeof(sigbuf)) {
270 		(void) fprintf(stderr, "rsa_verify: BN_numbits too big\n");
271 		return false;
272 	}
273 	BN_bn2bin(sig->sig, sigbuf);
274 
275 	n = __ops_rsa_public_decrypt(hashbuf_from_sig, sigbuf,
276 		(unsigned)(BN_num_bits(sig->sig) + 7) / 8, pubrsa);
277 	debug_len_decrypted = n;
278 
279 	if (n != keysize) {
280 		/* obviously, this includes error returns */
281 		return false;
282 	}
283 
284 	/* XXX: why is there a leading 0? The first byte should be 1... */
285 	/* XXX: because the decrypt should use keysize and not sigsize? */
286 	if (hashbuf_from_sig[0] != 0 || hashbuf_from_sig[1] != 1) {
287 		return false;
288 	}
289 
290 	switch (type) {
291 	case OPS_HASH_MD5:
292 		prefix = prefix_md5;
293 		plen = sizeof(prefix_md5);
294 		break;
295 	case OPS_HASH_SHA1:
296 		prefix = prefix_sha1;
297 		plen = sizeof(prefix_sha1);
298 		break;
299 	case OPS_HASH_SHA256:
300 		prefix = prefix_sha256;
301 		plen = sizeof(prefix_sha256);
302 		break;
303 	default:
304 		(void) fprintf(stderr, "Unknown hash algorithm: %d\n", type);
305 		return false;
306 	}
307 
308 	if (keysize - plen - hash_length < 10) {
309 		return false;
310 	}
311 
312 	for (n = 2; n < keysize - plen - hash_length - 1; ++n) {
313 		if (hashbuf_from_sig[n] != 0xff) {
314 			return false;
315 		}
316 	}
317 
318 	if (hashbuf_from_sig[n++] != 0) {
319 		return false;
320 	}
321 
322 	if (__ops_get_debug_level(__FILE__)) {
323 		unsigned	zz;
324 		unsigned	uu;
325 
326 		printf("\n");
327 		printf("hashbuf_from_sig\n");
328 		for (zz = 0; zz < debug_len_decrypted; zz++) {
329 			printf("%02x ", hashbuf_from_sig[n + zz]);
330 		}
331 		printf("\n");
332 		printf("prefix\n");
333 		for (zz = 0; zz < plen; zz++) {
334 			printf("%02x ", prefix[zz]);
335 		}
336 		printf("\n");
337 
338 		printf("\n");
339 		printf("hash from sig\n");
340 		for (uu = 0; uu < hash_length; uu++) {
341 			printf("%02x ", hashbuf_from_sig[n + plen + uu]);
342 		}
343 		printf("\n");
344 		printf("hash passed in (should match hash from sig)\n");
345 		for (uu = 0; uu < hash_length; uu++) {
346 			printf("%02x ", hash[uu]);
347 		}
348 		printf("\n");
349 	}
350 	if (memcmp(&hashbuf_from_sig[n], prefix, plen) != 0 ||
351 	    memcmp(&hashbuf_from_sig[n + plen], hash, hash_length) != 0) {
352 		return false;
353 	}
354 	return true;
355 }
356 
357 static void
358 hash_add_key(__ops_hash_t *hash, const __ops_pubkey_t *key)
359 {
360 	__ops_memory_t	*mem = __ops_memory_new();
361 	size_t		 len;
362 
363 	__ops_build_pubkey(mem, key, false);
364 	len = __ops_memory_get_length(mem);
365 	__ops_hash_add_int(hash, 0x99, 1);
366 	__ops_hash_add_int(hash, len, 2);
367 	hash->add(hash, __ops_memory_get_data(mem), len);
368 	__ops_memory_free(mem);
369 }
370 
371 static void
372 initialise_hash(__ops_hash_t * hash, const __ops_sig_t * sig)
373 {
374 	__ops_hash_any(hash, sig->info.hash_alg);
375 	hash->init(hash);
376 }
377 
378 static void
379 init_key_sig(__ops_hash_t * hash, const __ops_sig_t * sig,
380 		   const __ops_pubkey_t *key)
381 {
382 	initialise_hash(hash, sig);
383 	hash_add_key(hash, key);
384 }
385 
386 static void
387 hash_add_trailer(__ops_hash_t * hash, const __ops_sig_t * sig,
388 		 const unsigned char *raw_packet)
389 {
390 	if (sig->info.version == OPS_V4) {
391 		if (raw_packet) {
392 			hash->add(hash, raw_packet + sig->v4_hashed_data_start,
393 				  sig->info.v4_hashed_data_length);
394 		}
395 		__ops_hash_add_int(hash, (unsigned)sig->info.version, 1);
396 		__ops_hash_add_int(hash, 0xff, 1);
397 		__ops_hash_add_int(hash, sig->info.v4_hashed_data_length, 4);
398 	} else {
399 		__ops_hash_add_int(hash, (unsigned)sig->info.type, 1);
400 		__ops_hash_add_int(hash, (unsigned)sig->info.birthtime, 4);
401 	}
402 }
403 
404 /**
405    \ingroup Core_Signature
406    \brief Checks a signature
407    \param hash Signature Hash to be checked
408    \param length Signature Length
409    \param sig The Signature to be checked
410    \param signer The signer's public key
411    \return true if good; else false
412 */
413 bool
414 __ops_check_sig(const unsigned char *hash, unsigned length,
415 		    const __ops_sig_t * sig,
416 		    const __ops_pubkey_t * signer)
417 {
418 	bool   ret;
419 
420 	if (__ops_get_debug_level(__FILE__)) {
421 		printf("__ops_check_sig: (length %d) hash=", length);
422 		/* hashout[0]=0; */
423 		hexdump(hash, length, "");
424 	}
425 	ret = 0;
426 	switch (sig->info.key_alg) {
427 	case OPS_PKA_DSA:
428 		ret = __ops_dsa_verify(hash, length, &sig->info.sig.dsa,
429 				&signer->key.dsa);
430 		break;
431 
432 	case OPS_PKA_RSA:
433 		ret = rsa_verify(sig->info.hash_alg, hash, length,
434 				&sig->info.sig.rsa,
435 				&signer->key.rsa);
436 		break;
437 
438 	default:
439 		(void) fprintf(stderr, "__ops_check_sig: unusual alg\n");
440 		ret = false;
441 	}
442 
443 	return ret;
444 }
445 
446 static bool
447 hash_and_check_sig(__ops_hash_t * hash,
448 			 const __ops_sig_t * sig,
449 			 const __ops_pubkey_t * signer)
450 {
451 	unsigned char   hashout[OPS_MAX_HASH_SIZE];
452 	unsigned	n;
453 
454 	n = hash->finish(hash, hashout);
455 	return __ops_check_sig(hashout, n, sig, signer);
456 }
457 
458 static bool
459 finalise_sig(__ops_hash_t * hash,
460 		   const __ops_sig_t * sig,
461 		   const __ops_pubkey_t * signer,
462 		   const unsigned char *raw_packet)
463 {
464 	hash_add_trailer(hash, sig, raw_packet);
465 	return hash_and_check_sig(hash, sig, signer);
466 }
467 
468 /**
469  * \ingroup Core_Signature
470  *
471  * \brief Verify a certification signature.
472  *
473  * \param key The public key that was signed.
474  * \param id The user ID that was signed
475  * \param sig The signature.
476  * \param signer The public key of the signer.
477  * \param raw_packet The raw signature packet.
478  * \return true if OK; else false
479  */
480 bool
481 __ops_check_useridcert_sig(const __ops_pubkey_t * key,
482 			  const __ops_user_id_t * id,
483 			  const __ops_sig_t * sig,
484 			  const __ops_pubkey_t * signer,
485 			  const unsigned char *raw_packet)
486 {
487 	__ops_hash_t	hash;
488 	size_t          user_id_len = strlen((char *) id->user_id);
489 
490 	init_key_sig(&hash, sig, key);
491 
492 	if (sig->info.version == OPS_V4) {
493 		__ops_hash_add_int(&hash, 0xb4, 1);
494 		__ops_hash_add_int(&hash, user_id_len, 4);
495 	}
496 	hash.add(&hash, id->user_id, user_id_len);
497 
498 	return finalise_sig(&hash, sig, signer, raw_packet);
499 }
500 
501 /**
502  * \ingroup Core_Signature
503  *
504  * Verify a certification signature.
505  *
506  * \param key The public key that was signed.
507  * \param attribute The user attribute that was signed
508  * \param sig The signature.
509  * \param signer The public key of the signer.
510  * \param raw_packet The raw signature packet.
511  * \return true if OK; else false
512  */
513 bool
514 __ops_check_userattrcert_sig(const __ops_pubkey_t * key,
515 				const __ops_user_attribute_t *attribute,
516 				const __ops_sig_t *sig,
517 				const __ops_pubkey_t *signer,
518 				const unsigned char *raw_packet)
519 {
520 	__ops_hash_t      hash;
521 
522 	init_key_sig(&hash, sig, key);
523 
524 	if (sig->info.version == OPS_V4) {
525 		__ops_hash_add_int(&hash, 0xd1, 1);
526 		__ops_hash_add_int(&hash, attribute->data.len, 4);
527 	}
528 	hash.add(&hash, attribute->data.contents, attribute->data.len);
529 
530 	return finalise_sig(&hash, sig, signer, raw_packet);
531 }
532 
533 /**
534  * \ingroup Core_Signature
535  *
536  * Verify a subkey signature.
537  *
538  * \param key The public key whose subkey was signed.
539  * \param subkey The subkey of the public key that was signed.
540  * \param sig The signature.
541  * \param signer The public key of the signer.
542  * \param raw_packet The raw signature packet.
543  * \return true if OK; else false
544  */
545 bool
546 __ops_check_subkey_sig(const __ops_pubkey_t * key,
547 			   const __ops_pubkey_t * subkey,
548 			   const __ops_sig_t * sig,
549 			   const __ops_pubkey_t * signer,
550 			   const unsigned char *raw_packet)
551 {
552 	__ops_hash_t      hash;
553 
554 	init_key_sig(&hash, sig, key);
555 	hash_add_key(&hash, subkey);
556 
557 	return finalise_sig(&hash, sig, signer, raw_packet);
558 }
559 
560 /**
561  * \ingroup Core_Signature
562  *
563  * Verify a direct signature.
564  *
565  * \param key The public key which was signed.
566  * \param sig The signature.
567  * \param signer The public key of the signer.
568  * \param raw_packet The raw signature packet.
569  * \return true if OK; else false
570  */
571 bool
572 __ops_check_direct_sig(const __ops_pubkey_t * key,
573 			   const __ops_sig_t * sig,
574 			   const __ops_pubkey_t * signer,
575 			   const unsigned char *raw_packet)
576 {
577 	__ops_hash_t      hash;
578 
579 	init_key_sig(&hash, sig, key);
580 	return finalise_sig(&hash, sig, signer, raw_packet);
581 }
582 
583 /**
584  * \ingroup Core_Signature
585  *
586  * Verify a signature on a hash (the hash will have already been fed
587  * the material that was being signed, for example signed cleartext).
588  *
589  * \param hash A hash structure of appropriate type that has been fed
590  * the material to be signed. This MUST NOT have been finalised.
591  * \param sig The signature to be verified.
592  * \param signer The public key of the signer.
593  * \return true if OK; else false
594  */
595 bool
596 __ops_check_hash_sig(__ops_hash_t * hash,
597 			 const __ops_sig_t * sig,
598 			 const __ops_pubkey_t * signer)
599 {
600 	return (sig->info.hash_alg == hash->alg) ?
601 		finalise_sig(hash, sig, signer, NULL) :
602 		false;
603 }
604 
605 static void
606 start_sig_in_mem(__ops_create_sig_t * sig)
607 {
608 	/* since this has subpackets and stuff, we have to buffer the whole */
609 	/* thing to get counts before writing. */
610 	sig->mem = __ops_memory_new();
611 	__ops_memory_init(sig->mem, 100);
612 	__ops_writer_set_memory(sig->info, sig->mem);
613 
614 	/* write nearly up to the first subpacket */
615 	__ops_write_scalar((unsigned)sig->sig.info.version, 1, sig->info);
616 	__ops_write_scalar((unsigned)sig->sig.info.type, 1, sig->info);
617 	__ops_write_scalar((unsigned)sig->sig.info.key_alg, 1, sig->info);
618 	__ops_write_scalar((unsigned)sig->sig.info.hash_alg, 1, sig->info);
619 
620 	/* dummy hashed subpacket count */
621 	sig->hashed_count_offset = __ops_memory_get_length(sig->mem);
622 	__ops_write_scalar(0, 2, sig->info);
623 }
624 
625 /**
626  * \ingroup Core_Signature
627  *
628  * __ops_sig_start() creates a V4 public key signature with a SHA1 hash.
629  *
630  * \param sig The signature structure to initialise
631  * \param key The public key to be signed
632  * \param id The user ID being bound to the key
633  * \param type Signature type
634  */
635 void
636 __ops_sig_start_key_sig(__ops_create_sig_t * sig,
637 				  const __ops_pubkey_t * key,
638 				  const __ops_user_id_t * id,
639 				  __ops_sig_type_t type)
640 {
641 	sig->info = __ops_createinfo_new();
642 
643 	/* XXX:  refactor with check (in several ways - check should
644 	 * probably use the buffered writer to construct packets
645 	 * (done), and also should share code for hash calculation) */
646 	sig->sig.info.version = OPS_V4;
647 	sig->sig.info.hash_alg = OPS_HASH_SHA1;
648 	sig->sig.info.key_alg = key->alg;
649 	sig->sig.info.type = type;
650 
651 	sig->hashed_data_length = (unsigned)-1;
652 
653 	init_key_sig(&sig->hash, &sig->sig, key);
654 
655 	__ops_hash_add_int(&sig->hash, 0xb4, 1);
656 	__ops_hash_add_int(&sig->hash, strlen((char *) id->user_id), 4);
657 	sig->hash.add(&sig->hash, id->user_id, strlen((char *) id->user_id));
658 
659 	start_sig_in_mem(sig);
660 }
661 
662 /**
663  * \ingroup Core_Signature
664  *
665  * Create a V4 public key signature over some cleartext.
666  *
667  * \param sig The signature structure to initialise
668  * \param id
669  * \param type
670  * \todo Expand description. Allow other hashes.
671  */
672 
673 void
674 __ops_start_sig(__ops_create_sig_t *sig,
675 	      const __ops_seckey_t *key,
676 	      const __ops_hash_alg_t hash,
677 	      const __ops_sig_type_t type)
678 {
679 	sig->info = __ops_createinfo_new();
680 
681 	/* XXX:  refactor with check (in several ways - check should
682 	 * probably use the buffered writer to construct packets
683 	 * (done), and also should share code for hash calculation) */
684 	sig->sig.info.version = OPS_V4;
685 	sig->sig.info.key_alg = key->pubkey.alg;
686 	sig->sig.info.hash_alg = hash;
687 	sig->sig.info.type = type;
688 
689 	sig->hashed_data_length = (unsigned)-1;
690 
691 	if (__ops_get_debug_level(__FILE__)) {
692 		fprintf(stderr, "initialising hash for sig in mem\n");
693 	}
694 	initialise_hash(&sig->hash, &sig->sig);
695 	start_sig_in_mem(sig);
696 }
697 
698 /**
699  * \ingroup Core_Signature
700  *
701  * Add plaintext data to a signature-to-be.
702  *
703  * \param sig The signature-to-be.
704  * \param buf The plaintext data.
705  * \param length The amount of plaintext data.
706  */
707 void
708 __ops_sig_add_data(__ops_create_sig_t * sig, const void *buf,
709 		       size_t length)
710 {
711 	if (__ops_get_debug_level(__FILE__)) {
712 		(void) fprintf(stderr,
713 			"__ops_sig_add_data adds to hash\n");
714 	}
715 	sig->hash.add(&sig->hash, buf, length);
716 }
717 
718 /**
719  * \ingroup Core_Signature
720  *
721  * Mark the end of the hashed subpackets in the signature
722  *
723  * \param sig
724  */
725 
726 bool
727 __ops_sig_hashed_subpackets_end(__ops_create_sig_t * sig)
728 {
729 	sig->hashed_data_length = __ops_memory_get_length(sig->mem)
730 	- sig->hashed_count_offset - 2;
731 	__ops_memory_place_int(sig->mem, sig->hashed_count_offset,
732 			     sig->hashed_data_length, 2);
733 	/* dummy unhashed subpacket count */
734 	sig->unhashed_count_offset = __ops_memory_get_length(sig->mem);
735 	return __ops_write_scalar(0, 2, sig->info);
736 }
737 
738 /**
739  * \ingroup Core_Signature
740  *
741  * Write out a signature
742  *
743  * \param sig
744  * \param key
745  * \param seckey
746  * \param info
747  *
748  */
749 
750 bool
751 __ops_write_sig(__ops_create_sig_t * sig,
752 			const __ops_pubkey_t *key,
753 			const __ops_seckey_t *seckey,
754 			__ops_createinfo_t *info)
755 {
756 	size_t	l = __ops_memory_get_length(sig->mem);
757 	bool	rtn = false;
758 
759 	/* check key not decrypted */
760 	switch (seckey->pubkey.alg) {
761 	case OPS_PKA_RSA:
762 	case OPS_PKA_RSA_ENCRYPT_ONLY:
763 	case OPS_PKA_RSA_SIGN_ONLY:
764 		if (seckey->key.rsa.d == NULL) {
765 			(void) fprintf(stderr,
766 				"__ops_write_sig: null rsa.d\n");
767 			return false;
768 		}
769 		break;
770 
771 	case OPS_PKA_DSA:
772 		if (seckey->key.dsa.x == NULL) {
773 			(void) fprintf(stderr,
774 				"__ops_write_sig: null dsa.x\n");
775 			return false;
776 		}
777 		break;
778 
779 	default:
780 		(void) fprintf(stderr, "Unsupported algorithm %d\n",
781 				seckey->pubkey.alg);
782 		return false;
783 	}
784 
785 	if (sig->hashed_data_length == (unsigned) -1) {
786 		(void) fprintf(stderr,
787 			"ops_write_sig: bad hashed data len\n");
788 		return false;
789 	}
790 
791 	__ops_memory_place_int(sig->mem, sig->unhashed_count_offset,
792 			     l - sig->unhashed_count_offset - 2, 2);
793 
794 	/* add the packet from version number to end of hashed subpackets */
795 
796 	if (__ops_get_debug_level(__FILE__)) {
797 		(void) fprintf(stderr,
798 "--- Adding packet to hash from version number to hashed subpkts\n");
799 	}
800 	sig->hash.add(&sig->hash, __ops_memory_get_data(sig->mem),
801 		      sig->unhashed_count_offset);
802 
803 	/* add final trailer */
804 	__ops_hash_add_int(&sig->hash, (unsigned)sig->sig.info.version, 1);
805 	__ops_hash_add_int(&sig->hash, 0xff, 1);
806 	/* +6 for version, type, pk alg, hash alg, hashed subpacket length */
807 	__ops_hash_add_int(&sig->hash, sig->hashed_data_length + 6, 4);
808 
809 	if (__ops_get_debug_level(__FILE__)) {
810 		(void) fprintf(stderr,
811 "--- Finished adding packet to hash from version number to hashed subpkts\n");
812 	}
813 	/* XXX: technically, we could figure out how big the signature is */
814 	/* and write it directly to the output instead of via memory. */
815 	switch (seckey->pubkey.alg) {
816 	case OPS_PKA_RSA:
817 	case OPS_PKA_RSA_ENCRYPT_ONLY:
818 	case OPS_PKA_RSA_SIGN_ONLY:
819 		if (!rsa_sign(&sig->hash, &key->key.rsa, &seckey->key.rsa,
820 				sig->info)) {
821 			(void) fprintf(stderr,
822 				"__ops_write_sig: rsa_sign failure\n");
823 			return false;
824 		}
825 		break;
826 
827 	case OPS_PKA_DSA:
828 		if (!dsa_sign(&sig->hash, &key->key.dsa, &seckey->key.dsa,
829 				sig->info)) {
830 			(void) fprintf(stderr,
831 				"__ops_write_sig: dsa_sign failure\n");
832 			return false;
833 		}
834 		break;
835 
836 	default:
837 		(void) fprintf(stderr, "Unsupported algorithm %d\n",
838 					seckey->pubkey.alg);
839 		return false;
840 	}
841 
842 	rtn = __ops_write_ptag(OPS_PTAG_CT_SIGNATURE, info);
843 	if (rtn != false) {
844 		l = __ops_memory_get_length(sig->mem);
845 		rtn = __ops_write_length(l, info) &&
846 			__ops_write(__ops_memory_get_data(sig->mem), l, info);
847 	}
848 	__ops_memory_free(sig->mem);
849 
850 	if (rtn == false) {
851 		OPS_ERROR(&info->errors, OPS_E_W, "Cannot write signature");
852 	}
853 	return rtn;
854 }
855 
856 /**
857  * \ingroup Core_Signature
858  *
859  * __ops_sig_add_birthtime() adds a creation time to the signature.
860  *
861  * \param sig
862  * \param when
863  */
864 bool
865 __ops_sig_add_birthtime(__ops_create_sig_t * sig, time_t when)
866 {
867 	return __ops_write_ss_header(5, OPS_PTAG_SS_CREATION_TIME,
868 				sig->info) &&
869 		__ops_write_scalar((unsigned)when, 4, sig->info);
870 }
871 
872 /**
873  * \ingroup Core_Signature
874  *
875  * Adds issuer's key ID to the signature
876  *
877  * \param sig
878  * \param keyid
879  */
880 
881 bool
882 __ops_sig_add_issuer_key_id(__ops_create_sig_t * sig,
883 				const unsigned char keyid[OPS_KEY_ID_SIZE])
884 {
885 	return __ops_write_ss_header(OPS_KEY_ID_SIZE + 1,
886 				OPS_PTAG_SS_ISSUER_KEY_ID, sig->info) &&
887 		__ops_write(keyid, OPS_KEY_ID_SIZE, sig->info);
888 }
889 
890 /**
891  * \ingroup Core_Signature
892  *
893  * Adds primary user ID to the signature
894  *
895  * \param sig
896  * \param primary
897  */
898 void
899 __ops_sig_add_primary_user_id(__ops_create_sig_t * sig,
900 				  bool primary)
901 {
902 	__ops_write_ss_header(2, OPS_PTAG_SS_PRIMARY_USER_ID, sig->info);
903 	__ops_write_scalar(primary, 1, sig->info);
904 }
905 
906 /**
907  * \ingroup Core_Signature
908  *
909  * Get the hash structure in use for the signature.
910  *
911  * \param sig The signature structure.
912  * \return The hash structure.
913  */
914 __ops_hash_t     *
915 __ops_sig_get_hash(__ops_create_sig_t * sig)
916 {
917 	return &sig->hash;
918 }
919 
920 static int
921 open_output_file(__ops_createinfo_t ** cinfo,
922 			const char *input_filename,
923 			const char *output_filename,
924 			const bool use_armour,
925 			const bool overwrite)
926 {
927 	int             fd_out;
928 
929 	/* setup output file */
930 
931 	if (output_filename) {
932 		fd_out = __ops_setup_file_write(cinfo, output_filename,
933 					overwrite);
934 	} else {
935 		char           *myfilename = NULL;
936 		unsigned        filenamelen = strlen(input_filename) + 4 + 1;
937 
938 		myfilename = calloc(1, filenamelen);
939 		if (use_armour) {
940 			(void) snprintf(myfilename, filenamelen, "%s.asc",
941 					input_filename);
942 		} else {
943 			(void) snprintf(myfilename, filenamelen, "%s.gpg",
944 					input_filename);
945 		}
946 		fd_out = __ops_setup_file_write(cinfo, myfilename, overwrite);
947 		free(myfilename);
948 	}
949 
950 	return fd_out;
951 }
952 
953 /**
954    \ingroup HighLevel_Sign
955    \brief Sign a file with a Cleartext Signature
956    \param input_filename Name of file to be signed
957    \param output_filename Filename to be created. If NULL, filename will be constructed from the input_filename.
958    \param seckey Secret Key to sign with
959    \param overwrite Allow output file to be overwritten, if set
960    \return true if OK, else false
961 
962 */
963 bool
964 __ops_sign_file_as_cleartext(const char *input_filename,
965 			const char *output_filename,
966 			const __ops_seckey_t *seckey,
967 			const char *hashname,
968 			const bool overwrite)
969 {
970 	__ops_createinfo_t	*cinfo = NULL;
971 	__ops_create_sig_t	*sig = NULL;
972 	__ops_sig_type_t	 sig_type = OPS_SIG_BINARY;
973 	__ops_hash_alg_t	 hash_alg;
974 	unsigned char		 keyid[OPS_KEY_ID_SIZE];
975 	unsigned char		 buf[MAXBUF];
976 	bool			 rtn = false;
977 	bool			 use_armour = true;
978 	int			 fd_out = 0;
979 	int			 fd_in = 0;
980 
981 	/* check the hash algorithm */
982 	hash_alg = __ops_str_to_hash_alg(hashname);
983 	if (hash_alg == OPS_HASH_UNKNOWN) {
984 		(void) fprintf(stderr,
985 			"__ops_sign_file_as_cleartext: unknown hash algorithm"
986 			": \"%s\"\n", hashname);
987 		return false;
988 	}
989 
990 	/* open file to sign */
991 #ifdef O_BINARY
992 	fd_in = open(input_filename, O_RDONLY | O_BINARY);
993 #else
994 	fd_in = open(input_filename, O_RDONLY);
995 #endif
996 	if (fd_in < 0) {
997 		return false;
998 	}
999 
1000 	/* set up output file */
1001 	fd_out = open_output_file(&cinfo, input_filename, output_filename,
1002 			use_armour, overwrite);
1003 	if (fd_out < 0) {
1004 		close(fd_in);
1005 		return false;
1006 	}
1007 
1008 	/* set up signature */
1009 	sig = __ops_create_sig_new();
1010 	if (!sig) {
1011 		close(fd_in);
1012 		__ops_teardown_file_write(cinfo, fd_out);
1013 		return false;
1014 	}
1015 
1016 	/* \todo could add more error detection here */
1017 	__ops_start_sig(sig, seckey, hash_alg, sig_type);
1018 	if (__ops_writer_push_clearsigned(cinfo, sig) != true) {
1019 		return false;
1020 	}
1021 
1022 	/* Do the signing */
1023 	for (;;) {
1024 		int             n = 0;
1025 
1026 		n = read(fd_in, buf, sizeof(buf));
1027 		if (n == 0) {
1028 			break;
1029 		}
1030 		if (n < 0) {
1031 			(void) fprintf(stderr,
1032 				"__ops_sign_file_as_cleartext: bad read\n");
1033 			return false;
1034 		}
1035 		__ops_write(buf, (unsigned)n, cinfo);
1036 	}
1037 	close(fd_in);
1038 
1039 	/* add signature with subpackets: */
1040 	/* - creation time */
1041 	/* - key id */
1042 	rtn = __ops_writer_use_armored_sig(cinfo)
1043 		&& __ops_sig_add_birthtime(sig, time(NULL));
1044 	if (rtn == false) {
1045 		__ops_teardown_file_write(cinfo, fd_out);
1046 		return false;
1047 	}
1048 	__ops_keyid(keyid, OPS_KEY_ID_SIZE, OPS_KEY_ID_SIZE, &seckey->pubkey);
1049 
1050 	rtn = __ops_sig_add_issuer_key_id(sig, keyid) &&
1051 		__ops_sig_hashed_subpackets_end(sig) &&
1052 		__ops_write_sig(sig, &seckey->pubkey, seckey, cinfo);
1053 
1054 	__ops_teardown_file_write(cinfo, fd_out);
1055 
1056 	if (rtn == false) {
1057 		OPS_ERROR(&cinfo->errors, OPS_E_W,
1058 				"Cannot sign file as cleartext");
1059 	}
1060 	return rtn;
1061 }
1062 
1063 #if 0
1064 /* XXX commented out until I work out what header file to put this one in */
1065 /**
1066  * \ingroup HighLevel_Sign
1067  * \brief Sign a buffer with a Cleartext signature
1068  * \param cleartext Text to be signed
1069  * \param len Length of text
1070  * \param signed_cleartext __ops_memory_t struct in which to write the signed cleartext
1071  * \param seckey Secret key with which to sign the cleartext
1072  * \return true if OK; else false
1073 
1074  * \note It is the calling function's responsibility to free signed_cleartext
1075  * \note signed_cleartext should be a NULL pointer when passed in
1076 
1077  */
1078 bool
1079 __ops_sign_buf_as_cleartext(const char *cleartext,
1080 				const size_t len,
1081 				__ops_memory_t **signed_cleartext,
1082 				const __ops_seckey_t *seckey)
1083 {
1084 	bool   rtn = false;
1085 	unsigned char   keyid[OPS_KEY_ID_SIZE];
1086 	__ops_create_sig_t *sig = NULL;
1087 	__ops_createinfo_t *cinfo = NULL;
1088 
1089 	/* \todo allow choice of hash algorithams */
1090 	/* enforce use of SHA1 for now */
1091 
1092 	if (*signed_cleartext != 0x0) {
1093 		(void) fprintf(stderr,
1094 			"__ops_sign_buf_as_cleartext: non-null cleartext\n");
1095 		return false;
1096 	}
1097 
1098 	/* set up signature */
1099 	sig = __ops_create_sig_new();
1100 	if (!sig) {
1101 		return false;
1102 	}
1103 	/* \todo could add more error detection here */
1104 	__ops_start_sig(sig, seckey, OPS_HASH_SHA1, OPS_SIG_BINARY);
1105 
1106 	/* set up output file */
1107 	__ops_setup_memory_write(&cinfo, signed_cleartext, len);
1108 
1109 	/* Do the signing */
1110 	/* add signature with subpackets: */
1111 	/* - creation time */
1112 	/* - key id */
1113 	rtn = __ops_writer_push_clearsigned(cinfo, sig) &&
1114 		__ops_write(cleartext, len, cinfo) &&
1115 		__ops_writer_use_armored_sig(cinfo) &&
1116 		__ops_sig_add_birthtime(sig, time(NULL));
1117 
1118 	if (rtn == false) {
1119 		return false;
1120 	}
1121 	__ops_keyid(keyid, OPS_KEY_ID_SIZE, OPS_KEY_ID_SIZE, &seckey->pubkey);
1122 
1123 	rtn = __ops_sig_add_issuer_key_id(sig, keyid) &&
1124 		__ops_sig_hashed_subpackets_end(sig) &&
1125 		__ops_write_sig(sig, &seckey->pubkey, seckey, cinfo) &&
1126 		__ops_writer_close(cinfo);
1127 
1128 	/* Note: the calling function must free signed_cleartext */
1129 	__ops_createinfo_delete(cinfo);
1130 
1131 	return rtn;
1132 }
1133 #endif
1134 
1135 /**
1136 \ingroup HighLevel_Sign
1137 \brief Sign a file
1138 \param input_filename Input filename
1139 \param output_filename Output filename. If NULL, a name is constructed from the input filename.
1140 \param seckey Secret Key to use for signing
1141 \param use_armour Write armoured text, if set.
1142 \param overwrite May overwrite existing file, if set.
1143 \return true if OK; else false;
1144 
1145 */
1146 bool
1147 __ops_sign_file(const char *input_filename,
1148 		const char *output_filename,
1149 		const __ops_seckey_t *seckey,
1150 		const char *hashname,
1151 		const bool use_armour,
1152 		const bool overwrite)
1153 {
1154 	/* \todo allow choice of hash algorithams */
1155 	/* enforce use of SHA1 for now */
1156 
1157 	__ops_create_sig_t	*sig = NULL;
1158 	__ops_createinfo_t	*cinfo = NULL;
1159 	__ops_hash_alg_t	 hash_alg;
1160 	__ops_sig_type_t	 sig_type = OPS_SIG_BINARY;
1161 	__ops_memory_t		*mem_buf = NULL;
1162 	unsigned char		 keyid[OPS_KEY_ID_SIZE];
1163 	__ops_hash_t		*hash = NULL;
1164 	int			 errnum;
1165 	int			 fd_out = 0;
1166 
1167 	hash_alg = __ops_str_to_hash_alg(hashname);
1168 	if (hash_alg == OPS_HASH_UNKNOWN) {
1169 		(void) fprintf(stderr,
1170 			"__ops_sign_file: unknown hash algorithm: \"%s\"\n",
1171 			hashname);
1172 		return false;
1173 	}
1174 
1175 	/* read input file into buf */
1176 	mem_buf = __ops_fileread(input_filename, &errnum);
1177 	if (errnum) {
1178 		return false;
1179 	}
1180 
1181 	/* setup output file */
1182 	fd_out = open_output_file(&cinfo, input_filename, output_filename,
1183 			use_armour, overwrite);
1184 	if (fd_out < 0) {
1185 		__ops_memory_free(mem_buf);
1186 		return false;
1187 	}
1188 
1189 	/* set up signature */
1190 	sig = __ops_create_sig_new();
1191 	__ops_start_sig(sig, seckey, hash_alg, sig_type);
1192 
1193 	/* set armoured/not armoured here */
1194 	if (use_armour) {
1195 		__ops_writer_push_armoured_message(cinfo);
1196 	}
1197 
1198 	if (__ops_get_debug_level(__FILE__)) {
1199 		fprintf(stderr, "** Writing out one pass sig\n");
1200 	}
1201 	/* write one_pass_sig */
1202 	__ops_write_one_pass_sig(seckey, hash_alg, sig_type, cinfo);
1203 
1204 	/* hash file contents */
1205 	hash = __ops_sig_get_hash(sig);
1206 	hash->add(hash, __ops_memory_get_data(mem_buf),
1207 			__ops_memory_get_length(mem_buf));
1208 
1209 	/* output file contents as Literal Data packet */
1210 
1211 	if (__ops_get_debug_level(__FILE__)) {
1212 		fprintf(stderr, "** Writing out data now\n");
1213 	}
1214 	__ops_write_litdata(__ops_memory_get_data(mem_buf),
1215 		(const int)__ops_memory_get_length(mem_buf),
1216 		OPS_LDT_BINARY, cinfo);
1217 
1218 	if (__ops_get_debug_level(__FILE__)) {
1219 		fprintf(stderr, "** After Writing out data now\n");
1220 	}
1221 	/* add subpackets to signature */
1222 	/* - creation time */
1223 	/* - key id */
1224 
1225 	__ops_sig_add_birthtime(sig, time(NULL));
1226 
1227 	__ops_keyid(keyid, OPS_KEY_ID_SIZE, OPS_KEY_ID_SIZE, &seckey->pubkey);
1228 	__ops_sig_add_issuer_key_id(sig, keyid);
1229 
1230 	__ops_sig_hashed_subpackets_end(sig);
1231 
1232 	/* write out sig */
1233 	__ops_write_sig(sig, &seckey->pubkey, seckey, cinfo);
1234 
1235 	__ops_teardown_file_write(cinfo, fd_out);
1236 
1237 	/* tidy up */
1238 	__ops_create_sig_delete(sig);
1239 	__ops_memory_free(mem_buf);
1240 
1241 	return true;
1242 }
1243 
1244 #if 0
1245 /* XXX commented out until I work out what header file to put this one in */
1246 /**
1247 \ingroup HighLevel_Sign
1248 \brief Signs a buffer
1249 \param input Input text to be signed
1250 \param input_len Length of input text
1251 \param sig_type Signature type
1252 \param seckey Secret Key
1253 \param use_armour Write armoured text, if set
1254 \return New __ops_memory_t struct containing signed text
1255 \note It is the caller's responsibility to call __ops_memory_free(me)
1256 
1257 */
1258 __ops_memory_t   *
1259 __ops_sign_buf(const void *input,
1260 		const size_t input_len,
1261 		const __ops_sig_type_t sig_type,
1262 		const __ops_seckey_t * seckey,
1263 		const bool use_armour)
1264 {
1265 	/* \todo allow choice of hash algorithams */
1266 	/* enforce use of SHA1 for now */
1267 
1268 	unsigned char   keyid[OPS_KEY_ID_SIZE];
1269 	__ops_create_sig_t *sig = NULL;
1270 	__ops_createinfo_t *cinfo = NULL;
1271 	__ops_memory_t   *mem = __ops_memory_new();
1272 	__ops_hash_alg_t hash_alg = OPS_HASH_SHA1;
1273 	__ops_litdata_type_t ld_type;
1274 	__ops_hash_t     *hash = NULL;
1275 
1276 	/* setup literal data packet type */
1277 	ld_type = (sig_type == OPS_SIG_BINARY) ? OPS_LDT_BINARY : OPS_LDT_TEXT;
1278 
1279 
1280 	/* set up signature */
1281 	sig = __ops_create_sig_new();
1282 	__ops_start_sig(sig, seckey, hash_alg, sig_type);
1283 
1284 	/* setup writer */
1285 	__ops_setup_memory_write(&cinfo, &mem, input_len);
1286 
1287 	/* set armoured/not armoured here */
1288 	if (use_armour) {
1289 		__ops_writer_push_armoured_message(cinfo);
1290 	}
1291 
1292 	if (__ops_get_debug_level(__FILE__)) {
1293 		fprintf(stderr, "** Writing out one pass sig\n");
1294 	}
1295 	/* write one_pass_sig */
1296 	__ops_write_one_pass_sig(seckey, hash_alg, sig_type, cinfo);
1297 
1298 	/* hash file contents */
1299 	hash = __ops_sig_get_hash(sig);
1300 	hash->add(hash, input, input_len);
1301 
1302 	/* output file contents as Literal Data packet */
1303 
1304 	if (__ops_get_debug_level(__FILE__)) {
1305 		fprintf(stderr, "** Writing out data now\n");
1306 	}
1307 	__ops_write_litdata(input, input_len, ld_type, cinfo);
1308 
1309 	if (__ops_get_debug_level(__FILE__)) {
1310 		fprintf(stderr, "** After Writing out data now\n");
1311 	}
1312 	/* add subpackets to signature */
1313 	/* - creation time */
1314 	/* - key id */
1315 
1316 	__ops_sig_add_birthtime(sig, time(NULL));
1317 
1318 	__ops_keyid(keyid, OPS_KEY_ID_SIZE, OPS_KEY_ID_SIZE, &seckey->pubkey);
1319 	__ops_sig_add_issuer_key_id(sig, keyid);
1320 
1321 	__ops_sig_hashed_subpackets_end(sig);
1322 
1323 	/* write out sig */
1324 	__ops_write_sig(sig, &seckey->pubkey, seckey, cinfo);
1325 
1326 	/* tidy up */
1327 	__ops_writer_close(cinfo);
1328 	__ops_create_sig_delete(sig);
1329 
1330 	return mem;
1331 }
1332 #endif
1333