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