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