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