xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/create.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 #include <sys/types.h>
55 #include <sys/param.h>
56 #include <sys/stat.h>
57 #include <sys/mman.h>
58 
59 #ifdef HAVE_FCNTL_H
60 #include <fcntl.h>
61 #endif
62 
63 #include <string.h>
64 
65 #ifdef HAVE_UNISTD_H
66 #include <unistd.h>
67 #endif
68 
69 #ifdef HAVE_OPENSSL_CAST_H
70 #include <openssl/cast.h>
71 #endif
72 
73 #include "create.h"
74 #include "keyring.h"
75 #include "packet.h"
76 #include "signature.h"
77 #include "writer.h"
78 #include "readerwriter.h"
79 #include "keyring_local.h"
80 #include "loccreate.h"
81 #include "memory.h"
82 #include "netpgpdefs.h"
83 
84 /**
85  * \ingroup Core_Create
86  * \param length
87  * \param type
88  * \param info
89  * \return true if OK, otherwise false
90  */
91 
92 bool
93 __ops_write_ss_header(unsigned length, __ops_content_tag_t type,
94 		    __ops_createinfo_t *info)
95 {
96 	return __ops_write_length(length, info) &&
97 		__ops_write_scalar((unsigned)(type -
98 			OPS_PTAG_SIGNATURE_SUBPACKET_BASE), 1, info);
99 }
100 
101 /*
102  * XXX: the general idea of _fast_ is that it doesn't copy stuff the safe
103  * (i.e. non _fast_) version will, and so will also need to be freed.
104  */
105 
106 /**
107  * \ingroup Core_Create
108  *
109  * __ops_fast_create_user_id() sets id->user_id to the given user_id.
110  * This is fast because it is only copying a char*. However, if user_id
111  * is changed or freed in the future, this could have injurious results.
112  * \param id
113  * \param user_id
114  */
115 
116 void
117 __ops_fast_create_user_id(__ops_user_id_t * id, unsigned char *user_id)
118 {
119 	id->user_id = user_id;
120 }
121 
122 /**
123  * \ingroup Core_WritePackets
124  * \brief Writes a User Id packet
125  * \param id
126  * \param info
127  * \return true if OK, otherwise false
128  */
129 bool
130 __ops_write_struct_user_id(__ops_user_id_t *id,
131 			 __ops_createinfo_t *info)
132 {
133 	return __ops_write_ptag(OPS_PTAG_CT_USER_ID, info) &&
134 		__ops_write_length(strlen((char *) id->user_id), info) &&
135 		__ops_write(id->user_id, strlen((char *) id->user_id), info);
136 }
137 
138 /**
139  * \ingroup Core_WritePackets
140  * \brief Write a User Id packet.
141  * \param user_id
142  * \param info
143  *
144  * \return return value from __ops_write_struct_user_id()
145  */
146 bool
147 __ops_write_user_id(const unsigned char *user_id, __ops_createinfo_t *info)
148 {
149 	__ops_user_id_t   id;
150 
151 	id.user_id = __UNCONST(user_id);
152 	return __ops_write_struct_user_id(&id, info);
153 }
154 
155 /**
156 \ingroup Core_MPI
157 */
158 static unsigned
159 mpi_length(const BIGNUM *bn)
160 {
161 	return 2 + (BN_num_bits(bn) + 7) / 8;
162 }
163 
164 static unsigned
165 pubkey_length(const __ops_pubkey_t *key)
166 {
167 	switch (key->alg) {
168 	case OPS_PKA_RSA:
169 		return mpi_length(key->key.rsa.n) + mpi_length(key->key.rsa.e);
170 
171 	default:
172 		(void) fprintf(stderr,
173 			"pubkey_length: unknown key algorithm\n");
174 	}
175 	return 0;
176 }
177 
178 static unsigned
179 seckey_length(const __ops_seckey_t *key)
180 {
181 	int             len;
182 
183 	len = 0;
184 	switch (key->pubkey.alg) {
185 	case OPS_PKA_RSA:
186 		len = mpi_length(key->key.rsa.d) + mpi_length(key->key.rsa.p) +
187 			mpi_length(key->key.rsa.q) + mpi_length(key->key.rsa.u);
188 
189 		return len + pubkey_length(&key->pubkey);
190 	default:
191 		(void) fprintf(stderr,
192 			"pubkey_length: unknown key algorithm\n");
193 	}
194 	return 0;
195 }
196 
197 /**
198  * \ingroup Core_Create
199  * \param key
200  * \param t
201  * \param n
202  * \param e
203 */
204 void
205 __ops_fast_create_rsa_pubkey(__ops_pubkey_t *key, time_t t,
206 			       BIGNUM *n, BIGNUM *e)
207 {
208 	key->version = 4;
209 	key->birthtime = t;
210 	key->alg = OPS_PKA_RSA;
211 	key->key.rsa.n = n;
212 	key->key.rsa.e = e;
213 }
214 
215 /*
216  * Note that we support v3 keys here because they're needed for for
217  * verification - the writer doesn't allow them, though
218  */
219 static bool
220 write_pubkey_body(const __ops_pubkey_t * key,
221 		      __ops_createinfo_t * info)
222 {
223 	if (!(__ops_write_scalar((unsigned)key->version, 1, info) &&
224 	      __ops_write_scalar((unsigned)key->birthtime, 4, info))) {
225 		return false;
226 	}
227 
228 	if (key->version != 4 &&
229 	    !__ops_write_scalar(key->days_valid, 2, info)) {
230 		return false;
231 	}
232 
233 	if (!__ops_write_scalar((unsigned)key->alg, 1, info)) {
234 		return false;
235 	}
236 
237 	switch (key->alg) {
238 	case OPS_PKA_DSA:
239 		return __ops_write_mpi(key->key.dsa.p, info) &&
240 			__ops_write_mpi(key->key.dsa.q, info) &&
241 			__ops_write_mpi(key->key.dsa.g, info) &&
242 			__ops_write_mpi(key->key.dsa.y, info);
243 
244 	case OPS_PKA_RSA:
245 	case OPS_PKA_RSA_ENCRYPT_ONLY:
246 	case OPS_PKA_RSA_SIGN_ONLY:
247 		return __ops_write_mpi(key->key.rsa.n, info) &&
248 			__ops_write_mpi(key->key.rsa.e, info);
249 
250 	case OPS_PKA_ELGAMAL:
251 		return __ops_write_mpi(key->key.elgamal.p, info) &&
252 			__ops_write_mpi(key->key.elgamal.g, info) &&
253 			__ops_write_mpi(key->key.elgamal.y, info);
254 
255 	default:
256 		(void) fprintf(stderr,
257 			"write_pubkey_body: bad algorithm\n");
258 		break;
259 	}
260 	return false;
261 }
262 
263 /*
264  * Note that we support v3 keys here because they're needed for for
265  * verification - the writer doesn't allow them, though
266  */
267 static bool
268 write_seckey_body(const __ops_seckey_t * key,
269 		      const unsigned char *passphrase,
270 		      const size_t pplen,
271 		      __ops_createinfo_t * info)
272 {
273 	/* RFC4880 Section 5.5.3 Secret-Key Packet Formats */
274 
275 	__ops_crypt_t     crypted;
276 	__ops_hash_t      hash;
277 	unsigned char   hashed[OPS_SHA1_HASH_SIZE];
278 	unsigned char   sesskey[CAST_KEY_LENGTH];
279 	unsigned int    done = 0;
280 	unsigned int    i = 0;
281 
282 	if (!write_pubkey_body(&key->pubkey, info)) {
283 		return false;
284 	}
285 	if (key->s2k_usage != OPS_S2KU_ENCRYPTED_AND_HASHED) {
286 		(void) fprintf(stderr, "write_seckey_body: s2k usage\n");
287 		return false;
288 	}
289 	if (!__ops_write_scalar((unsigned)key->s2k_usage, 1, info)) {
290 		return false;
291 	}
292 
293 	if (key->alg != OPS_SA_CAST5) {
294 		(void) fprintf(stderr, "write_seckey_body: algorithm\n");
295 		return false;
296 	}
297 	if (!__ops_write_scalar((unsigned)key->alg, 1, info)) {
298 		return false;
299 	}
300 
301 	if (key->s2k_specifier != OPS_S2KS_SIMPLE &&
302 	    key->s2k_specifier != OPS_S2KS_SALTED) {
303 		/* = 1 \todo could also be iterated-and-salted */
304 		(void) fprintf(stderr, "write_seckey_body: s2k spec\n");
305 		return false;
306 	}
307 	if (!__ops_write_scalar((unsigned)key->s2k_specifier, 1, info)) {
308 		return false;
309 	}
310 
311 	if (key->hash_alg != OPS_HASH_SHA1) {
312 		(void) fprintf(stderr, "write_seckey_body: hash alg\n");
313 		return false;
314 	}
315 	if (!__ops_write_scalar((unsigned)key->hash_alg, 1, info)) {
316 		return false;
317 	}
318 
319 	switch (key->s2k_specifier) {
320 	case OPS_S2KS_SIMPLE:
321 		/* nothing more to do */
322 		break;
323 
324 	case OPS_S2KS_SALTED:
325 		/* 8-octet salt value */
326 		__ops_random(__UNCONST(&key->salt[0]), OPS_SALT_SIZE);
327 		if (!__ops_write(key->salt, OPS_SALT_SIZE, info)) {
328 			return false;
329 		}
330 		break;
331 
332 		/*
333 		 * \todo case OPS_S2KS_ITERATED_AND_SALTED: // 8-octet salt
334 		 * value // 1-octet count break;
335 		 */
336 
337 	default:
338 		(void) fprintf(stderr,
339 			"invalid/unsupported s2k specifier %d\n",
340 			key->s2k_specifier);
341 		return false;
342 	}
343 
344 	if (!__ops_write(&key->iv[0], __ops_block_size(key->alg), info)) {
345 		return false;
346 	}
347 
348 	/*
349 	 * create the session key for encrypting the algorithm-specific
350 	 * fields
351 	 */
352 
353 	switch (key->s2k_specifier) {
354 	case OPS_S2KS_SIMPLE:
355 	case OPS_S2KS_SALTED:
356 		/* RFC4880: section 3.7.1.1 and 3.7.1.2 */
357 
358 		done = 0;
359 		for (i = 0; done < CAST_KEY_LENGTH; i++) {
360 			unsigned int    j = 0;
361 			unsigned char   zero = 0;
362 			int             needed;
363 			int             use;
364 
365 			needed = CAST_KEY_LENGTH - done;
366 			use = MIN(needed, OPS_SHA1_HASH_SIZE);
367 
368 			__ops_hash_any(&hash, key->hash_alg);
369 			hash.init(&hash);
370 
371 			/* preload if iterating  */
372 			for (j = 0; j < i; j++) {
373 				/*
374 				 * Coverity shows a DEADCODE error on this
375 				 * line. This is expected since the hardcoded
376 				 * use of SHA1 and CAST5 means that it will
377 				 * not used. This will change however when
378 				 * other algorithms are supported.
379 				 */
380 				hash.add(&hash, &zero, 1);
381 			}
382 
383 			if (key->s2k_specifier == OPS_S2KS_SALTED) {
384 				hash.add(&hash, key->salt, OPS_SALT_SIZE);
385 			}
386 			hash.add(&hash, passphrase, pplen);
387 			hash.finish(&hash, hashed);
388 
389 			/*
390 			 * if more in hash than is needed by session key, use
391 			 * the leftmost octets
392 			 */
393 			(void) memcpy(sesskey + (i * OPS_SHA1_HASH_SIZE),
394 					hashed, (unsigned)use);
395 			done += use;
396 			if (done > CAST_KEY_LENGTH) {
397 				(void) fprintf(stderr,
398 					"write_seckey_body: short add\n");
399 				return false;
400 			}
401 		}
402 
403 		break;
404 
405 		/*
406 		 * \todo case OPS_S2KS_ITERATED_AND_SALTED: * 8-octet salt
407 		 * value * 1-octet count break;
408 		 */
409 
410 	default:
411 		(void) fprintf(stderr,
412 			"invalid/unsupported s2k specifier %d\n",
413 			key->s2k_specifier);
414 		return false;
415 	}
416 
417 	/* use this session key to encrypt */
418 
419 	__ops_crypt_any(&crypted, key->alg);
420 	crypted.set_iv(&crypted, key->iv);
421 	crypted.set_key(&crypted, sesskey);
422 	__ops_encrypt_init(&crypted);
423 
424 	if (__ops_get_debug_level(__FILE__)) {
425 		unsigned int    i2 = 0;
426 
427 		(void) fprintf(stderr, "\nWRITING:\niv=");
428 		for (i2 = 0; i2 < __ops_block_size(key->alg); i2++) {
429 			(void) fprintf(stderr, "%02x ", key->iv[i2]);
430 		}
431 		(void) fprintf(stderr, "\n");
432 
433 		(void) fprintf(stderr, "key=");
434 		for (i2 = 0; i2 < CAST_KEY_LENGTH; i2++) {
435 			(void) fprintf(stderr, "%02x ", sesskey[i2]);
436 		}
437 		(void) fprintf(stderr, "\n");
438 
439 		(void) fprintf(stderr, "turning encryption on...\n");
440 	}
441 	__ops_writer_push_encrypt_crypt(info, &crypted);
442 
443 	switch (key->pubkey.alg) {
444 		/* case OPS_PKA_DSA: */
445 		/* return __ops_write_mpi(key->key.dsa.x,info); */
446 
447 	case OPS_PKA_RSA:
448 	case OPS_PKA_RSA_ENCRYPT_ONLY:
449 	case OPS_PKA_RSA_SIGN_ONLY:
450 
451 		if (!__ops_write_mpi(key->key.rsa.d, info) ||
452 		    !__ops_write_mpi(key->key.rsa.p, info) ||
453 		    !__ops_write_mpi(key->key.rsa.q, info) ||
454 		    !__ops_write_mpi(key->key.rsa.u, info)) {
455 			if (__ops_get_debug_level(__FILE__)) {
456 				(void) fprintf(stderr,
457 					"4 x mpi not written - problem\n");
458 			}
459 			return false;
460 		}
461 		break;
462 
463 		/* case OPS_PKA_ELGAMAL: */
464 		/* return __ops_write_mpi(key->key.elgamal.x,info); */
465 
466 	default:
467 		return false;
468 	}
469 
470 	if (!__ops_write(key->checkhash, OPS_CHECKHASH_SIZE, info)) {
471 		return false;
472 	}
473 
474 	__ops_writer_pop(info);
475 
476 	return true;
477 }
478 
479 
480 /**
481    \ingroup HighLevel_KeyWrite
482 
483    \brief Writes a transferable PGP public key to the given output stream.
484 
485    \param keydata Key to be written
486    \param armoured Flag is set for armoured output
487    \param info Output stream
488 
489 */
490 
491 bool
492 __ops_write_transferable_pubkey(const __ops_keydata_t * keydata, bool armoured, __ops_createinfo_t * info)
493 {
494 	bool   rtn;
495 	unsigned int    i = 0, j = 0;
496 
497 	if (armoured) {
498 		__ops_writer_push_armoured(info, OPS_PGP_PUBLIC_KEY_BLOCK);
499 	}
500 	/* public key */
501 	rtn = __ops_write_struct_pubkey(&keydata->key.seckey.pubkey, info);
502 	if (rtn != true) {
503 		return rtn;
504 	}
505 
506 	/* TODO: revocation signatures go here */
507 
508 	/* user ids and corresponding signatures */
509 	for (i = 0; i < keydata->nuids; i++) {
510 		__ops_user_id_t  *uid = &keydata->uids[i];
511 
512 		rtn = __ops_write_struct_user_id(uid, info);
513 		if (!rtn) {
514 			return rtn;
515 		}
516 
517 		/* find signature for this packet if it exists */
518 		for (j = 0; j < keydata->nsigs; j++) {
519 			sigpacket_t    *sig = &keydata->sigs[i];
520 
521 			if (strcmp((char *) sig->userid->user_id,
522 					(char *) uid->user_id) == 0) {
523 				rtn = __ops_write(sig->packet->raw,
524 						sig->packet->length, info);
525 				if (!rtn) {
526 					return !rtn;
527 				}
528 			}
529 		}
530 	}
531 
532 	/* TODO: user attributes and corresponding signatures */
533 
534 	/*
535 	 * subkey packets and corresponding signatures and optional
536 	 * revocation
537 	 */
538 
539 	if (armoured) {
540 		writer_info_finalise(&info->errors, &info->winfo);
541 		__ops_writer_pop(info);
542 	}
543 	return rtn;
544 }
545 
546 /**
547    \ingroup HighLevel_KeyWrite
548 
549    \brief Writes a transferable PGP secret key to the given output stream.
550 
551    \param keydata Key to be written
552    \param passphrase
553    \param pplen
554    \param armoured Flag is set for armoured output
555    \param info Output stream
556 
557 */
558 
559 bool
560 __ops_write_transferable_seckey(const __ops_keydata_t *keydata,
561 	const unsigned char *passphrase, const size_t pplen,
562 	bool armoured, __ops_createinfo_t * info)
563 {
564 	unsigned	i = 0, j = 0;
565 	bool		rtn;
566 
567 	if (armoured) {
568 		__ops_writer_push_armoured(info, OPS_PGP_PRIVATE_KEY_BLOCK);
569 	}
570 	/* public key */
571 	rtn = __ops_write_struct_seckey(&keydata->key.seckey, passphrase,
572 			pplen, info);
573 	if (rtn != true) {
574 		return rtn;
575 	}
576 
577 	/* TODO: revocation signatures go here */
578 
579 	/* user ids and corresponding signatures */
580 	for (i = 0; i < keydata->nuids; i++) {
581 		__ops_user_id_t  *uid = &keydata->uids[i];
582 
583 		rtn = __ops_write_struct_user_id(uid, info);
584 		if (!rtn) {
585 			return rtn;
586 		}
587 
588 		/* find signature for this packet if it exists */
589 		for (j = 0; j < keydata->nsigs; j++) {
590 			sigpacket_t    *sig = &keydata->sigs[i];
591 
592 			if (strcmp((char *) sig->userid->user_id,
593 					(char *) uid->user_id) == 0) {
594 				rtn = __ops_write(sig->packet->raw,
595 						sig->packet->length, info);
596 				if (!rtn) {
597 					return !rtn;
598 				}
599 			}
600 		}
601 	}
602 
603 	/* TODO: user attributes and corresponding signatures */
604 
605 	/*
606 	 * subkey packets and corresponding signatures and optional
607 	 * revocation
608 	 */
609 
610 	if (armoured) {
611 		writer_info_finalise(&info->errors, &info->winfo);
612 		__ops_writer_pop(info);
613 	}
614 	return rtn;
615 }
616 
617 /**
618  * \ingroup Core_WritePackets
619  * \brief Writes a Public Key packet
620  * \param key
621  * \param info
622  * \return true if OK, otherwise false
623  */
624 bool
625 __ops_write_struct_pubkey(const __ops_pubkey_t * key,
626 			    __ops_createinfo_t * info)
627 {
628 	if (key->version != 4) {
629 		(void) fprintf(stderr,
630 			"__ops_write_struct_pubkey: wrong key version\n");
631 		return false;
632 	}
633 	return __ops_write_ptag(OPS_PTAG_CT_PUBLIC_KEY, info) &&
634 		__ops_write_length(1 + 4 + 1 + pubkey_length(key), info) &&
635 		write_pubkey_body(key, info);
636 }
637 
638 /**
639  * \ingroup Core_WritePackets
640  * \brief Writes one RSA public key packet.
641  * \param t Creation time
642  * \param n RSA public modulus
643  * \param e RSA public encryption exponent
644  * \param info Writer settings
645  *
646  * \return true if OK, otherwise false
647  */
648 
649 bool
650 __ops_write_rsa_pubkey(time_t t, const BIGNUM * n,
651 			 const BIGNUM * e,
652 			 __ops_createinfo_t * info)
653 {
654 	__ops_pubkey_t key;
655 
656 	__ops_fast_create_rsa_pubkey(&key, t, __UNCONST(n), __UNCONST(e));
657 	return __ops_write_struct_pubkey(&key, info);
658 }
659 
660 /**
661  * \ingroup Core_Create
662  * \param out
663  * \param key
664  * \param make_packet
665  */
666 
667 void
668 __ops_build_pubkey(__ops_memory_t * out, const __ops_pubkey_t * key,
669 		     bool make_packet)
670 {
671 	__ops_createinfo_t *info;
672 
673 	info = __ops_createinfo_new();
674 	__ops_memory_init(out, 128);
675 	__ops_writer_set_memory(info, out);
676 	write_pubkey_body(key, info);
677 	if (make_packet) {
678 		__ops_memory_make_packet(out, OPS_PTAG_CT_PUBLIC_KEY);
679 	}
680 	__ops_createinfo_delete(info);
681 }
682 
683 /**
684  * \ingroup Core_Create
685  *
686  * Create an RSA secret key structure. If a parameter is marked as
687  * [OPTIONAL], then it can be omitted and will be calculated from
688  * other parameters - or, in the case of e, will default to 0x10001.
689  *
690  * Parameters are _not_ copied, so will be freed if the structure is
691  * freed.
692  *
693  * \param key The key structure to be initialised.
694  * \param t
695  * \param d The RSA parameter d (=e^-1 mod (p-1)(q-1)) [OPTIONAL]
696  * \param p The RSA parameter p
697  * \param q The RSA parameter q (q > p)
698  * \param u The RSA parameter u (=p^-1 mod q) [OPTIONAL]
699  * \param n The RSA public parameter n (=p*q) [OPTIONAL]
700  * \param e The RSA public parameter e */
701 
702 void
703 __ops_fast_create_rsa_seckey(__ops_seckey_t * key, time_t t,
704 			     BIGNUM * d, BIGNUM * p, BIGNUM * q, BIGNUM * u,
705 			       BIGNUM * n, BIGNUM * e)
706 {
707 	__ops_fast_create_rsa_pubkey(&key->pubkey, t, n, e);
708 
709 	/* XXX: calculate optionals */
710 	key->key.rsa.d = d;
711 	key->key.rsa.p = p;
712 	key->key.rsa.q = q;
713 	key->key.rsa.u = u;
714 
715 	key->s2k_usage = OPS_S2KU_NONE;
716 
717 	/* XXX: sanity check and add errors... */
718 }
719 
720 /**
721  * \ingroup Core_WritePackets
722  * \brief Writes a Secret Key packet.
723  * \param key The secret key
724  * \param passphrase The passphrase
725  * \param pplen Length of passphrase
726  * \param info
727  * \return true if OK; else false
728  */
729 bool
730 __ops_write_struct_seckey(const __ops_seckey_t * key,
731 			    const unsigned char *passphrase,
732 			    const size_t pplen,
733 			    __ops_createinfo_t * info)
734 {
735 	int             length = 0;
736 
737 	if (key->pubkey.version != 4) {
738 		(void) fprintf(stderr,
739 			"__ops_write_struct_seckey: public key version\n");
740 		return false;
741 	}
742 
743 	/* Ref: RFC4880 Section 5.5.3 */
744 
745 	/* pubkey, excluding MPIs */
746 	length += 1 + 4 + 1 + 1;
747 
748 	/* s2k usage */
749 	length += 1;
750 
751 	switch (key->s2k_usage) {
752 	case OPS_S2KU_NONE:
753 		/* nothing to add */
754 		break;
755 
756 	case OPS_S2KU_ENCRYPTED_AND_HASHED:	/* 254 */
757 	case OPS_S2KU_ENCRYPTED:	/* 255 */
758 
759 		/* Ref: RFC4880 Section 3.7 */
760 		length += 1;	/* s2k_specifier */
761 
762 		switch (key->s2k_specifier) {
763 		case OPS_S2KS_SIMPLE:
764 			length += 1;	/* hash algorithm */
765 			break;
766 
767 		case OPS_S2KS_SALTED:
768 			length += 1 + 8;	/* hash algorithm + salt */
769 			break;
770 
771 		case OPS_S2KS_ITERATED_AND_SALTED:
772 			length += 1 + 8 + 1;	/* hash algorithm, salt +
773 						 * count */
774 			break;
775 
776 		default:
777 			(void) fprintf(stderr,
778 				"__ops_write_struct_seckey: s2k spec\n");
779 			return false;
780 		}
781 		break;
782 
783 	default:
784 		(void) fprintf(stderr,
785 			"__ops_write_struct_seckey: s2k usage\n");
786 		return false;
787 	}
788 
789 	/* IV */
790 	if (key->s2k_usage != 0) {
791 		length += __ops_block_size(key->alg);
792 	}
793 	/* checksum or hash */
794 	switch (key->s2k_usage) {
795 	case 0:
796 	case 255:
797 		length += 2;
798 		break;
799 
800 	case 254:
801 		length += 20;
802 		break;
803 
804 	default:
805 		(void) fprintf(stderr,
806 			"__ops_write_struct_seckey: s2k cksum usage\n");
807 		return false;
808 	}
809 
810 	/* secret key and public key MPIs */
811 	length += seckey_length(key);
812 
813 	return __ops_write_ptag(OPS_PTAG_CT_SECRET_KEY, info) &&
814 		/* __ops_write_length(1+4+1+1+seckey_length(key)+2,info) && */
815 		__ops_write_length((unsigned)length, info) &&
816 		write_seckey_body(key, passphrase, pplen, info);
817 }
818 
819 /**
820  * \ingroup Core_Create
821  *
822  * \brief Create a new __ops_createinfo_t structure.
823  *
824  * \return the new structure.
825  * \note It is the responsiblity of the caller to call __ops_createinfo_delete().
826  * \sa __ops_createinfo_delete()
827  */
828 __ops_createinfo_t *
829 __ops_createinfo_new(void)
830 {
831 	return calloc(1, sizeof(__ops_createinfo_t));
832 }
833 
834 /**
835  * \ingroup Core_Create
836  * \brief Delete an __ops_createinfo_t strucut and associated resources.
837  *
838  * Delete an __ops_createinfo_t structure. If a writer is active, then
839  * that is also deleted.
840  *
841  * \param info the structure to be deleted.
842  */
843 void
844 __ops_createinfo_delete(__ops_createinfo_t * info)
845 {
846 	writer_info_delete(&info->winfo);
847 	(void) free(info);
848 }
849 
850 /**
851  \ingroup Core_Create
852  \brief Calculate the checksum for a session key
853  \param sesskey Session Key to use
854  \param cs Checksum to be written
855  \return true if OK; else false
856 */
857 bool
858 __ops_calc_sesskey_checksum(__ops_pk_sesskey_t * sesskey, unsigned char cs[2])
859 {
860 	unsigned int    i = 0;
861 	unsigned long   checksum = 0;
862 
863 	if (!__ops_is_sa_supported(sesskey->symm_alg)) {
864 		return false;
865 	}
866 
867 	for (i = 0; i < __ops_key_size(sesskey->symm_alg); i++) {
868 		checksum += sesskey->key[i];
869 	}
870 	checksum = checksum % 65536;
871 
872 	cs[0] = (unsigned char)((checksum >> 8) & 0xff);
873 	cs[1] = (unsigned char)(checksum & 0xff);
874 
875 	if (__ops_get_debug_level(__FILE__)) {
876 		(void) fprintf(stderr,"\nm buf checksum: ");
877 		(void) fprintf(stderr," %2x",cs[0]);
878 		(void) fprintf(stderr," %2x\n",cs[1]);
879 	}
880 	return true;
881 }
882 
883 static bool
884 create_unencoded_m_buf(__ops_pk_sesskey_t * sesskey, unsigned char *m_buf)
885 {
886 	int             i = 0;
887 
888 	/* m_buf is the buffer which will be encoded in PKCS#1 block */
889 	/* encoding to form the "m" value used in the  */
890 	/* Public Key Encrypted Session Key Packet */
891 	/*
892 	 * as defined in RFC Section 5.1 "Public-Key Encrypted Session Key
893 	 * Packet"
894 	 */
895 
896 	m_buf[0] = sesskey->symm_alg;
897 
898 	if (sesskey->symm_alg != OPS_SA_CAST5) {
899 		(void) fprintf(stderr, "create_unencoded_m_buf: symm alg\n");
900 		return false;
901 	}
902 	for (i = 0; i < CAST_KEY_LENGTH; i++) {
903 		m_buf[1 + i] = sesskey->key[i];
904 	}
905 
906 	return (__ops_calc_sesskey_checksum(sesskey,
907 				m_buf + 1 + CAST_KEY_LENGTH));
908 }
909 
910 /**
911 \ingroup Core_Create
912 \brief implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC
913 \param M
914 \param mLen
915 \param pubkey
916 \param EM
917 \return true if OK; else false
918 */
919 bool
920 encode_m_buf(const unsigned char *M, size_t mLen,
921 	     const __ops_pubkey_t * pubkey,
922 	     unsigned char *EM)
923 {
924 	unsigned int    k;
925 	unsigned        i;
926 
927 	/* implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC */
928 
929 	if (pubkey->alg != OPS_PKA_RSA) {
930 		(void) fprintf(stderr, "encode_m_buf: pubkey algorithm\n");
931 		return false;
932 	}
933 
934 	k = BN_num_bytes(pubkey->key.rsa.n);
935 	if (mLen > k - 11) {
936 		(void) fprintf(stderr, "encode_m_buf: message too long\n");
937 		return false;
938 	}
939 	/* these two bytes defined by RFC */
940 	EM[0] = 0x00;
941 	EM[1] = 0x02;
942 
943 	/* add non-zero random bytes of length k - mLen -3 */
944 	for (i = 2; i < k - mLen - 1; ++i) {
945 		do {
946 			__ops_random(EM + i, 1);
947 		} while (EM[i] == 0);
948 	}
949 
950 	if (i < 8 + 2) {
951 		(void) fprintf(stderr, "encode_m_buf: bad i len\n");
952 		return false;
953 	}
954 
955 	EM[i++] = 0;
956 
957 	(void) memcpy(EM + i, M, mLen);
958 
959 	if (__ops_get_debug_level(__FILE__)) {
960 		unsigned int    i2 = 0;
961 
962 		(void) fprintf(stderr, "Encoded Message: \n");
963 		for (i2 = 0; i2 < mLen; i2++) {
964 			(void) fprintf(stderr, "%2x ", EM[i2]);
965 		}
966 		(void) fprintf(stderr, "\n");
967 	}
968 	return true;
969 }
970 
971 /**
972  \ingroup Core_Create
973 \brief Creates an __ops_pk_sesskey_t struct from keydata
974 \param key Keydata to use
975 \return __ops_pk_sesskey_t struct
976 \note It is the caller's responsiblity to free the returned pointer
977 \note Currently hard-coded to use CAST5
978 \note Currently hard-coded to use RSA
979 */
980 __ops_pk_sesskey_t *
981 __ops_create_pk_sesskey(const __ops_keydata_t * key)
982 {
983 	/*
984          * Creates a random session key and encrypts it for the given key
985          *
986          * Session Key is for use with a SK algo,
987          * can be any, we're hardcoding CAST5 for now
988          *
989          * Encryption used is PK,
990          * can be any, we're hardcoding RSA for now
991          */
992 
993 	const __ops_pubkey_t *pub_key = __ops_get_pubkey(key);
994 #define SZ_UNENCODED_M_BUF CAST_KEY_LENGTH+1+2
995 	unsigned char   unencoded_m_buf[SZ_UNENCODED_M_BUF];
996 	const size_t    sz_encoded_m_buf = BN_num_bytes(pub_key->key.rsa.n);
997 	unsigned char  *encoded_m_buf = calloc(1, sz_encoded_m_buf);
998 
999 	__ops_pk_sesskey_t *sesskey = calloc(1, sizeof(*sesskey));
1000 	if (key->type != OPS_PTAG_CT_PUBLIC_KEY) {
1001 		(void) fprintf(stderr,
1002 			"__ops_create_pk_sesskey: bad type\n");
1003 		return NULL;
1004 	}
1005 	sesskey->version = OPS_PKSK_V3;
1006 	(void) memcpy(sesskey->key_id, key->key_id,
1007 			sizeof(sesskey->key_id));
1008 
1009 	if (__ops_get_debug_level(__FILE__)) {
1010 		unsigned int    i = 0;
1011 
1012 		(void) fprintf(stderr, "Encrypting for RSA key id : ");
1013 		for (i = 0; i < sizeof(sesskey->key_id); i++) {
1014 			(void) fprintf(stderr, "%2x ", key->key_id[i]);
1015 		}
1016 		(void) fprintf(stderr, "\n");
1017 	}
1018 	if (key->key.pubkey.alg != OPS_PKA_RSA) {
1019 		(void) fprintf(stderr,
1020 			"__ops_create_pk_sesskey: bad pubkey algorithm\n");
1021 		return NULL;
1022 	}
1023 	sesskey->alg = key->key.pubkey.alg;
1024 
1025 	/* \todo allow user to specify other algorithm */
1026 	sesskey->symm_alg = OPS_SA_CAST5;
1027 	__ops_random(sesskey->key, CAST_KEY_LENGTH);
1028 
1029 	if (__ops_get_debug_level(__FILE__)) {
1030 		unsigned int    i = 0;
1031 
1032 		(void) fprintf(stderr,
1033 			"CAST5 session key created (len=%d):\n ",
1034 			CAST_KEY_LENGTH);
1035 		for (i = 0; i < CAST_KEY_LENGTH; i++) {
1036 			(void) fprintf(stderr, "%2x ", sesskey->key[i]);
1037 		}
1038 		(void) fprintf(stderr, "\n");
1039 	}
1040 	if (create_unencoded_m_buf(sesskey, &unencoded_m_buf[0]) == false) {
1041 		(void) free(encoded_m_buf);
1042 		return NULL;
1043 	}
1044 	if (__ops_get_debug_level(__FILE__)) {
1045 		unsigned int    i = 0;
1046 
1047 		printf("unencoded m buf:\n");
1048 		for (i = 0; i < SZ_UNENCODED_M_BUF; i++) {
1049 			printf("%2x ", unencoded_m_buf[i]);
1050 		}
1051 		printf("\n");
1052 	}
1053 	encode_m_buf(&unencoded_m_buf[0], SZ_UNENCODED_M_BUF, pub_key,
1054 			&encoded_m_buf[0]);
1055 
1056 	/* and encrypt it */
1057 	if (!__ops_rsa_encrypt_mpi(encoded_m_buf, sz_encoded_m_buf, pub_key,
1058 			&sesskey->parameters)) {
1059 		(void) free(encoded_m_buf);
1060 		return NULL;
1061 	}
1062 	(void) free(encoded_m_buf);
1063 	return sesskey;
1064 }
1065 
1066 /**
1067 \ingroup Core_WritePackets
1068 \brief Writes Public Key Session Key packet
1069 \param info Write settings
1070 \param pksk Public Key Session Key to write out
1071 \return true if OK; else false
1072 */
1073 bool
1074 __ops_write_pk_sesskey(__ops_createinfo_t * info,
1075 			 __ops_pk_sesskey_t * pksk)
1076 {
1077 	if (pksk == NULL) {
1078 		(void) fprintf(stderr,
1079 			"__ops_write_pk_sesskey: NULL pksk\n");
1080 		return false;
1081 	}
1082 	if (pksk->alg != OPS_PKA_RSA) {
1083 		(void) fprintf(stderr,
1084 			"__ops_write_pk_sesskey: bad algorithm\n");
1085 		return false;
1086 	}
1087 
1088 	return __ops_write_ptag(OPS_PTAG_CT_PK_SESSION_KEY, info) &&
1089 		__ops_write_length((unsigned)(1 + 8 + 1 + BN_num_bytes(pksk->parameters.rsa.encrypted_m) + 2), info) &&
1090 		__ops_write_scalar((unsigned)pksk->version, 1, info) &&
1091 		__ops_write(pksk->key_id, 8, info) &&
1092 		__ops_write_scalar((unsigned)pksk->alg, 1, info) &&
1093 		__ops_write_mpi(pksk->parameters.rsa.encrypted_m, info)
1094 	/* ??	&& __ops_write_scalar(0, 2, info); */
1095 		;
1096 }
1097 
1098 /**
1099 \ingroup Core_WritePackets
1100 \brief Writes MDC packet
1101 \param hashed Hash for MDC
1102 \param info Write settings
1103 \return true if OK; else false
1104 */
1105 
1106 bool
1107 __ops_write_mdc(const unsigned char *hashed, __ops_createinfo_t *info)
1108 {
1109 	/* write it out */
1110 	return __ops_write_ptag(OPS_PTAG_CT_MDC, info) &&
1111 		__ops_write_length(OPS_SHA1_HASH_SIZE, info) &&
1112 		__ops_write(hashed, OPS_SHA1_HASH_SIZE, info);
1113 }
1114 
1115 /**
1116 \ingroup Core_WritePackets
1117 \brief Writes Literal Data packet from buffer
1118 \param data Buffer to write out
1119 \param maxlen Max length of buffer
1120 \param type Literal Data Type
1121 \param info Write settings
1122 \return true if OK; else false
1123 */
1124 bool
1125 __ops_write_litdata(const unsigned char *data,
1126 				const int maxlen,
1127 				const __ops_litdata_type_t type,
1128 				__ops_createinfo_t * info)
1129 {
1130 	/*
1131          * RFC4880 does not specify a meaning for filename or date.
1132          * It is implementation-dependent.
1133          * We will not implement them.
1134          */
1135 	/* \todo do we need to check text data for <cr><lf> line endings ? */
1136 	return __ops_write_ptag(OPS_PTAG_CT_LITERAL_DATA, info) &&
1137 		__ops_write_length((unsigned)(1 + 1 + 4 + maxlen), info) &&
1138 		__ops_write_scalar((unsigned)type, 1, info) &&
1139 		__ops_write_scalar(0, 1, info) &&
1140 		__ops_write_scalar(0, 4, info) &&
1141 		__ops_write(data, (unsigned)maxlen, info);
1142 }
1143 
1144 /**
1145 \ingroup Core_WritePackets
1146 \brief Writes Literal Data packet from contents of file
1147 \param filename Name of file to read from
1148 \param type Literal Data Type
1149 \param info Write settings
1150 \return true if OK; else false
1151 */
1152 
1153 bool
1154 __ops_fileread_litdata(const char *filename,
1155 				 const __ops_litdata_type_t type,
1156 				 __ops_createinfo_t * info)
1157 {
1158 	unsigned char    buf[1024];
1159 	unsigned char	*mmapped;
1160 	__ops_memory_t	*mem = NULL;
1161 	struct stat	 st;
1162 	size_t           len = 0;
1163 	int              fd = 0;
1164 	bool   		 rtn;
1165 
1166 #ifdef O_BINARY
1167 	fd = open(filename, O_RDONLY | O_BINARY);
1168 #else
1169 	fd = open(filename, O_RDONLY);
1170 #endif
1171 	if (fd < 0)
1172 		return false;
1173 
1174 	mem = __ops_memory_new();
1175 	mmapped = MAP_FAILED;
1176 #ifdef USE_MMAP_FOR_FILES
1177 	if (fstat(fd, &st) == 0) {
1178 		mem->length = (unsigned)st.st_size;
1179 		mmapped = mem->buf = mmap(NULL, (size_t)st.st_size, PROT_READ,
1180 					MAP_FILE | MAP_PRIVATE, fd, 0);
1181 	}
1182 #endif
1183 	if (mmapped == MAP_FAILED) {
1184 		__ops_memory_init(mem, (size_t)st.st_size);
1185 		for (;;) {
1186 			ssize_t         n = 0;
1187 
1188 			if ((n = read(fd, buf, sizeof(buf))) == 0) {
1189 				break;
1190 			}
1191 			__ops_memory_add(mem, buf, (unsigned)n);
1192 		}
1193 	}
1194 	(void) close(fd);
1195 
1196 	/* \todo do we need to check text data for <cr><lf> line endings ? */
1197 	len = __ops_memory_get_length(mem);
1198 	rtn = __ops_write_ptag(OPS_PTAG_CT_LITERAL_DATA, info) &&
1199 		__ops_write_length(1 + 1 + 4 + len, info) &&
1200 		__ops_write_scalar((unsigned)type, 1, info) &&
1201 		__ops_write_scalar(0, 1, info)	/* filename */ &&
1202 		__ops_write_scalar(0, 4, info)	/* date */ &&
1203 		__ops_write(__ops_memory_get_data(mem), len, info);
1204 
1205 #ifdef USE_MMAP_FOR_FILES
1206 	if (mmapped != MAP_FAILED) {
1207 		munmap(mmapped, mem->length);
1208 		mmapped = buf;
1209 	}
1210 #endif
1211 	if (mmapped == NULL) {
1212 		__ops_memory_free(mem);
1213 	}
1214 	return rtn;
1215 }
1216 
1217 /**
1218    \ingroup HighLevel_General
1219 
1220    \brief Reads contents of file into new __ops_memory_t struct.
1221 
1222    \param filename Filename to read from
1223    \param errnum Pointer to error
1224    \return new __ops_memory_t pointer containing the contents of the file
1225 
1226    \note If there was an error opening the file or reading from it,
1227    	errnum is set to the cause
1228    \note It is the caller's responsibility to call __ops_memory_free(mem)
1229 */
1230 __ops_memory_t   *
1231 __ops_fileread(const char *filename, int *errnum)
1232 {
1233 	__ops_memory_t   *mem = NULL;
1234 	unsigned char    buf[1024];
1235 	struct stat	 st;
1236 	int              fd = 0;
1237 
1238 	*errnum = 0;
1239 #ifdef O_BINARY
1240 	fd = open(filename, O_RDONLY | O_BINARY);
1241 #else
1242 	fd = open(filename, O_RDONLY);
1243 #endif
1244 	if (fd < 0) {
1245 		*errnum = errno;
1246 		return false;
1247 	}
1248 	mem = __ops_memory_new();
1249 	(void) fstat(fd, &st);
1250 	__ops_memory_init(mem, (unsigned)st.st_size);
1251 	for (;;) {
1252 		ssize_t         n = 0;
1253 
1254 		n = read(fd, buf, sizeof(buf));
1255 		if (n < 0) {
1256 			*errnum = errno;
1257 			break;
1258 		}
1259 		if (!n) {
1260 			break;
1261 		}
1262 		__ops_memory_add(mem, buf, (unsigned)n);
1263 	}
1264 	(void) close(fd);
1265 	return mem;
1266 }
1267 
1268 /**
1269    \ingroup HighLevel_General
1270 
1271    \brief Writes contents of buffer into file
1272 
1273    \param filename Filename to write to
1274    \param buf Buffer to write to file
1275    \param len Size of buffer
1276    \param overwrite Flag to set whether to overwrite an existing file
1277    \return 1 if OK; 0 if error
1278 */
1279 
1280 int
1281 __ops_filewrite(const char *filename, const char *buf,
1282 			const size_t len, const bool overwrite)
1283 {
1284 	int		flags = 0;
1285 	int		fd = 0;
1286 
1287 	flags = O_WRONLY | O_CREAT;
1288 	if (overwrite == true) {
1289 		flags |= O_TRUNC;
1290 	} else {
1291 		flags |= O_EXCL;
1292 	}
1293 #ifdef O_BINARY
1294 	flags |= O_BINARY;
1295 #endif
1296 	fd = open(filename, flags, 0600);
1297 	if (fd < 0) {
1298 		perror(NULL);
1299 		return 0;
1300 	}
1301 	if (write(fd, buf, len) != (int)len) {
1302 		return 0;
1303 	}
1304 
1305 	return (close(fd) == 0);
1306 }
1307 
1308 /**
1309 \ingroup Core_WritePackets
1310 \brief Write Symmetrically Encrypted packet
1311 \param data Data to encrypt
1312 \param len Length of data
1313 \param info Write settings
1314 \return true if OK; else false
1315 \note Hard-coded to use AES256
1316 */
1317 bool
1318 __ops_write_symm_enc_data(const unsigned char *data,
1319 				       const int len,
1320 				       __ops_createinfo_t * info)
1321 {
1322 			/* buffer to write encrypted data to */
1323 	unsigned char  *encrypted = (unsigned char *) NULL;
1324 	__ops_crypt_t	crypt_info;
1325 	size_t		encrypted_sz = 0;	/* size of encrypted data */
1326 	int             done = 0;
1327 
1328 	/* \todo assume AES256 for now */
1329 	__ops_crypt_any(&crypt_info, OPS_SA_AES_256);
1330 	__ops_encrypt_init(&crypt_info);
1331 
1332 	encrypted_sz = len + crypt_info.blocksize + 2;
1333 	encrypted = calloc(1, encrypted_sz);
1334 
1335 	done = __ops_encrypt_se(&crypt_info, encrypted, data, (unsigned)len);
1336 	if (done != len) {
1337 		(void) fprintf(stderr,
1338 "__ops_write_symm_enc_data: done != len\n");
1339 		return false;
1340 	}
1341 
1342 	return __ops_write_ptag(OPS_PTAG_CT_SE_DATA, info) &&
1343 		__ops_write_length(1 + encrypted_sz, info) &&
1344 		__ops_write(data, (unsigned)len, info);
1345 }
1346 
1347 /**
1348 \ingroup Core_WritePackets
1349 \brief Write a One Pass Signature packet
1350 \param seckey Secret Key to use
1351 \param hash_alg Hash Algorithm to use
1352 \param sig_type Signature type
1353 \param info Write settings
1354 \return true if OK; else false
1355 */
1356 bool
1357 __ops_write_one_pass_sig(const __ops_seckey_t * seckey,
1358 		       const __ops_hash_alg_t hash_alg,
1359 		       const __ops_sig_type_t sig_type,
1360 		       __ops_createinfo_t * info)
1361 {
1362 	unsigned char   keyid[OPS_KEY_ID_SIZE];
1363 
1364 	if (__ops_get_debug_level(__FILE__)) {
1365 		fprintf(stderr, "calling __ops_keyid in write_one_pass_sig: this calls sha1_init\n");
1366 	}
1367 	__ops_keyid(keyid, OPS_KEY_ID_SIZE, OPS_KEY_ID_SIZE, &seckey->pubkey);
1368 
1369 	return __ops_write_ptag(OPS_PTAG_CT_ONE_PASS_SIGNATURE, info) &&
1370 		__ops_write_length(1 + 1 + 1 + 1 + 8 + 1, info) &&
1371 		__ops_write_scalar(3, 1, info)	/* version */ &&
1372 		__ops_write_scalar((unsigned)sig_type, 1, info) &&
1373 		__ops_write_scalar((unsigned)hash_alg, 1, info) &&
1374 		__ops_write_scalar((unsigned)seckey->pubkey.alg, 1, info) &&
1375 		__ops_write(keyid, 8, info) &&
1376 		__ops_write_scalar(1, 1, info);
1377 }
1378