xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/create.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
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.34 2010/09/01 17:25:57 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, uint8_t *m_buf)
847 {
848 	int             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  */
852 	/* Public Key Encrypted Session Key Packet */
853 	/*
854 	 * as defined in RFC Section 5.1 "Public-Key Encrypted Session Key
855 	 * Packet"
856 	 */
857 
858 	m_buf[0] = sesskey->symm_alg;
859 
860 	if (sesskey->symm_alg != OPS_SA_CAST5) {
861 		(void) fprintf(stderr, "create_unencoded_m_buf: symm alg\n");
862 		return 0;
863 	}
864 	for (i = 0; i < CAST_KEY_LENGTH; i++) {
865 		/* XXX - Flexelint - Warning 679: Suspicious Truncation in arithmetic expression combining with pointer */
866 		m_buf[1 + i] = sesskey->key[i];
867 	}
868 
869 	return (__ops_calc_sesskey_checksum(sesskey,
870 				m_buf + 1 + CAST_KEY_LENGTH));
871 }
872 
873 /**
874 \ingroup Core_Create
875 \brief implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC
876 \param M
877 \param mLen
878 \param pubkey
879 \param EM
880 \return 1 if OK; else 0
881 */
882 unsigned
883 encode_m_buf(const uint8_t *M, size_t mLen, const __ops_pubkey_t * pubkey,
884 	     uint8_t *EM)
885 {
886 	unsigned    k;
887 	unsigned        i;
888 
889 	/* implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC */
890 	switch (pubkey->alg) {
891 	case OPS_PKA_RSA:
892 		break;
893 	case OPS_PKA_DSA:
894 	case OPS_PKA_ELGAMAL:
895 		(void) fprintf(stderr, "encode_m_buf: DSA/Elgamal encryption not implemented yet\n");
896 		break;
897 	default:
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 		hexdump(stderr, "Encoded Message:", EM, mLen);
929 	}
930 	return 1;
931 }
932 
933 /**
934  \ingroup Core_Create
935 \brief Creates an __ops_pk_sesskey_t struct from keydata
936 \param key Keydata to use
937 \return __ops_pk_sesskey_t struct
938 \note It is the caller's responsiblity to free the returned pointer
939 \note Currently hard-coded to use CAST5
940 \note Currently hard-coded to use RSA
941 */
942 __ops_pk_sesskey_t *
943 __ops_create_pk_sesskey(const __ops_key_t *key)
944 {
945 	/*
946          * Creates a random session key and encrypts it for the given key
947          *
948          * Session Key is for use with a SK algo,
949          * can be any, we're hardcoding CAST5 for now
950          *
951          * Encryption used is PK,
952          * can be any, we're hardcoding RSA for now
953          */
954 
955 #define SZ_UNENCODED_M_BUF (CAST_KEY_LENGTH + 1 + 2)
956 
957 	const __ops_pubkey_t	*pubkey;
958 	__ops_pk_sesskey_t	*sesskey;
959 	const uint8_t		*id;
960 	uint8_t			 unencoded_m_buf[SZ_UNENCODED_M_BUF];
961 	uint8_t			*encoded_m_buf;
962 	size_t			 sz_encoded_m_buf;
963 
964 	if (memcmp(key->encid, "\0\0\0\0\0\0\0\0", 8) == 0) {
965 		pubkey = __ops_get_pubkey(key);
966 		id = key->sigid;
967 	} else {
968 		pubkey = &key->enckey;
969 		id = key->encid;
970 	}
971 	sz_encoded_m_buf = BN_num_bytes(pubkey->key.rsa.n);
972 	if ((encoded_m_buf = calloc(1, sz_encoded_m_buf)) == NULL) {
973 		(void) fprintf(stderr,
974 			"__ops_create_pk_sesskey: can't allocate\n");
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(encoded_m_buf);
981 		return NULL;
982 	}
983 	if (key->type != OPS_PTAG_CT_PUBLIC_KEY) {
984 		(void) fprintf(stderr,
985 			"__ops_create_pk_sesskey: bad type\n");
986 		free(encoded_m_buf);
987 		free(sesskey);
988 		return NULL;
989 	}
990 	sesskey->version = OPS_PKSK_V3;
991 	(void) memcpy(sesskey->key_id, id, sizeof(sesskey->key_id));
992 
993 	if (__ops_get_debug_level(__FILE__)) {
994 		hexdump(stderr, "Encrypting for RSA keyid", id, sizeof(sesskey->key_id));
995 	}
996 	switch (pubkey->alg) {
997 	case OPS_PKA_RSA:
998 	case OPS_PKA_DSA:
999 	case OPS_PKA_ELGAMAL:
1000 		break;
1001 	default:
1002 		(void) fprintf(stderr,
1003 			"__ops_create_pk_sesskey: bad pubkey algorithm\n");
1004 		free(encoded_m_buf);
1005 		free(sesskey);
1006 		return NULL;
1007 	}
1008 	sesskey->alg = pubkey->alg;
1009 
1010 	/* \todo allow user to specify other algorithm */
1011 	sesskey->symm_alg = OPS_SA_CAST5;
1012 	__ops_random(sesskey->key, CAST_KEY_LENGTH);
1013 
1014 	if (__ops_get_debug_level(__FILE__)) {
1015 		hexdump(stderr, "CAST5 sesskey created", sesskey->key, CAST_KEY_LENGTH);
1016 	}
1017 	if (create_unencoded_m_buf(sesskey, &unencoded_m_buf[0]) == 0) {
1018 		free(encoded_m_buf);
1019 		free(sesskey);
1020 		return NULL;
1021 	}
1022 	if (__ops_get_debug_level(__FILE__)) {
1023 		hexdump(stderr, "uuencoded m buf", unencoded_m_buf, SZ_UNENCODED_M_BUF);
1024 	}
1025 	encode_m_buf(unencoded_m_buf, SZ_UNENCODED_M_BUF, pubkey, encoded_m_buf);
1026 
1027 	/* and encrypt it */
1028 	switch (key->key.pubkey.alg) {
1029 	case OPS_PKA_RSA:
1030 		if (!__ops_rsa_encrypt_mpi(encoded_m_buf, sz_encoded_m_buf, pubkey,
1031 				&sesskey->params)) {
1032 			free(encoded_m_buf);
1033 			free(sesskey);
1034 			return NULL;
1035 		}
1036 		break;
1037 	case OPS_PKA_DSA:
1038 	case OPS_PKA_ELGAMAL:
1039 		(void) fprintf(stderr, "DSA/Elgamal encryption not supported yet\n");
1040 		free(encoded_m_buf);
1041 		free(sesskey);
1042 		return NULL;
1043 	default:
1044 		/* will not get here - for lint only */
1045 		break;
1046 	}
1047 	free(encoded_m_buf);
1048 	return sesskey;
1049 }
1050 
1051 /**
1052 \ingroup Core_WritePackets
1053 \brief Writes Public Key Session Key packet
1054 \param info Write settings
1055 \param pksk Public Key Session Key to write out
1056 \return 1 if OK; else 0
1057 */
1058 unsigned
1059 __ops_write_pk_sesskey(__ops_output_t *output, __ops_pk_sesskey_t *pksk)
1060 {
1061 	/* XXX - Flexelint - Pointer parameter 'pksk' (line 1076) could be declared as pointing to const */
1062 	if (pksk == NULL) {
1063 		(void) fprintf(stderr,
1064 			"__ops_write_pk_sesskey: NULL pksk\n");
1065 		return 0;
1066 	}
1067 	switch (pksk->alg) {
1068 	case OPS_PKA_RSA:
1069 		return __ops_write_ptag(output, OPS_PTAG_CT_PK_SESSION_KEY) &&
1070 			__ops_write_length(output, (unsigned)(1 + 8 + 1 +
1071 				BN_num_bytes(pksk->params.rsa.encrypted_m) + 2)) &&
1072 			__ops_write_scalar(output, (unsigned)pksk->version, 1) &&
1073 			__ops_write(output, pksk->key_id, 8) &&
1074 			__ops_write_scalar(output, (unsigned)pksk->alg, 1) &&
1075 			__ops_write_mpi(output, pksk->params.rsa.encrypted_m)
1076 			/* ??	&& __ops_write_scalar(output, 0, 2); */
1077 			;
1078 	case OPS_PKA_DSA:
1079 	case OPS_PKA_ELGAMAL:
1080 		(void) fprintf(stderr, "__ops_write_pk_sesskey: DSA/Elgamal encryption not implemented yet\n");
1081 		return 0;
1082 	default:
1083 		(void) fprintf(stderr,
1084 			"__ops_write_pk_sesskey: bad algorithm\n");
1085 		return 0;
1086 	}
1087 }
1088 
1089 /**
1090 \ingroup Core_WritePackets
1091 \brief Writes MDC packet
1092 \param hashed Hash for MDC
1093 \param output Write settings
1094 \return 1 if OK; else 0
1095 */
1096 
1097 unsigned
1098 __ops_write_mdc(__ops_output_t *output, const uint8_t *hashed)
1099 {
1100 	/* write it out */
1101 	return __ops_write_ptag(output, OPS_PTAG_CT_MDC) &&
1102 		__ops_write_length(output, OPS_SHA1_HASH_SIZE) &&
1103 		__ops_write(output, hashed, OPS_SHA1_HASH_SIZE);
1104 }
1105 
1106 /**
1107 \ingroup Core_WritePackets
1108 \brief Writes Literal Data packet from buffer
1109 \param data Buffer to write out
1110 \param maxlen Max length of buffer
1111 \param type Literal Data Type
1112 \param output Write settings
1113 \return 1 if OK; else 0
1114 */
1115 unsigned
1116 __ops_write_litdata(__ops_output_t *output,
1117 			const uint8_t *data,
1118 			const int maxlen,
1119 			const __ops_litdata_enum type)
1120 {
1121 	/*
1122          * RFC4880 does not specify a meaning for filename or date.
1123          * It is implementation-dependent.
1124          * We will not implement them.
1125          */
1126 	/* \todo do we need to check text data for <cr><lf> line endings ? */
1127 	return __ops_write_ptag(output, OPS_PTAG_CT_LITDATA) &&
1128 		__ops_write_length(output, (unsigned)(1 + 1 + 4 + maxlen)) &&
1129 		__ops_write_scalar(output, (unsigned)type, 1) &&
1130 		__ops_write_scalar(output, 0, 1) &&
1131 		__ops_write_scalar(output, 0, 4) &&
1132 		__ops_write(output, data, (unsigned)maxlen);
1133 }
1134 
1135 /**
1136 \ingroup Core_WritePackets
1137 \brief Writes Literal Data packet from contents of file
1138 \param filename Name of file to read from
1139 \param type Literal Data Type
1140 \param output Write settings
1141 \return 1 if OK; else 0
1142 */
1143 
1144 unsigned
1145 __ops_fileread_litdata(const char *filename,
1146 				 const __ops_litdata_enum type,
1147 				 __ops_output_t *output)
1148 {
1149 	__ops_memory_t	*mem;
1150 	unsigned   	 ret;
1151 	int		 len;
1152 
1153 	mem = __ops_memory_new();
1154 	if (!__ops_mem_readfile(mem, filename)) {
1155 		(void) fprintf(stderr, "__ops_mem_readfile of '%s' failed\n", filename);
1156 		return 0;
1157 	}
1158 	len = (int)__ops_mem_len(mem);
1159 	ret = __ops_write_litdata(output, __ops_mem_data(mem), len, type);
1160 	__ops_memory_free(mem);
1161 	return ret;
1162 }
1163 
1164 /**
1165    \ingroup HighLevel_General
1166 
1167    \brief Writes contents of buffer into file
1168 
1169    \param filename Filename to write to
1170    \param buf Buffer to write to file
1171    \param len Size of buffer
1172    \param overwrite Flag to set whether to overwrite an existing file
1173    \return 1 if OK; 0 if error
1174 */
1175 
1176 int
1177 __ops_filewrite(const char *filename, const char *buf,
1178 			const size_t len, const unsigned overwrite)
1179 {
1180 	int		flags;
1181 	int		fd;
1182 
1183 	flags = O_WRONLY | O_CREAT;
1184 	if (overwrite) {
1185 		flags |= O_TRUNC;
1186 	} else {
1187 		flags |= O_EXCL;
1188 	}
1189 #ifdef O_BINARY
1190 	flags |= O_BINARY;
1191 #endif
1192 	fd = open(filename, flags, 0600);
1193 	if (fd < 0) {
1194 		(void) fprintf(stderr, "can't open '%s'\n", filename);
1195 		return 0;
1196 	}
1197 	if (write(fd, buf, len) != (int)len) {
1198 		(void) close(fd);
1199 		return 0;
1200 	}
1201 
1202 	return (close(fd) == 0);
1203 }
1204 
1205 /**
1206 \ingroup Core_WritePackets
1207 \brief Write Symmetrically Encrypted packet
1208 \param data Data to encrypt
1209 \param len Length of data
1210 \param output Write settings
1211 \return 1 if OK; else 0
1212 \note Hard-coded to use AES256
1213 */
1214 unsigned
1215 __ops_write_symm_enc_data(const uint8_t *data,
1216 				       const int len,
1217 				       __ops_output_t * output)
1218 {
1219 	__ops_crypt_t	crypt_info;
1220 	uint8_t		*encrypted = (uint8_t *) NULL;
1221 	size_t		encrypted_sz;
1222 	int             done = 0;
1223 
1224 	/* \todo assume AES256 for now */
1225 	__ops_crypt_any(&crypt_info, OPS_SA_AES_256);
1226 	__ops_encrypt_init(&crypt_info);
1227 
1228 	encrypted_sz = (size_t)(len + crypt_info.blocksize + 2);
1229 	if ((encrypted = calloc(1, encrypted_sz)) == NULL) {
1230 		(void) fprintf(stderr, "can't allocate %" PRIsize "d\n",
1231 			encrypted_sz);
1232 		return 0;
1233 	}
1234 
1235 	done = (int)__ops_encrypt_se(&crypt_info, encrypted, data, (unsigned)len);
1236 	if (done != len) {
1237 		(void) fprintf(stderr,
1238 			"__ops_write_symm_enc_data: done != len\n");
1239 		return 0;
1240 	}
1241 
1242 	return __ops_write_ptag(output, OPS_PTAG_CT_SE_DATA) &&
1243 		__ops_write_length(output, (unsigned)(1 + encrypted_sz)) &&
1244 		__ops_write(output, data, (unsigned)len);
1245 }
1246 
1247 /**
1248 \ingroup Core_WritePackets
1249 \brief Write a One Pass Signature packet
1250 \param seckey Secret Key to use
1251 \param hash_alg Hash Algorithm to use
1252 \param sig_type Signature type
1253 \param output Write settings
1254 \return 1 if OK; else 0
1255 */
1256 unsigned
1257 __ops_write_one_pass_sig(__ops_output_t *output,
1258 			const __ops_seckey_t *seckey,
1259 			const __ops_hash_alg_t hash_alg,
1260 			const __ops_sig_type_t sig_type)
1261 {
1262 	uint8_t   keyid[OPS_KEY_ID_SIZE];
1263 
1264 	__ops_keyid(keyid, OPS_KEY_ID_SIZE, &seckey->pubkey, OPS_HASH_SHA1); /* XXX - hardcoded */
1265 	return __ops_write_ptag(output, OPS_PTAG_CT_1_PASS_SIG) &&
1266 		__ops_write_length(output, 1 + 1 + 1 + 1 + 8 + 1) &&
1267 		__ops_write_scalar(output, 3, 1)	/* version */ &&
1268 		__ops_write_scalar(output, (unsigned)sig_type, 1) &&
1269 		__ops_write_scalar(output, (unsigned)hash_alg, 1) &&
1270 		__ops_write_scalar(output, (unsigned)seckey->pubkey.alg, 1) &&
1271 		__ops_write(output, keyid, 8) &&
1272 		__ops_write_scalar(output, 1, 1);
1273 }
1274