xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/create.c (revision 41335e2ddaa521cf708f9bc68e3f0f894d352972)
12232f800Sagc /*-
22232f800Sagc  * Copyright (c) 2009 The NetBSD Foundation, Inc.
32232f800Sagc  * All rights reserved.
42232f800Sagc  *
52232f800Sagc  * This code is derived from software contributed to The NetBSD Foundation
62232f800Sagc  * by Alistair Crooks (agc@NetBSD.org)
72232f800Sagc  *
82232f800Sagc  * Redistribution and use in source and binary forms, with or without
92232f800Sagc  * modification, are permitted provided that the following conditions
102232f800Sagc  * are met:
112232f800Sagc  * 1. Redistributions of source code must retain the above copyright
122232f800Sagc  *    notice, this list of conditions and the following disclaimer.
132232f800Sagc  * 2. Redistributions in binary form must reproduce the above copyright
142232f800Sagc  *    notice, this list of conditions and the following disclaimer in the
152232f800Sagc  *    documentation and/or other materials provided with the distribution.
162232f800Sagc  *
172232f800Sagc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
182232f800Sagc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
192232f800Sagc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
202232f800Sagc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
212232f800Sagc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
222232f800Sagc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
232232f800Sagc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
242232f800Sagc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
252232f800Sagc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
262232f800Sagc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
272232f800Sagc  * POSSIBILITY OF SUCH DAMAGE.
282232f800Sagc  */
2993bf6008Sagc /*
3093bf6008Sagc  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
3193bf6008Sagc  * All rights reserved.
3293bf6008Sagc  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
3393bf6008Sagc  * their moral rights under the UK Copyright Design and Patents Act 1988 to
3493bf6008Sagc  * be recorded as the authors of this copyright work.
3593bf6008Sagc  *
3693bf6008Sagc  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
3793bf6008Sagc  * use this file except in compliance with the License.
3893bf6008Sagc  *
3993bf6008Sagc  * You may obtain a copy of the License at
4093bf6008Sagc  *     http://www.apache.org/licenses/LICENSE-2.0
4193bf6008Sagc  *
4293bf6008Sagc  * Unless required by applicable law or agreed to in writing, software
4393bf6008Sagc  * distributed under the License is distributed on an "AS IS" BASIS,
4493bf6008Sagc  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4593bf6008Sagc  *
4693bf6008Sagc  * See the License for the specific language governing permissions and
4793bf6008Sagc  * limitations under the License.
4893bf6008Sagc  */
4993bf6008Sagc 
5093bf6008Sagc /** \file
5193bf6008Sagc  */
5293bf6008Sagc #include "config.h"
5393bf6008Sagc 
5457324b9fSagc #ifdef HAVE_SYS_CDEFS_H
5557324b9fSagc #include <sys/cdefs.h>
5657324b9fSagc #endif
5757324b9fSagc 
5857324b9fSagc #if defined(__NetBSD__)
5957324b9fSagc __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
60*41335e2dSagc __RCSID("$NetBSD: create.c,v 1.17 2009/06/09 00:51:01 agc Exp $");
6157324b9fSagc #endif
6257324b9fSagc 
63bcfd8565Sagc #include <sys/types.h>
642232f800Sagc #include <sys/param.h>
65bcfd8565Sagc #include <sys/stat.h>
66bcfd8565Sagc #include <sys/mman.h>
67bcfd8565Sagc 
68bcfd8565Sagc #ifdef HAVE_FCNTL_H
69bcfd8565Sagc #include <fcntl.h>
70bcfd8565Sagc #endif
71bcfd8565Sagc 
72bcfd8565Sagc #include <string.h>
73bcfd8565Sagc 
74bcfd8565Sagc #ifdef HAVE_UNISTD_H
75bcfd8565Sagc #include <unistd.h>
76bcfd8565Sagc #endif
77bcfd8565Sagc 
7893bf6008Sagc #ifdef HAVE_OPENSSL_CAST_H
7993bf6008Sagc #include <openssl/cast.h>
8093bf6008Sagc #endif
8193bf6008Sagc 
8293bf6008Sagc #include "create.h"
8393bf6008Sagc #include "keyring.h"
8493bf6008Sagc #include "packet.h"
8593bf6008Sagc #include "signature.h"
8693bf6008Sagc #include "writer.h"
8793bf6008Sagc #include "readerwriter.h"
8893bf6008Sagc #include "memory.h"
8993bf6008Sagc #include "netpgpdefs.h"
906715e11aSagc #include "netpgpdigest.h"
9193bf6008Sagc 
9293bf6008Sagc /**
9393bf6008Sagc  * \ingroup Core_Create
9493bf6008Sagc  * \param length
9593bf6008Sagc  * \param type
9657324b9fSagc  * \param output
974b3a3e18Sagc  * \return 1 if OK, otherwise 0
9893bf6008Sagc  */
9993bf6008Sagc 
1004b3a3e18Sagc unsigned
10157324b9fSagc __ops_write_ss_header(__ops_output_t *output,
10257324b9fSagc 			unsigned length,
10357324b9fSagc 			__ops_content_tag_t type)
10493bf6008Sagc {
10557324b9fSagc 	return __ops_write_length(output, length) &&
10657324b9fSagc 		__ops_write_scalar(output, (unsigned)(type -
107648b5a99Sagc 				OPS_PTAG_SIG_SUBPKT_BASE), 1);
10893bf6008Sagc }
10993bf6008Sagc 
11093bf6008Sagc /*
11193bf6008Sagc  * XXX: the general idea of _fast_ is that it doesn't copy stuff the safe
11293bf6008Sagc  * (i.e. non _fast_) version will, and so will also need to be freed.
11393bf6008Sagc  */
11493bf6008Sagc 
11593bf6008Sagc /**
11693bf6008Sagc  * \ingroup Core_Create
11793bf6008Sagc  *
11857324b9fSagc  * __ops_fast_create_userid() sets id->userid to the given userid.
11957324b9fSagc  * This is fast because it is only copying a char*. However, if userid
12093bf6008Sagc  * is changed or freed in the future, this could have injurious results.
12193bf6008Sagc  * \param id
12257324b9fSagc  * \param userid
12393bf6008Sagc  */
12493bf6008Sagc 
12593bf6008Sagc void
12657324b9fSagc __ops_fast_create_userid(__ops_userid_t *id, unsigned char *userid)
12793bf6008Sagc {
12857324b9fSagc 	id->userid = userid;
12993bf6008Sagc }
13093bf6008Sagc 
13193bf6008Sagc /**
13293bf6008Sagc  * \ingroup Core_WritePackets
13393bf6008Sagc  * \brief Writes a User Id packet
13493bf6008Sagc  * \param id
13557324b9fSagc  * \param output
1364b3a3e18Sagc  * \return 1 if OK, otherwise 0
13793bf6008Sagc  */
1384b3a3e18Sagc unsigned
13957324b9fSagc __ops_write_struct_userid(__ops_output_t *output, __ops_userid_t *id)
14093bf6008Sagc {
14157324b9fSagc 	return __ops_write_ptag(output, OPS_PTAG_CT_USER_ID) &&
14257324b9fSagc 		__ops_write_length(output, strlen((char *) id->userid)) &&
14357324b9fSagc 		__ops_write(output, id->userid, strlen((char *) id->userid));
14493bf6008Sagc }
14593bf6008Sagc 
14693bf6008Sagc /**
14793bf6008Sagc  * \ingroup Core_WritePackets
14893bf6008Sagc  * \brief Write a User Id packet.
14957324b9fSagc  * \param userid
15057324b9fSagc  * \param output
15193bf6008Sagc  *
15257324b9fSagc  * \return return value from __ops_write_struct_userid()
15393bf6008Sagc  */
1544b3a3e18Sagc unsigned
15557324b9fSagc __ops_write_userid(const unsigned char *userid, __ops_output_t *output)
15693bf6008Sagc {
15757324b9fSagc 	__ops_userid_t   id;
15893bf6008Sagc 
15957324b9fSagc 	id.userid = __UNCONST(userid);
16057324b9fSagc 	return __ops_write_struct_userid(output, &id);
16193bf6008Sagc }
16293bf6008Sagc 
16393bf6008Sagc /**
16493bf6008Sagc \ingroup Core_MPI
16593bf6008Sagc */
16693bf6008Sagc static unsigned
16793bf6008Sagc mpi_length(const BIGNUM *bn)
16893bf6008Sagc {
16993bf6008Sagc 	return 2 + (BN_num_bits(bn) + 7) / 8;
17093bf6008Sagc }
17193bf6008Sagc 
17293bf6008Sagc static unsigned
1733326c4c5Sagc pubkey_length(const __ops_pubkey_t *key)
17493bf6008Sagc {
1752232f800Sagc 	switch (key->alg) {
17693bf6008Sagc 	case OPS_PKA_RSA:
17793bf6008Sagc 		return mpi_length(key->key.rsa.n) + mpi_length(key->key.rsa.e);
17893bf6008Sagc 
17993bf6008Sagc 	default:
180ed0df671Sagc 		(void) fprintf(stderr,
1813326c4c5Sagc 			"pubkey_length: unknown key algorithm\n");
18293bf6008Sagc 	}
18393bf6008Sagc 	return 0;
18493bf6008Sagc }
18593bf6008Sagc 
18693bf6008Sagc static unsigned
1873326c4c5Sagc seckey_length(const __ops_seckey_t *key)
18893bf6008Sagc {
189ed0df671Sagc 	int             len;
19093bf6008Sagc 
191ed0df671Sagc 	len = 0;
1922232f800Sagc 	switch (key->pubkey.alg) {
19393bf6008Sagc 	case OPS_PKA_RSA:
194ed0df671Sagc 		len = mpi_length(key->key.rsa.d) + mpi_length(key->key.rsa.p) +
195bcfd8565Sagc 			mpi_length(key->key.rsa.q) + mpi_length(key->key.rsa.u);
19693bf6008Sagc 
1973326c4c5Sagc 		return len + pubkey_length(&key->pubkey);
19893bf6008Sagc 	default:
199ed0df671Sagc 		(void) fprintf(stderr,
20057324b9fSagc 			"seckey_length: unknown key algorithm\n");
20193bf6008Sagc 	}
202ed0df671Sagc 	return 0;
20393bf6008Sagc }
20493bf6008Sagc 
20593bf6008Sagc /**
20693bf6008Sagc  * \ingroup Core_Create
20793bf6008Sagc  * \param key
20893bf6008Sagc  * \param t
20993bf6008Sagc  * \param n
21093bf6008Sagc  * \param e
21193bf6008Sagc */
21293bf6008Sagc void
2133326c4c5Sagc __ops_fast_create_rsa_pubkey(__ops_pubkey_t *key, time_t t,
21493bf6008Sagc 			       BIGNUM *n, BIGNUM *e)
21593bf6008Sagc {
21693bf6008Sagc 	key->version = 4;
2173326c4c5Sagc 	key->birthtime = t;
2182232f800Sagc 	key->alg = OPS_PKA_RSA;
21993bf6008Sagc 	key->key.rsa.n = n;
22093bf6008Sagc 	key->key.rsa.e = e;
22193bf6008Sagc }
22293bf6008Sagc 
22393bf6008Sagc /*
22493bf6008Sagc  * Note that we support v3 keys here because they're needed for for
22593bf6008Sagc  * verification - the writer doesn't allow them, though
22693bf6008Sagc  */
2274b3a3e18Sagc static unsigned
228c64158a1Sagc write_pubkey_body(const __ops_pubkey_t *key, __ops_output_t *output)
22993bf6008Sagc {
23057324b9fSagc 	if (!(__ops_write_scalar(output, (unsigned)key->version, 1) &&
23157324b9fSagc 	      __ops_write_scalar(output, (unsigned)key->birthtime, 4))) {
2324b3a3e18Sagc 		return 0;
233bcfd8565Sagc 	}
23493bf6008Sagc 
235bcfd8565Sagc 	if (key->version != 4 &&
23657324b9fSagc 	    !__ops_write_scalar(output, key->days_valid, 2)) {
2374b3a3e18Sagc 		return 0;
238bcfd8565Sagc 	}
23993bf6008Sagc 
24057324b9fSagc 	if (!__ops_write_scalar(output, (unsigned)key->alg, 1)) {
2414b3a3e18Sagc 		return 0;
242bcfd8565Sagc 	}
24393bf6008Sagc 
2442232f800Sagc 	switch (key->alg) {
24593bf6008Sagc 	case OPS_PKA_DSA:
24657324b9fSagc 		return __ops_write_mpi(output, key->key.dsa.p) &&
24757324b9fSagc 			__ops_write_mpi(output, key->key.dsa.q) &&
24857324b9fSagc 			__ops_write_mpi(output, key->key.dsa.g) &&
24957324b9fSagc 			__ops_write_mpi(output, key->key.dsa.y);
25093bf6008Sagc 
25193bf6008Sagc 	case OPS_PKA_RSA:
25293bf6008Sagc 	case OPS_PKA_RSA_ENCRYPT_ONLY:
25393bf6008Sagc 	case OPS_PKA_RSA_SIGN_ONLY:
25457324b9fSagc 		return __ops_write_mpi(output, key->key.rsa.n) &&
25557324b9fSagc 			__ops_write_mpi(output, key->key.rsa.e);
25693bf6008Sagc 
25793bf6008Sagc 	case OPS_PKA_ELGAMAL:
25857324b9fSagc 		return __ops_write_mpi(output, key->key.elgamal.p) &&
25957324b9fSagc 			__ops_write_mpi(output, key->key.elgamal.g) &&
26057324b9fSagc 			__ops_write_mpi(output, key->key.elgamal.y);
26193bf6008Sagc 
26293bf6008Sagc 	default:
263ed0df671Sagc 		(void) fprintf(stderr,
2643326c4c5Sagc 			"write_pubkey_body: bad algorithm\n");
26593bf6008Sagc 		break;
26693bf6008Sagc 	}
2674b3a3e18Sagc 	return 0;
26893bf6008Sagc }
26993bf6008Sagc 
27093bf6008Sagc /*
27157324b9fSagc  * Note that we support v3 keys here because they're needed for
27293bf6008Sagc  * verification - the writer doesn't allow them, though
27393bf6008Sagc  */
2744b3a3e18Sagc static unsigned
2753326c4c5Sagc write_seckey_body(const __ops_seckey_t *key,
27693bf6008Sagc 		      const unsigned char *passphrase,
27793bf6008Sagc 		      const size_t pplen,
27857324b9fSagc 		      __ops_output_t *output)
27993bf6008Sagc {
28093bf6008Sagc 	/* RFC4880 Section 5.5.3 Secret-Key Packet Formats */
28193bf6008Sagc 
28293bf6008Sagc 	__ops_crypt_t     crypted;
28393bf6008Sagc 	__ops_hash_t      hash;
28493bf6008Sagc 	unsigned char   hashed[OPS_SHA1_HASH_SIZE];
2852232f800Sagc 	unsigned char   sesskey[CAST_KEY_LENGTH];
28693bf6008Sagc 	unsigned int    done = 0;
28793bf6008Sagc 	unsigned int    i = 0;
28893bf6008Sagc 
28957324b9fSagc 	if (!write_pubkey_body(&key->pubkey, output)) {
2904b3a3e18Sagc 		return 0;
291bcfd8565Sagc 	}
292ed0df671Sagc 	if (key->s2k_usage != OPS_S2KU_ENCRYPTED_AND_HASHED) {
2933326c4c5Sagc 		(void) fprintf(stderr, "write_seckey_body: s2k usage\n");
2944b3a3e18Sagc 		return 0;
295ed0df671Sagc 	}
29657324b9fSagc 	if (!__ops_write_scalar(output, (unsigned)key->s2k_usage, 1)) {
2974b3a3e18Sagc 		return 0;
298bcfd8565Sagc 	}
29993bf6008Sagc 
3002232f800Sagc 	if (key->alg != OPS_SA_CAST5) {
3013326c4c5Sagc 		(void) fprintf(stderr, "write_seckey_body: algorithm\n");
3024b3a3e18Sagc 		return 0;
303ed0df671Sagc 	}
30457324b9fSagc 	if (!__ops_write_scalar(output, (unsigned)key->alg, 1)) {
3054b3a3e18Sagc 		return 0;
306bcfd8565Sagc 	}
30793bf6008Sagc 
308ed0df671Sagc 	if (key->s2k_specifier != OPS_S2KS_SIMPLE &&
309ed0df671Sagc 	    key->s2k_specifier != OPS_S2KS_SALTED) {
310bcfd8565Sagc 		/* = 1 \todo could also be iterated-and-salted */
3113326c4c5Sagc 		(void) fprintf(stderr, "write_seckey_body: s2k spec\n");
3124b3a3e18Sagc 		return 0;
313ed0df671Sagc 	}
31457324b9fSagc 	if (!__ops_write_scalar(output, (unsigned)key->s2k_specifier, 1)) {
3154b3a3e18Sagc 		return 0;
316bcfd8565Sagc 	}
31793bf6008Sagc 
3182232f800Sagc 	if (key->hash_alg != OPS_HASH_SHA1) {
3193326c4c5Sagc 		(void) fprintf(stderr, "write_seckey_body: hash alg\n");
3204b3a3e18Sagc 		return 0;
321ed0df671Sagc 	}
32257324b9fSagc 	if (!__ops_write_scalar(output, (unsigned)key->hash_alg, 1)) {
3234b3a3e18Sagc 		return 0;
324bcfd8565Sagc 	}
32593bf6008Sagc 
32693bf6008Sagc 	switch (key->s2k_specifier) {
32793bf6008Sagc 	case OPS_S2KS_SIMPLE:
32893bf6008Sagc 		/* nothing more to do */
32993bf6008Sagc 		break;
33093bf6008Sagc 
33193bf6008Sagc 	case OPS_S2KS_SALTED:
33293bf6008Sagc 		/* 8-octet salt value */
33393bf6008Sagc 		__ops_random(__UNCONST(&key->salt[0]), OPS_SALT_SIZE);
33457324b9fSagc 		if (!__ops_write(output, key->salt, OPS_SALT_SIZE)) {
3354b3a3e18Sagc 			return 0;
336bcfd8565Sagc 		}
33793bf6008Sagc 		break;
33893bf6008Sagc 
33993bf6008Sagc 		/*
34093bf6008Sagc 		 * \todo case OPS_S2KS_ITERATED_AND_SALTED: // 8-octet salt
34193bf6008Sagc 		 * value // 1-octet count break;
34293bf6008Sagc 		 */
34393bf6008Sagc 
34493bf6008Sagc 	default:
345bcfd8565Sagc 		(void) fprintf(stderr,
346bcfd8565Sagc 			"invalid/unsupported s2k specifier %d\n",
347bcfd8565Sagc 			key->s2k_specifier);
3484b3a3e18Sagc 		return 0;
34993bf6008Sagc 	}
35093bf6008Sagc 
35157324b9fSagc 	if (!__ops_write(output, &key->iv[0], __ops_block_size(key->alg))) {
3524b3a3e18Sagc 		return 0;
353bcfd8565Sagc 	}
35493bf6008Sagc 
35593bf6008Sagc 	/*
35693bf6008Sagc 	 * create the session key for encrypting the algorithm-specific
35793bf6008Sagc 	 * fields
35893bf6008Sagc 	 */
35993bf6008Sagc 
36093bf6008Sagc 	switch (key->s2k_specifier) {
36193bf6008Sagc 	case OPS_S2KS_SIMPLE:
36293bf6008Sagc 	case OPS_S2KS_SALTED:
36393bf6008Sagc 		/* RFC4880: section 3.7.1.1 and 3.7.1.2 */
36493bf6008Sagc 
36593bf6008Sagc 		done = 0;
36693bf6008Sagc 		for (i = 0; done < CAST_KEY_LENGTH; i++) {
36793bf6008Sagc 			unsigned int    j = 0;
36893bf6008Sagc 			unsigned char   zero = 0;
3692232f800Sagc 			int             needed;
370d21b929eSagc 			int             size;
37193bf6008Sagc 
3722232f800Sagc 			needed = CAST_KEY_LENGTH - done;
373d21b929eSagc 			size = MIN(needed, OPS_SHA1_HASH_SIZE);
3742232f800Sagc 
3752232f800Sagc 			__ops_hash_any(&hash, key->hash_alg);
37693bf6008Sagc 			hash.init(&hash);
37793bf6008Sagc 
37893bf6008Sagc 			/* preload if iterating  */
37993bf6008Sagc 			for (j = 0; j < i; j++) {
38093bf6008Sagc 				/*
38193bf6008Sagc 				 * Coverity shows a DEADCODE error on this
38293bf6008Sagc 				 * line. This is expected since the hardcoded
38393bf6008Sagc 				 * use of SHA1 and CAST5 means that it will
38493bf6008Sagc 				 * not used. This will change however when
38593bf6008Sagc 				 * other algorithms are supported.
38693bf6008Sagc 				 */
38793bf6008Sagc 				hash.add(&hash, &zero, 1);
38893bf6008Sagc 			}
38993bf6008Sagc 
39093bf6008Sagc 			if (key->s2k_specifier == OPS_S2KS_SALTED) {
39193bf6008Sagc 				hash.add(&hash, key->salt, OPS_SALT_SIZE);
39293bf6008Sagc 			}
39393bf6008Sagc 			hash.add(&hash, passphrase, pplen);
39493bf6008Sagc 			hash.finish(&hash, hashed);
39593bf6008Sagc 
39693bf6008Sagc 			/*
39793bf6008Sagc 			 * if more in hash than is needed by session key, use
39893bf6008Sagc 			 * the leftmost octets
39993bf6008Sagc 			 */
4002232f800Sagc 			(void) memcpy(sesskey + (i * OPS_SHA1_HASH_SIZE),
401d21b929eSagc 					hashed, (unsigned)size);
402d21b929eSagc 			done += size;
403ed0df671Sagc 			if (done > CAST_KEY_LENGTH) {
404ed0df671Sagc 				(void) fprintf(stderr,
4053326c4c5Sagc 					"write_seckey_body: short add\n");
4064b3a3e18Sagc 				return 0;
407ed0df671Sagc 			}
40893bf6008Sagc 		}
40993bf6008Sagc 
41093bf6008Sagc 		break;
41193bf6008Sagc 
41293bf6008Sagc 		/*
41393bf6008Sagc 		 * \todo case OPS_S2KS_ITERATED_AND_SALTED: * 8-octet salt
41493bf6008Sagc 		 * value * 1-octet count break;
41593bf6008Sagc 		 */
41693bf6008Sagc 
41793bf6008Sagc 	default:
418bcfd8565Sagc 		(void) fprintf(stderr,
419bcfd8565Sagc 			"invalid/unsupported s2k specifier %d\n",
420bcfd8565Sagc 			key->s2k_specifier);
4214b3a3e18Sagc 		return 0;
42293bf6008Sagc 	}
42393bf6008Sagc 
42493bf6008Sagc 	/* use this session key to encrypt */
42593bf6008Sagc 
4262232f800Sagc 	__ops_crypt_any(&crypted, key->alg);
42793bf6008Sagc 	crypted.set_iv(&crypted, key->iv);
4282232f800Sagc 	crypted.set_key(&crypted, sesskey);
42993bf6008Sagc 	__ops_encrypt_init(&crypted);
43093bf6008Sagc 
43193bf6008Sagc 	if (__ops_get_debug_level(__FILE__)) {
43293bf6008Sagc 		unsigned int    i2 = 0;
43385073018Sagc 
434bcfd8565Sagc 		(void) fprintf(stderr, "\nWRITING:\niv=");
4352232f800Sagc 		for (i2 = 0; i2 < __ops_block_size(key->alg); i2++) {
436bcfd8565Sagc 			(void) fprintf(stderr, "%02x ", key->iv[i2]);
43793bf6008Sagc 		}
438bcfd8565Sagc 		(void) fprintf(stderr, "\n");
43993bf6008Sagc 
440bcfd8565Sagc 		(void) fprintf(stderr, "key=");
44193bf6008Sagc 		for (i2 = 0; i2 < CAST_KEY_LENGTH; i2++) {
4422232f800Sagc 			(void) fprintf(stderr, "%02x ", sesskey[i2]);
44393bf6008Sagc 		}
444bcfd8565Sagc 		(void) fprintf(stderr, "\n");
44593bf6008Sagc 
446bcfd8565Sagc 		(void) fprintf(stderr, "turning encryption on...\n");
44793bf6008Sagc 	}
4480df5e957Sagc 	__ops_push_enc_crypt(output, &crypted);
44993bf6008Sagc 
4502232f800Sagc 	switch (key->pubkey.alg) {
45193bf6008Sagc 		/* case OPS_PKA_DSA: */
45257324b9fSagc 		/* return __ops_write_mpi(output, key->key.dsa.x); */
45393bf6008Sagc 
45493bf6008Sagc 	case OPS_PKA_RSA:
45593bf6008Sagc 	case OPS_PKA_RSA_ENCRYPT_ONLY:
45693bf6008Sagc 	case OPS_PKA_RSA_SIGN_ONLY:
45793bf6008Sagc 
45857324b9fSagc 		if (!__ops_write_mpi(output, key->key.rsa.d) ||
45957324b9fSagc 		    !__ops_write_mpi(output, key->key.rsa.p) ||
46057324b9fSagc 		    !__ops_write_mpi(output, key->key.rsa.q) ||
46157324b9fSagc 		    !__ops_write_mpi(output, key->key.rsa.u)) {
46293bf6008Sagc 			if (__ops_get_debug_level(__FILE__)) {
4633326c4c5Sagc 				(void) fprintf(stderr,
4643326c4c5Sagc 					"4 x mpi not written - problem\n");
46593bf6008Sagc 			}
4664b3a3e18Sagc 			return 0;
46793bf6008Sagc 		}
46893bf6008Sagc 		break;
46993bf6008Sagc 
47093bf6008Sagc 		/* case OPS_PKA_ELGAMAL: */
47157324b9fSagc 		/* return __ops_write_mpi(output, key->key.elgamal.x); */
47293bf6008Sagc 
47393bf6008Sagc 	default:
4744b3a3e18Sagc 		return 0;
47593bf6008Sagc 	}
47693bf6008Sagc 
47757324b9fSagc 	if (!__ops_write(output, key->checkhash, OPS_CHECKHASH_SIZE)) {
4784b3a3e18Sagc 		return 0;
479bcfd8565Sagc 	}
48093bf6008Sagc 
48157324b9fSagc 	__ops_writer_pop(output);
48293bf6008Sagc 
4834b3a3e18Sagc 	return 1;
48493bf6008Sagc }
48593bf6008Sagc 
48657324b9fSagc /**
48757324b9fSagc  * \ingroup Core_WritePackets
48857324b9fSagc  * \brief Writes a Public Key packet
48957324b9fSagc  * \param key
49057324b9fSagc  * \param output
49157324b9fSagc  * \return 1 if OK, otherwise 0
49257324b9fSagc  */
49357324b9fSagc static unsigned
49457324b9fSagc write_struct_pubkey(__ops_output_t *output, const __ops_pubkey_t *key)
49557324b9fSagc {
49657324b9fSagc 	if (key->version != 4) {
49757324b9fSagc 		(void) fprintf(stderr,
49857324b9fSagc 			"write_struct_pubkey: wrong key version\n");
49957324b9fSagc 		return 0;
50057324b9fSagc 	}
50157324b9fSagc 	return __ops_write_ptag(output, OPS_PTAG_CT_PUBLIC_KEY) &&
50257324b9fSagc 		__ops_write_length(output, 1 + 4 + 1 + pubkey_length(key)) &&
50357324b9fSagc 		write_pubkey_body(key, output);
50457324b9fSagc }
50557324b9fSagc 
50693bf6008Sagc 
50793bf6008Sagc /**
50893bf6008Sagc    \ingroup HighLevel_KeyWrite
50993bf6008Sagc 
51093bf6008Sagc    \brief Writes a transferable PGP public key to the given output stream.
51193bf6008Sagc 
51293bf6008Sagc    \param keydata Key to be written
51393bf6008Sagc    \param armoured Flag is set for armoured output
51457324b9fSagc    \param output Output stream
51593bf6008Sagc 
51693bf6008Sagc */
51793bf6008Sagc 
5184b3a3e18Sagc unsigned
5190df5e957Sagc __ops_write_xfer_pubkey(__ops_output_t *output,
520*41335e2dSagc 			const __ops_key_t *keydata,
521c64158a1Sagc 			const unsigned armoured)
52293bf6008Sagc {
52393bf6008Sagc 	unsigned int    i = 0, j = 0;
52493bf6008Sagc 
52593bf6008Sagc 	if (armoured) {
52657324b9fSagc 		__ops_writer_push_armoured(output, OPS_PGP_PUBLIC_KEY_BLOCK);
52793bf6008Sagc 	}
52893bf6008Sagc 	/* public key */
52957324b9fSagc 	if (!write_struct_pubkey(output, &keydata->key.seckey.pubkey)) {
53057324b9fSagc 		return 0;
531bcfd8565Sagc 	}
53293bf6008Sagc 
53393bf6008Sagc 	/* TODO: revocation signatures go here */
53493bf6008Sagc 
53593bf6008Sagc 	/* user ids and corresponding signatures */
536*41335e2dSagc 	for (i = 0; i < keydata->uidc; i++) {
53757324b9fSagc 		__ops_userid_t  *uid = &keydata->uids[i];
53893bf6008Sagc 
53957324b9fSagc 		if (!__ops_write_struct_userid(output, uid)) {
54057324b9fSagc 			return 0;
541bcfd8565Sagc 		}
54293bf6008Sagc 
54393bf6008Sagc 		/* find signature for this packet if it exists */
544*41335e2dSagc 		for (j = 0; j < keydata->sigc; j++) {
54593bf6008Sagc 			sigpacket_t    *sig = &keydata->sigs[i];
546bcfd8565Sagc 
54757324b9fSagc 			if (strcmp((char *) sig->userid->userid,
54857324b9fSagc 					(char *) uid->userid) == 0) {
54957324b9fSagc 				if (!__ops_write(output, sig->packet->raw,
55057324b9fSagc 						sig->packet->length)) {
55157324b9fSagc 					return 0;
55293bf6008Sagc 				}
55393bf6008Sagc 			}
55493bf6008Sagc 		}
555bcfd8565Sagc 	}
55693bf6008Sagc 
55793bf6008Sagc 	/* TODO: user attributes and corresponding signatures */
55893bf6008Sagc 
55993bf6008Sagc 	/*
56093bf6008Sagc 	 * subkey packets and corresponding signatures and optional
56193bf6008Sagc 	 * revocation
56293bf6008Sagc 	 */
56393bf6008Sagc 
56493bf6008Sagc 	if (armoured) {
56557324b9fSagc 		writer_info_finalise(&output->errors, &output->writer);
56657324b9fSagc 		__ops_writer_pop(output);
56793bf6008Sagc 	}
56857324b9fSagc 	return 1;
56993bf6008Sagc }
57093bf6008Sagc 
57193bf6008Sagc /**
57293bf6008Sagc    \ingroup HighLevel_KeyWrite
57393bf6008Sagc 
57493bf6008Sagc    \brief Writes a transferable PGP secret key to the given output stream.
57593bf6008Sagc 
57693bf6008Sagc    \param keydata Key to be written
57793bf6008Sagc    \param passphrase
57893bf6008Sagc    \param pplen
57993bf6008Sagc    \param armoured Flag is set for armoured output
58057324b9fSagc    \param output Output stream
58193bf6008Sagc 
58293bf6008Sagc */
58393bf6008Sagc 
5844b3a3e18Sagc unsigned
5850df5e957Sagc __ops_write_xfer_seckey(__ops_output_t *output,
586*41335e2dSagc 				const __ops_key_t *keydata,
58757324b9fSagc 				const unsigned char *passphrase,
58857324b9fSagc 				const size_t pplen,
58957324b9fSagc 				unsigned armoured)
59093bf6008Sagc {
59185073018Sagc 	unsigned	i = 0, j = 0;
59293bf6008Sagc 
59393bf6008Sagc 	if (armoured) {
59457324b9fSagc 		__ops_writer_push_armoured(output, OPS_PGP_PRIVATE_KEY_BLOCK);
59593bf6008Sagc 	}
59693bf6008Sagc 	/* public key */
59757324b9fSagc 	if (!__ops_write_struct_seckey(&keydata->key.seckey, passphrase,
59857324b9fSagc 			pplen, output)) {
59957324b9fSagc 		return 0;
600bcfd8565Sagc 	}
60193bf6008Sagc 
60293bf6008Sagc 	/* TODO: revocation signatures go here */
60393bf6008Sagc 
60493bf6008Sagc 	/* user ids and corresponding signatures */
605*41335e2dSagc 	for (i = 0; i < keydata->uidc; i++) {
60657324b9fSagc 		__ops_userid_t  *uid = &keydata->uids[i];
60793bf6008Sagc 
60857324b9fSagc 		if (!__ops_write_struct_userid(output, uid)) {
60957324b9fSagc 			return 0;
610bcfd8565Sagc 		}
61193bf6008Sagc 
61293bf6008Sagc 		/* find signature for this packet if it exists */
613*41335e2dSagc 		for (j = 0; j < keydata->sigc; j++) {
61493bf6008Sagc 			sigpacket_t    *sig = &keydata->sigs[i];
615bcfd8565Sagc 
61657324b9fSagc 			if (strcmp((char *) sig->userid->userid,
61757324b9fSagc 					(char *) uid->userid) == 0) {
61857324b9fSagc 				if (!__ops_write(output, sig->packet->raw,
61957324b9fSagc 						sig->packet->length)) {
62057324b9fSagc 					return 0;
62193bf6008Sagc 				}
62293bf6008Sagc 			}
62393bf6008Sagc 		}
624bcfd8565Sagc 	}
62593bf6008Sagc 
62693bf6008Sagc 	/* TODO: user attributes and corresponding signatures */
62793bf6008Sagc 
62893bf6008Sagc 	/*
62993bf6008Sagc 	 * subkey packets and corresponding signatures and optional
63093bf6008Sagc 	 * revocation
63193bf6008Sagc 	 */
63293bf6008Sagc 
63393bf6008Sagc 	if (armoured) {
63457324b9fSagc 		writer_info_finalise(&output->errors, &output->writer);
63557324b9fSagc 		__ops_writer_pop(output);
63693bf6008Sagc 	}
63757324b9fSagc 	return 1;
63893bf6008Sagc }
63993bf6008Sagc 
64093bf6008Sagc /**
64193bf6008Sagc  * \ingroup Core_WritePackets
64293bf6008Sagc  * \brief Writes one RSA public key packet.
64393bf6008Sagc  * \param t Creation time
64493bf6008Sagc  * \param n RSA public modulus
64593bf6008Sagc  * \param e RSA public encryption exponent
64657324b9fSagc  * \param output Writer settings
64793bf6008Sagc  *
6484b3a3e18Sagc  * \return 1 if OK, otherwise 0
64993bf6008Sagc  */
65093bf6008Sagc 
6514b3a3e18Sagc unsigned
6523326c4c5Sagc __ops_write_rsa_pubkey(time_t t, const BIGNUM *n,
65393bf6008Sagc 			 const BIGNUM *e,
65457324b9fSagc 			 __ops_output_t *output)
65593bf6008Sagc {
6563326c4c5Sagc 	__ops_pubkey_t key;
65793bf6008Sagc 
6583326c4c5Sagc 	__ops_fast_create_rsa_pubkey(&key, t, __UNCONST(n), __UNCONST(e));
65957324b9fSagc 	return write_struct_pubkey(output, &key);
66093bf6008Sagc }
66193bf6008Sagc 
66293bf6008Sagc /**
66393bf6008Sagc  * \ingroup Core_Create
66493bf6008Sagc  * \param out
66593bf6008Sagc  * \param key
66693bf6008Sagc  * \param make_packet
66793bf6008Sagc  */
66893bf6008Sagc 
66993bf6008Sagc void
6703326c4c5Sagc __ops_build_pubkey(__ops_memory_t *out, const __ops_pubkey_t *key,
6714b3a3e18Sagc 		     unsigned make_packet)
67293bf6008Sagc {
67357324b9fSagc 	__ops_output_t *output;
67493bf6008Sagc 
67557324b9fSagc 	output = __ops_output_new();
67693bf6008Sagc 	__ops_memory_init(out, 128);
67757324b9fSagc 	__ops_writer_set_memory(output, out);
67857324b9fSagc 	write_pubkey_body(key, output);
679bcfd8565Sagc 	if (make_packet) {
68093bf6008Sagc 		__ops_memory_make_packet(out, OPS_PTAG_CT_PUBLIC_KEY);
681bcfd8565Sagc 	}
68257324b9fSagc 	__ops_output_delete(output);
68393bf6008Sagc }
68493bf6008Sagc 
68593bf6008Sagc /**
68693bf6008Sagc  * \ingroup Core_Create
68793bf6008Sagc  *
68893bf6008Sagc  * Create an RSA secret key structure. If a parameter is marked as
68993bf6008Sagc  * [OPTIONAL], then it can be omitted and will be calculated from
690*41335e2dSagc  * other params - or, in the case of e, will default to 0x10001.
69193bf6008Sagc  *
69293bf6008Sagc  * Parameters are _not_ copied, so will be freed if the structure is
69393bf6008Sagc  * freed.
69493bf6008Sagc  *
69593bf6008Sagc  * \param key The key structure to be initialised.
69693bf6008Sagc  * \param t
69793bf6008Sagc  * \param d The RSA parameter d (=e^-1 mod (p-1)(q-1)) [OPTIONAL]
69893bf6008Sagc  * \param p The RSA parameter p
69993bf6008Sagc  * \param q The RSA parameter q (q > p)
70093bf6008Sagc  * \param u The RSA parameter u (=p^-1 mod q) [OPTIONAL]
70193bf6008Sagc  * \param n The RSA public parameter n (=p*q) [OPTIONAL]
70293bf6008Sagc  * \param e The RSA public parameter e */
70393bf6008Sagc 
70493bf6008Sagc void
7053326c4c5Sagc __ops_fast_create_rsa_seckey(__ops_seckey_t *key, time_t t,
70693bf6008Sagc 			     BIGNUM *d, BIGNUM *p, BIGNUM *q, BIGNUM *u,
70793bf6008Sagc 			       BIGNUM *n, BIGNUM *e)
70893bf6008Sagc {
7093326c4c5Sagc 	__ops_fast_create_rsa_pubkey(&key->pubkey, t, n, e);
71093bf6008Sagc 
71193bf6008Sagc 	/* XXX: calculate optionals */
71293bf6008Sagc 	key->key.rsa.d = d;
71393bf6008Sagc 	key->key.rsa.p = p;
71493bf6008Sagc 	key->key.rsa.q = q;
71593bf6008Sagc 	key->key.rsa.u = u;
71693bf6008Sagc 
71793bf6008Sagc 	key->s2k_usage = OPS_S2KU_NONE;
71893bf6008Sagc 
71993bf6008Sagc 	/* XXX: sanity check and add errors... */
72093bf6008Sagc }
72193bf6008Sagc 
72293bf6008Sagc /**
72393bf6008Sagc  * \ingroup Core_WritePackets
72493bf6008Sagc  * \brief Writes a Secret Key packet.
72593bf6008Sagc  * \param key The secret key
72693bf6008Sagc  * \param passphrase The passphrase
72793bf6008Sagc  * \param pplen Length of passphrase
72857324b9fSagc  * \param output
7294b3a3e18Sagc  * \return 1 if OK; else 0
73093bf6008Sagc  */
7314b3a3e18Sagc unsigned
7323326c4c5Sagc __ops_write_struct_seckey(const __ops_seckey_t *key,
73393bf6008Sagc 			    const unsigned char *passphrase,
73493bf6008Sagc 			    const size_t pplen,
73557324b9fSagc 			    __ops_output_t *output)
73693bf6008Sagc {
73793bf6008Sagc 	int             length = 0;
73893bf6008Sagc 
739ed0df671Sagc 	if (key->pubkey.version != 4) {
740ed0df671Sagc 		(void) fprintf(stderr,
7413326c4c5Sagc 			"__ops_write_struct_seckey: public key version\n");
7424b3a3e18Sagc 		return 0;
743ed0df671Sagc 	}
74493bf6008Sagc 
74593bf6008Sagc 	/* Ref: RFC4880 Section 5.5.3 */
74693bf6008Sagc 
747bcfd8565Sagc 	/* pubkey, excluding MPIs */
74893bf6008Sagc 	length += 1 + 4 + 1 + 1;
74993bf6008Sagc 
75093bf6008Sagc 	/* s2k usage */
75193bf6008Sagc 	length += 1;
75293bf6008Sagc 
75393bf6008Sagc 	switch (key->s2k_usage) {
75493bf6008Sagc 	case OPS_S2KU_NONE:
75593bf6008Sagc 		/* nothing to add */
75693bf6008Sagc 		break;
75793bf6008Sagc 
75893bf6008Sagc 	case OPS_S2KU_ENCRYPTED_AND_HASHED:	/* 254 */
75993bf6008Sagc 	case OPS_S2KU_ENCRYPTED:	/* 255 */
76093bf6008Sagc 
76193bf6008Sagc 		/* Ref: RFC4880 Section 3.7 */
76293bf6008Sagc 		length += 1;	/* s2k_specifier */
76393bf6008Sagc 
76493bf6008Sagc 		switch (key->s2k_specifier) {
76593bf6008Sagc 		case OPS_S2KS_SIMPLE:
76693bf6008Sagc 			length += 1;	/* hash algorithm */
76793bf6008Sagc 			break;
76893bf6008Sagc 
76993bf6008Sagc 		case OPS_S2KS_SALTED:
77093bf6008Sagc 			length += 1 + 8;	/* hash algorithm + salt */
77193bf6008Sagc 			break;
77293bf6008Sagc 
77393bf6008Sagc 		case OPS_S2KS_ITERATED_AND_SALTED:
77493bf6008Sagc 			length += 1 + 8 + 1;	/* hash algorithm, salt +
77593bf6008Sagc 						 * count */
77693bf6008Sagc 			break;
77793bf6008Sagc 
77893bf6008Sagc 		default:
779ed0df671Sagc 			(void) fprintf(stderr,
7803326c4c5Sagc 				"__ops_write_struct_seckey: s2k spec\n");
7814b3a3e18Sagc 			return 0;
78293bf6008Sagc 		}
78393bf6008Sagc 		break;
78493bf6008Sagc 
78593bf6008Sagc 	default:
786ed0df671Sagc 		(void) fprintf(stderr,
7873326c4c5Sagc 			"__ops_write_struct_seckey: s2k usage\n");
7884b3a3e18Sagc 		return 0;
78993bf6008Sagc 	}
79093bf6008Sagc 
79193bf6008Sagc 	/* IV */
7924b3a3e18Sagc 	if (key->s2k_usage) {
7932232f800Sagc 		length += __ops_block_size(key->alg);
79493bf6008Sagc 	}
79593bf6008Sagc 	/* checksum or hash */
79693bf6008Sagc 	switch (key->s2k_usage) {
79793bf6008Sagc 	case 0:
79893bf6008Sagc 	case 255:
79993bf6008Sagc 		length += 2;
80093bf6008Sagc 		break;
80193bf6008Sagc 
80293bf6008Sagc 	case 254:
8036715e11aSagc 		length += OPS_CHECKHASH_SIZE;
80493bf6008Sagc 		break;
80593bf6008Sagc 
80693bf6008Sagc 	default:
807ed0df671Sagc 		(void) fprintf(stderr,
8083326c4c5Sagc 			"__ops_write_struct_seckey: s2k cksum usage\n");
8094b3a3e18Sagc 		return 0;
81093bf6008Sagc 	}
81193bf6008Sagc 
81293bf6008Sagc 	/* secret key and public key MPIs */
8133326c4c5Sagc 	length += seckey_length(key);
81493bf6008Sagc 
81557324b9fSagc 	return __ops_write_ptag(output, OPS_PTAG_CT_SECRET_KEY) &&
81657324b9fSagc 		/* __ops_write_length(output,1+4+1+1+seckey_length(key)+2) && */
81757324b9fSagc 		__ops_write_length(output, (unsigned)length) &&
81857324b9fSagc 		write_seckey_body(key, passphrase, pplen, output);
81993bf6008Sagc }
82093bf6008Sagc 
82193bf6008Sagc /**
82293bf6008Sagc  * \ingroup Core_Create
82393bf6008Sagc  *
82457324b9fSagc  * \brief Create a new __ops_output_t structure.
82593bf6008Sagc  *
82693bf6008Sagc  * \return the new structure.
82757324b9fSagc  * \note It is the responsiblity of the caller to call __ops_output_delete().
82857324b9fSagc  * \sa __ops_output_delete()
82993bf6008Sagc  */
83057324b9fSagc __ops_output_t *
83157324b9fSagc __ops_output_new(void)
83293bf6008Sagc {
83357324b9fSagc 	return calloc(1, sizeof(__ops_output_t));
83493bf6008Sagc }
83593bf6008Sagc 
83693bf6008Sagc /**
83793bf6008Sagc  * \ingroup Core_Create
83857324b9fSagc  * \brief Delete an __ops_output_t strucut and associated resources.
83993bf6008Sagc  *
84057324b9fSagc  * Delete an __ops_output_t structure. If a writer is active, then
84193bf6008Sagc  * that is also deleted.
84293bf6008Sagc  *
84393bf6008Sagc  * \param info the structure to be deleted.
84493bf6008Sagc  */
84593bf6008Sagc void
84657324b9fSagc __ops_output_delete(__ops_output_t *output)
84793bf6008Sagc {
84857324b9fSagc 	writer_info_delete(&output->writer);
84957324b9fSagc 	(void) free(output);
85093bf6008Sagc }
85193bf6008Sagc 
85293bf6008Sagc /**
85393bf6008Sagc  \ingroup Core_Create
85493bf6008Sagc  \brief Calculate the checksum for a session key
8552232f800Sagc  \param sesskey Session Key to use
85693bf6008Sagc  \param cs Checksum to be written
8574b3a3e18Sagc  \return 1 if OK; else 0
85893bf6008Sagc */
8594b3a3e18Sagc unsigned
8602232f800Sagc __ops_calc_sesskey_checksum(__ops_pk_sesskey_t *sesskey, unsigned char cs[2])
86193bf6008Sagc {
86293bf6008Sagc 	unsigned int    i = 0;
86393bf6008Sagc 	unsigned long   checksum = 0;
86493bf6008Sagc 
8652232f800Sagc 	if (!__ops_is_sa_supported(sesskey->symm_alg)) {
8664b3a3e18Sagc 		return 0;
867bcfd8565Sagc 	}
86893bf6008Sagc 
8692232f800Sagc 	for (i = 0; i < __ops_key_size(sesskey->symm_alg); i++) {
8702232f800Sagc 		checksum += sesskey->key[i];
87193bf6008Sagc 	}
87293bf6008Sagc 	checksum = checksum % 65536;
87393bf6008Sagc 
874efdd9dbaSagc 	cs[0] = (unsigned char)((checksum >> 8) & 0xff);
875efdd9dbaSagc 	cs[1] = (unsigned char)(checksum & 0xff);
87693bf6008Sagc 
877efdd9dbaSagc 	if (__ops_get_debug_level(__FILE__)) {
878efdd9dbaSagc 		(void) fprintf(stderr,"\nm buf checksum: ");
879efdd9dbaSagc 		(void) fprintf(stderr," %2x",cs[0]);
880efdd9dbaSagc 		(void) fprintf(stderr," %2x\n",cs[1]);
881efdd9dbaSagc 	}
8824b3a3e18Sagc 	return 1;
88393bf6008Sagc }
88493bf6008Sagc 
8854b3a3e18Sagc static unsigned
8862232f800Sagc create_unencoded_m_buf(__ops_pk_sesskey_t *sesskey, unsigned char *m_buf)
88793bf6008Sagc {
88893bf6008Sagc 	int             i = 0;
88993bf6008Sagc 
89093bf6008Sagc 	/* m_buf is the buffer which will be encoded in PKCS#1 block */
89193bf6008Sagc 	/* encoding to form the "m" value used in the  */
89293bf6008Sagc 	/* Public Key Encrypted Session Key Packet */
89393bf6008Sagc 	/*
89493bf6008Sagc 	 * as defined in RFC Section 5.1 "Public-Key Encrypted Session Key
89593bf6008Sagc 	 * Packet"
89693bf6008Sagc 	 */
89793bf6008Sagc 
8982232f800Sagc 	m_buf[0] = sesskey->symm_alg;
89993bf6008Sagc 
9002232f800Sagc 	if (sesskey->symm_alg != OPS_SA_CAST5) {
901ed0df671Sagc 		(void) fprintf(stderr, "create_unencoded_m_buf: symm alg\n");
9024b3a3e18Sagc 		return 0;
903ed0df671Sagc 	}
90493bf6008Sagc 	for (i = 0; i < CAST_KEY_LENGTH; i++) {
9052232f800Sagc 		m_buf[1 + i] = sesskey->key[i];
90693bf6008Sagc 	}
90793bf6008Sagc 
9082232f800Sagc 	return (__ops_calc_sesskey_checksum(sesskey,
909bcfd8565Sagc 				m_buf + 1 + CAST_KEY_LENGTH));
91093bf6008Sagc }
91193bf6008Sagc 
91293bf6008Sagc /**
91393bf6008Sagc \ingroup Core_Create
91493bf6008Sagc \brief implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC
91593bf6008Sagc \param M
91693bf6008Sagc \param mLen
9170c310959Sagc \param pubkey
91893bf6008Sagc \param EM
9194b3a3e18Sagc \return 1 if OK; else 0
92093bf6008Sagc */
9214b3a3e18Sagc unsigned
92293bf6008Sagc encode_m_buf(const unsigned char *M, size_t mLen,
9230c310959Sagc 	     const __ops_pubkey_t * pubkey,
924bcfd8565Sagc 	     unsigned char *EM)
92593bf6008Sagc {
92693bf6008Sagc 	unsigned int    k;
92793bf6008Sagc 	unsigned        i;
92893bf6008Sagc 
92993bf6008Sagc 	/* implementation of EME-PKCS1-v1_5-ENCODE, as defined in OpenPGP RFC */
93093bf6008Sagc 
9312232f800Sagc 	if (pubkey->alg != OPS_PKA_RSA) {
9320c310959Sagc 		(void) fprintf(stderr, "encode_m_buf: pubkey algorithm\n");
9334b3a3e18Sagc 		return 0;
934ed0df671Sagc 	}
93593bf6008Sagc 
9360c310959Sagc 	k = BN_num_bytes(pubkey->key.rsa.n);
93793bf6008Sagc 	if (mLen > k - 11) {
938ed0df671Sagc 		(void) fprintf(stderr, "encode_m_buf: message too long\n");
9394b3a3e18Sagc 		return 0;
94093bf6008Sagc 	}
94193bf6008Sagc 	/* these two bytes defined by RFC */
94293bf6008Sagc 	EM[0] = 0x00;
94393bf6008Sagc 	EM[1] = 0x02;
94493bf6008Sagc 
94593bf6008Sagc 	/* add non-zero random bytes of length k - mLen -3 */
946bcfd8565Sagc 	for (i = 2; i < k - mLen - 1; ++i) {
947bcfd8565Sagc 		do {
94893bf6008Sagc 			__ops_random(EM + i, 1);
949bcfd8565Sagc 		} while (EM[i] == 0);
950bcfd8565Sagc 	}
95193bf6008Sagc 
952ed0df671Sagc 	if (i < 8 + 2) {
953ed0df671Sagc 		(void) fprintf(stderr, "encode_m_buf: bad i len\n");
9544b3a3e18Sagc 		return 0;
955ed0df671Sagc 	}
95693bf6008Sagc 
95793bf6008Sagc 	EM[i++] = 0;
95893bf6008Sagc 
95993bf6008Sagc 	(void) memcpy(EM + i, M, mLen);
96093bf6008Sagc 
96193bf6008Sagc 	if (__ops_get_debug_level(__FILE__)) {
96293bf6008Sagc 		unsigned int    i2 = 0;
963bcfd8565Sagc 
964bcfd8565Sagc 		(void) fprintf(stderr, "Encoded Message: \n");
965bcfd8565Sagc 		for (i2 = 0; i2 < mLen; i2++) {
966bcfd8565Sagc 			(void) fprintf(stderr, "%2x ", EM[i2]);
967bcfd8565Sagc 		}
968bcfd8565Sagc 		(void) fprintf(stderr, "\n");
96993bf6008Sagc 	}
9704b3a3e18Sagc 	return 1;
97193bf6008Sagc }
97293bf6008Sagc 
97393bf6008Sagc /**
97493bf6008Sagc  \ingroup Core_Create
9752232f800Sagc \brief Creates an __ops_pk_sesskey_t struct from keydata
97693bf6008Sagc \param key Keydata to use
9772232f800Sagc \return __ops_pk_sesskey_t struct
97893bf6008Sagc \note It is the caller's responsiblity to free the returned pointer
97993bf6008Sagc \note Currently hard-coded to use CAST5
98093bf6008Sagc \note Currently hard-coded to use RSA
98193bf6008Sagc */
9822232f800Sagc __ops_pk_sesskey_t *
983*41335e2dSagc __ops_create_pk_sesskey(const __ops_key_t *key)
98493bf6008Sagc {
98593bf6008Sagc 	/*
98693bf6008Sagc          * Creates a random session key and encrypts it for the given key
98793bf6008Sagc          *
98893bf6008Sagc          * Session Key is for use with a SK algo,
98993bf6008Sagc          * can be any, we're hardcoding CAST5 for now
99093bf6008Sagc          *
99193bf6008Sagc          * Encryption used is PK,
99293bf6008Sagc          * can be any, we're hardcoding RSA for now
99393bf6008Sagc          */
99493bf6008Sagc 
99557324b9fSagc 	const __ops_pubkey_t *pubkey = __ops_get_pubkey(key);
99693bf6008Sagc #define SZ_UNENCODED_M_BUF CAST_KEY_LENGTH+1+2
99793bf6008Sagc 	unsigned char   unencoded_m_buf[SZ_UNENCODED_M_BUF];
99857324b9fSagc 	const size_t    sz_encoded_m_buf = BN_num_bytes(pubkey->key.rsa.n);
99993bf6008Sagc 	unsigned char  *encoded_m_buf = calloc(1, sz_encoded_m_buf);
100093bf6008Sagc 
10012232f800Sagc 	__ops_pk_sesskey_t *sesskey = calloc(1, sizeof(*sesskey));
1002ed0df671Sagc 	if (key->type != OPS_PTAG_CT_PUBLIC_KEY) {
1003ed0df671Sagc 		(void) fprintf(stderr,
10042232f800Sagc 			"__ops_create_pk_sesskey: bad type\n");
1005ed0df671Sagc 		return NULL;
1006ed0df671Sagc 	}
10072232f800Sagc 	sesskey->version = OPS_PKSK_V3;
10082232f800Sagc 	(void) memcpy(sesskey->key_id, key->key_id,
10092232f800Sagc 			sizeof(sesskey->key_id));
101093bf6008Sagc 
101193bf6008Sagc 	if (__ops_get_debug_level(__FILE__)) {
101293bf6008Sagc 		unsigned int    i = 0;
101393bf6008Sagc 
1014bcfd8565Sagc 		(void) fprintf(stderr, "Encrypting for RSA key id : ");
10152232f800Sagc 		for (i = 0; i < sizeof(sesskey->key_id); i++) {
1016bcfd8565Sagc 			(void) fprintf(stderr, "%2x ", key->key_id[i]);
1017bcfd8565Sagc 		}
1018bcfd8565Sagc 		(void) fprintf(stderr, "\n");
101993bf6008Sagc 	}
10202232f800Sagc 	if (key->key.pubkey.alg != OPS_PKA_RSA) {
1021ed0df671Sagc 		(void) fprintf(stderr,
10222232f800Sagc 			"__ops_create_pk_sesskey: bad pubkey algorithm\n");
1023ed0df671Sagc 		return NULL;
1024ed0df671Sagc 	}
10252232f800Sagc 	sesskey->alg = key->key.pubkey.alg;
102693bf6008Sagc 
102793bf6008Sagc 	/* \todo allow user to specify other algorithm */
10282232f800Sagc 	sesskey->symm_alg = OPS_SA_CAST5;
10292232f800Sagc 	__ops_random(sesskey->key, CAST_KEY_LENGTH);
103093bf6008Sagc 
103193bf6008Sagc 	if (__ops_get_debug_level(__FILE__)) {
103293bf6008Sagc 		unsigned int    i = 0;
1033bcfd8565Sagc 
1034bcfd8565Sagc 		(void) fprintf(stderr,
1035bcfd8565Sagc 			"CAST5 session key created (len=%d):\n ",
1036bcfd8565Sagc 			CAST_KEY_LENGTH);
1037bcfd8565Sagc 		for (i = 0; i < CAST_KEY_LENGTH; i++) {
10382232f800Sagc 			(void) fprintf(stderr, "%2x ", sesskey->key[i]);
1039bcfd8565Sagc 		}
1040bcfd8565Sagc 		(void) fprintf(stderr, "\n");
104193bf6008Sagc 	}
10424b3a3e18Sagc 	if (create_unencoded_m_buf(sesskey, &unencoded_m_buf[0]) == 0) {
1043bcfd8565Sagc 		(void) free(encoded_m_buf);
104493bf6008Sagc 		return NULL;
104593bf6008Sagc 	}
104693bf6008Sagc 	if (__ops_get_debug_level(__FILE__)) {
104793bf6008Sagc 		unsigned int    i = 0;
1048bcfd8565Sagc 
104993bf6008Sagc 		printf("unencoded m buf:\n");
1050bcfd8565Sagc 		for (i = 0; i < SZ_UNENCODED_M_BUF; i++) {
105193bf6008Sagc 			printf("%2x ", unencoded_m_buf[i]);
1052bcfd8565Sagc 		}
105393bf6008Sagc 		printf("\n");
105493bf6008Sagc 	}
105557324b9fSagc 	encode_m_buf(&unencoded_m_buf[0], SZ_UNENCODED_M_BUF, pubkey,
1056bcfd8565Sagc 			&encoded_m_buf[0]);
105793bf6008Sagc 
105893bf6008Sagc 	/* and encrypt it */
105957324b9fSagc 	if (!__ops_rsa_encrypt_mpi(encoded_m_buf, sz_encoded_m_buf, pubkey,
1060*41335e2dSagc 			&sesskey->params)) {
1061bcfd8565Sagc 		(void) free(encoded_m_buf);
106293bf6008Sagc 		return NULL;
106393bf6008Sagc 	}
1064bcfd8565Sagc 	(void) free(encoded_m_buf);
10652232f800Sagc 	return sesskey;
106693bf6008Sagc }
106793bf6008Sagc 
106893bf6008Sagc /**
106993bf6008Sagc \ingroup Core_WritePackets
107093bf6008Sagc \brief Writes Public Key Session Key packet
107193bf6008Sagc \param info Write settings
107293bf6008Sagc \param pksk Public Key Session Key to write out
10734b3a3e18Sagc \return 1 if OK; else 0
107493bf6008Sagc */
10754b3a3e18Sagc unsigned
107657324b9fSagc __ops_write_pk_sesskey(__ops_output_t *output, __ops_pk_sesskey_t *pksk)
107793bf6008Sagc {
1078ed0df671Sagc 	if (pksk == NULL) {
1079ed0df671Sagc 		(void) fprintf(stderr,
10802232f800Sagc 			"__ops_write_pk_sesskey: NULL pksk\n");
10814b3a3e18Sagc 		return 0;
1082ed0df671Sagc 	}
10832232f800Sagc 	if (pksk->alg != OPS_PKA_RSA) {
1084ed0df671Sagc 		(void) fprintf(stderr,
10852232f800Sagc 			"__ops_write_pk_sesskey: bad algorithm\n");
10864b3a3e18Sagc 		return 0;
1087ed0df671Sagc 	}
108893bf6008Sagc 
108957324b9fSagc 	return __ops_write_ptag(output, OPS_PTAG_CT_PK_SESSION_KEY) &&
109057324b9fSagc 		__ops_write_length(output, (unsigned)(1 + 8 + 1 +
1091*41335e2dSagc 			BN_num_bytes(pksk->params.rsa.encrypted_m) + 2)) &&
109257324b9fSagc 		__ops_write_scalar(output, (unsigned)pksk->version, 1) &&
109357324b9fSagc 		__ops_write(output, pksk->key_id, 8) &&
109457324b9fSagc 		__ops_write_scalar(output, (unsigned)pksk->alg, 1) &&
1095*41335e2dSagc 		__ops_write_mpi(output, pksk->params.rsa.encrypted_m)
109657324b9fSagc 	/* ??	&& __ops_write_scalar(output, 0, 2); */
109793bf6008Sagc 		;
109893bf6008Sagc }
109993bf6008Sagc 
110093bf6008Sagc /**
110193bf6008Sagc \ingroup Core_WritePackets
110293bf6008Sagc \brief Writes MDC packet
110393bf6008Sagc \param hashed Hash for MDC
110457324b9fSagc \param output Write settings
11054b3a3e18Sagc \return 1 if OK; else 0
110693bf6008Sagc */
110793bf6008Sagc 
11084b3a3e18Sagc unsigned
110957324b9fSagc __ops_write_mdc(const unsigned char *hashed, __ops_output_t *output)
111093bf6008Sagc {
111193bf6008Sagc 	/* write it out */
111257324b9fSagc 	return __ops_write_ptag(output, OPS_PTAG_CT_MDC) &&
111357324b9fSagc 		__ops_write_length(output, OPS_SHA1_HASH_SIZE) &&
111457324b9fSagc 		__ops_write(output, hashed, OPS_SHA1_HASH_SIZE);
111593bf6008Sagc }
111693bf6008Sagc 
111793bf6008Sagc /**
111893bf6008Sagc \ingroup Core_WritePackets
111993bf6008Sagc \brief Writes Literal Data packet from buffer
112093bf6008Sagc \param data Buffer to write out
112193bf6008Sagc \param maxlen Max length of buffer
112293bf6008Sagc \param type Literal Data Type
112357324b9fSagc \param output Write settings
11244b3a3e18Sagc \return 1 if OK; else 0
112593bf6008Sagc */
11264b3a3e18Sagc unsigned
112757324b9fSagc __ops_write_litdata(__ops_output_t *output,
112857324b9fSagc 			const unsigned char *data,
112993bf6008Sagc 			const int maxlen,
113057324b9fSagc 			const __ops_litdata_type_t type)
113193bf6008Sagc {
113293bf6008Sagc 	/*
113393bf6008Sagc          * RFC4880 does not specify a meaning for filename or date.
113493bf6008Sagc          * It is implementation-dependent.
113593bf6008Sagc          * We will not implement them.
113693bf6008Sagc          */
113793bf6008Sagc 	/* \todo do we need to check text data for <cr><lf> line endings ? */
1138*41335e2dSagc 	return __ops_write_ptag(output, OPS_PTAG_CT_LITDATA) &&
113957324b9fSagc 		__ops_write_length(output, (unsigned)(1 + 1 + 4 + maxlen)) &&
114057324b9fSagc 		__ops_write_scalar(output, (unsigned)type, 1) &&
114157324b9fSagc 		__ops_write_scalar(output, 0, 1) &&
114257324b9fSagc 		__ops_write_scalar(output, 0, 4) &&
114357324b9fSagc 		__ops_write(output, data, (unsigned)maxlen);
114493bf6008Sagc }
114593bf6008Sagc 
114693bf6008Sagc /**
114793bf6008Sagc \ingroup Core_WritePackets
114893bf6008Sagc \brief Writes Literal Data packet from contents of file
114993bf6008Sagc \param filename Name of file to read from
115093bf6008Sagc \param type Literal Data Type
115157324b9fSagc \param output Write settings
11524b3a3e18Sagc \return 1 if OK; else 0
115393bf6008Sagc */
115493bf6008Sagc 
11554b3a3e18Sagc unsigned
11563326c4c5Sagc __ops_fileread_litdata(const char *filename,
11573326c4c5Sagc 				 const __ops_litdata_type_t type,
115857324b9fSagc 				 __ops_output_t *output)
115993bf6008Sagc {
116085073018Sagc 	__ops_memory_t	*mem = NULL;
116157324b9fSagc 	unsigned   	 ret;
11620df5e957Sagc 	size_t		 len;
116393bf6008Sagc 
116493bf6008Sagc 	mem = __ops_memory_new();
11650df5e957Sagc 	if (!__ops_mem_readfile(mem, filename)) {
11660df5e957Sagc 		return 0;
116785073018Sagc 	}
116857324b9fSagc 	len = __ops_mem_len(mem);
1169*41335e2dSagc 	ret = __ops_write_ptag(output, OPS_PTAG_CT_LITDATA) &&
117057324b9fSagc 		__ops_write_length(output, 1 + 1 + 4 + len) &&
117157324b9fSagc 		__ops_write_scalar(output, (unsigned)type, 1) &&
117257324b9fSagc 		__ops_write_scalar(output, 0, 1) /* filename */ &&
117357324b9fSagc 		__ops_write_scalar(output, 0, 4) /* date */ &&
117457324b9fSagc 		__ops_write(output, __ops_mem_data(mem), len);
117593bf6008Sagc 	__ops_memory_free(mem);
117657324b9fSagc 	return ret;
117793bf6008Sagc }
117893bf6008Sagc 
117993bf6008Sagc /**
118093bf6008Sagc    \ingroup HighLevel_General
118193bf6008Sagc 
1182efdd9dbaSagc    \brief Writes contents of buffer into file
118393bf6008Sagc 
118493bf6008Sagc    \param filename Filename to write to
118593bf6008Sagc    \param buf Buffer to write to file
118693bf6008Sagc    \param len Size of buffer
118793bf6008Sagc    \param overwrite Flag to set whether to overwrite an existing file
118893bf6008Sagc    \return 1 if OK; 0 if error
118993bf6008Sagc */
119093bf6008Sagc 
119193bf6008Sagc int
11923326c4c5Sagc __ops_filewrite(const char *filename, const char *buf,
11934b3a3e18Sagc 			const size_t len, const unsigned overwrite)
119493bf6008Sagc {
119593bf6008Sagc 	int		flags = 0;
1196de704779Sagc 	int		fd = 0;
119793bf6008Sagc 
119893bf6008Sagc 	flags = O_WRONLY | O_CREAT;
11994b3a3e18Sagc 	if (overwrite) {
120093bf6008Sagc 		flags |= O_TRUNC;
1201de704779Sagc 	} else {
120293bf6008Sagc 		flags |= O_EXCL;
1203de704779Sagc 	}
120493bf6008Sagc #ifdef O_BINARY
120593bf6008Sagc 	flags |= O_BINARY;
120693bf6008Sagc #endif
120793bf6008Sagc 	fd = open(filename, flags, 0600);
120893bf6008Sagc 	if (fd < 0) {
120993bf6008Sagc 		perror(NULL);
121093bf6008Sagc 		return 0;
121193bf6008Sagc 	}
12123326c4c5Sagc 	if (write(fd, buf, len) != (int)len) {
121393bf6008Sagc 		return 0;
1214bcfd8565Sagc 	}
121593bf6008Sagc 
12163326c4c5Sagc 	return (close(fd) == 0);
121793bf6008Sagc }
121893bf6008Sagc 
121993bf6008Sagc /**
122093bf6008Sagc \ingroup Core_WritePackets
122193bf6008Sagc \brief Write Symmetrically Encrypted packet
122293bf6008Sagc \param data Data to encrypt
122393bf6008Sagc \param len Length of data
122457324b9fSagc \param output Write settings
12254b3a3e18Sagc \return 1 if OK; else 0
122693bf6008Sagc \note Hard-coded to use AES256
122793bf6008Sagc */
12284b3a3e18Sagc unsigned
12293326c4c5Sagc __ops_write_symm_enc_data(const unsigned char *data,
123093bf6008Sagc 				       const int len,
123157324b9fSagc 				       __ops_output_t * output)
123293bf6008Sagc {
1233efdd9dbaSagc 			/* buffer to write encrypted data to */
12343326c4c5Sagc 	unsigned char  *encrypted = (unsigned char *) NULL;
123593bf6008Sagc 	__ops_crypt_t	crypt_info;
1236efdd9dbaSagc 	size_t		encrypted_sz = 0;	/* size of encrypted data */
1237efdd9dbaSagc 	int             done = 0;
123893bf6008Sagc 
123993bf6008Sagc 	/* \todo assume AES256 for now */
124093bf6008Sagc 	__ops_crypt_any(&crypt_info, OPS_SA_AES_256);
124193bf6008Sagc 	__ops_encrypt_init(&crypt_info);
124293bf6008Sagc 
124393bf6008Sagc 	encrypted_sz = len + crypt_info.blocksize + 2;
124493bf6008Sagc 	encrypted = calloc(1, encrypted_sz);
124593bf6008Sagc 
1246efdd9dbaSagc 	done = __ops_encrypt_se(&crypt_info, encrypted, data, (unsigned)len);
1247ed0df671Sagc 	if (done != len) {
1248ed0df671Sagc 		(void) fprintf(stderr,
12493326c4c5Sagc 			"__ops_write_symm_enc_data: done != len\n");
12504b3a3e18Sagc 		return 0;
1251ed0df671Sagc 	}
125293bf6008Sagc 
125357324b9fSagc 	return __ops_write_ptag(output, OPS_PTAG_CT_SE_DATA) &&
125457324b9fSagc 		__ops_write_length(output, 1 + encrypted_sz) &&
125557324b9fSagc 		__ops_write(output, data, (unsigned)len);
125693bf6008Sagc }
125793bf6008Sagc 
125893bf6008Sagc /**
125993bf6008Sagc \ingroup Core_WritePackets
126093bf6008Sagc \brief Write a One Pass Signature packet
12610c310959Sagc \param seckey Secret Key to use
126293bf6008Sagc \param hash_alg Hash Algorithm to use
126393bf6008Sagc \param sig_type Signature type
126457324b9fSagc \param output Write settings
12654b3a3e18Sagc \return 1 if OK; else 0
126693bf6008Sagc */
12674b3a3e18Sagc unsigned
126857324b9fSagc __ops_write_one_pass_sig(__ops_output_t *output,
126957324b9fSagc 			const __ops_seckey_t *seckey,
12702232f800Sagc 			const __ops_hash_alg_t hash_alg,
127157324b9fSagc 			const __ops_sig_type_t sig_type)
127293bf6008Sagc {
127393bf6008Sagc 	unsigned char   keyid[OPS_KEY_ID_SIZE];
127485073018Sagc 
12750c310959Sagc 	__ops_keyid(keyid, OPS_KEY_ID_SIZE, OPS_KEY_ID_SIZE, &seckey->pubkey);
1276648b5a99Sagc 	return __ops_write_ptag(output, OPS_PTAG_CT_1_PASS_SIG) &&
127757324b9fSagc 		__ops_write_length(output, 1 + 1 + 1 + 1 + 8 + 1) &&
127857324b9fSagc 		__ops_write_scalar(output, 3, 1)	/* version */ &&
127957324b9fSagc 		__ops_write_scalar(output, (unsigned)sig_type, 1) &&
128057324b9fSagc 		__ops_write_scalar(output, (unsigned)hash_alg, 1) &&
128157324b9fSagc 		__ops_write_scalar(output, (unsigned)seckey->pubkey.alg, 1) &&
128257324b9fSagc 		__ops_write(output, keyid, 8) &&
128357324b9fSagc 		__ops_write_scalar(output, 1, 1);
128493bf6008Sagc }
1285