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