xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/create.c (revision 651dd2889a90c73d5cca8dee2f69ba66b194cb04)
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.26 2010/05/08 00:33:28 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, uint8_t *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 uint8_t *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 uint8_t *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	done = 0;
284 	unsigned	i = 0;
285 	uint8_t		hashed[OPS_SHA1_HASH_SIZE];
286 	uint8_t		sesskey[CAST_KEY_LENGTH];
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 	if (!__ops_write_scalar(output, (unsigned)key->hash_alg, 1)) {
317 		return 0;
318 	}
319 
320 	switch (key->s2k_specifier) {
321 	case OPS_S2KS_SIMPLE:
322 		/* nothing more to do */
323 		break;
324 
325 	case OPS_S2KS_SALTED:
326 		/* 8-octet salt value */
327 		__ops_random(__UNCONST(&key->salt[0]), OPS_SALT_SIZE);
328 		if (!__ops_write(output, key->salt, OPS_SALT_SIZE)) {
329 			return 0;
330 		}
331 		break;
332 
333 		/*
334 		 * \todo case OPS_S2KS_ITERATED_AND_SALTED: // 8-octet salt
335 		 * value // 1-octet count break;
336 		 */
337 
338 	default:
339 		(void) fprintf(stderr,
340 			"invalid/unsupported s2k specifier %d\n",
341 			key->s2k_specifier);
342 		return 0;
343 	}
344 
345 	if (!__ops_write(output, &key->iv[0], __ops_block_size(key->alg))) {
346 		return 0;
347 	}
348 
349 	/*
350 	 * create the session key for encrypting the algorithm-specific
351 	 * fields
352 	 */
353 
354 	switch (key->s2k_specifier) {
355 	case OPS_S2KS_SIMPLE:
356 	case OPS_S2KS_SALTED:
357 		/* RFC4880: section 3.7.1.1 and 3.7.1.2 */
358 
359 		for (done = 0, i = 0; done < CAST_KEY_LENGTH; i++) {
360 			unsigned 	j;
361 			uint8_t		zero = 0;
362 			int             needed;
363 			int             size;
364 
365 			needed = CAST_KEY_LENGTH - done;
366 			size = MIN(needed, OPS_SHA1_HASH_SIZE);
367 
368 			__ops_hash_any(&hash, key->hash_alg);
369 			if (!hash.init(&hash)) {
370 				(void) fprintf(stderr, "write_seckey_body: bad alloc\n");
371 				return 0;
372 			}
373 
374 			/* preload if iterating  */
375 			for (j = 0; j < i; j++) {
376 				/*
377 				 * Coverity shows a DEADCODE error on this
378 				 * line. This is expected since the hardcoded
379 				 * use of SHA1 and CAST5 means that it will
380 				 * not used. This will change however when
381 				 * other algorithms are supported.
382 				 */
383 				hash.add(&hash, &zero, 1);
384 			}
385 
386 			if (key->s2k_specifier == OPS_S2KS_SALTED) {
387 				hash.add(&hash, key->salt, OPS_SALT_SIZE);
388 			}
389 			hash.add(&hash, passphrase, pplen);
390 			hash.finish(&hash, hashed);
391 
392 			/*
393 			 * if more in hash than is needed by session key, use
394 			 * the leftmost octets
395 			 */
396 			(void) memcpy(&sesskey[i * OPS_SHA1_HASH_SIZE],
397 					hashed, (unsigned)size);
398 			done += (unsigned)size;
399 			if (done > CAST_KEY_LENGTH) {
400 				(void) fprintf(stderr,
401 					"write_seckey_body: short add\n");
402 				return 0;
403 			}
404 		}
405 
406 		break;
407 
408 		/*
409 		 * \todo case OPS_S2KS_ITERATED_AND_SALTED: * 8-octet salt
410 		 * value * 1-octet count break;
411 		 */
412 
413 	default:
414 		(void) fprintf(stderr,
415 			"invalid/unsupported s2k specifier %d\n",
416 			key->s2k_specifier);
417 		return 0;
418 	}
419 
420 	/* use this session key to encrypt */
421 
422 	__ops_crypt_any(&crypted, key->alg);
423 	crypted.set_iv(&crypted, key->iv);
424 	crypted.set_crypt_key(&crypted, sesskey);
425 	__ops_encrypt_init(&crypted);
426 
427 	if (__ops_get_debug_level(__FILE__)) {
428 		(void) fprintf(stderr, "\nWRITING:\niv=");
429 		hexdump(stderr, key->iv, __ops_block_size(key->alg), " ");
430 		(void) fprintf(stderr, "\nkey=");
431 		hexdump(stderr, sesskey, CAST_KEY_LENGTH, " ");
432 		(void) fprintf(stderr, "\nturning encryption on...\n");
433 	}
434 	__ops_push_enc_crypt(output, &crypted);
435 
436 	switch (key->pubkey.alg) {
437 		/* case OPS_PKA_DSA: */
438 		/* return __ops_write_mpi(output, key->key.dsa.x); */
439 
440 	case OPS_PKA_RSA:
441 	case OPS_PKA_RSA_ENCRYPT_ONLY:
442 	case OPS_PKA_RSA_SIGN_ONLY:
443 
444 		if (!__ops_write_mpi(output, key->key.rsa.d) ||
445 		    !__ops_write_mpi(output, key->key.rsa.p) ||
446 		    !__ops_write_mpi(output, key->key.rsa.q) ||
447 		    !__ops_write_mpi(output, key->key.rsa.u)) {
448 			if (__ops_get_debug_level(__FILE__)) {
449 				(void) fprintf(stderr,
450 					"4 x mpi not written - problem\n");
451 			}
452 			return 0;
453 		}
454 		break;
455 
456 		/* case OPS_PKA_ELGAMAL: */
457 		/* return __ops_write_mpi(output, key->key.elgamal.x); */
458 
459 	default:
460 		return 0;
461 	}
462 
463 	if (!__ops_write(output, key->checkhash, OPS_CHECKHASH_SIZE)) {
464 		return 0;
465 	}
466 
467 	__ops_writer_pop(output);
468 
469 	return 1;
470 }
471 
472 /**
473  * \ingroup Core_WritePackets
474  * \brief Writes a Public Key packet
475  * \param key
476  * \param output
477  * \return 1 if OK, otherwise 0
478  */
479 static unsigned
480 write_struct_pubkey(__ops_output_t *output, const __ops_pubkey_t *key)
481 {
482 	if (key->version != 4) {
483 		(void) fprintf(stderr,
484 			"write_struct_pubkey: wrong key version\n");
485 		return 0;
486 	}
487 	return __ops_write_ptag(output, OPS_PTAG_CT_PUBLIC_KEY) &&
488 		__ops_write_length(output, 1 + 4 + 1 + pubkey_length(key)) &&
489 		write_pubkey_body(key, output);
490 }
491 
492 
493 /**
494    \ingroup HighLevel_KeyWrite
495 
496    \brief Writes a transferable PGP public key to the given output stream.
497 
498    \param keydata Key to be written
499    \param armoured Flag is set for armoured output
500    \param output Output stream
501 
502 */
503 
504 unsigned
505 __ops_write_xfer_pubkey(__ops_output_t *output,
506 			const __ops_key_t *key,
507 			const unsigned armoured)
508 {
509 	unsigned    i, j;
510 
511 	if (armoured) {
512 		__ops_writer_push_armoured(output, OPS_PGP_PUBLIC_KEY_BLOCK);
513 	}
514 	/* public key */
515 	if (!write_struct_pubkey(output, &key->key.seckey.pubkey)) {
516 		return 0;
517 	}
518 
519 	/* TODO: revocation signatures go here */
520 
521 	/* user ids and corresponding signatures */
522 	for (i = 0; i < key->uidc; i++) {
523 		if (!__ops_write_struct_userid(output, &key->uids[i])) {
524 			return 0;
525 		}
526 		for (j = 0; j < key->packetc; j++) {
527 			if (!__ops_write(output, key->packets[j].raw, key->packets[j].length)) {
528 				return 0;
529 			}
530 		}
531 	}
532 
533 	/* TODO: user attributes and corresponding signatures */
534 
535 	/*
536 	 * subkey packets and corresponding signatures and optional
537 	 * revocation
538 	 */
539 
540 	if (armoured) {
541 		__ops_writer_info_finalise(&output->errors, &output->writer);
542 		__ops_writer_pop(output);
543 	}
544 	return 1;
545 }
546 
547 /**
548    \ingroup HighLevel_KeyWrite
549 
550    \brief Writes a transferable PGP secret key to the given output stream.
551 
552    \param keydata Key to be written
553    \param passphrase
554    \param pplen
555    \param armoured Flag is set for armoured output
556    \param output Output stream
557 
558 */
559 
560 unsigned
561 __ops_write_xfer_seckey(__ops_output_t *output,
562 				const __ops_key_t *key,
563 				const uint8_t *passphrase,
564 				const size_t pplen,
565 				unsigned armoured)
566 {
567 	unsigned	i, j;
568 
569 	if (armoured) {
570 		__ops_writer_push_armoured(output, OPS_PGP_PRIVATE_KEY_BLOCK);
571 	}
572 	/* public key */
573 	if (!__ops_write_struct_seckey(&key->key.seckey, passphrase,
574 			pplen, output)) {
575 		return 0;
576 	}
577 
578 	/* TODO: revocation signatures go here */
579 
580 	/* user ids and corresponding signatures */
581 	for (i = 0; i < key->uidc; i++) {
582 		if (!__ops_write_struct_userid(output, &key->uids[i])) {
583 			return 0;
584 		}
585 		for (j = 0; j < key->packetc; j++) {
586 			if (!__ops_write(output, key->packets[j].raw, key->packets[j].length)) {
587 				return 0;
588 			}
589 		}
590 	}
591 
592 	/* TODO: user attributes and corresponding signatures */
593 
594 	/*
595 	 * subkey packets and corresponding signatures and optional
596 	 * revocation
597 	 */
598 
599 	if (armoured) {
600 		__ops_writer_info_finalise(&output->errors, &output->writer);
601 		__ops_writer_pop(output);
602 	}
603 	return 1;
604 }
605 
606 /**
607  * \ingroup Core_WritePackets
608  * \brief Writes one RSA public key packet.
609  * \param t Creation time
610  * \param n RSA public modulus
611  * \param e RSA public encryption exponent
612  * \param output Writer settings
613  *
614  * \return 1 if OK, otherwise 0
615  */
616 
617 unsigned
618 __ops_write_rsa_pubkey(time_t t, const BIGNUM *n,
619 			 const BIGNUM *e,
620 			 __ops_output_t *output)
621 {
622 	__ops_pubkey_t key;
623 
624 	__ops_fast_create_rsa_pubkey(&key, t, __UNCONST(n), __UNCONST(e));
625 	return write_struct_pubkey(output, &key);
626 }
627 
628 /**
629  * \ingroup Core_Create
630  * \param out
631  * \param key
632  * \param make_packet
633  */
634 
635 void
636 __ops_build_pubkey(__ops_memory_t *out, const __ops_pubkey_t *key,
637 		     unsigned make_packet)
638 {
639 	__ops_output_t *output;
640 
641 	output = __ops_output_new();
642 	__ops_memory_init(out, 128);
643 	__ops_writer_set_memory(output, out);
644 	write_pubkey_body(key, output);
645 	if (make_packet) {
646 		__ops_memory_make_packet(out, OPS_PTAG_CT_PUBLIC_KEY);
647 	}
648 	__ops_output_delete(output);
649 }
650 
651 /**
652  * \ingroup Core_Create
653  *
654  * Create an RSA secret key structure. If a parameter is marked as
655  * [OPTIONAL], then it can be omitted and will be calculated from
656  * other params - or, in the case of e, will default to 0x10001.
657  *
658  * Parameters are _not_ copied, so will be freed if the structure is
659  * freed.
660  *
661  * \param key The key structure to be initialised.
662  * \param t
663  * \param d The RSA parameter d (=e^-1 mod (p-1)(q-1)) [OPTIONAL]
664  * \param p The RSA parameter p
665  * \param q The RSA parameter q (q > p)
666  * \param u The RSA parameter u (=p^-1 mod q) [OPTIONAL]
667  * \param n The RSA public parameter n (=p*q) [OPTIONAL]
668  * \param e The RSA public parameter e */
669 
670 void
671 __ops_fast_create_rsa_seckey(__ops_seckey_t *key, time_t t,
672 			     BIGNUM *d, BIGNUM *p, BIGNUM *q, BIGNUM *u,
673 			       BIGNUM *n, BIGNUM *e)
674 {
675 	__ops_fast_create_rsa_pubkey(&key->pubkey, t, n, e);
676 
677 	/* XXX: calculate optionals */
678 	key->key.rsa.d = d;
679 	key->key.rsa.p = p;
680 	key->key.rsa.q = q;
681 	key->key.rsa.u = u;
682 
683 	key->s2k_usage = OPS_S2KU_NONE;
684 
685 	/* XXX: sanity check and add errors... */
686 }
687 
688 /**
689  * \ingroup Core_WritePackets
690  * \brief Writes a Secret Key packet.
691  * \param key The secret key
692  * \param passphrase The passphrase
693  * \param pplen Length of passphrase
694  * \param output
695  * \return 1 if OK; else 0
696  */
697 unsigned
698 __ops_write_struct_seckey(const __ops_seckey_t *key,
699 			    const uint8_t *passphrase,
700 			    const size_t pplen,
701 			    __ops_output_t *output)
702 {
703 	int             length = 0;
704 
705 	if (key->pubkey.version != 4) {
706 		(void) fprintf(stderr,
707 			"__ops_write_struct_seckey: public key version\n");
708 		return 0;
709 	}
710 
711 	/* Ref: RFC4880 Section 5.5.3 */
712 
713 	/* pubkey, excluding MPIs */
714 	length += 1 + 4 + 1 + 1;
715 
716 	/* s2k usage */
717 	length += 1;
718 
719 	switch (key->s2k_usage) {
720 	case OPS_S2KU_NONE:
721 		/* nothing to add */
722 		break;
723 
724 	case OPS_S2KU_ENCRYPTED_AND_HASHED:	/* 254 */
725 	case OPS_S2KU_ENCRYPTED:	/* 255 */
726 
727 		/* Ref: RFC4880 Section 3.7 */
728 		length += 1;	/* s2k_specifier */
729 
730 		switch (key->s2k_specifier) {
731 		case OPS_S2KS_SIMPLE:
732 			length += 1;	/* hash algorithm */
733 			break;
734 
735 		case OPS_S2KS_SALTED:
736 			length += 1 + 8;	/* hash algorithm + salt */
737 			break;
738 
739 		case OPS_S2KS_ITERATED_AND_SALTED:
740 			length += 1 + 8 + 1;	/* hash algorithm, salt +
741 						 * count */
742 			break;
743 
744 		default:
745 			(void) fprintf(stderr,
746 				"__ops_write_struct_seckey: s2k spec\n");
747 			return 0;
748 		}
749 		break;
750 
751 	default:
752 		(void) fprintf(stderr,
753 			"__ops_write_struct_seckey: s2k usage\n");
754 		return 0;
755 	}
756 
757 	/* IV */
758 	if (key->s2k_usage) {
759 		length += __ops_block_size(key->alg);
760 	}
761 	/* checksum or hash */
762 	switch (key->s2k_usage) {
763 	case OPS_S2KU_NONE:
764 	case OPS_S2KU_ENCRYPTED:
765 		length += 2;
766 		break;
767 
768 	case OPS_S2KU_ENCRYPTED_AND_HASHED:
769 		length += OPS_CHECKHASH_SIZE;
770 		break;
771 
772 	default:
773 		(void) fprintf(stderr,
774 			"__ops_write_struct_seckey: s2k cksum usage\n");
775 		return 0;
776 	}
777 
778 	/* secret key and public key MPIs */
779 	length += (unsigned)seckey_length(key);
780 
781 	return __ops_write_ptag(output, OPS_PTAG_CT_SECRET_KEY) &&
782 		/* __ops_write_length(output,1+4+1+1+seckey_length(key)+2) && */
783 		__ops_write_length(output, (unsigned)length) &&
784 		write_seckey_body(key, passphrase, pplen, output);
785 }
786 
787 /**
788  * \ingroup Core_Create
789  *
790  * \brief Create a new __ops_output_t structure.
791  *
792  * \return the new structure.
793  * \note It is the responsiblity of the caller to call __ops_output_delete().
794  * \sa __ops_output_delete()
795  */
796 __ops_output_t *
797 __ops_output_new(void)
798 {
799 	return calloc(1, sizeof(__ops_output_t));
800 }
801 
802 /**
803  * \ingroup Core_Create
804  * \brief Delete an __ops_output_t strucut and associated resources.
805  *
806  * Delete an __ops_output_t structure. If a writer is active, then
807  * that is also deleted.
808  *
809  * \param info the structure to be deleted.
810  */
811 void
812 __ops_output_delete(__ops_output_t *output)
813 {
814 	__ops_writer_info_delete(&output->writer);
815 	free(output);
816 }
817 
818 /**
819  \ingroup Core_Create
820  \brief Calculate the checksum for a session key
821  \param sesskey Session Key to use
822  \param cs Checksum to be written
823  \return 1 if OK; else 0
824 */
825 unsigned
826 __ops_calc_sesskey_checksum(__ops_pk_sesskey_t *sesskey, uint8_t cs[2])
827 {
828 	uint32_t   checksum = 0;
829 	unsigned    i;
830 
831 	if (!__ops_is_sa_supported(sesskey->symm_alg)) {
832 		return 0;
833 	}
834 
835 	for (i = 0; i < __ops_key_size(sesskey->symm_alg); i++) {
836 		checksum += sesskey->key[i];
837 	}
838 	checksum = checksum % 65536;
839 
840 	cs[0] = (uint8_t)((checksum >> 8) & 0xff);
841 	cs[1] = (uint8_t)(checksum & 0xff);
842 
843 	if (__ops_get_debug_level(__FILE__)) {
844 		(void) fprintf(stderr,"\nm buf checksum: ");
845 		(void) fprintf(stderr," %2x",cs[0]);
846 		(void) fprintf(stderr," %2x\n",cs[1]);
847 	}
848 	return 1;
849 }
850 
851 static unsigned
852 create_unencoded_m_buf(__ops_pk_sesskey_t *sesskey, uint8_t *m_buf)
853 {
854 	int             i;
855 
856 	/* m_buf is the buffer which will be encoded in PKCS#1 block */
857 	/* encoding to form the "m" value used in the  */
858 	/* Public Key Encrypted Session Key Packet */
859 	/*
860 	 * as defined in RFC Section 5.1 "Public-Key Encrypted Session Key
861 	 * Packet"
862 	 */
863 
864 	m_buf[0] = sesskey->symm_alg;
865 
866 	if (sesskey->symm_alg != OPS_SA_CAST5) {
867 		(void) fprintf(stderr, "create_unencoded_m_buf: symm alg\n");
868 		return 0;
869 	}
870 	for (i = 0; i < CAST_KEY_LENGTH; i++) {
871 		/* XXX - Flexelint - Warning 679: Suspicious Truncation in arithmetic expression combining with pointer */
872 		m_buf[1 + i] = sesskey->key[i];
873 	}
874 
875 	return (__ops_calc_sesskey_checksum(sesskey,
876 				m_buf + 1 + CAST_KEY_LENGTH));
877 }
878 
879 /**
880 \ingroup Core_Create
881 \brief implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC
882 \param M
883 \param mLen
884 \param pubkey
885 \param EM
886 \return 1 if OK; else 0
887 */
888 unsigned
889 encode_m_buf(const uint8_t *M, size_t mLen, const __ops_pubkey_t * pubkey,
890 	     uint8_t *EM)
891 {
892 	unsigned    k;
893 	unsigned        i;
894 
895 	/* implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC */
896 
897 	if (pubkey->alg != OPS_PKA_RSA) {
898 		(void) fprintf(stderr, "encode_m_buf: pubkey algorithm\n");
899 		return 0;
900 	}
901 
902 	k = (unsigned)BN_num_bytes(pubkey->key.rsa.n);
903 	if (mLen > k - 11) {
904 		(void) fprintf(stderr, "encode_m_buf: message too long\n");
905 		return 0;
906 	}
907 	/* these two bytes defined by RFC */
908 	EM[0] = 0x00;
909 	EM[1] = 0x02;
910 
911 	/* add non-zero random bytes of length k - mLen -3 */
912 	for (i = 2; i < (k - mLen) - 1; ++i) {
913 		do {
914 			__ops_random(EM + i, 1);
915 		} while (EM[i] == 0);
916 	}
917 
918 	if (i < 8 + 2) {
919 		(void) fprintf(stderr, "encode_m_buf: bad i len\n");
920 		return 0;
921 	}
922 
923 	EM[i++] = 0;
924 
925 	(void) memcpy(EM + i, M, mLen);
926 
927 	if (__ops_get_debug_level(__FILE__)) {
928 		unsigned    i2;
929 
930 		(void) fprintf(stderr, "Encoded Message: \n");
931 		for (i2 = 0; i2 < mLen; i2++) {
932 			(void) fprintf(stderr, "%2x ", EM[i2]);
933 		}
934 		(void) fprintf(stderr, "\n");
935 	}
936 	return 1;
937 }
938 
939 /**
940  \ingroup Core_Create
941 \brief Creates an __ops_pk_sesskey_t struct from keydata
942 \param key Keydata to use
943 \return __ops_pk_sesskey_t struct
944 \note It is the caller's responsiblity to free the returned pointer
945 \note Currently hard-coded to use CAST5
946 \note Currently hard-coded to use RSA
947 */
948 __ops_pk_sesskey_t *
949 __ops_create_pk_sesskey(const __ops_key_t *key)
950 {
951 	/*
952          * Creates a random session key and encrypts it for the given key
953          *
954          * Session Key is for use with a SK algo,
955          * can be any, we're hardcoding CAST5 for now
956          *
957          * Encryption used is PK,
958          * can be any, we're hardcoding RSA for now
959          */
960 
961 #define SZ_UNENCODED_M_BUF (CAST_KEY_LENGTH + 1 + 2)
962 
963 	const __ops_pubkey_t	*pubkey;
964 	__ops_pk_sesskey_t	*sesskey;
965 	uint8_t			 unencoded_m_buf[SZ_UNENCODED_M_BUF];
966 	uint8_t			*encoded_m_buf;
967 	size_t			 sz_encoded_m_buf;
968 
969 	pubkey = __ops_get_pubkey(key);
970 	sz_encoded_m_buf = BN_num_bytes(pubkey->key.rsa.n);
971 	if ((encoded_m_buf = calloc(1, sz_encoded_m_buf)) == NULL) {
972 		(void) fprintf(stderr,
973 			"__ops_create_pk_sesskey: can't allocate\n");
974 		return NULL;
975 	}
976 	if ((sesskey = calloc(1, sizeof(*sesskey))) == NULL) {
977 		(void) fprintf(stderr,
978 			"__ops_create_pk_sesskey: can't allocate\n");
979 		free(encoded_m_buf);
980 		return NULL;
981 	}
982 	if (key->type != OPS_PTAG_CT_PUBLIC_KEY) {
983 		(void) fprintf(stderr,
984 			"__ops_create_pk_sesskey: bad type\n");
985 		free(encoded_m_buf);
986 		free(sesskey);
987 		return NULL;
988 	}
989 	sesskey->version = OPS_PKSK_V3;
990 	(void) memcpy(sesskey->key_id, key->key_id,
991 			sizeof(sesskey->key_id));
992 
993 	if (__ops_get_debug_level(__FILE__)) {
994 		unsigned    i;
995 
996 		(void) fprintf(stderr, "Encrypting for RSA key id : ");
997 		for (i = 0; i < sizeof(sesskey->key_id); i++) {
998 			(void) fprintf(stderr, "%2x ", key->key_id[i]);
999 		}
1000 		(void) fprintf(stderr, "\n");
1001 	}
1002 	if (key->key.pubkey.alg != OPS_PKA_RSA) {
1003 		(void) fprintf(stderr,
1004 			"__ops_create_pk_sesskey: bad pubkey algorithm\n");
1005 		free(encoded_m_buf);
1006 		free(sesskey);
1007 		return NULL;
1008 	}
1009 	sesskey->alg = key->key.pubkey.alg;
1010 
1011 	/* \todo allow user to specify other algorithm */
1012 	sesskey->symm_alg = OPS_SA_CAST5;
1013 	__ops_random(sesskey->key, CAST_KEY_LENGTH);
1014 
1015 	if (__ops_get_debug_level(__FILE__)) {
1016 		unsigned    i;
1017 
1018 		(void) fprintf(stderr,
1019 			"CAST5 session key created (len=%d):\n ",
1020 			CAST_KEY_LENGTH);
1021 		for (i = 0; i < CAST_KEY_LENGTH; i++) {
1022 			(void) fprintf(stderr, "%2x ", sesskey->key[i]);
1023 		}
1024 		(void) fprintf(stderr, "\n");
1025 	}
1026 	if (create_unencoded_m_buf(sesskey, &unencoded_m_buf[0]) == 0) {
1027 		free(encoded_m_buf);
1028 		free(sesskey);
1029 		return NULL;
1030 	}
1031 	if (__ops_get_debug_level(__FILE__)) {
1032 		unsigned    i;
1033 
1034 		printf("unencoded m buf:\n");
1035 		for (i = 0; i < SZ_UNENCODED_M_BUF; i++) {
1036 			printf("%2x ", unencoded_m_buf[i]);
1037 		}
1038 		printf("\n");
1039 	}
1040 	encode_m_buf(&unencoded_m_buf[0], SZ_UNENCODED_M_BUF, pubkey,
1041 			&encoded_m_buf[0]);
1042 
1043 	/* and encrypt it */
1044 	if (!__ops_rsa_encrypt_mpi(encoded_m_buf, sz_encoded_m_buf, pubkey,
1045 			&sesskey->params)) {
1046 		free(encoded_m_buf);
1047 		free(sesskey);
1048 		return NULL;
1049 	}
1050 	free(encoded_m_buf);
1051 	return sesskey;
1052 }
1053 
1054 /**
1055 \ingroup Core_WritePackets
1056 \brief Writes Public Key Session Key packet
1057 \param info Write settings
1058 \param pksk Public Key Session Key to write out
1059 \return 1 if OK; else 0
1060 */
1061 unsigned
1062 __ops_write_pk_sesskey(__ops_output_t *output, __ops_pk_sesskey_t *pksk)
1063 {
1064 	/* XXX - Flexelint - Pointer parameter 'pksk' (line 1076) could be declared as pointing to const */
1065 	if (pksk == NULL) {
1066 		(void) fprintf(stderr,
1067 			"__ops_write_pk_sesskey: NULL pksk\n");
1068 		return 0;
1069 	}
1070 	if (pksk->alg != OPS_PKA_RSA) {
1071 		(void) fprintf(stderr,
1072 			"__ops_write_pk_sesskey: bad algorithm\n");
1073 		return 0;
1074 	}
1075 	return __ops_write_ptag(output, OPS_PTAG_CT_PK_SESSION_KEY) &&
1076 		__ops_write_length(output, (unsigned)(1 + 8 + 1 +
1077 			BN_num_bytes(pksk->params.rsa.encrypted_m) + 2)) &&
1078 		__ops_write_scalar(output, (unsigned)pksk->version, 1) &&
1079 		__ops_write(output, pksk->key_id, 8) &&
1080 		__ops_write_scalar(output, (unsigned)pksk->alg, 1) &&
1081 		__ops_write_mpi(output, pksk->params.rsa.encrypted_m)
1082 	/* ??	&& __ops_write_scalar(output, 0, 2); */
1083 		;
1084 }
1085 
1086 /**
1087 \ingroup Core_WritePackets
1088 \brief Writes MDC packet
1089 \param hashed Hash for MDC
1090 \param output Write settings
1091 \return 1 if OK; else 0
1092 */
1093 
1094 unsigned
1095 __ops_write_mdc(__ops_output_t *output, const uint8_t *hashed)
1096 {
1097 	/* write it out */
1098 	return __ops_write_ptag(output, OPS_PTAG_CT_MDC) &&
1099 		__ops_write_length(output, OPS_SHA1_HASH_SIZE) &&
1100 		__ops_write(output, hashed, OPS_SHA1_HASH_SIZE);
1101 }
1102 
1103 /**
1104 \ingroup Core_WritePackets
1105 \brief Writes Literal Data packet from buffer
1106 \param data Buffer to write out
1107 \param maxlen Max length of buffer
1108 \param type Literal Data Type
1109 \param output Write settings
1110 \return 1 if OK; else 0
1111 */
1112 unsigned
1113 __ops_write_litdata(__ops_output_t *output,
1114 			const uint8_t *data,
1115 			const int maxlen,
1116 			const __ops_litdata_type_t type)
1117 {
1118 	/*
1119          * RFC4880 does not specify a meaning for filename or date.
1120          * It is implementation-dependent.
1121          * We will not implement them.
1122          */
1123 	/* \todo do we need to check text data for <cr><lf> line endings ? */
1124 	return __ops_write_ptag(output, OPS_PTAG_CT_LITDATA) &&
1125 		__ops_write_length(output, (unsigned)(1 + 1 + 4 + maxlen)) &&
1126 		__ops_write_scalar(output, (unsigned)type, 1) &&
1127 		__ops_write_scalar(output, 0, 1) &&
1128 		__ops_write_scalar(output, 0, 4) &&
1129 		__ops_write(output, data, (unsigned)maxlen);
1130 }
1131 
1132 /**
1133 \ingroup Core_WritePackets
1134 \brief Writes Literal Data packet from contents of file
1135 \param filename Name of file to read from
1136 \param type Literal Data Type
1137 \param output Write settings
1138 \return 1 if OK; else 0
1139 */
1140 
1141 unsigned
1142 __ops_fileread_litdata(const char *filename,
1143 				 const __ops_litdata_type_t type,
1144 				 __ops_output_t *output)
1145 {
1146 	__ops_memory_t	*mem;
1147 	unsigned   	 ret;
1148 	int		 len;
1149 
1150 	mem = __ops_memory_new();
1151 	if (!__ops_mem_readfile(mem, filename)) {
1152 		(void) fprintf(stderr, "__ops_mem_readfile of '%s' failed\n", filename);
1153 		return 0;
1154 	}
1155 	len = (size_t)__ops_mem_len(mem);
1156 	ret = __ops_write_litdata(output, __ops_mem_data(mem), len, type);
1157 	__ops_memory_free(mem);
1158 	return ret;
1159 }
1160 
1161 /**
1162    \ingroup HighLevel_General
1163 
1164    \brief Writes contents of buffer into file
1165 
1166    \param filename Filename to write to
1167    \param buf Buffer to write to file
1168    \param len Size of buffer
1169    \param overwrite Flag to set whether to overwrite an existing file
1170    \return 1 if OK; 0 if error
1171 */
1172 
1173 int
1174 __ops_filewrite(const char *filename, const char *buf,
1175 			const size_t len, const unsigned overwrite)
1176 {
1177 	int		flags;
1178 	int		fd;
1179 
1180 	flags = O_WRONLY | O_CREAT;
1181 	if (overwrite) {
1182 		flags |= O_TRUNC;
1183 	} else {
1184 		flags |= O_EXCL;
1185 	}
1186 #ifdef O_BINARY
1187 	flags |= O_BINARY;
1188 #endif
1189 	fd = open(filename, flags, 0600);
1190 	if (fd < 0) {
1191 		(void) fprintf(stderr, "can't open '%s'\n", filename);
1192 		return 0;
1193 	}
1194 	if (write(fd, buf, len) != (int)len) {
1195 		(void) close(fd);
1196 		return 0;
1197 	}
1198 
1199 	return (close(fd) == 0);
1200 }
1201 
1202 /**
1203 \ingroup Core_WritePackets
1204 \brief Write Symmetrically Encrypted packet
1205 \param data Data to encrypt
1206 \param len Length of data
1207 \param output Write settings
1208 \return 1 if OK; else 0
1209 \note Hard-coded to use AES256
1210 */
1211 unsigned
1212 __ops_write_symm_enc_data(const uint8_t *data,
1213 				       const int len,
1214 				       __ops_output_t * output)
1215 {
1216 	__ops_crypt_t	crypt_info;
1217 	uint8_t		*encrypted = (uint8_t *) NULL;
1218 	size_t		encrypted_sz;
1219 	int             done = 0;
1220 
1221 	/* \todo assume AES256 for now */
1222 	__ops_crypt_any(&crypt_info, OPS_SA_AES_256);
1223 	__ops_encrypt_init(&crypt_info);
1224 
1225 	encrypted_sz = (size_t)(len + crypt_info.blocksize + 2);
1226 	if ((encrypted = calloc(1, encrypted_sz)) == NULL) {
1227 		(void) fprintf(stderr, "can't allocate %" PRIsize "d\n",
1228 			encrypted_sz);
1229 		return 0;
1230 	}
1231 
1232 	done = __ops_encrypt_se(&crypt_info, encrypted, data, (unsigned)len);
1233 	if (done != len) {
1234 		(void) fprintf(stderr,
1235 			"__ops_write_symm_enc_data: done != len\n");
1236 		return 0;
1237 	}
1238 
1239 	return __ops_write_ptag(output, OPS_PTAG_CT_SE_DATA) &&
1240 		__ops_write_length(output, 1 + encrypted_sz) &&
1241 		__ops_write(output, data, (unsigned)len);
1242 }
1243 
1244 /**
1245 \ingroup Core_WritePackets
1246 \brief Write a One Pass Signature packet
1247 \param seckey Secret Key to use
1248 \param hash_alg Hash Algorithm to use
1249 \param sig_type Signature type
1250 \param output Write settings
1251 \return 1 if OK; else 0
1252 */
1253 unsigned
1254 __ops_write_one_pass_sig(__ops_output_t *output,
1255 			const __ops_seckey_t *seckey,
1256 			const __ops_hash_alg_t hash_alg,
1257 			const __ops_sig_type_t sig_type)
1258 {
1259 	uint8_t   keyid[OPS_KEY_ID_SIZE];
1260 
1261 	__ops_keyid(keyid, OPS_KEY_ID_SIZE, &seckey->pubkey);
1262 	return __ops_write_ptag(output, OPS_PTAG_CT_1_PASS_SIG) &&
1263 		__ops_write_length(output, 1 + 1 + 1 + 1 + 8 + 1) &&
1264 		__ops_write_scalar(output, 3, 1)	/* version */ &&
1265 		__ops_write_scalar(output, (unsigned)sig_type, 1) &&
1266 		__ops_write_scalar(output, (unsigned)hash_alg, 1) &&
1267 		__ops_write_scalar(output, (unsigned)seckey->pubkey.alg, 1) &&
1268 		__ops_write(output, keyid, 8) &&
1269 		__ops_write_scalar(output, 1, 1);
1270 }
1271