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