From c27f695a37bf68e4f2735817e25a10620c256556 Mon Sep 17 00:00:00 2001 From: csoler Date: Wed, 4 Apr 2012 19:27:07 +0000 Subject: [PATCH] updated to trunk of openpgp-sdk git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-OpenPGP@5078 b45a01b8-16f6-495d-af2f-9b41ad6348cc --- libretroshare/src/pgp/pgphandler.cc | 138 ++++- libretroshare/src/pgp/pgphandler.h | 39 +- libretroshare/src/pgp/test_pgp_handler.cc | 10 +- libretroshare/src/pqi/authgpg.cc | 4 +- openpgpsdk/include/openpgpsdk/compress.h | 2 + openpgpsdk/include/openpgpsdk/create.h | 2 + openpgpsdk/include/openpgpsdk/crypto.h | 7 + openpgpsdk/include/openpgpsdk/errors.h | 1 + openpgpsdk/include/openpgpsdk/literal.h | 35 ++ openpgpsdk/include/openpgpsdk/packet-parse.h | 3 +- openpgpsdk/include/openpgpsdk/packet.h | 11 +- openpgpsdk/include/openpgpsdk/partial.h | 54 ++ openpgpsdk/include/openpgpsdk/signature.h | 1 + openpgpsdk/include/openpgpsdk/streamwriter.h | 2 +- openpgpsdk/include/openpgpsdk/types.h | 6 +- openpgpsdk/include/openpgpsdk/validate.h | 2 +- openpgpsdk/src/accumulate.c | 6 +- openpgpsdk/src/compress.c | 217 +++++++- openpgpsdk/src/create.c | 112 +++- openpgpsdk/src/crypto.c | 167 ++++-- openpgpsdk/src/errors.c | 22 + openpgpsdk/src/keyring.c | 60 +- openpgpsdk/src/keyring_local.h | 63 +++ openpgpsdk/src/openssl_crypto.c | 12 +- openpgpsdk/src/packet-parse.c | 47 +- openpgpsdk/src/packet-print.c | 21 +- openpgpsdk/src/packet-show.c | 3 + openpgpsdk/src/reader.c | 4 +- openpgpsdk/src/readerwriter.c | 11 +- openpgpsdk/src/signature.c | 556 +++++++++++-------- openpgpsdk/src/src.pro | 2 + openpgpsdk/src/symmetric.c | 174 +++++- openpgpsdk/src/util.c | 48 +- openpgpsdk/src/validate.c | 1 + openpgpsdk/src/writer_armour.c | 43 +- openpgpsdk/src/writer_encrypt_se_ip.c | 51 +- openpgpsdk/src/writer_literal.c | 85 +++ openpgpsdk/src/writer_partial.c | 381 +++++++++++++ openpgpsdk/src/writer_stream_encrypt_se_ip.c | 300 +++------- 39 files changed, 1956 insertions(+), 747 deletions(-) create mode 100644 openpgpsdk/include/openpgpsdk/literal.h create mode 100644 openpgpsdk/include/openpgpsdk/partial.h create mode 100644 openpgpsdk/src/keyring_local.h create mode 100644 openpgpsdk/src/writer_literal.c create mode 100644 openpgpsdk/src/writer_partial.c diff --git a/libretroshare/src/pgp/pgphandler.cc b/libretroshare/src/pgp/pgphandler.cc index a3eb9ee47..158cc676b 100644 --- a/libretroshare/src/pgp/pgphandler.cc +++ b/libretroshare/src/pgp/pgphandler.cc @@ -29,37 +29,116 @@ std::string PGPIdType::toStdString() const return res ; } +std::string PGPFingerprintType::toStdString() const +{ + static const char out[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' } ; -PGPIdType::PGPIdType(const std::string& s) + std::string res ; + + for(int j = 0; j < KEY_FINGERPRINT_SIZE; j++) + { + res += out[ (bytes[j]>>4) ] ; + res += out[ bytes[j] & 0xf ] ; + } + + return res ; +} + + +PGPIdType PGPIdType::fromUserId_hex(const std::string& s) { int n=0; if(s.length() != KEY_ID_SIZE*2) throw std::runtime_error("PGPIdType::PGPIdType: can only init from 16 chars hexadecimal string") ; + PGPIdType res ; + for(int i = 0; i < KEY_ID_SIZE; ++i) { - bytes[i] = 0 ; + res.bytes[i] = 0 ; for(int k=0;k<2;++k) { char b = s[n++] ; if(b >= 'A' && b <= 'F') - bytes[i] += (b-'A'+10) << 4*(1-k) ; + res.bytes[i] += (b-'A'+10) << 4*(1-k) ; else if(b >= 'a' && b <= 'f') - bytes[i] += (b-'a'+10) << 4*(1-k) ; + res.bytes[i] += (b-'a'+10) << 4*(1-k) ; else if(b >= '0' && b <= '9') - bytes[i] += (b-'0') << 4*(1-k) ; + res.bytes[i] += (b-'0') << 4*(1-k) ; else throw std::runtime_error("PGPIdType::Sha1CheckSum: can't init from non pure hexadecimal string") ; } } + return res ; } +PGPIdType PGPIdType::fromFingerprint_hex(const std::string& s) +{ + if(s.length() != PGPFingerprintType::KEY_FINGERPRINT_SIZE*2) + throw std::runtime_error("PGPIdType::PGPIdType: can only init from 40 chars hexadecimal string") ; + PGPIdType res ; + + int n=PGPFingerprintType::KEY_FINGERPRINT_SIZE - PGPIdType::KEY_ID_SIZE -1; + + for(int i = 0; i < PGPIdType::KEY_ID_SIZE; ++i) + { + res.bytes[i] = 0 ; + + for(int k=0;k<2;++k) + { + char b = s[n++] ; + + if(b >= 'A' && b <= 'F') + res.bytes[i] += (b-'A'+10) << 4*(1-k) ; + else if(b >= 'a' && b <= 'f') + res.bytes[i] += (b-'a'+10) << 4*(1-k) ; + else if(b >= '0' && b <= '9') + res.bytes[i] += (b-'0') << 4*(1-k) ; + else + throw std::runtime_error("PGPIdType::Sha1CheckSum: can't init from non pure hexadecimal string") ; + } + } + return res ; +} +PGPFingerprintType PGPFingerprintType::fromFingerprint_hex(const std::string& s) +{ + int n=0; + if(s.length() != PGPFingerprintType::KEY_FINGERPRINT_SIZE*2) + throw std::runtime_error("PGPIdType::PGPIdType: can only init from 40 chars hexadecimal string") ; + + PGPFingerprintType res ; + + for(int i = 0; i < PGPFingerprintType::KEY_FINGERPRINT_SIZE; ++i) + { + res.bytes[i] = 0 ; + + for(int k=0;k<2;++k) + { + char b = s[n++] ; + + if(b >= 'A' && b <= 'F') + res.bytes[i] += (b-'A'+10) << 4*(1-k) ; + else if(b >= 'a' && b <= 'f') + res.bytes[i] += (b-'a'+10) << 4*(1-k) ; + else if(b >= '0' && b <= '9') + res.bytes[i] += (b-'0') << 4*(1-k) ; + else + throw std::runtime_error("PGPIdType::Sha1CheckSum: can't init from non pure hexadecimal string") ; + } + } + return res ; +} PGPIdType::PGPIdType(const unsigned char b[]) { - memcpy(bytes,b,8) ; + memcpy(bytes,b,KEY_ID_SIZE) ; } +PGPFingerprintType::PGPFingerprintType(const unsigned char b[]) +{ + memcpy(bytes,b,KEY_FINGERPRINT_SIZE) ; +} + uint64_t PGPIdType::toUInt64() const { @@ -210,7 +289,6 @@ bool PGPHandler::GeneratePGPCertificate(const std::string& name, const std::stri ops_write_transferable_secret_key(key,(unsigned char *)passphrase.c_str(),passphrase.length(),ops_false,cinfo); ops_keydata_free(key) ; - free(key) ; // 3 - read the file into a keyring @@ -388,18 +466,48 @@ bool PGPHandler::SignDataBin(const PGPIdType& id,const void *data, const uint32_ return true ; } -bool PGPHandler::VerifySignBin(const void *data, uint32_t data_len, unsigned char *sign, unsigned int sign_len, const std::string &withfingerprint) +bool PGPHandler::getKeyFingerprint(const PGPIdType& id,PGPFingerprintType& fp) const { - ops_memory_t *mem = ops_memory_new() ; - ops_memory_add(mem,(unsigned char *)sign,sign_len) ; + const ops_keydata_t *key = getPublicKey(id) ; - ops_validate_result_t *result = (ops_validate_result_t*)ops_mallocz(sizeof(ops_validate_result_t)) ; - ops_boolean_t res = ops_validate_mem(result, mem, ops_false, _pubring); + if(key == NULL) + return false ; - ops_validate_result_free(result) ; + ops_fingerprint_t f ; + ops_fingerprint(&f,&key->key.pkey) ; - // no need to clear mem. It's already deleted by ops_validate_mem (weird but true). + fp = PGPFingerprintType(f.fingerprint) ; - return res ; + return true ; +} + +bool PGPHandler::VerifySignBin(const void *data, uint32_t data_len, unsigned char *sign, unsigned int sign_len, const PGPFingerprintType& key_fingerprint) +{ + PGPIdType id = PGPIdType::fromFingerprint_hex(key_fingerprint.toStdString()) ; + const ops_keydata_t *key = getPublicKey(id) ; + + if(key == NULL) + { + std::cerr << "No key returned by fingerprint " << key_fingerprint.toStdString() << ", and ID " << id.toStdString() << ", signature verification failed!" << std::endl; + return false ; + } + + // Check that fingerprint is the same. + const ops_public_key_t *pkey = &key->key.pkey ; + ops_fingerprint_t fp ; + ops_fingerprint(&fp,pkey) ; + + if(key_fingerprint != PGPFingerprintType(fp.fingerprint)) + { + std::cerr << "Key fingerprint does not match " << key_fingerprint.toStdString() << ", for ID " << id.toStdString() << ", signature verification failed!" << std::endl; + return false ; + } + + ops_signature_t signature ; +// ops_signature_add_data(&signature,sign,sign_len) ; + +// ops_boolean_t valid=check_binary_signature(data_len,data,signature,pkey) ; + + return false ; } diff --git a/libretroshare/src/pgp/pgphandler.h b/libretroshare/src/pgp/pgphandler.h index 05a4131d1..390713861 100644 --- a/libretroshare/src/pgp/pgphandler.h +++ b/libretroshare/src/pgp/pgphandler.h @@ -18,10 +18,12 @@ class PGPIdType { public: static const int KEY_ID_SIZE = 8 ; - PGPIdType() {} - PGPIdType(const std::string& hex_string) ; - PGPIdType(const unsigned char bytes[]) ; + + static PGPIdType fromUserId_hex(const std::string& hex_string) ; + static PGPIdType fromFingerprint_hex(const std::string& hex_string) ; + + explicit PGPIdType(const unsigned char bytes[]) ; std::string toStdString() const ; uint64_t toUInt64() const ; @@ -30,6 +32,33 @@ class PGPIdType private: unsigned char bytes[KEY_ID_SIZE] ; }; +class PGPFingerprintType +{ + public: + static const int KEY_FINGERPRINT_SIZE = 20 ; + + static PGPFingerprintType fromFingerprint_hex(const std::string& hex_string) ; + explicit PGPFingerprintType(const unsigned char bytes[]) ; + + std::string toStdString() const ; + const unsigned char *toByteArray() const { return &bytes[0] ; } + + bool operator==(const PGPFingerprintType& fp) const + { + for(int i=0;ifpr) { -#ifdef GPG_DEBUG +//#ifdef GPG_DEBUG fprintf(stderr, "AuthGPGimpl::VerifySignature() for the fingerprint key : "); std::cerr << withfingerprint; fprintf(stderr, "\n"); -#endif +//#endif valid = true; break; } diff --git a/openpgpsdk/include/openpgpsdk/compress.h b/openpgpsdk/include/openpgpsdk/compress.h index 49fb286d7..7cac1ceb2 100644 --- a/openpgpsdk/include/openpgpsdk/compress.h +++ b/openpgpsdk/include/openpgpsdk/compress.h @@ -30,3 +30,5 @@ int ops_decompress(ops_region_t *region,ops_parse_info_t *parse_info, ops_boolean_t ops_write_compressed(const unsigned char* data, const unsigned int len, ops_create_info_t *cinfo); + +void ops_writer_push_compressed(ops_create_info_t *cinfo); diff --git a/openpgpsdk/include/openpgpsdk/create.h b/openpgpsdk/include/openpgpsdk/create.h index 3ef24854e..c56b27e6e 100644 --- a/openpgpsdk/include/openpgpsdk/create.h +++ b/openpgpsdk/include/openpgpsdk/create.h @@ -43,6 +43,8 @@ struct ops_create_info ops_error_t *errors; /*!< an error stack */ }; +void ops_prepare_parent_info(ops_create_info_t *parent_info, + ops_writer_info_t *winfo); ops_create_info_t *ops_create_info_new(void); void ops_create_info_delete(ops_create_info_t *info); diff --git a/openpgpsdk/include/openpgpsdk/crypto.h b/openpgpsdk/include/openpgpsdk/crypto.h index a7f09529d..cb6cf1549 100644 --- a/openpgpsdk/include/openpgpsdk/crypto.h +++ b/openpgpsdk/include/openpgpsdk/crypto.h @@ -30,6 +30,12 @@ #include "packet.h" #include "packet-parse.h" #include +#include +#include + +#if OPENSSL_VERSION_NUMBER < 0x00908030L +# define OPENSSL_NO_CAMELLIA +#endif #define OPS_MIN_HASH_SIZE 16 @@ -166,6 +172,7 @@ void ops_writer_push_encrypt(ops_create_info_t *info, ops_boolean_t ops_encrypt_file(const char* input_filename, const char* output_filename, const ops_keydata_t *pub_key, const ops_boolean_t use_armour, const ops_boolean_t allow_overwrite); ops_boolean_t ops_decrypt_file(const char* input_filename, const char* output_filename, ops_keyring_t *keyring, const ops_boolean_t use_armour, const ops_boolean_t allow_overwrite,ops_parse_cb_t* cb_get_passphrase); +extern void ops_encrypt_stream(ops_create_info_t* cinfo, const ops_keydata_t* public_key, const ops_secret_key_t* secret_key, const ops_boolean_t compress, const ops_boolean_t use_armour); // Keys ops_boolean_t ops_rsa_generate_keypair(const int numbits, const unsigned long e, ops_keydata_t* keydata); diff --git a/openpgpsdk/include/openpgpsdk/errors.h b/openpgpsdk/include/openpgpsdk/errors.h index e67e71d1e..6ff958c2d 100644 --- a/openpgpsdk/include/openpgpsdk/errors.h +++ b/openpgpsdk/include/openpgpsdk/errors.h @@ -113,6 +113,7 @@ void ops_print_error(ops_error_t *err); void ops_print_errors(ops_error_t *errstack); void ops_free_errors(ops_error_t *errstack); int ops_has_error(ops_error_t *errstack, ops_errcode_t errcode); +void ops_move_errors(ops_create_info_t *source, ops_error_t **errstack); #define OPS_SYSTEM_ERROR_1(err,code,syscall,fmt,arg) do { ops_push_error(err,OPS_E_SYSTEM_ERROR,errno,__FILE__,__LINE__,syscall); ops_push_error(err,code,0,__FILE__,__LINE__,fmt,arg); } while(0) #define OPS_MEMORY_ERROR(err) {fprintf(stderr, "Memory error\n");} // \todo placeholder for better error handling diff --git a/openpgpsdk/include/openpgpsdk/literal.h b/openpgpsdk/include/openpgpsdk/literal.h new file mode 100644 index 000000000..8b1c30e6b --- /dev/null +++ b/openpgpsdk/include/openpgpsdk/literal.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2005-2009 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __OPS_LITERAL_H__ +#define __OPS_LITERAL_H__ + + +ops_boolean_t write_literal_header(ops_create_info_t *info, + void *header_data); + +void ops_writer_push_literal(ops_create_info_t *info); +void ops_writer_push_literal_with_opts(ops_create_info_t *info, + unsigned int buf_size); + +#endif /* __OPS_LITERAL_H__ */ + +// EOF diff --git a/openpgpsdk/include/openpgpsdk/packet-parse.h b/openpgpsdk/include/openpgpsdk/packet-parse.h index 93090e3e9..f0bcfb8da 100644 --- a/openpgpsdk/include/openpgpsdk/packet-parse.h +++ b/openpgpsdk/include/openpgpsdk/packet-parse.h @@ -132,7 +132,6 @@ int ops_parse_errs(ops_parse_info_t *parse_info,ops_ulong_list_t *errs); void ops_parse_and_validate(ops_parse_info_t *parse_info); - void ops_parse_options(ops_parse_info_t *pinfo,ops_content_tag_t tag, ops_parse_type_t type); @@ -140,7 +139,7 @@ ops_boolean_t ops_limited_read(unsigned char *dest,size_t length, ops_region_t *region,ops_error_t **errors, ops_reader_info_t *rinfo, ops_parse_cb_info_t *cbinfo); -ops_boolean_t ops_stacked_limited_read(unsigned char *dest,unsigned length, +ops_boolean_t ops_stacked_limited_read(void *dest,unsigned length, ops_region_t *region, ops_error_t **errors, ops_reader_info_t *rinfo, diff --git a/openpgpsdk/include/openpgpsdk/packet.h b/openpgpsdk/include/openpgpsdk/packet.h index 5730dba36..0ab8f76fb 100644 --- a/openpgpsdk/include/openpgpsdk/packet.h +++ b/openpgpsdk/include/openpgpsdk/packet.h @@ -127,7 +127,6 @@ typedef enum #define OPS_PTAG_NF_CONTENT_TAG_SHIFT 0 - /** Structure to hold one parse error string. */ typedef struct { @@ -310,6 +309,9 @@ typedef enum OPS_SA_AES_192 =8, /*!< AES with 192-bit key */ OPS_SA_AES_256 =9, /*!< AES with 256-bit key */ OPS_SA_TWOFISH =10, /*!< Twofish with 256-bit key (TWOFISH) */ + OPS_SA_CAMELLIA_128 =11, /*!< Camellia with 128-bit key */ + OPS_SA_CAMELLIA_192 =12, /*!< Camellia with 192-bit key */ + OPS_SA_CAMELLIA_256 =13, /*!< Camellia with 256-bit key */ } ops_symmetric_algorithm_t; /** Hashing Algorithm Numbers. @@ -358,7 +360,8 @@ typedef struct ops_public_key_t public_key; ops_s2k_usage_t s2k_usage; ops_s2k_specifier_t s2k_specifier; - ops_symmetric_algorithm_t algorithm; + ops_symmetric_algorithm_t algorithm; // the algorithm used to encrypt + // the key ops_hash_algorithm_t hash_algorithm; unsigned char salt[OPS_SALT_SIZE]; unsigned octet_count; @@ -658,8 +661,8 @@ typedef struct /** Signature Subpacket : Revocation Key */ typedef struct { - unsigned char cclass; - unsigned char algid; + unsigned char clss; /* class - name changed for C++ */ + unsigned char algid; unsigned char fingerprint[20]; } ops_ss_revocation_key_t; diff --git a/openpgpsdk/include/openpgpsdk/partial.h b/openpgpsdk/include/openpgpsdk/partial.h new file mode 100644 index 000000000..dabf98c8a --- /dev/null +++ b/openpgpsdk/include/openpgpsdk/partial.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2005-2009 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer, Alasdair Mackintosh. + * The Contributors have asserted their moral rights under the + * UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __OPS_PARTIAL_H__ +#define __OPS_PARTIAL_H__ + +#include "types.h" +#include "writer.h" + +/** + * Function that writes out a packet header. See + * ops_writer_push_partial + */ +typedef ops_boolean_t ops_write_partial_header_t(ops_create_info_t *info, + void *data); + +typedef ops_boolean_t ops_write_partial_trailer_t(ops_create_info_t *info, + void *data); + +void ops_writer_push_partial(size_t packet_size, + ops_create_info_t *info, + ops_content_tag_t tag, + ops_write_partial_header_t *header_writer, + void *header_data); + +void ops_writer_push_partial_with_trailer( + size_t packet_size, + ops_create_info_t *cinfo, + ops_content_tag_t tag, + ops_write_partial_header_t *header_writer, + void *header_data, + ops_write_partial_trailer_t *trailer_writer, + void *trailer_data); + +#endif /* __OPS_PARTIAL_H__ */ diff --git a/openpgpsdk/include/openpgpsdk/signature.h b/openpgpsdk/include/openpgpsdk/signature.h index c555d6aca..66294451c 100644 --- a/openpgpsdk/include/openpgpsdk/signature.h +++ b/openpgpsdk/include/openpgpsdk/signature.h @@ -91,5 +91,6 @@ ops_boolean_t ops_sign_file_as_cleartext(const char* input_filename, const char* ops_boolean_t ops_sign_buf_as_cleartext(const char* input, const size_t len, ops_memory_t** output, const ops_secret_key_t *skey); ops_boolean_t ops_sign_file(const char* input_filename, const char* output_filename, const ops_secret_key_t *skey, const ops_boolean_t use_armour, const ops_boolean_t overwrite); ops_memory_t * ops_sign_buf(const void* input, const size_t input_len, const ops_sig_type_t sig_type, const ops_secret_key_t *skey, const ops_boolean_t use_armour); +ops_boolean_t ops_writer_push_signed(ops_create_info_t *cinfo, const ops_sig_type_t sig_type, const ops_secret_key_t *skey); #endif diff --git a/openpgpsdk/include/openpgpsdk/streamwriter.h b/openpgpsdk/include/openpgpsdk/streamwriter.h index c9bd51709..70f77990d 100644 --- a/openpgpsdk/include/openpgpsdk/streamwriter.h +++ b/openpgpsdk/include/openpgpsdk/streamwriter.h @@ -25,6 +25,6 @@ #include void ops_writer_push_stream_encrypt_se_ip(ops_create_info_t *cinfo, - const ops_key_data_t *pub_key); + const ops_keydata_t *pub_key); #endif /*__OPS_STREAMWRITER_H__*/ diff --git a/openpgpsdk/include/openpgpsdk/types.h b/openpgpsdk/include/openpgpsdk/types.h index 8c31139bd..2f3c20bb5 100644 --- a/openpgpsdk/include/openpgpsdk/types.h +++ b/openpgpsdk/include/openpgpsdk/types.h @@ -189,6 +189,10 @@ typedef enum ops_content_tag_t ops_ss_type_t; typedef unsigned char ops_ss_rr_code_t; /** ops_parse_type_t */ + +/** Used to specify whether subpackets should be returned raw, parsed or ignored. + */ + typedef enum ops_parse_type_t ops_parse_type_t; /** ops_parser_content_t */ @@ -208,8 +212,6 @@ typedef enum { OPS_WF_DUMMY, } ops_writer_flags_t; -/** ops_writer_ret_t */ -/* typedef enum ops_writer_ret_t ops_writer_ret_t; */ /** * \ingroup Create diff --git a/openpgpsdk/include/openpgpsdk/validate.h b/openpgpsdk/include/openpgpsdk/validate.h index 39755328c..7337a6136 100644 --- a/openpgpsdk/include/openpgpsdk/validate.h +++ b/openpgpsdk/include/openpgpsdk/validate.h @@ -71,7 +71,7 @@ typedef struct } validate_key_cb_arg_t; /** Struct use with the validate_data_cb callback */ -typedef struct +typedef struct validate_data_cb_arg { enum { diff --git a/openpgpsdk/src/accumulate.c b/openpgpsdk/src/accumulate.c index c2989d9ad..dac56e609 100644 --- a/openpgpsdk/src/accumulate.c +++ b/openpgpsdk/src/accumulate.c @@ -91,13 +91,15 @@ accumulate_cb(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo) return OPS_KEEP_MEMORY; } // assert(cur); - ops_add_userid_to_keydata(cur, &content->user_id); + ops_add_userid_to_keydata(cur, &content->user_id); + free(content->user_id.user_id); return OPS_KEEP_MEMORY; case OPS_PARSER_PACKET_END: if(!cur) return OPS_RELEASE_MEMORY; - ops_add_packet_to_keydata(cur, &content->packet); + ops_add_packet_to_keydata(cur, &content->packet); + free(content->packet.raw); return OPS_KEEP_MEMORY; case OPS_PARSER_ERROR: diff --git a/openpgpsdk/src/compress.c b/openpgpsdk/src/compress.c index c214a1b3f..ec9d993ce 100644 --- a/openpgpsdk/src/compress.c +++ b/openpgpsdk/src/compress.c @@ -1,8 +1,9 @@ /* - * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * Copyright (c) 2005-2009 Nominet UK (www.nic.uk) * All rights reserved. - * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted - * their moral rights under the UK Copyright Design and Patents Act 1988 to + * Contributors: Ben Laurie, Rachel Willmer, Alasdair Mackintosh. + * The Contributors have asserted their moral rights under the + * UK Copyright Design and Patents Act 1988 to * be recorded as the authors of this copyright work. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not @@ -21,7 +22,7 @@ /** \file */ - + #include #include #include @@ -33,8 +34,12 @@ #include #include "parse_local.h" #include +#include + +static const int debug = 0; #define DECOMPRESS_BUFFER 1024 +#define COMPRESS_BUFFER 32768 typedef struct { @@ -63,13 +68,15 @@ typedef struct z_stream stream; unsigned char *src; unsigned char *dst; + size_t bytes_in; + size_t bytes_out; } compress_arg_t; // \todo remove code duplication between this and bzip2_compressed_data_reader static int zlib_compressed_data_reader(void *dest,size_t length, - ops_error_t **errors, - ops_reader_info_t *rinfo, - ops_parse_cb_info_t *cbinfo) + ops_error_t **errors, + ops_reader_info_t *rinfo, + ops_parse_cb_info_t *cbinfo) { z_decompress_arg_t *arg=ops_reader_get_arg(rinfo); assert(arg->type==OPS_C_ZIP || arg->type==OPS_C_ZLIB); @@ -84,7 +91,8 @@ static int zlib_compressed_data_reader(void *dest,size_t length, if(arg->region->length_read == arg->region->length) { if(arg->inflate_ret != Z_STREAM_END) - OPS_ERROR(cbinfo->errors, OPS_E_P_DECOMPRESSION_ERROR,"Compressed data didn't end when region ended."); + OPS_ERROR(cbinfo->errors, OPS_E_P_DECOMPRESSION_ERROR, + "Compressed data didn't end when region ended."); /* else return 0; @@ -130,7 +138,8 @@ static int zlib_compressed_data_reader(void *dest,size_t length, { if(!arg->region->indeterminate && arg->region->length_read != arg->region->length) - OPS_ERROR(cbinfo->errors,OPS_E_P_DECOMPRESSION_ERROR,"Compressed stream ended before packet end."); + OPS_ERROR(cbinfo->errors,OPS_E_P_DECOMPRESSION_ERROR, + "Compressed stream ended before packet end."); } else if(ret != Z_OK) { @@ -153,9 +162,9 @@ static int zlib_compressed_data_reader(void *dest,size_t length, // \todo remove code duplication between this and zlib_compressed_data_reader static int bzip2_compressed_data_reader(void *dest,size_t length, - ops_error_t **errors, - ops_reader_info_t *rinfo, - ops_parse_cb_info_t *cbinfo) + ops_error_t **errors, + ops_reader_info_t *rinfo, + ops_parse_cb_info_t *cbinfo) { bz_decompress_arg_t *arg=ops_reader_get_arg(rinfo); assert(arg->type==OPS_C_BZIP2); @@ -170,7 +179,8 @@ static int bzip2_compressed_data_reader(void *dest,size_t length, if(arg->region->length_read == arg->region->length) { if(arg->inflate_ret != BZ_STREAM_END) - OPS_ERROR(cbinfo->errors, OPS_E_P_DECOMPRESSION_ERROR,"Compressed data didn't end when region ended."); + OPS_ERROR(cbinfo->errors, OPS_E_P_DECOMPRESSION_ERROR, + "Compressed data didn't end when region ended."); } while(length > 0) @@ -197,8 +207,8 @@ static int bzip2_compressed_data_reader(void *dest,size_t length, else n=sizeof arg->in; - if(!ops_stacked_limited_read((unsigned char *)arg->in,n,arg->region, - errors,rinfo,cbinfo)) + if(!ops_stacked_limited_read(arg->in, n, arg->region, errors, + rinfo, cbinfo)) return -1; arg->bzstream.next_in=arg->in; @@ -211,11 +221,13 @@ static int bzip2_compressed_data_reader(void *dest,size_t length, { if(!arg->region->indeterminate && arg->region->length_read != arg->region->length) - OPS_ERROR(cbinfo->errors,OPS_E_P_DECOMPRESSION_ERROR,"Compressed stream ended before packet end."); + OPS_ERROR(cbinfo->errors, OPS_E_P_DECOMPRESSION_ERROR, + "Compressed stream ended before packet end."); } else if(ret != BZ_OK) { - OPS_ERROR_1(cbinfo->errors,OPS_E_P_DECOMPRESSION_ERROR,"Invalid return %d from BZ2_bzDecompress", ret); + OPS_ERROR_1(cbinfo->errors, OPS_E_P_DECOMPRESSION_ERROR, + "Invalid return %d from BZ2_bzDecompress", ret); } arg->inflate_ret=ret; } @@ -280,7 +292,8 @@ int ops_decompress(ops_region_t *region,ops_parse_info_t *parse_info, break; default: - OPS_ERROR_1(&parse_info->errors, OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG, "Compression algorithm %d is not yet supported", type); + OPS_ERROR_1(&parse_info->errors, OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG, + "Compression algorithm %d is not yet supported", type); return 0; } @@ -303,7 +316,8 @@ int ops_decompress(ops_region_t *region,ops_parse_info_t *parse_info, break; default: - OPS_ERROR_1(&parse_info->errors, OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG, "Compression algorithm %d is not yet supported", type); + OPS_ERROR_1(&parse_info->errors, OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG, + "Compression algorithm %d is not yet supported", type); return 0; } @@ -313,7 +327,9 @@ int ops_decompress(ops_region_t *region,ops_parse_info_t *parse_info, case OPS_C_ZLIB: if(ret != Z_OK) { - OPS_ERROR_1(&parse_info->errors, OPS_E_P_DECOMPRESSION_ERROR, "Cannot initialise ZIP or ZLIB stream for decompression: error=%d", ret); + OPS_ERROR_1(&parse_info->errors, OPS_E_P_DECOMPRESSION_ERROR, + "Cannot initialise ZIP or ZLIB stream " + "for decompression: error=%d", ret); return 0; } ops_reader_push(parse_info,zlib_compressed_data_reader,NULL,&z_arg); @@ -322,14 +338,17 @@ int ops_decompress(ops_region_t *region,ops_parse_info_t *parse_info, case OPS_C_BZIP2: if (ret != BZ_OK) { - OPS_ERROR_1(&parse_info->errors, OPS_E_P_DECOMPRESSION_ERROR, "Cannot initialise BZIP2 stream for decompression: error=%d", ret); + OPS_ERROR_1(&parse_info->errors, OPS_E_P_DECOMPRESSION_ERROR, + "Cannot initialise BZIP2 stream " + "for decompression: error=%d", ret); return 0; } ops_reader_push(parse_info,bzip2_compressed_data_reader,NULL,&bz_arg); break; default: - OPS_ERROR_1(&parse_info->errors, OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG, "Compression algorithm %d is not yet supported", type); + OPS_ERROR_1(&parse_info->errors, OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG, + "Compression algorithm %d is not yet supported", type); return 0; } @@ -402,4 +421,158 @@ ops_boolean_t ops_write_compressed(const unsigned char *data, && ops_write(compress->dst, compress->stream.total_out,cinfo)); } + +// Writes out the header for the compressed packet. Invoked by the +// partial stream writer. Note that writing the packet tag and the +// packet length is handled by the partial stream writer. +static ops_boolean_t write_compressed_header(ops_create_info_t *info, + void *header_data) + { + OPS_USED(header_data); + // Write the compression type. Currently we just use ZLIB + ops_write_scalar(OPS_C_ZLIB, 1, info); + return ops_true; + } + +static void zlib_error(ops_error_t **errors, z_stream *stream, int error) + { + OPS_ERROR_2(errors,OPS_E_FAIL, + "Error from compression stream %d (%s)", error, + stream->msg == NULL ? "Unknown" : stream->msg); + } + +static ops_boolean_t stream_compress_writer(const unsigned char *src, + unsigned length, + ops_error_t **errors, + ops_writer_info_t *winfo) + { + // ZLib doesn't like being asked to compress nothing, so return if + // we are given no input. + if (length == 0) + return ops_true; + if (debug) + fprintf(stderr, "Compressing %u bytes\n", length); + compress_arg_t* compress = ops_writer_get_arg(winfo); + compress->bytes_in += length; + compress->stream.next_in = (void*) src; + compress->stream.avail_in = length; + ops_boolean_t result = ops_true; + do + { + compress->stream.next_out = compress->dst; + compress->stream.avail_out = COMPRESS_BUFFER; + int retcode = deflate(&compress->stream, Z_NO_FLUSH); + if (retcode != Z_OK) + { + zlib_error(errors, &compress->stream, retcode); + deflateEnd(&compress->stream); + return ops_false; + } + unsigned bytes_to_write = COMPRESS_BUFFER - compress->stream.avail_out; + if (debug) + fprintf(stderr, "bytes_to_write = %u\n", bytes_to_write); + compress->bytes_out += bytes_to_write; + result = ops_stacked_write(compress->dst, bytes_to_write, errors, + winfo); + } + while (result && compress->stream.avail_out == 0); + + return result; + } + +static ops_boolean_t stream_compress_finaliser(ops_error_t **errors, + ops_writer_info_t *winfo) + { + compress_arg_t* compress = ops_writer_get_arg(winfo); + compress->stream.next_in = NULL; + compress->stream.avail_in = 0; + int retcode = Z_OK; + int output_size = COMPRESS_BUFFER; + ops_boolean_t result = ops_true; + do + { + compress->stream.next_out = compress->dst; + compress->stream.avail_out = output_size; + retcode = deflate(&compress->stream, Z_FINISH); + if (retcode != Z_STREAM_END && retcode != Z_OK) + { + zlib_error(errors, &compress->stream, retcode); + deflateEnd(&compress->stream); + return ops_false; + } + int bytes_to_write = output_size - compress->stream.avail_out; + if (debug) + fprintf(stderr, "At end, bytes_to_write = %u\n", bytes_to_write); + compress->bytes_out += bytes_to_write; + result = ops_stacked_write(compress->dst, bytes_to_write, errors, + winfo); + + // If deflate returns Z_OK after we have asked to flush, it means + // that there was not enough space in the output buffer. Increase + // the buffer size and try again. + if (retcode != Z_STREAM_END) + { + if (debug) + fprintf(stderr, "Reallocating %u\n", output_size * 2); + output_size *= 2; + compress->dst = realloc(compress->dst, output_size); + } + } + while (result && retcode != Z_STREAM_END); + + int error = deflateEnd(&compress->stream); + if (error != Z_OK) + { + zlib_error(errors, &compress->stream, error); + return ops_false; + } + return result; + } + +static void stream_compress_destroyer(ops_writer_info_t *winfo) + { + compress_arg_t* compress = ops_writer_get_arg(winfo); + if (debug) + fprintf(stderr, "Compressed %zu to %zu\n", compress->bytes_in, + compress->bytes_out); + free(compress->dst); + free(compress); + } + +/** +\ingroup Core_WritePackets +\brief Pushes a compressed writer onto the stack. Data written + will be encoded as a compressed packet. +\param cinfo Write settings +*/ +void ops_writer_push_compressed(ops_create_info_t *cinfo) + { + // This is a streaming writer, so we don't know the length in + // advance. Use a partial writer to handle the partial body + // packet lengths. + ops_writer_push_partial(COMPRESS_BUFFER, + cinfo, OPS_PTAG_CT_COMPRESSED, + write_compressed_header, NULL); + + // Create arg to be used with this writer + // Remember to free this in the destroyer + compress_arg_t *compress = ops_mallocz(sizeof *compress); + + compress->dst = malloc(COMPRESS_BUFFER); + const int level=Z_DEFAULT_COMPRESSION; // \todo allow varying levels + compress->stream.zalloc=Z_NULL; + compress->stream.zfree=Z_NULL; + compress->stream.opaque=NULL; + compress->stream.avail_out = COMPRESS_BUFFER; + // all other fields set to zero by use of ops_mallocz + + if (deflateInit(&compress->stream, level) != Z_OK) + // can't initialise. Is there a better way to handle this? + assert(0); + + // And push writer on stack + ops_writer_push(cinfo, stream_compress_writer, stream_compress_finaliser, + stream_compress_destroyer, compress); + } + // EOF diff --git a/openpgpsdk/src/create.c b/openpgpsdk/src/create.c index 83861eeee..7341b6124 100644 --- a/openpgpsdk/src/create.c +++ b/openpgpsdk/src/create.c @@ -103,7 +103,8 @@ ops_boolean_t ops_write_struct_user_id(ops_user_id_t *id, * * \return return value from ops_write_struct_user_id() */ -ops_boolean_t ops_write_user_id(const unsigned char *user_id,ops_create_info_t *info) +ops_boolean_t ops_write_user_id(const unsigned char *user_id, + ops_create_info_t *info) { ops_user_id_t id; @@ -204,6 +205,7 @@ static ops_boolean_t write_public_key_body(const ops_public_key_t *key, && ops_write_mpi(key->key.elgamal.y,info); default: + fprintf(stderr, "Unknown algorithm %d\n", key->algorithm); assert(0); break; } @@ -239,7 +241,8 @@ static ops_boolean_t write_secret_key_body(const ops_secret_key_t *key, if (!ops_write_scalar(key->algorithm,1,info)) return ops_false; - assert(key->s2k_specifier==OPS_S2KS_SIMPLE || key->s2k_specifier==OPS_S2KS_SALTED); // = 1 \todo could also be iterated-and-salted + assert(key->s2k_specifier==OPS_S2KS_SIMPLE + || key->s2k_specifier==OPS_S2KS_SALTED); // = 1 \todo could also be iterated-and-salted if (!ops_write_scalar(key->s2k_specifier,1,info)) return ops_false; @@ -268,7 +271,8 @@ static ops_boolean_t write_secret_key_body(const ops_secret_key_t *key, */ default: - fprintf(stderr,"invalid/unsupported s2k specifier %d\n", key->s2k_specifier); + fprintf(stderr,"invalid/unsupported s2k specifier %d\n", + key->s2k_specifier); assert(0); } @@ -313,7 +317,8 @@ static ops_boolean_t write_secret_key_body(const ops_secret_key_t *key, hash.add(&hash, passphrase, pplen); hash.finish(&hash, hashed); - // if more in hash than is needed by session key, use the leftmost octets + // if more in hash than is needed by session key, use the + // leftmost octets memcpy(session_key+(i*SHA_DIGEST_LENGTH), hashed, use); done += use; assert(done<=CAST_KEY_LENGTH); @@ -329,7 +334,8 @@ static ops_boolean_t write_secret_key_body(const ops_secret_key_t *key, */ default: - fprintf(stderr,"invalid/unsupported s2k specifier %d\n", key->s2k_specifier); + fprintf(stderr,"invalid/unsupported s2k specifier %d\n", + key->s2k_specifier); assert(0); } @@ -432,7 +438,9 @@ static ops_boolean_t write_secret_key_body(const ops_secret_key_t *key, \endcode */ -ops_boolean_t ops_write_transferable_public_key(const ops_keydata_t *keydata, ops_boolean_t armoured, ops_create_info_t *info) +ops_boolean_t ops_write_transferable_public_key(const ops_keydata_t *keydata, + ops_boolean_t armoured, + ops_create_info_t *info) { ops_boolean_t rtn; unsigned int i=0,j=0; @@ -757,6 +765,47 @@ ops_boolean_t ops_write_struct_secret_key(const ops_secret_key_t *key, && write_secret_key_body(key,passphrase,pplen,info); } +/** + * \ingroup InternalAPI + * + * \brief Initialise a temporary info structure that can be used for + * writing to a writer's parent. + * + * This is used by writers who want to use the various ops_write functions + * in order to write to the parent writer. + * Example code: + * \code + * ops_boolean_t writer(const unsigned char *src, + * unsigned length, + * ops_error_t **errors, + * ops_writer_info_t *winfo) { + * ops_create_info_t parent; + * ops_prepare_parent_info(&parent, winfo, errors); + * + * // The ptag will be written to the parent writer + * ops_write_ptag(OPS_PTAG_CT_LITERAL_DATA, &parent); + * + * // The data is written to the parent. This line is + // equivalent to: + * // ops_stacked_write(src, length, errors, winfo); + * ops_boolean_t result = ops_write(src, length, info); + * ops_move_errors(&parent_info, errors); + * return result; + * \endcode + * + * \note It is the responsiblity of the caller to assign space for the parent + * structure, typically on the stack. IOn order to report errors correctly, + * use ops_move_errors() after the write operation. + * + * \see ops_move_errors + */ +void ops_prepare_parent_info(ops_create_info_t *parent_info, + ops_writer_info_t *winfo) + { + parent_info->winfo = *winfo->next; + parent_info->errors = NULL; + } + /** * \ingroup Core_Create * @@ -791,7 +840,8 @@ void ops_create_info_delete(ops_create_info_t *info) \param cs Checksum to be written \return ops_true if OK; else ops_false */ -ops_boolean_t ops_calc_session_key_checksum(ops_pk_session_key_t *session_key, unsigned char cs[2]) +ops_boolean_t ops_calc_session_key_checksum(ops_pk_session_key_t *session_key, + unsigned char cs[2]) { unsigned int i=0; unsigned long checksum=0; @@ -814,7 +864,8 @@ ops_boolean_t ops_calc_session_key_checksum(ops_pk_session_key_t *session_key, u // fprintf(stderr," %2x\n",cs[1]); } -static ops_boolean_t create_unencoded_m_buf(ops_pk_session_key_t *session_key, unsigned char *m_buf) +static ops_boolean_t create_unencoded_m_buf(ops_pk_session_key_t *session_key, + unsigned char *m_buf) { int i=0; // unsigned long checksum=0; @@ -826,7 +877,7 @@ static ops_boolean_t create_unencoded_m_buf(ops_pk_session_key_t *session_key, u m_buf[0]=session_key->symmetric_algorithm; - assert(session_key->symmetric_algorithm==OPS_SA_CAST5); + assert(session_key->symmetric_algorithm == OPS_SA_CAST5); for (i=0; ikey[i]; @@ -898,7 +949,8 @@ ops_boolean_t encode_m_buf(const unsigned char *M, size_t mLen, \brief Creates an ops_pk_session_key_t struct from keydata \param key Keydata to use \return ops_pk_session_key_t struct -\note It is the caller's responsiblity to free the returned pointer +\note It is the caller's responsiblity to free the returned pointer. Before freeing, + the key must be cleared by calling ops_pk_session_key_free() \note Currently hard-coded to use CAST5 \note Currently hard-coded to use RSA */ @@ -946,7 +998,8 @@ ops_pk_session_key_t *ops_create_pk_session_key(const ops_keydata_t *key) if (debug) { unsigned int i=0; - fprintf(stderr,"CAST5 session key created (len=%d):\n ", CAST_KEY_LENGTH); + fprintf(stderr,"CAST5 session key created (len=%d):\n ", + CAST_KEY_LENGTH); for (i=0; ikey[i]); fprintf(stderr,"\n"); @@ -966,10 +1019,12 @@ ops_pk_session_key_t *ops_create_pk_session_key(const ops_keydata_t *key) printf("%2x ", unencoded_m_buf[i]); printf("\n"); } - encode_m_buf(&unencoded_m_buf[0], SZ_UNENCODED_M_BUF, pub_key, &encoded_m_buf[0]); + encode_m_buf(&unencoded_m_buf[0], SZ_UNENCODED_M_BUF, pub_key, + &encoded_m_buf[0]); // and encrypt it - if(!ops_rsa_encrypt_mpi(encoded_m_buf, sz_encoded_m_buf, pub_key, &session_key->parameters)) + if(!ops_rsa_encrypt_mpi(encoded_m_buf, sz_encoded_m_buf, pub_key, + &session_key->parameters)) { free (encoded_m_buf); return NULL; @@ -993,7 +1048,9 @@ ops_boolean_t ops_write_pk_session_key(ops_create_info_t *info, assert(pksk->algorithm == OPS_PKA_RSA); return ops_write_ptag(OPS_PTAG_CT_PK_SESSION_KEY, info) - && ops_write_length(1 + 8 + 1 + BN_num_bytes(pksk->parameters.rsa.encrypted_m) + 2, info) + && ops_write_length(1 + 8 + 1 + + BN_num_bytes(pksk->parameters.rsa.encrypted_m) + + 2, info) && ops_write_scalar(pksk->version, 1, info) && ops_write(pksk->key_id, 8, info) && ops_write_scalar(pksk->algorithm, 1, info) @@ -1056,9 +1113,10 @@ ops_boolean_t ops_write_literal_data_from_buf(const unsigned char *data, \return ops_true if OK; else ops_false */ -ops_boolean_t ops_write_literal_data_from_file(const char *filename, - const ops_literal_data_type_t type, - ops_create_info_t *info) +ops_boolean_t +ops_write_literal_data_from_file(const char *filename, + const ops_literal_data_type_t type, + ops_create_info_t *info) { size_t initial_size=1024; int fd=0; @@ -1066,8 +1124,7 @@ ops_boolean_t ops_write_literal_data_from_file(const char *filename, unsigned char buf[1024]; ops_memory_t* mem=NULL; size_t len=0; - -#ifdef WIN32 +#ifdef WINDOWS_SYS fd=open(filename,O_RDONLY | O_BINARY); #else fd=open(filename,O_RDONLY); @@ -1109,7 +1166,8 @@ ops_boolean_t ops_write_literal_data_from_file(const char *filename, \param errnum Pointer to error \return new ops_memory_t pointer containing the contents of the file - \note If there was an error opening the file or reading from it, errnum is set to the cause + \note If there was an error opening the file or reading from it, + errnum is set to the cause \note It is the caller's responsibility to call ops_memory_free(mem) */ @@ -1122,8 +1180,7 @@ ops_memory_t* ops_write_mem_from_file(const char *filename, int* errnum) ops_memory_t* mem=NULL; *errnum=0; - -#ifdef WIN32 +#ifdef WINDOWS_SYS fd=open(filename,O_RDONLY | O_BINARY); #else fd=open(filename,O_RDONLY); @@ -1165,7 +1222,8 @@ ops_memory_t* ops_write_mem_from_file(const char *filename, int* errnum) \return 1 if OK; 0 if error */ -int ops_write_file_from_buf(const char *filename, const char* buf, const size_t len, const ops_boolean_t overwrite) +int ops_write_file_from_buf(const char *filename, const char* buf, + const size_t len, const ops_boolean_t overwrite) { int fd=0; size_t n=0; @@ -1176,9 +1234,10 @@ int ops_write_file_from_buf(const char *filename, const char* buf, const size_t flags |= O_TRUNC; else flags |= O_EXCL; -#ifdef WIN32 +#ifdef WINDOWS_SYS flags |= O_BINARY; #endif + fd=open(filename,flags, 0600); if (fd < 0) { @@ -1212,7 +1271,7 @@ ops_boolean_t ops_write_symmetrically_encrypted_data(const unsigned char *data, int done=0; ops_crypt_t crypt_info; int encrypted_sz=0;// size of encrypted data - unsigned char *encrypted=(unsigned char *)NULL; // buffer to write encrypted data to + unsigned char *encrypted=NULL; // buffer to write encrypted data to // \todo assume AES256 for now ops_crypt_any(&crypt_info, OPS_SA_AES_256); @@ -1246,7 +1305,8 @@ ops_boolean_t ops_write_one_pass_sig(const ops_secret_key_t* skey, { unsigned char keyid[OPS_KEY_ID_SIZE]; if (debug) - { fprintf(stderr,"calling ops_keyid in write_one_pass_sig: this calls sha1_init\n"); } + fprintf(stderr, "calling ops_keyid in write_one_pass_sig: " + "this calls sha1_init\n"); ops_keyid(keyid,&skey->public_key); return ops_write_ptag(OPS_PTAG_CT_ONE_PASS_SIGNATURE, info) diff --git a/openpgpsdk/src/crypto.c b/openpgpsdk/src/crypto.c index 3c6a88cad..5b98bf472 100644 --- a/openpgpsdk/src/crypto.c +++ b/openpgpsdk/src/crypto.c @@ -19,9 +19,12 @@ * limitations under the License. */ +#include #include +#include #include #include +#include #include #include "parse_local.h" @@ -41,8 +44,9 @@ \return length of MPI \note only RSA at present */ -int ops_decrypt_and_unencode_mpi(unsigned char *buf,unsigned buflen,const BIGNUM *encmpi, - const ops_secret_key_t *skey) +int ops_decrypt_and_unencode_mpi(unsigned char *buf, unsigned buflen, + const BIGNUM *encmpi, + const ops_secret_key_t *skey) { unsigned char encmpibuf[8192]; unsigned char mpibuf[8192]; @@ -53,7 +57,7 @@ int ops_decrypt_and_unencode_mpi(unsigned char *buf,unsigned buflen,const BIGNUM mpisize=BN_num_bytes(encmpi); /* MPI can't be more than 65,536 */ assert(mpisize <= sizeof encmpibuf); - BN_bn2bin(encmpi,encmpibuf); + BN_bn2bin(encmpi, encmpibuf); assert(skey->public_key.algorithm == OPS_PKA_RSA); @@ -65,9 +69,9 @@ int ops_decrypt_and_unencode_mpi(unsigned char *buf,unsigned buflen,const BIGNUM fprintf(stderr,"\n"); */ - n=ops_rsa_private_decrypt(mpibuf,encmpibuf,(BN_num_bits(encmpi)+7)/8, - &skey->key.rsa,&skey->public_key.key.rsa); - assert(n!=-1); + n=ops_rsa_private_decrypt(mpibuf, encmpibuf, (BN_num_bits(encmpi)+7)/8, + &skey->key.rsa, &skey->public_key.key.rsa); + assert(n != -1); /* fprintf(stderr,"decrypted encoded m buf : "); @@ -102,7 +106,7 @@ int ops_decrypt_and_unencode_mpi(unsigned char *buf,unsigned buflen,const BIGNUM // this is the unencoded m buf if((unsigned)(n-i) <= buflen) - memcpy(buf,mpibuf+i,n-i); + memcpy(buf, mpibuf+i, n-i); /* printf("decoded m buf:\n"); @@ -120,16 +124,17 @@ int ops_decrypt_and_unencode_mpi(unsigned char *buf,unsigned buflen,const BIGNUM \brief RSA-encrypt an MPI */ ops_boolean_t ops_rsa_encrypt_mpi(const unsigned char *encoded_m_buf, - const size_t sz_encoded_m_buf, - const ops_public_key_t *pkey, - ops_pk_session_key_parameters_t *skp) + const size_t sz_encoded_m_buf, + const ops_public_key_t *pkey, + ops_pk_session_key_parameters_t *skp) { assert(sz_encoded_m_buf==(size_t) BN_num_bytes(pkey->key.rsa.n)); unsigned char encmpibuf[8192]; int n=0; - n=ops_rsa_public_encrypt(encmpibuf, encoded_m_buf, sz_encoded_m_buf, &pkey->key.rsa); + n=ops_rsa_public_encrypt(encmpibuf, encoded_m_buf, sz_encoded_m_buf, + &pkey->key.rsa); assert(n!=-1); if(n <= 0) @@ -151,7 +156,8 @@ ops_boolean_t ops_rsa_encrypt_mpi(const unsigned char *encoded_m_buf, #define MAXBUF 1024 static ops_parse_cb_return_t -callback_write_parsed(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo); +callback_write_parsed(const ops_parser_content_t *content_, + ops_parse_cb_info_t *cbinfo); /** \ingroup HighLevel_Crypto @@ -163,17 +169,20 @@ Encrypt a file \param allow_overwrite Allow output file to be overwrwritten if it exists \return ops_true if OK; else ops_false */ -ops_boolean_t ops_encrypt_file(const char* input_filename, const char* output_filename, const ops_keydata_t *pub_key, const ops_boolean_t use_armour, const ops_boolean_t allow_overwrite) +ops_boolean_t ops_encrypt_file(const char* input_filename, + const char* output_filename, + const ops_keydata_t *pub_key, + const ops_boolean_t use_armour, + const ops_boolean_t allow_overwrite) { int fd_in=0; int fd_out=0; ops_create_info_t *cinfo; - -#ifdef WIN32 - fd_in=open(input_filename,O_RDONLY | O_BINARY); +#ifdef WINDOWS_SYS + fd_in=open(input_filename, O_RDONLY | O_BINARY); #else - fd_in=open(input_filename,O_RDONLY); + fd_in=open(input_filename, O_RDONLY ); #endif if(fd_in < 0) { @@ -190,37 +199,76 @@ ops_boolean_t ops_encrypt_file(const char* input_filename, const char* output_fi ops_writer_push_armoured_message(cinfo); // Push the encrypted writer - ops_writer_push_encrypt_se_ip(cinfo,pub_key); + ops_writer_push_stream_encrypt_se_ip(cinfo, pub_key); + ops_writer_push_literal(cinfo); // Do the writing - unsigned char* buf=NULL; - size_t bufsz=16; - int done=0; + unsigned buffer[10240]; for (;;) { - buf=realloc(buf,done+bufsz); - - int n=0; + int n=0; - n=read(fd_in,buf+done,bufsz); - if (!n) - break; - assert(n>=0); - done+=n; + n=read(fd_in, buffer, sizeof buffer); + if (!n) + break; + assert(n >= 0); + + // FIXME: apparently writing can't fail. + ops_write(buffer, n, cinfo); } - // This does the writing - ops_write(buf,done,cinfo); // tidy up close(fd_in); - free(buf); - ops_teardown_file_write(cinfo,fd_out); + ops_teardown_file_write(cinfo, fd_out); return ops_true; } +/** + \ingroup HighLevel_Crypto + Encrypt a compressed, signed stream. + \param cinfo the structure describing where the output will be written. + \param public_key the key used to encrypt the data + \param secret_key the key used to sign the data. If NULL, the data + will not be signed + \param compress If true, compress the stream before encrypting + \param use_armour Write armoured text, if set + \see ops_setup_file_write + + Example Code: + \code + const char* filename = "armour_nocompress_sign.asc"; + ops_create_info_t *info; + int fd = ops_setup_file_write(&info, filename, ops_true); + if (fd < 0) { + fprintf(stderr, "Cannot write to %s\n", filename); + return -1; + } + ops_encrypt_stream(info, public_key, secret_key, ops_false, ops_true); + ops_write(cleartext, strlen(cleartext), info); + ops_writer_close(info); + ops_create_info_delete(info); + \endcode +*/ +extern void ops_encrypt_stream(ops_create_info_t* cinfo, + const ops_keydata_t* public_key, + const ops_secret_key_t* secret_key, + const ops_boolean_t compress, + const ops_boolean_t use_armour) + { + if (use_armour) + ops_writer_push_armoured_message(cinfo); + ops_writer_push_stream_encrypt_se_ip(cinfo, public_key); + if (compress) + ops_writer_push_compressed(cinfo); + if (secret_key != NULL) + ops_writer_push_signed(cinfo, OPS_SIG_BINARY, secret_key); + else + ops_writer_push_literal(cinfo); + } + /** \ingroup HighLevel_Crypto \brief Decrypt a file. @@ -232,7 +280,12 @@ ops_boolean_t ops_encrypt_file(const char* input_filename, const char* output_fi \param cb_get_passphrase Callback to use to get passphrase */ -ops_boolean_t ops_decrypt_file(const char* input_filename, const char* output_filename, ops_keyring_t* keyring, const ops_boolean_t use_armour, const ops_boolean_t allow_overwrite, ops_parse_cb_t* cb_get_passphrase) +ops_boolean_t ops_decrypt_file(const char* input_filename, + const char* output_filename, + ops_keyring_t* keyring, + const ops_boolean_t use_armour, + const ops_boolean_t allow_overwrite, + ops_parse_cb_t* cb_get_passphrase) { int fd_in=0; int fd_out=0; @@ -243,9 +296,9 @@ ops_boolean_t ops_decrypt_file(const char* input_filename, const char* output_fi // setup for reading from given input file fd_in=ops_setup_file_read(&pinfo, input_filename, - NULL, - callback_write_parsed, - ops_false); + NULL, + callback_write_parsed, + ops_false); if (fd_in < 0) { perror(input_filename); @@ -256,12 +309,13 @@ ops_boolean_t ops_decrypt_file(const char* input_filename, const char* output_fi if (output_filename) { - fd_out=ops_setup_file_write(&pinfo->cbinfo.cinfo, output_filename, allow_overwrite); + fd_out=ops_setup_file_write(&pinfo->cbinfo.cinfo, output_filename, + allow_overwrite); if (fd_out < 0) { perror(output_filename); - ops_teardown_file_read(pinfo,fd_in); + ops_teardown_file_read(pinfo, fd_in); return ops_false; } } @@ -269,26 +323,29 @@ ops_boolean_t ops_decrypt_file(const char* input_filename, const char* output_fi { int suffixlen=4; char *defaultsuffix=".decrypted"; - const char *suffix=input_filename+strlen((char *)input_filename)-suffixlen; - if (!strcmp(suffix,".gpg") || !strcmp(suffix,".asc")) + const char *suffix=input_filename+strlen(input_filename)-suffixlen; + if (!strcmp(suffix, ".gpg") || !strcmp(suffix, ".asc")) { myfilename=ops_mallocz(strlen(input_filename)-suffixlen+1); - strncpy(myfilename,input_filename,strlen(input_filename)-suffixlen); + strncpy(myfilename, input_filename, + strlen(input_filename)-suffixlen); } else { unsigned filenamelen=strlen(input_filename)+strlen(defaultsuffix)+1; myfilename=ops_mallocz(filenamelen); - snprintf(myfilename,filenamelen,"%s%s",input_filename,defaultsuffix); + snprintf(myfilename, filenamelen, "%s%s", input_filename, + defaultsuffix); } - fd_out=ops_setup_file_write(&pinfo->cbinfo.cinfo, myfilename, allow_overwrite); + fd_out=ops_setup_file_write(&pinfo->cbinfo.cinfo, myfilename, + allow_overwrite); if (fd_out < 0) { perror(myfilename); free(myfilename); - ops_teardown_file_read(pinfo,fd_in); + ops_teardown_file_read(pinfo, fd_in); return ops_false; } @@ -325,9 +382,11 @@ ops_boolean_t ops_decrypt_file(const char* input_filename, const char* output_fi } static ops_parse_cb_return_t -callback_write_parsed(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo) +callback_write_parsed(const ops_parser_content_t *content_, + ops_parse_cb_info_t *cbinfo) { - ops_parser_content_union_t* content=(ops_parser_content_union_t *)&content_->content; + ops_parser_content_union_t* content + =(ops_parser_content_union_t *)&content_->content; static ops_boolean_t skipping; // ops_boolean_t write=ops_true; @@ -350,26 +409,26 @@ callback_write_parsed(const ops_parser_content_t *content_,ops_parse_cb_info_t * puts("Skipping..."); skipping=ops_true; } - fwrite(content->unarmoured_text.data,1, - content->unarmoured_text.length,stdout); + fwrite(content->unarmoured_text.data, 1, + content->unarmoured_text.length, stdout); break; case OPS_PTAG_CT_PK_SESSION_KEY: - return callback_pk_session_key(content_,cbinfo); + return callback_pk_session_key(content_, cbinfo); break; case OPS_PARSER_CMD_GET_SECRET_KEY: - return callback_cmd_get_secret_key(content_,cbinfo); + return callback_cmd_get_secret_key(content_, cbinfo); break; case OPS_PARSER_CMD_GET_SK_PASSPHRASE: // return callback_cmd_get_secret_key_passphrase(content_,cbinfo); - return cbinfo->cryptinfo.cb_get_passphrase(content_,cbinfo); + return cbinfo->cryptinfo.cb_get_passphrase(content_, cbinfo); break; case OPS_PTAG_CT_LITERAL_DATA_BODY: - return callback_literal_data(content_,cbinfo); - break; + return callback_literal_data(content_, cbinfo); + break; case OPS_PTAG_CT_ARMOUR_HEADER: case OPS_PTAG_CT_ARMOUR_TRAILER: diff --git a/openpgpsdk/src/errors.c b/openpgpsdk/src/errors.c index 9ba02f4a0..2de42341b 100644 --- a/openpgpsdk/src/errors.c +++ b/openpgpsdk/src/errors.c @@ -208,4 +208,26 @@ void ops_free_errors(ops_error_t *errstack) } } +/** +\ingroup InternalAPI +\brief Moves errors from a create info structure to another error stack. + +The error stack wil be moved from the source structure to the destination +stack. If the destination already has errors defined, the errors will +be appended. +*/ +void ops_move_errors(ops_create_info_t *source, ops_error_t **dest) + { + if (*dest == NULL) + *dest = source->errors; + else + { + ops_error_t *last = *dest; + while(last->next != NULL) + last = last->next; + last->next = source->errors; + } + source->errors = NULL; + } + // EOF diff --git a/openpgpsdk/src/keyring.c b/openpgpsdk/src/keyring.c index 1e1243b3f..aabaa6a9b 100644 --- a/openpgpsdk/src/keyring.c +++ b/openpgpsdk/src/keyring.c @@ -61,16 +61,8 @@ ops_keydata_t *ops_keydata_new(void) { return ops_mallocz(sizeof(ops_keydata_t)); } -/** - \ingroup HighLevel_Keyring - - \brief Frees keydata and its memory - - \param keydata Key to be freed. - - \note This frees the keydata itself, as well as any other memory alloc-ed by it. -*/ -void ops_keydata_free(ops_keydata_t *keydata) +// Frees the content of a keydata structure, but not the keydata itself. +static void keydata_internal_free(ops_keydata_t *keydata) { unsigned n; @@ -98,7 +90,22 @@ void ops_keydata_free(ops_keydata_t *keydata) else ops_secret_key_free(&keydata->key.skey); -/* free(keydata); */ + } + +/** + \ingroup HighLevel_Keyring + + \brief Frees keydata and its memory + + \param keydata Key to be freed. + + \note This frees the keydata itself, as well as any other memory + alloc-ed by it. +*/ +void ops_keydata_free(ops_keydata_t *keydata) + { + keydata_internal_free(keydata); + free(keydata); } // \todo check where userid pointers are copied @@ -420,15 +427,11 @@ const unsigned char* ops_get_user_id(const ops_keydata_t *key, unsigned index) ops_boolean_t ops_is_key_supported(const ops_keydata_t *keydata) { - if ( keydata->type == OPS_PTAG_CT_PUBLIC_KEY ) { - if ( keydata->key.pkey.algorithm == OPS_PKA_RSA ) { + if(keydata->type == OPS_PTAG_CT_PUBLIC_KEY) + { + if(keydata->key.pkey.algorithm == OPS_PKA_RSA) return ops_true; } - } else if ( keydata->type == OPS_PTAG_CT_PUBLIC_KEY ) { - if ( keydata->key.skey.algorithm == (ops_symmetric_algorithm_t)OPS_PKA_RSA ) { - return ops_true; - } - } return ops_false; } @@ -688,9 +691,8 @@ ops_boolean_t ops_keyring_read_from_file(ops_keyring_t *keyring, const ops_boole // ops_parse_options(pinfo,OPS_PTAG_SS_ALL,OPS_PARSE_RAW); ops_parse_options(pinfo,OPS_PTAG_SS_ALL,OPS_PARSE_PARSED); - -#ifdef WIN32 - fd=open(filename,O_RDONLY|O_BINARY); +#ifdef WINDOWS_SYS + fd=open(filename,O_RDONLY | O_BINARY); #else fd=open(filename,O_RDONLY); #endif @@ -766,11 +768,10 @@ ops_boolean_t ops_keyring_read_from_mem(ops_keyring_t *keyring, const ops_boolea ops_parse_info_t *pinfo=NULL; ops_boolean_t res = ops_true; - pinfo=ops_parse_info_new(); + ops_setup_memory_read(&pinfo, mem, NULL, cb_keyring_read, + OPS_ACCUMULATE_NO); ops_parse_options(pinfo,OPS_PTAG_SS_ALL,OPS_PARSE_PARSED); - ops_setup_memory_read(&pinfo, mem, NULL, cb_keyring_read, OPS_ACCUMULATE_NO); - if (armour) { ops_reader_push_dearmour(pinfo); } @@ -787,7 +788,9 @@ ops_boolean_t ops_keyring_read_from_mem(ops_keyring_t *keyring, const ops_boolea if (armour) ops_reader_pop_dearmour(pinfo); - // don't call teardown_memory_read because memory was passed in + // don't call teardown_memory_read because memory was passed + // in. But we need to free the parse_info object allocated by + // ops_setup_memory_read(). ops_parse_info_delete(pinfo); return res; @@ -804,9 +807,10 @@ ops_boolean_t ops_keyring_read_from_mem(ops_keyring_t *keyring, const ops_boolea */ void ops_keyring_free(ops_keyring_t *keyring) { - int n; - for(n=0;nnkeys;++n) - ops_keydata_free(&keyring->keys[n]) ; + int i; + + for (i = 0; i < keyring->nkeys; i++) + keydata_internal_free(&keyring->keys[i]); free(keyring->keys); keyring->keys=NULL; diff --git a/openpgpsdk/src/keyring_local.h b/openpgpsdk/src/keyring_local.h new file mode 100644 index 000000000..5c3860f35 --- /dev/null +++ b/openpgpsdk/src/keyring_local.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted + * their moral rights under the UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** \file + */ + +#include + +#define DECLARE_ARRAY(type,arr) unsigned n##arr; unsigned n##arr##_allocated; type *arr +#define EXPAND_ARRAY(str,arr) do if(str->n##arr == str->n##arr##_allocated) \ + { \ + str->n##arr##_allocated=str->n##arr##_allocated*2+10; \ + str->arr=realloc(str->arr,str->n##arr##_allocated*sizeof *str->arr); \ + } while(0) + +/** ops_keydata_key_t + */ +typedef union + { + ops_public_key_t pkey; + ops_secret_key_t skey; + } ops_keydata_key_t; + + +/** sigpacket_t */ +typedef struct + { + ops_user_id_t* userid; + ops_packet_t* packet; + } sigpacket_t; + +// XXX: gonna have to expand this to hold onto subkeys, too... +/** \struct ops_keydata + * \todo expand to hold onto subkeys + */ +struct ops_keydata + { + DECLARE_ARRAY(ops_user_id_t,uids); + DECLARE_ARRAY(ops_packet_t,packets); + DECLARE_ARRAY(sigpacket_t, sigs); + unsigned char key_id[8]; + ops_fingerprint_t fingerprint; + ops_content_tag_t type; + ops_keydata_key_t key; + }; diff --git a/openpgpsdk/src/openssl_crypto.c b/openpgpsdk/src/openssl_crypto.c index b8a5cc28c..6b48d2897 100644 --- a/openpgpsdk/src/openssl_crypto.c +++ b/openpgpsdk/src/openssl_crypto.c @@ -608,7 +608,8 @@ void ops_crypto_init() void ops_crypto_finish() { CRYPTO_cleanup_all_ex_data(); - ERR_remove_state(0); + // FIXME: what should we do instead (function is deprecated)? + // ERR_remove_state(0); #ifdef DMALLOC CRYPTO_mem_leaks_fp(stderr); #endif @@ -632,18 +633,21 @@ const char *ops_text_from_hash(ops_hash_t *hash) \return ops_true if key generated successfully; otherwise ops_false \note It is the caller's responsibility to call ops_keydata_free(keydata) */ -ops_boolean_t ops_rsa_generate_keypair(const int numbits, const unsigned long e, ops_keydata_t* keydata) +ops_boolean_t ops_rsa_generate_keypair(const int numbits, const unsigned long e, + ops_keydata_t* keydata) { ops_secret_key_t *skey=NULL; - RSA *rsa=NULL; + RSA *rsa=RSA_new(); BN_CTX *ctx=BN_CTX_new(); + BIGNUM *ebn=BN_new(); ops_keydata_init(keydata,OPS_PTAG_CT_SECRET_KEY); skey=ops_get_writable_secret_key_from_data(keydata); // generate the key pair - rsa=RSA_generate_key(numbits,e,NULL,NULL); + BN_set_word(ebn,e); + RSA_generate_key_ex(rsa,numbits,ebn,NULL); // populate ops key from ssl key diff --git a/openpgpsdk/src/packet-parse.c b/openpgpsdk/src/packet-parse.c index 9ab743ab3..1a5c856e5 100644 --- a/openpgpsdk/src/packet-parse.c +++ b/openpgpsdk/src/packet-parse.c @@ -371,12 +371,14 @@ ops_boolean_t ops_limited_read(unsigned char *dest,size_t length, \ingroup Core_ReadPackets \brief Call ops_limited_read on next in stack */ -ops_boolean_t ops_stacked_limited_read(unsigned char *dest,unsigned length, +ops_boolean_t ops_stacked_limited_read(void *dest, unsigned length, ops_region_t *region, ops_error_t **errors, ops_reader_info_t *rinfo, ops_parse_cb_info_t *cbinfo) - { return ops_limited_read(dest,length,region,errors,rinfo->next,cbinfo); } + { + return ops_limited_read(dest, length, region, errors, rinfo->next, cbinfo); + } static ops_boolean_t limited_read(unsigned char *dest,unsigned length, ops_region_t *region,ops_parse_info_t *info) @@ -989,10 +991,6 @@ void ops_public_key_free(ops_public_key_t *p) free_BN(&p->key.elgamal.g); free_BN(&p->key.elgamal.y); break; - - //case 0: - // nothing to free - // break; default: assert(0); @@ -1251,8 +1249,6 @@ static int parse_user_id(ops_region_t *region,ops_parse_info_t *pinfo) CBP(pinfo,OPS_PTAG_CT_USER_ID,&content); - free(C.user_id.user_id) ; - return 1; } @@ -1307,6 +1303,7 @@ void ops_signature_free(ops_signature_t *sig) default: assert(0); } + free(sig->info.v4_hashed_data); } /** @@ -1609,10 +1606,10 @@ static int parse_one_signature_subpacket(ops_signature_t *sig, break; case OPS_PTAG_SS_REVOCATION_KEY: - /* octet 0 = class. Bit 0x80 must be set */ - if(!limited_read (&C.ss_revocation_key.cclass,1,&subregion,pinfo)) + /* octet 0 = clss. Bit 0x80 must be set */ + if(!limited_read (&C.ss_revocation_key.clss,1,&subregion,pinfo)) return 0; - if(!(C.ss_revocation_key.cclass&0x80)) + if(!(C.ss_revocation_key.clss&0x80)) { printf("Warning: OPS_PTAG_SS_REVOCATION_KEY class: " "Bit 0x80 should be set\n"); @@ -1906,8 +1903,6 @@ static int parse_v4_signature(ops_region_t *region,ops_parse_info_t *pinfo) CBP(pinfo,OPS_PTAG_CT_SIGNATURE_FOOTER,&content); - free(C.signature.info.v4_hashed_data) ; - return 1; } @@ -2227,7 +2222,6 @@ static int parse_secret_key(ops_region_t *region,ops_parse_info_t *pinfo) int ret=1; ops_region_t encregion; ops_region_t *saved_region=NULL; - size_t checksum_length=2; ops_hash_t checkhash; int blocksize; ops_boolean_t crypted; @@ -2252,8 +2246,6 @@ static int parse_secret_key(ops_region_t *region,ops_parse_info_t *pinfo) if(!limited_read(c,1,region,pinfo)) return 0; C.secret_key.s2k_usage=c[0]; - if(C.secret_key.s2k_usage == OPS_S2KU_ENCRYPTED_AND_HASHED) - checksum_length=20; if(C.secret_key.s2k_usage == OPS_S2KU_ENCRYPTED || C.secret_key.s2k_usage == OPS_S2KU_ENCRYPTED_AND_HASHED) @@ -2891,6 +2883,7 @@ static int ops_parse_one_packet(ops_parse_info_t *pinfo, { C.error.error="Format error (ptag bit not set)"; CBP(pinfo,OPS_PARSER_ERROR,&content); + OPS_ERROR(&pinfo->errors, OPS_E_P_UNKNOWN_TAG, C.error.error); return 0; } C.ptag.new_format=!!(*ptag&OPS_PTAG_NEW_FORMAT); @@ -2904,7 +2897,7 @@ static int ops_parse_one_packet(ops_parse_info_t *pinfo, } else { - ops_boolean_t rb; + ops_boolean_t rb = ops_false; C.ptag.content_tag=(*ptag&OPS_PTAG_OF_CONTENT_TAG_MASK) >> OPS_PTAG_OF_CONTENT_TAG_SHIFT; @@ -2930,8 +2923,11 @@ static int ops_parse_one_packet(ops_parse_info_t *pinfo, break; } if(!rb) - return 0; - } + { + OPS_ERROR(&pinfo->errors, OPS_E_P, "Cannot read tag length"); + return 0; + } + } CBP(pinfo,OPS_PARSER_PTAG,&content); @@ -3028,17 +3024,17 @@ static int ops_parse_one_packet(ops_parse_info_t *pinfo, { C.packet.length=pinfo->rinfo.alength; C.packet.raw=pinfo->rinfo.accumulated; + + CBP(pinfo,OPS_PARSER_PACKET_END,&content); + //free(pinfo->rinfo.accumulated); pinfo->rinfo.accumulated=NULL; pinfo->rinfo.asize=0; - CBP(pinfo,OPS_PARSER_PACKET_END,&content); } else C.packet.raw = NULL ; pinfo->rinfo.alength=0; - free(C.packet.raw) ; - if(r < 0) return -1; @@ -3099,11 +3095,13 @@ int ops_parse(ops_parse_info_t *pinfo) unsigned long pktlen; do + // Parse until we get a return code of 0 (error) or -1 (EOF) { r=ops_parse_one_packet(pinfo,&pktlen); - } while (r != -1); + } while (r > 0); return pinfo->errors ? 0 : 1; + return r == -1 ? 0 : 1; } /** @@ -3117,8 +3115,7 @@ int ops_parse(ops_parse_info_t *pinfo) int ops_parse_and_print_errors(ops_parse_info_t *pinfo) { - int r; - r=ops_parse(pinfo); + ops_parse(pinfo); ops_print_errors(pinfo->errors); return pinfo->errors ? 0 : 1; } diff --git a/openpgpsdk/src/packet-print.c b/openpgpsdk/src/packet-print.c index 607a4bb8d..7d6fee2d3 100644 --- a/openpgpsdk/src/packet-print.c +++ b/openpgpsdk/src/packet-print.c @@ -496,7 +496,7 @@ static void print_text_breakdown( ops_text_t *text) for(i=0 ; iknown.used ; i++) { print_indent(); - printf("%s",prefix); + fputs(prefix,stdout); printf("%s\n",text->known.strings[i]); } @@ -513,7 +513,7 @@ static void print_text_breakdown( ops_text_t *text) for( i=0; i < text->unknown.used; i++) { print_indent(); - printf("%s",prefix); + fputs(prefix,stdout); printf("%s\n",text->unknown.strings[i]); } @@ -849,11 +849,10 @@ int ops_print_packet(const ops_parser_content_t *content_) start_subpacket(content_->tag); /* not yet tested */ printf (" revocation key: class=0x%x", - content->ss_revocation_key.cclass); - if (content->ss_revocation_key.cclass&0x40) + content->ss_revocation_key.clss); + if (content->ss_revocation_key.clss&0x40) printf (" (sensitive)"); - printf (", algid=0x%x", - content->ss_revocation_key.algid); + printf (", algid=0x%x", content->ss_revocation_key.algid); printf(", fingerprint="); hexdump(content->ss_revocation_key.fingerprint,20); printf("\n"); @@ -862,8 +861,7 @@ int ops_print_packet(const ops_parser_content_t *content_) case OPS_PTAG_SS_ISSUER_KEY_ID: start_subpacket(content_->tag); - print_hexdump("Issuer Key Id", - &content->ss_issuer_key_id.key_id[0], + print_hexdump("Issuer Key Id", &content->ss_issuer_key_id.key_id[0], sizeof content->ss_issuer_key_id.key_id); end_subpacket(); break; @@ -1434,11 +1432,10 @@ static ops_parse_cb_return_t cb_list_packets(const ops_parser_content_t * conten start_subpacket(content_->tag); /* not yet tested */ printf (" revocation key: class=0x%x", - content->ss_revocation_key.class); - if (content->ss_revocation_key.class&0x40) + content->ss_revocation_key.clss); + if (content->ss_revocation_key.clss&0x40) printf (" (sensitive)"); - printf (", algid=0x%x", - content->ss_revocation_key.algid); + printf (", algid=0x%x", content->ss_revocation_key.algid); printf(", fingerprint="); hexdump(content->ss_revocation_key.fingerprint,20); printf("\n"); diff --git a/openpgpsdk/src/packet-show.c b/openpgpsdk/src/packet-show.c index a0eb6da22..8be6c7563 100644 --- a/openpgpsdk/src/packet-show.c +++ b/openpgpsdk/src/packet-show.c @@ -212,6 +212,9 @@ static ops_map_t symmetric_algorithm_map[] = { OPS_SA_AES_192, "AES (192-bit key)" }, { OPS_SA_AES_256, "AES (256-bit key)" }, { OPS_SA_TWOFISH, "Twofish(256-bit key)" }, + { OPS_SA_CAMELLIA_128, "Camellia (128-bit key)" }, + { OPS_SA_CAMELLIA_192, "Camellia (192-bit key)" }, + { OPS_SA_CAMELLIA_256, "Camellia (256-bit key)" }, { 0x00, NULL }, /* this is the end-of-array marker */ }; diff --git a/openpgpsdk/src/reader.c b/openpgpsdk/src/reader.c index 341542b2f..24fc8a041 100644 --- a/openpgpsdk/src/reader.c +++ b/openpgpsdk/src/reader.c @@ -81,7 +81,9 @@ void ops_reader_push(ops_parse_info_t *pinfo,ops_reader_t *reader,ops_reader_des void ops_reader_pop(ops_parse_info_t *pinfo) { ops_reader_info_t *next=pinfo->rinfo.next; - + // We are about to overwrite pinfo->rinfo, so free any data in the + // old rinfo structure first. + free(pinfo->rinfo.accumulated); pinfo->rinfo=*next; free(next); } diff --git a/openpgpsdk/src/readerwriter.c b/openpgpsdk/src/readerwriter.c index c927a9a4a..24c9e534d 100644 --- a/openpgpsdk/src/readerwriter.c +++ b/openpgpsdk/src/readerwriter.c @@ -139,8 +139,7 @@ int ops_setup_file_write(ops_create_info_t **cinfo, const char* filename, ops_bo flags |= O_TRUNC; else flags |= O_EXCL; - -#ifdef WIN32 +#ifdef WINDOWS_SYS flags |= O_BINARY; #endif @@ -182,10 +181,10 @@ int ops_setup_file_append(ops_create_info_t **cinfo, const char* filename) * initialise needed structures for writing to file */ -#ifdef WIN32 +#ifdef WINDOWS_SYS fd=open(filename,O_WRONLY | O_APPEND | O_BINARY, 0600); #else - fd=open(filename,O_WRONLY | O_APPEND, 0600); + fd=open(filename,O_WRONLY | O_APPEND , 0600); #endif if(fd < 0) { @@ -231,10 +230,10 @@ int ops_setup_file_read(ops_parse_info_t **pinfo, const char *filename, * initialise needed structures for reading */ -#ifdef WIN32 +#ifdef WINDOWS_SYS fd=open(filename,O_RDONLY | O_BINARY); #else - fd=open(filename,O_RDONLY); + fd=open(filename,O_RDONLY ); #endif if (fd < 0) { diff --git a/openpgpsdk/src/signature.c b/openpgpsdk/src/signature.c index f510ea7dd..7c7895176 100644 --- a/openpgpsdk/src/signature.c +++ b/openpgpsdk/src/signature.c @@ -1,8 +1,9 @@ /* - * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * Copyright (c) 2005-2009 Nominet UK (www.nic.uk) * All rights reserved. - * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted - * their moral rights under the UK Copyright Design and Patents Act 1988 to + * Contributors: Ben Laurie, Rachel Willmer, Alasdair Mackintosh. + * The Contributors have asserted their moral rights under the + * UK Copyright Design and Patents Act 1988 to * be recorded as the authors of this copyright work. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not @@ -26,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -98,18 +101,16 @@ static unsigned char prefix_sha256[]={ 0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86, \return ops_true if OK; else ops_false */ ops_boolean_t encode_hash_buf(const unsigned char *M, size_t mLen, - const ops_hash_algorithm_t hash_alg, - unsigned char* EM -) + const ops_hash_algorithm_t hash_alg, + unsigned char* EM) { // implementation of EMSA-PKCS1-v1_5, as defined in OpenPGP RFC unsigned i; - - int n=0; + int n; ops_hash_t hash; int hash_sz=0; - int encoded_hash_sz=0; + // int encoded_hash_sz=0; int prefix_sz=0; unsigned padding_sz=0; unsigned encoded_msg_sz=0; @@ -119,9 +120,9 @@ ops_boolean_t encode_hash_buf(const unsigned char *M, size_t mLen, // 1. Apply hash function to M - ops_hash_any(&hash,hash_alg); + ops_hash_any(&hash, hash_alg); hash.init(&hash); - hash.add(&hash,M,mLen); + hash.add(&hash, M, mLen); // \todo combine with rsa_sign @@ -133,7 +134,7 @@ ops_boolean_t encode_hash_buf(const unsigned char *M, size_t mLen, prefix=prefix_sha1; prefix_sz=sizeof prefix_sha1; hash_sz=OPS_SHA1_HASH_SIZE; - encoded_hash_sz=hash_sz+prefix_sz; + // encoded_hash_sz=hash_sz+prefix_sz; // \todo why is Ben using a PS size of 90 in rsa_sign? // (keysize-hashsize-1-2) padding_sz=90; @@ -157,12 +158,13 @@ ops_boolean_t encode_hash_buf(const unsigned char *M, size_t mLen, EM[i++]=0x00; - memcpy(&EM[i],prefix,prefix_sz); + memcpy(&EM[i], prefix, prefix_sz); i+=prefix_sz; // finally, write out hashed result - n=hash.finish(&hash,&EM[i]); + n=hash.finish(&hash, &EM[i]); + assert(n == hash_sz); encoded_msg_sz=i+hash_sz-1; @@ -170,10 +172,10 @@ ops_boolean_t encode_hash_buf(const unsigned char *M, size_t mLen, if (debug) { - fprintf(stderr,"Encoded Message: \n"); + fprintf(stderr, "Encoded Message: \n"); for (i=0; in)+7)/8; + keysize=BN_num_bytes(rsa->n); assert(keysize <= sizeof hashbuf); assert(10+hashsize <= keysize); hashbuf[0]=0; hashbuf[1]=1; if (debug) - { printf("rsa_sign: PS is %d\n", keysize-hashsize-1-2); } + printf("rsa_sign: PS is %d\n", keysize-hashsize-1-2); for(n=2 ; n < keysize-hashsize-1 ; ++n) hashbuf[n]=0xff; hashbuf[n++]=0; - memcpy(&hashbuf[n],prefix_sha1,sizeof prefix_sha1); + memcpy(&hashbuf[n], prefix_sha1, sizeof prefix_sha1); n+=sizeof prefix_sha1; - t=hash->finish(hash,&hashbuf[n]); + t=hash->finish(hash, &hashbuf[n]); assert(t == 20); - ops_write(&hashbuf[n],2,opt); + ops_write(&hashbuf[n], 2, opt); n+=t; assert(n == keysize); - t=ops_rsa_private_encrypt(sigbuf,hashbuf,keysize,srsa,rsa); - bn=BN_bin2bn(sigbuf,t,NULL); - ops_write_mpi(bn,opt); + t=ops_rsa_private_encrypt(sigbuf, hashbuf, keysize, srsa, rsa); + bn=BN_bin2bn(sigbuf, t, NULL); + ops_write_mpi(bn, opt); BN_free(bn); } -static void dsa_sign(ops_hash_t *hash, - const ops_dsa_public_key_t *dsa, - const ops_dsa_secret_key_t *sdsa, - ops_create_info_t *cinfo) +static void dsa_sign(ops_hash_t *hash, const ops_dsa_public_key_t *dsa, + const ops_dsa_secret_key_t *sdsa, ops_create_info_t *cinfo) { unsigned char hashbuf[8192]; unsigned hashsize; @@ -241,23 +240,23 @@ static void dsa_sign(ops_hash_t *hash, hashsize=20; // finalise hash - t=hash->finish(hash,&hashbuf[0]); - assert(t==20); + t=hash->finish(hash, &hashbuf[0]); + assert(t == 20); - ops_write(&hashbuf[0],2,cinfo); + ops_write(&hashbuf[0], 2, cinfo); // write signature to buf DSA_SIG* dsasig; - dsasig=ops_dsa_sign(hashbuf,hashsize,sdsa,dsa); + dsasig=ops_dsa_sign(hashbuf, hashsize, sdsa, dsa); // convert and write the sig out to memory - ops_write_mpi(dsasig->r,cinfo); - ops_write_mpi(dsasig->s,cinfo); + ops_write_mpi(dsasig->r, cinfo); + ops_write_mpi(dsasig->s, cinfo); DSA_SIG_free(dsasig); } static ops_boolean_t rsa_verify(ops_hash_algorithm_t type, - const unsigned char *hash,size_t hash_length, + const unsigned char *hash, size_t hash_length, const ops_rsa_signature_t *sig, const ops_rsa_public_key_t *rsa) { @@ -272,9 +271,10 @@ static ops_boolean_t rsa_verify(ops_hash_algorithm_t type, /* RSA key can't be bigger than 65535 bits, so... */ assert(keysize <= sizeof hashbuf_from_sig); assert((unsigned)BN_num_bits(sig->sig) <= 8*sizeof sigbuf); - BN_bn2bin(sig->sig,sigbuf); + BN_bn2bin(sig->sig, sigbuf); - n=ops_rsa_public_decrypt(hashbuf_from_sig,sigbuf,(BN_num_bits(sig->sig)+7)/8,rsa); + n=ops_rsa_public_decrypt(hashbuf_from_sig, sigbuf, BN_num_bytes(sig->sig), + rsa); int debug_len_decrypted=n; if(n != keysize) // obviously, this includes error returns @@ -310,75 +310,75 @@ static ops_boolean_t rsa_verify(ops_hash_algorithm_t type, printf("\n"); printf("hashbuf_from_sig\n"); for (zz=0; zzadd(hash,ops_memory_get_data(mem),l); + ops_hash_add_int(hash, 0x99, 1); + ops_hash_add_int(hash, l, 2); + hash->add(hash, ops_memory_get_data(mem), l); ops_memory_free(mem); } -static void initialise_hash(ops_hash_t *hash,const ops_signature_t *sig) +static void initialise_hash(ops_hash_t *hash, const ops_signature_t *sig) { - ops_hash_any(hash,sig->info.hash_algorithm); + ops_hash_any(hash, sig->info.hash_algorithm); hash->init(hash); } -static void init_key_signature(ops_hash_t *hash,const ops_signature_t *sig, - const ops_public_key_t *key) +static void init_key_signature(ops_hash_t *hash, const ops_signature_t *sig, + const ops_public_key_t *key) { - initialise_hash(hash,sig); - hash_add_key(hash,key); + initialise_hash(hash, sig); + hash_add_key(hash, key); } -static void hash_add_trailer(ops_hash_t *hash,const ops_signature_t *sig, +static void hash_add_trailer(ops_hash_t *hash, const ops_signature_t *sig, const unsigned char *raw_packet) { if(sig->info.version == OPS_V4) { if(raw_packet) - hash->add(hash,raw_packet+sig->v4_hashed_data_start, + hash->add(hash, raw_packet+sig->v4_hashed_data_start, sig->info.v4_hashed_data_length); - ops_hash_add_int(hash,sig->info.version,1); - ops_hash_add_int(hash,0xff,1); - ops_hash_add_int(hash,sig->info.v4_hashed_data_length,4); + ops_hash_add_int(hash, sig->info.version, 1); + ops_hash_add_int(hash, 0xff, 1); + ops_hash_add_int(hash, sig->info.v4_hashed_data_length, 4); } else { - ops_hash_add_int(hash,sig->info.type,1); - ops_hash_add_int(hash,sig->info.creation_time,4); + ops_hash_add_int(hash, sig->info.type, 1); + ops_hash_add_int(hash, sig->info.creation_time, 4); } } @@ -391,7 +391,7 @@ static void hash_add_trailer(ops_hash_t *hash,const ops_signature_t *sig, \param signer The signer's public key \return ops_true if good; else ops_false */ -ops_boolean_t ops_check_signature(const unsigned char *hash,unsigned length, +ops_boolean_t ops_check_signature(const unsigned char *hash, unsigned length, const ops_signature_t *sig, const ops_public_key_t *signer) { @@ -406,12 +406,13 @@ ops_boolean_t ops_check_signature(const unsigned char *hash,unsigned length, switch(sig->info.key_algorithm) { case OPS_PKA_DSA: - ret=ops_dsa_verify(hash,length,&sig->info.signature.dsa,&signer->key.dsa); + ret=ops_dsa_verify(hash, length, &sig->info.signature.dsa, + &signer->key.dsa); break; case OPS_PKA_RSA: - ret=rsa_verify(sig->info.hash_algorithm,hash,length,&sig->info.signature.rsa, - &signer->key.rsa); + ret=rsa_verify(sig->info.hash_algorithm, hash, length, + &sig->info.signature.rsa, &signer->key.rsa); break; default: @@ -428,9 +429,9 @@ static ops_boolean_t hash_and_check_signature(ops_hash_t *hash, int n; unsigned char hashout[OPS_MAX_HASH_SIZE]; - n=hash->finish(hash,hashout); + n=hash->finish(hash, hashout); - return ops_check_signature(hashout,n,sig,signer); + return ops_check_signature(hashout, n, sig, signer); } static ops_boolean_t finalise_signature(ops_hash_t *hash, @@ -438,8 +439,8 @@ static ops_boolean_t finalise_signature(ops_hash_t *hash, const ops_public_key_t *signer, const unsigned char *raw_packet) { - hash_add_trailer(hash,sig,raw_packet); - return hash_and_check_signature(hash,sig,signer); + hash_add_trailer(hash, sig, raw_packet); + return hash_and_check_signature(hash, sig, signer); } /** @@ -464,16 +465,16 @@ ops_check_user_id_certification_signature(const ops_public_key_t *key, ops_hash_t hash; size_t user_id_len=strlen((char *)id->user_id); - init_key_signature(&hash,sig,key); + init_key_signature(&hash, sig, key); if(sig->info.version == OPS_V4) { - ops_hash_add_int(&hash,0xb4,1); - ops_hash_add_int(&hash,user_id_len,4); + ops_hash_add_int(&hash, 0xb4, 1); + ops_hash_add_int(&hash, user_id_len, 4); } - hash.add(&hash,id->user_id,user_id_len); + hash.add(&hash, id->user_id, user_id_len); - return finalise_signature(&hash,sig,signer,raw_packet); + return finalise_signature(&hash, sig, signer, raw_packet); } /** @@ -490,23 +491,23 @@ ops_check_user_id_certification_signature(const ops_public_key_t *key, */ ops_boolean_t ops_check_user_attribute_certification_signature(const ops_public_key_t *key, - const ops_user_attribute_t *attribute, - const ops_signature_t *sig, - const ops_public_key_t *signer, - const unsigned char *raw_packet) + const ops_user_attribute_t *attribute, + const ops_signature_t *sig, + const ops_public_key_t *signer, + const unsigned char *raw_packet) { ops_hash_t hash; - init_key_signature(&hash,sig,key); + init_key_signature(&hash, sig, key); if(sig->info.version == OPS_V4) { - ops_hash_add_int(&hash,0xd1,1); - ops_hash_add_int(&hash,attribute->data.len,4); + ops_hash_add_int(&hash, 0xd1, 1); + ops_hash_add_int(&hash, attribute->data.len, 4); } - hash.add(&hash,attribute->data.contents,attribute->data.len); + hash.add(&hash, attribute->data.contents, attribute->data.len); - return finalise_signature(&hash,sig,signer,raw_packet); + return finalise_signature(&hash, sig, signer, raw_packet); } /** @@ -530,10 +531,10 @@ ops_check_subkey_signature(const ops_public_key_t *key, { ops_hash_t hash; - init_key_signature(&hash,sig,key); - hash_add_key(&hash,subkey); + init_key_signature(&hash, sig, key); + hash_add_key(&hash, subkey); - return finalise_signature(&hash,sig,signer,raw_packet); + return finalise_signature(&hash, sig, signer, raw_packet); } /** @@ -555,8 +556,8 @@ ops_check_direct_signature(const ops_public_key_t *key, { ops_hash_t hash; - init_key_signature(&hash,sig,key); - return finalise_signature(&hash,sig,signer,raw_packet); + init_key_signature(&hash, sig, key); + return finalise_signature(&hash, sig, signer, raw_packet); } /** @@ -572,14 +573,13 @@ ops_check_direct_signature(const ops_public_key_t *key, * \return ops_true if OK; else ops_false */ ops_boolean_t -ops_check_hash_signature(ops_hash_t *hash, - const ops_signature_t *sig, +ops_check_hash_signature(ops_hash_t *hash, const ops_signature_t *sig, const ops_public_key_t *signer) { if(sig->info.hash_algorithm != hash->algorithm) return ops_false; - return finalise_signature(hash,sig,signer,NULL); + return finalise_signature(hash, sig, signer, NULL); } static void start_signature_in_mem(ops_create_signature_t *sig) @@ -587,18 +587,18 @@ static void start_signature_in_mem(ops_create_signature_t *sig) // since this has subpackets and stuff, we have to buffer the whole // thing to get counts before writing. sig->mem=ops_memory_new(); - ops_memory_init(sig->mem,100); - ops_writer_set_memory(sig->info,sig->mem); + ops_memory_init(sig->mem, 100); + ops_writer_set_memory(sig->info, sig->mem); // write nearly up to the first subpacket - ops_write_scalar(sig->sig.info.version,1,sig->info); - ops_write_scalar(sig->sig.info.type,1,sig->info); - ops_write_scalar(sig->sig.info.key_algorithm,1,sig->info); - ops_write_scalar(sig->sig.info.hash_algorithm,1,sig->info); + ops_write_scalar(sig->sig.info.version, 1, sig->info); + ops_write_scalar(sig->sig.info.type, 1, sig->info); + ops_write_scalar(sig->sig.info.key_algorithm, 1, sig->info); + ops_write_scalar(sig->sig.info.hash_algorithm, 1, sig->info); // dummy hashed subpacket count sig->hashed_count_offset=ops_memory_get_length(sig->mem); - ops_write_scalar(0,2,sig->info); + ops_write_scalar(0, 2, sig->info); } /** @@ -628,11 +628,11 @@ void ops_signature_start_key_signature(ops_create_signature_t *sig, sig->hashed_data_length=-1; - init_key_signature(&sig->hash,&sig->sig,key); + init_key_signature(&sig->hash, &sig->sig, key); - ops_hash_add_int(&sig->hash,0xb4,1); - ops_hash_add_int(&sig->hash,strlen((char *)id->user_id),4); - sig->hash.add(&sig->hash,id->user_id,strlen((char *)id->user_id)); + ops_hash_add_int(&sig->hash, 0xb4, 1); + ops_hash_add_int(&sig->hash, strlen((char *)id->user_id), 4); + sig->hash.add(&sig->hash, id->user_id, strlen((char *)id->user_id)); start_signature_in_mem(sig); } @@ -649,9 +649,9 @@ void ops_signature_start_key_signature(ops_create_signature_t *sig, */ static void ops_signature_start_signature(ops_create_signature_t *sig, - const ops_secret_key_t *key, - const ops_hash_algorithm_t hash, - const ops_sig_type_t type) + const ops_secret_key_t *key, + const ops_hash_algorithm_t hash, + const ops_sig_type_t type) { sig->info=ops_create_info_new(); @@ -666,8 +666,8 @@ static void ops_signature_start_signature(ops_create_signature_t *sig, sig->hashed_data_length=-1; if (debug) - { fprintf(stderr,"initialising hash for sig in mem\n"); } - initialise_hash(&sig->hash,&sig->sig); + { fprintf(stderr, "initialising hash for sig in mem\n"); } + initialise_hash(&sig->hash, &sig->sig); start_signature_in_mem(sig); } @@ -676,11 +676,11 @@ static void ops_signature_start_signature(ops_create_signature_t *sig, * \brief Setup to start a cleartext's signature */ void ops_signature_start_cleartext_signature(ops_create_signature_t *sig, - const ops_secret_key_t *key, - const ops_hash_algorithm_t hash, - const ops_sig_type_t type) + const ops_secret_key_t *key, + const ops_hash_algorithm_t hash, + const ops_sig_type_t type) { - ops_signature_start_signature(sig,key,hash,type); + ops_signature_start_signature(sig, key, hash, type); } /** @@ -688,11 +688,11 @@ void ops_signature_start_cleartext_signature(ops_create_signature_t *sig, * \brief Setup to start a message's signature */ void ops_signature_start_message_signature(ops_create_signature_t *sig, - const ops_secret_key_t *key, - const ops_hash_algorithm_t hash, - const ops_sig_type_t type) + const ops_secret_key_t *key, + const ops_hash_algorithm_t hash, + const ops_sig_type_t type) { - ops_signature_start_signature(sig,key,hash,type); + ops_signature_start_signature(sig, key, hash, type); } /** @@ -704,12 +704,12 @@ void ops_signature_start_message_signature(ops_create_signature_t *sig, * \param buf The plaintext data. * \param length The amount of plaintext data. */ -void ops_signature_add_data(ops_create_signature_t *sig,const void *buf, +void ops_signature_add_data(ops_create_signature_t *sig, const void *buf, size_t length) { if (debug) - { fprintf(stderr,"ops_signature_add_data adds to hash\n"); } - sig->hash.add(&sig->hash,buf,length); + { fprintf(stderr, "ops_signature_add_data adds to hash\n"); } + sig->hash.add(&sig->hash, buf, length); } /** @@ -724,11 +724,11 @@ ops_boolean_t ops_signature_hashed_subpackets_end(ops_create_signature_t *sig) { sig->hashed_data_length=ops_memory_get_length(sig->mem) -sig->hashed_count_offset-2; - ops_memory_place_int(sig->mem,sig->hashed_count_offset, - sig->hashed_data_length,2); + ops_memory_place_int(sig->mem, sig->hashed_count_offset, + sig->hashed_data_length, 2); // dummy unhashed subpacket count sig->unhashed_count_offset=ops_memory_get_length(sig->mem); - return ops_write_scalar(0,2,sig->info); + return ops_write_scalar(0, 2, sig->info); } /** @@ -743,8 +743,10 @@ ops_boolean_t ops_signature_hashed_subpackets_end(ops_create_signature_t *sig) * */ -ops_boolean_t ops_write_signature(ops_create_signature_t *sig, const ops_public_key_t *key, - const ops_secret_key_t *skey, ops_create_info_t *info) +ops_boolean_t ops_write_signature(ops_create_signature_t *sig, + const ops_public_key_t *key, + const ops_secret_key_t *skey, + ops_create_info_t *info) { ops_boolean_t rtn=ops_false; size_t l=ops_memory_get_length(sig->mem); @@ -763,31 +765,34 @@ ops_boolean_t ops_write_signature(ops_create_signature_t *sig, const ops_public_ break; default: - fprintf(stderr,"Unsupported algorithm %d\n", skey->public_key.algorithm); + fprintf(stderr, "Unsupported algorithm %d\n", + skey->public_key.algorithm); assert(0); } assert(sig->hashed_data_length != (unsigned)-1); - ops_memory_place_int(sig->mem,sig->unhashed_count_offset, - l-sig->unhashed_count_offset-2,2); + ops_memory_place_int(sig->mem, sig->unhashed_count_offset, + l-sig->unhashed_count_offset-2, 2); // add the packet from version number to end of hashed subpackets if (debug) - { fprintf(stderr, "--- Adding packet to hash from version number to hashed subpkts\n"); } + { fprintf(stderr, "--- Adding packet to hash from version number to" + " hashed subpkts\n"); } - sig->hash.add(&sig->hash,ops_memory_get_data(sig->mem), + sig->hash.add(&sig->hash, ops_memory_get_data(sig->mem), sig->unhashed_count_offset); // add final trailer - ops_hash_add_int(&sig->hash,sig->sig.info.version,1); - ops_hash_add_int(&sig->hash,0xff,1); + ops_hash_add_int(&sig->hash, sig->sig.info.version, 1); + ops_hash_add_int(&sig->hash, 0xff, 1); // +6 for version, type, pk alg, hash alg, hashed subpacket length - ops_hash_add_int(&sig->hash,sig->hashed_data_length+6,4); + ops_hash_add_int(&sig->hash, sig->hashed_data_length+6, 4); if (debug) - { fprintf(stderr, "--- Finished adding packet to hash from version number to hashed subpkts\n"); } + { fprintf(stderr, "--- Finished adding packet to hash from version" + " number to hashed subpkts\n"); } // XXX: technically, we could figure out how big the signature is // and write it directly to the output instead of via memory. @@ -796,34 +801,31 @@ ops_boolean_t ops_write_signature(ops_create_signature_t *sig, const ops_public_ case OPS_PKA_RSA: case OPS_PKA_RSA_ENCRYPT_ONLY: case OPS_PKA_RSA_SIGN_ONLY: - rsa_sign(&sig->hash,&key->key.rsa,&skey->key.rsa,sig->info); + rsa_sign(&sig->hash, &key->key.rsa, &skey->key.rsa, sig->info); break; case OPS_PKA_DSA: - dsa_sign(&sig->hash,&key->key.dsa,&skey->key.dsa,sig->info); + dsa_sign(&sig->hash, &key->key.dsa, &skey->key.dsa, sig->info); break; default: - fprintf(stderr,"Unsupported algorithm %d\n", skey->public_key.algorithm); + fprintf(stderr, "Unsupported algorithm %d\n", + skey->public_key.algorithm); assert(0); } - - - rtn=ops_write_ptag(OPS_PTAG_CT_SIGNATURE,info); - if (rtn!=ops_false) + rtn=ops_write_ptag(OPS_PTAG_CT_SIGNATURE, info); + if (rtn) { l=ops_memory_get_length(sig->mem); - rtn = ops_write_length(l,info) - && ops_write(ops_memory_get_data(sig->mem),l,info); + rtn = ops_write_length(l, info) + && ops_write(ops_memory_get_data(sig->mem), l, info); } ops_memory_free(sig->mem); - if (rtn==ops_false) - { - OPS_ERROR(&info->errors,OPS_E_W,"Cannot write signature"); - } + if (!rtn) + OPS_ERROR(&info->errors, OPS_E_W, "Cannot write signature"); return rtn; } @@ -835,10 +837,11 @@ ops_boolean_t ops_write_signature(ops_create_signature_t *sig, const ops_public_ * \param sig * \param when */ -ops_boolean_t ops_signature_add_creation_time(ops_create_signature_t *sig,time_t when) +ops_boolean_t ops_signature_add_creation_time(ops_create_signature_t *sig, + time_t when) { - return ops_write_ss_header(5,OPS_PTAG_SS_CREATION_TIME,sig->info) - && ops_write_scalar(when,4,sig->info); + return ops_write_ss_header(5, OPS_PTAG_SS_CREATION_TIME, sig->info) + && ops_write_scalar(when, 4, sig->info); } /** @@ -850,11 +853,13 @@ ops_boolean_t ops_signature_add_creation_time(ops_create_signature_t *sig,time_t * \param keyid */ -ops_boolean_t ops_signature_add_issuer_key_id(ops_create_signature_t *sig, - const unsigned char keyid[OPS_KEY_ID_SIZE]) +ops_boolean_t +ops_signature_add_issuer_key_id(ops_create_signature_t *sig, + const unsigned char keyid[OPS_KEY_ID_SIZE]) { - return ops_write_ss_header(OPS_KEY_ID_SIZE+1,OPS_PTAG_SS_ISSUER_KEY_ID,sig->info) - && ops_write(keyid,OPS_KEY_ID_SIZE,sig->info); + return ops_write_ss_header(OPS_KEY_ID_SIZE+1, OPS_PTAG_SS_ISSUER_KEY_ID, + sig->info) + && ops_write(keyid, OPS_KEY_ID_SIZE, sig->info); } /** @@ -868,8 +873,8 @@ ops_boolean_t ops_signature_add_issuer_key_id(ops_create_signature_t *sig, void ops_signature_add_primary_user_id(ops_create_signature_t *sig, ops_boolean_t primary) { - ops_write_ss_header(2,OPS_PTAG_SS_PRIMARY_USER_ID,sig->info); - ops_write_scalar(primary,1,sig->info); + ops_write_ss_header(2, OPS_PTAG_SS_PRIMARY_USER_ID, sig->info); + ops_write_scalar(primary, 1, sig->info); } /** @@ -883,26 +888,28 @@ void ops_signature_add_primary_user_id(ops_create_signature_t *sig, ops_hash_t *ops_signature_get_hash(ops_create_signature_t *sig) { return &sig->hash; } -static int open_output_file(ops_create_info_t **cinfo, const char* input_filename, const char* output_filename, const ops_boolean_t use_armour, const ops_boolean_t overwrite) +static int open_output_file(ops_create_info_t **cinfo, + const char* input_filename, + const char* output_filename, + const ops_boolean_t use_armour, + const ops_boolean_t overwrite) { int fd_out; // setup output file if (output_filename) - { fd_out=ops_setup_file_write(cinfo, output_filename, overwrite); - } else { char *myfilename=NULL; unsigned filenamelen=strlen(input_filename)+4+1; myfilename=ops_mallocz(filenamelen); if (use_armour) - snprintf(myfilename,filenamelen,"%s.asc",input_filename); + snprintf(myfilename, filenamelen, "%s.asc", input_filename); else - snprintf(myfilename,filenamelen,"%s.gpg",input_filename); - fd_out=ops_setup_file_write(cinfo, myfilename, overwrite); + snprintf(myfilename, filenamelen, "%s.gpg", input_filename); + fd_out=ops_setup_file_write(cinfo, myfilename, overwrite); free(myfilename); } @@ -929,7 +936,10 @@ static int open_output_file(ops_create_info_t **cinfo, const char* input_filenam } \endcode */ -ops_boolean_t ops_sign_file_as_cleartext(const char* input_filename, const char* output_filename, const ops_secret_key_t *skey, const ops_boolean_t overwrite) +ops_boolean_t ops_sign_file_as_cleartext(const char* input_filename, + const char* output_filename, + const ops_secret_key_t *skey, + const ops_boolean_t overwrite) { // \todo allow choice of hash algorithams // enforce use of SHA1 for now @@ -946,10 +956,10 @@ ops_boolean_t ops_sign_file_as_cleartext(const char* input_filename, const char* ops_boolean_t use_armour=ops_true; // open file to sign -#ifdef WIN32 - fd_in=open(input_filename,O_RDONLY | O_BINARY); +#ifdef WINDOWS_SYS + fd_in=open(input_filename, O_RDONLY | O_BINARY); #else - fd_in=open(input_filename,O_RDONLY); + fd_in=open(input_filename, O_RDONLY ); #endif if(fd_in < 0) { @@ -958,7 +968,8 @@ ops_boolean_t ops_sign_file_as_cleartext(const char* input_filename, const char* // set up output file - fd_out=open_output_file(&cinfo, input_filename, output_filename, use_armour, overwrite); + fd_out=open_output_file(&cinfo, input_filename, output_filename, use_armour, + overwrite); if (fd_out < 0) { @@ -971,14 +982,15 @@ ops_boolean_t ops_sign_file_as_cleartext(const char* input_filename, const char* if (!sig) { close (fd_in); - ops_teardown_file_write(cinfo,fd_out); + ops_teardown_file_write(cinfo, fd_out); return ops_false; } // \todo could add more error detection here - ops_signature_start_cleartext_signature(sig,skey,OPS_HASH_SHA1,OPS_SIG_BINARY); - if (ops_writer_push_clearsigned(cinfo,sig)!=ops_true) - { return ops_false; } + ops_signature_start_cleartext_signature(sig, skey, + OPS_HASH_SHA1, OPS_SIG_BINARY); + if (!ops_writer_push_clearsigned(cinfo, sig)) + return ops_false; // Do the signing @@ -986,11 +998,11 @@ ops_boolean_t ops_sign_file_as_cleartext(const char* input_filename, const char* { int n=0; - n=read(fd_in,buf,sizeof(buf)); + n=read(fd_in, buf, sizeof(buf)); if (!n) break; assert(n>=0); - ops_write(buf,n,cinfo); + ops_write(buf, n, cinfo); } close(fd_in); @@ -998,25 +1010,23 @@ ops_boolean_t ops_sign_file_as_cleartext(const char* input_filename, const char* // - creation time // - key id rtn = ops_writer_switch_to_armoured_signature(cinfo) - && ops_signature_add_creation_time(sig,time(NULL)); - if (rtn==ops_false) + && ops_signature_add_creation_time(sig, time(NULL)); + if (!rtn) { - ops_teardown_file_write(cinfo,fd_out); + ops_teardown_file_write(cinfo, fd_out); return ops_false; } - ops_keyid(keyid,&skey->public_key); + ops_keyid(keyid, &skey->public_key); - rtn = ops_signature_add_issuer_key_id(sig,keyid) + rtn = ops_signature_add_issuer_key_id(sig, keyid) && ops_signature_hashed_subpackets_end(sig) - && ops_write_signature(sig,&skey->public_key,skey,cinfo); + && ops_write_signature(sig, &skey->public_key, skey, cinfo); - ops_teardown_file_write(cinfo,fd_out); + ops_teardown_file_write(cinfo, fd_out); - if (rtn==ops_false) - { - OPS_ERROR(&cinfo->errors,OPS_E_W,"Cannot sign file as cleartext"); - } + if (!rtn) + OPS_ERROR(&cinfo->errors, OPS_E_W, "Cannot sign file as cleartext"); return rtn; } @@ -1049,7 +1059,9 @@ ops_boolean_t ops_sign_file_as_cleartext(const char* input_filename, const char* } \endcode */ -ops_boolean_t ops_sign_buf_as_cleartext(const char* cleartext, const size_t len, ops_memory_t** signed_cleartext, const ops_secret_key_t *skey) +ops_boolean_t ops_sign_buf_as_cleartext(const char* cleartext, const size_t len, + ops_memory_t** signed_cleartext, + const ops_secret_key_t *skey) { ops_boolean_t rtn=ops_false; @@ -1061,17 +1073,16 @@ ops_boolean_t ops_sign_buf_as_cleartext(const char* cleartext, const size_t len, ops_create_info_t *cinfo=NULL; - assert(*signed_cleartext==NULL); + assert(*signed_cleartext == NULL); // set up signature sig=ops_create_signature_new(); if (!sig) - { return ops_false; - } // \todo could add more error detection here - ops_signature_start_cleartext_signature(sig,skey,OPS_HASH_SHA1,OPS_SIG_BINARY); + ops_signature_start_cleartext_signature(sig, skey, OPS_HASH_SHA1, + OPS_SIG_BINARY); // set up output file ops_setup_memory_write(&cinfo, signed_cleartext, len); @@ -1080,21 +1091,19 @@ ops_boolean_t ops_sign_buf_as_cleartext(const char* cleartext, const size_t len, // add signature with subpackets: // - creation time // - key id - rtn = ops_writer_push_clearsigned(cinfo,sig) - && ops_write(cleartext,len,cinfo) + rtn = ops_writer_push_clearsigned(cinfo, sig) + && ops_write(cleartext, len, cinfo) && ops_writer_switch_to_armoured_signature(cinfo) - && ops_signature_add_creation_time(sig,time(NULL)); + && ops_signature_add_creation_time(sig, time(NULL)); - if (rtn==ops_false) - { + if (!rtn) return ops_false; - } - ops_keyid(keyid,&skey->public_key); + ops_keyid(keyid, &skey->public_key); - rtn = ops_signature_add_issuer_key_id(sig,keyid) + rtn = ops_signature_add_issuer_key_id(sig, keyid) && ops_signature_hashed_subpackets_end(sig) - && ops_write_signature(sig,&skey->public_key,skey,cinfo) + && ops_write_signature(sig, &skey->public_key, skey, cinfo) && ops_writer_close(cinfo); // Note: the calling function must free signed_cleartext @@ -1127,7 +1136,11 @@ void example(const ops_secret_key_t *skey) } \endcode */ -ops_boolean_t ops_sign_file(const char* input_filename, const char* output_filename, const ops_secret_key_t *skey, const ops_boolean_t use_armour, const ops_boolean_t overwrite) +ops_boolean_t ops_sign_file(const char* input_filename, + const char* output_filename, + const ops_secret_key_t *skey, + const ops_boolean_t use_armour, + const ops_boolean_t overwrite) { // \todo allow choice of hash algorithams // enforce use of SHA1 for now @@ -1147,13 +1160,14 @@ ops_boolean_t ops_sign_file(const char* input_filename, const char* output_filen // read input file into buf int errnum; - mem_buf=ops_write_mem_from_file(input_filename,&errnum); + mem_buf=ops_write_mem_from_file(input_filename, &errnum); if (errnum) return ops_false; // setup output file - fd_out=open_output_file(&cinfo, input_filename, output_filename, use_armour, overwrite); + fd_out=open_output_file(&cinfo, input_filename, output_filename, use_armour, + overwrite); if (fd_out < 0) { @@ -1177,31 +1191,34 @@ ops_boolean_t ops_sign_file(const char* input_filename, const char* output_filen // hash file contents hash=ops_signature_get_hash(sig); - hash->add(hash, ops_memory_get_data(mem_buf), ops_memory_get_length(mem_buf)); + hash->add(hash, ops_memory_get_data(mem_buf), + ops_memory_get_length(mem_buf)); // output file contents as Literal Data packet if (debug) - { fprintf(stderr,"** Writing out data now\n"); } + fprintf(stderr,"** Writing out data now\n"); - ops_write_literal_data_from_buf(ops_memory_get_data(mem_buf), ops_memory_get_length(mem_buf), OPS_LDT_BINARY, cinfo); + ops_write_literal_data_from_buf(ops_memory_get_data(mem_buf), + ops_memory_get_length(mem_buf), + OPS_LDT_BINARY, cinfo); if (debug) - { fprintf(stderr,"** After Writing out data now\n");} + fprintf(stderr, "** After Writing out data now\n"); // add subpackets to signature // - creation time // - key id - ops_signature_add_creation_time(sig,time(NULL)); + ops_signature_add_creation_time(sig, time(NULL)); - ops_keyid(keyid,&skey->public_key); - ops_signature_add_issuer_key_id(sig,keyid); + ops_keyid(keyid, &skey->public_key); + ops_signature_add_issuer_key_id(sig, keyid); ops_signature_hashed_subpackets_end(sig); // write out sig - ops_write_signature(sig,&skey->public_key,skey,cinfo); + ops_write_signature(sig, &skey->public_key, skey, cinfo); ops_teardown_file_write(cinfo, fd_out); @@ -1246,7 +1263,10 @@ void example(const ops_secret_key_t *skey) } \endcode */ -ops_memory_t* ops_sign_buf(const void* input, const size_t input_len, const ops_sig_type_t sig_type, const ops_secret_key_t *skey, const ops_boolean_t use_armour) +ops_memory_t* ops_sign_buf(const void* input, const size_t input_len, + const ops_sig_type_t sig_type, + const ops_secret_key_t *skey, + const ops_boolean_t use_armour) { // \todo allow choice of hash algorithams // enforce use of SHA1 for now @@ -1262,7 +1282,7 @@ ops_memory_t* ops_sign_buf(const void* input, const size_t input_len, const ops_ ops_hash_t* hash=NULL; // setup literal data packet type - if (sig_type==OPS_SIG_BINARY) + if (sig_type == OPS_SIG_BINARY) ld_type=OPS_LDT_BINARY; else ld_type=OPS_LDT_TEXT; @@ -1279,7 +1299,7 @@ ops_memory_t* ops_sign_buf(const void* input, const size_t input_len, const ops_ ops_writer_push_armoured_message(cinfo); if (debug) - { fprintf(stderr, "** Writing out one pass sig\n"); } + fprintf(stderr, "** Writing out one pass sig\n"); // write one_pass_sig ops_write_one_pass_sig(skey, hash_alg, sig_type, cinfo); @@ -1291,26 +1311,26 @@ ops_memory_t* ops_sign_buf(const void* input, const size_t input_len, const ops_ // output file contents as Literal Data packet if (debug) - { fprintf(stderr,"** Writing out data now\n"); } + fprintf(stderr,"** Writing out data now\n"); ops_write_literal_data_from_buf(input, input_len, ld_type, cinfo); if (debug) - { fprintf(stderr,"** After Writing out data now\n");} + fprintf(stderr,"** After Writing out data now\n"); // add subpackets to signature // - creation time // - key id - ops_signature_add_creation_time(sig,time(NULL)); + ops_signature_add_creation_time(sig, time(NULL)); - ops_keyid(keyid,&skey->public_key); - ops_signature_add_issuer_key_id(sig,keyid); + ops_keyid(keyid, &skey->public_key); + ops_signature_add_issuer_key_id(sig, keyid); ops_signature_hashed_subpackets_end(sig); // write out sig - ops_write_signature(sig,&skey->public_key,skey,cinfo); + ops_write_signature(sig, &skey->public_key, skey, cinfo); // tidy up ops_writer_close(cinfo); @@ -1320,4 +1340,100 @@ ops_memory_t* ops_sign_buf(const void* input, const size_t input_len, const ops_ return mem; } +typedef struct { + ops_create_signature_t *signature; + const ops_secret_key_t *skey; + ops_hash_algorithm_t hash_alg; + ops_sig_type_t sig_type; +} signature_arg_t; + +static ops_boolean_t stream_signature_writer(const unsigned char *src, + unsigned length, + ops_error_t **errors, + ops_writer_info_t *winfo) + { + signature_arg_t* arg = ops_writer_get_arg(winfo); + // Add the input data to the hash. At the end, we will use the hash + // to generate a signature packet. + ops_hash_t* hash = ops_signature_get_hash(arg->signature); + hash->add(hash, src, length); + + return ops_stacked_write(src, length, errors, winfo); + } + +static ops_boolean_t stream_signature_write_trailer(ops_create_info_t *cinfo, + void *data) + { + signature_arg_t* arg = data; + unsigned char keyid[OPS_KEY_ID_SIZE]; + + // add subpackets to signature + // - creation time + // - key id + ops_signature_add_creation_time(arg->signature,time(NULL)); + ops_keyid(keyid, &arg->skey->public_key); + ops_signature_add_issuer_key_id(arg->signature, keyid); + ops_signature_hashed_subpackets_end(arg->signature); + + // write out signature + return ops_write_signature(arg->signature, &arg->skey->public_key, + arg->skey, cinfo); + } + +static void stream_signature_destroyer(ops_writer_info_t *winfo) + { + signature_arg_t* arg = ops_writer_get_arg(winfo); + ops_create_signature_delete(arg->signature); + free(arg); + } + +/** +\ingroup Core_WritePackets +\brief Pushes a signed writer onto the stack. + +Data written will be encoded as a onepass signature packet, followed +by a literal packet, followed by a signature packet. Once this writer +has been added to the stack, cleartext can be written straight to the +output, and it will be encoded as a literal packet and signed. + +\param cinfo Write settings +\param sig_type the type of input to be signed (text or binary) +\param skey the key used to sign the stream. +\return false if the initial onepass packet could not be created. +*/ +ops_boolean_t ops_writer_push_signed(ops_create_info_t *cinfo, + const ops_sig_type_t sig_type, + const ops_secret_key_t *skey) + { + // \todo allow choice of hash algorithams + // enforce use of SHA1 for now + + // Create arg to be used with this writer + // Remember to free this in the destroyer + signature_arg_t *signature_arg = ops_mallocz(sizeof *signature_arg); + signature_arg->signature = ops_create_signature_new(); + signature_arg->hash_alg = OPS_HASH_SHA1; + signature_arg->skey = skey; + signature_arg->sig_type = sig_type; + ops_signature_start_message_signature(signature_arg->signature, + signature_arg->skey, + signature_arg->hash_alg, + signature_arg->sig_type); + + if (!ops_write_one_pass_sig(signature_arg->skey, + signature_arg->hash_alg, + signature_arg->sig_type, + cinfo)) + return ops_false; + + ops_writer_push_partial_with_trailer(0, cinfo, OPS_PTAG_CT_LITERAL_DATA, + write_literal_header, NULL, + stream_signature_write_trailer, + signature_arg); + // And push writer on stack + ops_writer_push(cinfo, stream_signature_writer, NULL, + stream_signature_destroyer,signature_arg); + return ops_true; + } + // EOF diff --git a/openpgpsdk/src/src.pro b/openpgpsdk/src/src.pro index 973fa33e1..22e397690 100644 --- a/openpgpsdk/src/src.pro +++ b/openpgpsdk/src/src.pro @@ -41,6 +41,8 @@ SOURCES += accumulate.c \ validate.c \ writer.c \ writer_armour.c \ + writer_partial.c \ + writer_literal.c \ writer_encrypt.c \ writer_encrypt_se_ip.c \ writer_fd.c \ diff --git a/openpgpsdk/src/symmetric.c b/openpgpsdk/src/symmetric.c index 9b37e595f..30dc0b74b 100644 --- a/openpgpsdk/src/symmetric.c +++ b/openpgpsdk/src/symmetric.c @@ -24,9 +24,12 @@ #include #include #ifndef OPENSSL_NO_IDEA -#include +# include #endif #include +#ifndef OPENSSL_NO_CAMELLIA +# include +#endif #include #include "parse_local.h" @@ -278,6 +281,138 @@ static const ops_crypt_t aes256= TRAILER }; +#ifndef OPENSSL_NO_CAMELLIA + +// CAMELLIA with 128-bit key + +#define KEYBITS_CAMELLIA128 128 + +static void camellia128_init(ops_crypt_t *crypt) + { + if (crypt->encrypt_key) + free(crypt->encrypt_key); + crypt->encrypt_key=malloc(sizeof(CAMELLIA_KEY)); + if (Camellia_set_key(crypt->key,KEYBITS_CAMELLIA128,crypt->encrypt_key)) + fprintf(stderr,"camellia128_init: Error setting encrypt_key\n"); + + if (crypt->decrypt_key) + free(crypt->decrypt_key); + crypt->decrypt_key=malloc(sizeof(CAMELLIA_KEY)); + if (Camellia_set_key(crypt->key,KEYBITS_CAMELLIA128,crypt->decrypt_key)) + fprintf(stderr,"camellia128_init: Error setting decrypt_key\n"); + } + +static void camellia_block_encrypt(ops_crypt_t *crypt,void *out,const void *in) + { Camellia_encrypt(in,out,crypt->encrypt_key); } + +static void camellia_block_decrypt(ops_crypt_t *crypt,void *out,const void *in) + { Camellia_decrypt(in,out,crypt->decrypt_key); } + +static void camellia_cfb_encrypt(ops_crypt_t *crypt,void *out,const void *in, size_t count) + { + Camellia_cfb128_encrypt(in,out,count, + crypt->encrypt_key, crypt->iv, (int *)&crypt->num, + CAMELLIA_ENCRYPT); + } + +static void camellia_cfb_decrypt(ops_crypt_t *crypt,void *out,const void *in, size_t count) + { + Camellia_cfb128_encrypt(in,out,count, + crypt->encrypt_key, crypt->iv, (int *)&crypt->num, + CAMELLIA_DECRYPT); + } + +static const ops_crypt_t camellia128= + { + OPS_SA_CAMELLIA_128, + CAMELLIA_BLOCK_SIZE, + KEYBITS_CAMELLIA128/8, + std_set_iv, + std_set_key, + camellia128_init, + std_resync, + camellia_block_encrypt, + camellia_block_decrypt, + camellia_cfb_encrypt, + camellia_cfb_decrypt, + std_finish, + TRAILER + }; + +// CAMELLIA with 192-bit key + +#define KEYBITS_CAMELLIA192 192 + +static void camellia192_init(ops_crypt_t *crypt) + { + if (crypt->encrypt_key) + free(crypt->encrypt_key); + crypt->encrypt_key=malloc(sizeof(CAMELLIA_KEY)); + if (Camellia_set_key(crypt->key,KEYBITS_CAMELLIA192,crypt->encrypt_key)) + fprintf(stderr,"camellia192_init: Error setting encrypt_key\n"); + + if (crypt->decrypt_key) + free(crypt->decrypt_key); + crypt->decrypt_key=malloc(sizeof(CAMELLIA_KEY)); + if (Camellia_set_key(crypt->key,KEYBITS_CAMELLIA192,crypt->decrypt_key)) + fprintf(stderr,"camellia192_init: Error setting decrypt_key\n"); + } + +static const ops_crypt_t camellia192= + { + OPS_SA_CAMELLIA_192, + CAMELLIA_BLOCK_SIZE, + KEYBITS_CAMELLIA192/8, + std_set_iv, + std_set_key, + camellia192_init, + std_resync, + camellia_block_encrypt, + camellia_block_decrypt, + camellia_cfb_encrypt, + camellia_cfb_decrypt, + std_finish, + TRAILER + }; + +// CAMELLIA with 256-bit key + +#define KEYBITS_CAMELLIA256 256 + +static void camellia256_init(ops_crypt_t *crypt) + { + if (crypt->encrypt_key) + free(crypt->encrypt_key); + crypt->encrypt_key=malloc(sizeof(CAMELLIA_KEY)); + if (Camellia_set_key(crypt->key,KEYBITS_CAMELLIA256,crypt->encrypt_key)) + fprintf(stderr,"camellia256_init: Error setting encrypt_key\n"); + + if (crypt->decrypt_key) + free(crypt->decrypt_key); + crypt->decrypt_key=malloc(sizeof(CAMELLIA_KEY)); + if (Camellia_set_key(crypt->key,KEYBITS_CAMELLIA256,crypt->decrypt_key)) + fprintf(stderr,"camellia256_init: Error setting decrypt_key\n"); + } + +static const ops_crypt_t camellia256= + { + OPS_SA_CAMELLIA_256, + CAMELLIA_BLOCK_SIZE, + KEYBITS_CAMELLIA256/8, + std_set_iv, + std_set_key, + camellia256_init, + std_resync, + camellia_block_encrypt, + camellia_block_decrypt, + camellia_cfb_encrypt, + camellia_cfb_decrypt, + std_finish, + TRAILER + }; + +#endif // ndef OPENSSL_NO_CAMELLIA + // Triple DES static void tripledes_init(ops_crypt_t *crypt) @@ -309,20 +444,28 @@ static void tripledes_block_decrypt(ops_crypt_t *crypt,void *out, DES_ecb3_encrypt((void *)in,out,&keys[0],&keys[1],&keys[2],DES_DECRYPT); } -static void tripledes_cfb_encrypt(ops_crypt_t *crypt ATTRIBUTE_UNUSED,void *out ATTRIBUTE_UNUSED,const void *in ATTRIBUTE_UNUSED, size_t count ATTRIBUTE_UNUSED) +static void tripledes_cfb_encrypt(ops_crypt_t *crypt ATTRIBUTE_UNUSED, + void *out ATTRIBUTE_UNUSED, + const void *in ATTRIBUTE_UNUSED, + size_t count ATTRIBUTE_UNUSED) { DES_key_schedule *keys=crypt->encrypt_key; DES_ede3_cfb64_encrypt(in,out,count, - &keys[0],&keys[1],&keys[2], (DES_cblock *)crypt->iv, (int *)&crypt->num, - DES_ENCRYPT); + &keys[0],&keys[1],&keys[2], + (DES_cblock *)crypt->iv, (int *)&crypt->num, + DES_ENCRYPT); } -static void tripledes_cfb_decrypt(ops_crypt_t *crypt ATTRIBUTE_UNUSED,void *out ATTRIBUTE_UNUSED,const void *in ATTRIBUTE_UNUSED, size_t count ATTRIBUTE_UNUSED) +static void tripledes_cfb_decrypt(ops_crypt_t *crypt ATTRIBUTE_UNUSED, + void *out ATTRIBUTE_UNUSED, + const void *in ATTRIBUTE_UNUSED, + size_t count ATTRIBUTE_UNUSED) { DES_key_schedule *keys=crypt->encrypt_key; DES_ede3_cfb64_encrypt(in,out,count, - &keys[0],&keys[1],&keys[2], (DES_cblock *)crypt->iv, (int *)&crypt->num, - DES_DECRYPT); + &keys[0],&keys[1],&keys[2], + (DES_cblock *)crypt->iv, (int *)&crypt->num, + DES_DECRYPT); } static const ops_crypt_t tripledes= @@ -360,11 +503,23 @@ static const ops_crypt_t *get_proto(ops_symmetric_algorithm_t alg) case OPS_SA_AES_256: return &aes256; +#ifndef OPENSSL_NO_CAMELLIA + case OPS_SA_CAMELLIA_128: + return &camellia128; + + case OPS_SA_CAMELLIA_192: + return &camellia192; + + case OPS_SA_CAMELLIA_256: + return &camellia256; +#endif // ndef OPENSSL_NO_CAMELLIA + case OPS_SA_TRIPLEDES: return &tripledes; default: - fprintf(stderr,"Unknown algorithm: %d (%s)\n",alg,ops_show_symmetric_algorithm(alg)); + fprintf(stderr,"Unknown algorithm: %d (%s)\n",alg, + ops_show_symmetric_algorithm(alg)); // assert(0); } @@ -483,6 +638,9 @@ ops_boolean_t ops_is_sa_supported(ops_symmetric_algorithm_t alg) { case OPS_SA_AES_128: case OPS_SA_AES_256: + case OPS_SA_CAMELLIA_128: + case OPS_SA_CAMELLIA_192: + case OPS_SA_CAMELLIA_256: case OPS_SA_CAST5: case OPS_SA_TRIPLEDES: #ifndef OPENSSL_NO_IDEA diff --git a/openpgpsdk/src/util.c b/openpgpsdk/src/util.c index 8e4fd3846..88fe3f100 100644 --- a/openpgpsdk/src/util.c +++ b/openpgpsdk/src/util.c @@ -1,4 +1,4 @@ -/* + /* * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) * All rights reserved. * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted @@ -106,52 +106,6 @@ void ops_finish(void) ops_crypto_finish(); } -typedef struct - { - const unsigned char *buffer; - size_t length; - size_t offset; - } reader_mem_arg_t; - -static int mem_reader(void *dest,size_t length,ops_error_t **errors, - ops_reader_info_t *rinfo,ops_parse_cb_info_t *cbinfo) - { - reader_mem_arg_t *arg=ops_reader_get_arg(rinfo); - unsigned n; - - OPS_USED(cbinfo); - OPS_USED(errors); - - if(arg->offset+length > arg->length) - n=arg->length-arg->offset; - else - n=length; - - if(n == 0) - return 0; - - memcpy(dest,arg->buffer+arg->offset,n); - arg->offset+=n; - - return n; - } - -static void mem_destroyer(ops_reader_info_t *rinfo) - { free(ops_reader_get_arg(rinfo)); } - -// Note that its the caller's responsibility to ensure buffer continues to -// exist -void ops_reader_set_memory(ops_parse_info_t *pinfo,const void *buffer, - size_t length) - { - reader_mem_arg_t *arg=malloc(sizeof *arg); - - arg->buffer=buffer; - arg->length=length; - arg->offset=0; - ops_reader_set(pinfo,mem_reader,mem_destroyer,arg); - } - /** \ingroup HighLevel_Misc \brief mallocs and zeros memory diff --git a/openpgpsdk/src/validate.c b/openpgpsdk/src/validate.c index 4070b9181..bcc1a862a 100644 --- a/openpgpsdk/src/validate.c +++ b/openpgpsdk/src/validate.c @@ -321,6 +321,7 @@ ops_validate_key_cb(const ops_parser_content_t *content_,ops_parse_cb_info_t *cb case OPS_PARSER_PTAG: case OPS_PTAG_CT_SIGNATURE_HEADER: case OPS_PARSER_PACKET_END: + case OPS_PTAG_CT_TRUST: break; case OPS_PARSER_CMD_GET_SK_PASSPHRASE: diff --git a/openpgpsdk/src/writer_armour.c b/openpgpsdk/src/writer_armour.c index 09e4bdfc7..847249362 100644 --- a/openpgpsdk/src/writer_armour.c +++ b/openpgpsdk/src/writer_armour.c @@ -34,6 +34,10 @@ static int debug=0; +#define LINE_LENGTH 75 + +static const char newline[] = "\r\n"; + /** * \struct dash_escaped_arg_t */ @@ -164,6 +168,8 @@ ops_boolean_t ops_writer_push_clearsigned(ops_create_info_t *info, */ typedef struct { + size_t chars_written; + ops_boolean_t writing_trailer; unsigned pos; unsigned char t; unsigned checksum; @@ -172,6 +178,17 @@ typedef struct static char b64map[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" "0123456789+/"; +static ops_boolean_t check_newline(base64_arg_t* arg, + ops_error_t **errors, + ops_writer_info_t *winfo) + { + arg->chars_written++; + if (!arg->writing_trailer && arg->chars_written % LINE_LENGTH == 0) + if (!ops_stacked_write(newline, strlen(newline), errors, winfo)) + return ops_false; + return ops_true; + } + static ops_boolean_t base64_writer(const unsigned char *src, unsigned length,ops_error_t **errors, ops_writer_info_t *winfo) @@ -209,6 +226,8 @@ static ops_boolean_t base64_writer(const unsigned char *src, arg->t+=src[n] >> 6; if(!ops_stacked_write(&b64map[arg->t],1,errors,winfo)) return ops_false; + if(!check_newline(arg, errors, winfo)) + return ops_false; /* 00000000 00000000 00XXXXXX */ if(!ops_stacked_write(&b64map[src[n++]&0x3f],1,errors,winfo)) @@ -216,8 +235,9 @@ static ops_boolean_t base64_writer(const unsigned char *src, arg->pos=0; } - } - + if (!check_newline(arg, errors, winfo)) + return ops_false; + } return ops_true; } @@ -246,7 +266,10 @@ static ops_boolean_t signature_finaliser(ops_error_t **errors, c[0]=arg->checksum >> 16; c[1]=arg->checksum >> 8; c[2]=arg->checksum; - /* push the checksum through our own writer */ + /* push the checksum through our own writer. Turn off the + writing_body flag so we don't put a newline in the trailer. + */ + arg->writing_trailer = ops_true; if(!base64_writer(c,3,errors,winfo)) return ops_false; @@ -278,7 +301,7 @@ static ops_boolean_t linebreak_writer(const unsigned char *src, if(arg->pos == BREAKPOS) { - if(!ops_stacked_write("\r\n",2,errors,winfo)) + if(!ops_stacked_write(newline,strlen(newline),errors,winfo)) return ops_false; arg->pos=0; } @@ -348,7 +371,10 @@ static ops_boolean_t armoured_message_finaliser(ops_error_t **errors, c[0]=arg->checksum >> 16; c[1]=arg->checksum >> 8; c[2]=arg->checksum; - /* push the checksum through our own writer */ + /* push the checksum through our own writer. Turn off the + writing_body flag so we don't put a newline in the trailer. + */ + arg->writing_trailer = ops_true; if(!base64_writer(c,3,errors,winfo)) return ops_false; @@ -368,7 +394,7 @@ void ops_writer_push_armoured_message(ops_create_info_t *info) base64_arg_t *base64; ops_write(header,sizeof header-1,info); - ops_write("\r\n",2,info); + ops_write(newline,strlen(newline),info); base64=ops_mallocz(sizeof *base64); base64->checksum=CRC24_INIT; ops_writer_push(info,base64_writer,armoured_message_finaliser,ops_writer_generic_destroyer,base64); @@ -421,7 +447,10 @@ static ops_boolean_t armoured_finaliser(ops_armor_type_t type, ops_error_t **err c[0]=arg->checksum >> 16; c[1]=arg->checksum >> 8; c[2]=arg->checksum; - /* push the checksum through our own writer */ + /* push the checksum through our own writer. Turn off the + writing_body flag so we don't put a newline in the trailer. + */ + arg->writing_trailer = ops_true; if(!base64_writer(c,3,errors,winfo)) return ops_false; diff --git a/openpgpsdk/src/writer_encrypt_se_ip.c b/openpgpsdk/src/writer_encrypt_se_ip.c index 438266da6..0c1b2c78d 100644 --- a/openpgpsdk/src/writer_encrypt_se_ip.c +++ b/openpgpsdk/src/writer_encrypt_se_ip.c @@ -50,7 +50,7 @@ static ops_boolean_t encrypt_se_ip_writer(const unsigned char *src, unsigned length, ops_error_t **errors, ops_writer_info_t *winfo); -static void encrypt_se_ip_destroyer (ops_writer_info_t *winfo); +static void encrypt_se_ip_destroyer(ops_writer_info_t *winfo); // @@ -59,9 +59,9 @@ static void encrypt_se_ip_destroyer (ops_writer_info_t *winfo); \brief Push Encrypted SE IP Writer onto stack */ void ops_writer_push_encrypt_se_ip(ops_create_info_t *cinfo, - const ops_keydata_t *pub_key) + const ops_keydata_t *pub_key) { - ops_crypt_t* encrypt; + ops_crypt_t *encrypt; unsigned char *iv=NULL; // Create arg to be used with this writer @@ -69,9 +69,9 @@ void ops_writer_push_encrypt_se_ip(ops_create_info_t *cinfo, encrypt_se_ip_arg_t *arg=ops_mallocz(sizeof *arg); // Create and write encrypted PK session key - ops_pk_session_key_t* encrypted_pk_session_key; + ops_pk_session_key_t *encrypted_pk_session_key; encrypted_pk_session_key=ops_create_pk_session_key(pub_key); - ops_write_pk_session_key(cinfo,encrypted_pk_session_key); + ops_write_pk_session_key(cinfo, encrypted_pk_session_key); // Setup the arg encrypt=ops_mallocz(sizeof *encrypt); @@ -84,8 +84,10 @@ void ops_writer_push_encrypt_se_ip(ops_create_info_t *cinfo, arg->crypt=encrypt; // And push writer on stack - ops_writer_push(cinfo,encrypt_se_ip_writer,NULL,encrypt_se_ip_destroyer,arg); + ops_writer_push(cinfo, encrypt_se_ip_writer, NULL, encrypt_se_ip_destroyer, + arg); // tidy up + ops_pk_session_key_free(encrypted_pk_session_key); free(encrypted_pk_session_key); free(iv); } @@ -109,13 +111,13 @@ static ops_boolean_t encrypt_se_ip_writer(const unsigned char *src, ops_create_info_t *my_cinfo; const unsigned int bufsz=128; // initial value; gets expanded as necessary - ops_setup_memory_write(&cinfo_literal,&mem_literal,bufsz); - ops_setup_memory_write(&cinfo_compressed,&mem_compressed,bufsz); - ops_setup_memory_write(&my_cinfo,&my_mem,bufsz); + ops_setup_memory_write(&cinfo_literal, &mem_literal, bufsz); + ops_setup_memory_write(&cinfo_compressed, &mem_compressed, bufsz); + ops_setup_memory_write(&my_cinfo, &my_mem, bufsz); // create literal data packet from source data ops_write_literal_data_from_buf(src, length, OPS_LDT_BINARY, cinfo_literal); - assert(ops_memory_get_length(mem_literal)>length); + assert(ops_memory_get_length(mem_literal) > length); // create compressed packet from literal data packet ops_write_compressed(ops_memory_get_data(mem_literal), @@ -126,7 +128,8 @@ static ops_boolean_t encrypt_se_ip_writer(const unsigned char *src, ops_write_se_ip_pktset(ops_memory_get_data(mem_compressed), ops_memory_get_length(mem_compressed), arg->crypt, my_cinfo); - assert(ops_memory_get_length(my_mem)>ops_memory_get_length(mem_compressed)); + assert(ops_memory_get_length(my_mem) + > ops_memory_get_length(mem_compressed)); // now write memory to next writer rtn=ops_stacked_write(ops_memory_get_data(my_mem), @@ -150,9 +153,9 @@ static void encrypt_se_ip_destroyer (ops_writer_info_t *winfo) } ops_boolean_t ops_write_se_ip_pktset(const unsigned char *data, - const unsigned int len, - ops_crypt_t *crypt, - ops_create_info_t *cinfo) + const unsigned int len, + ops_crypt_t *crypt, + ops_create_info_t *cinfo) { unsigned char hashed[SHA_DIGEST_LENGTH]; const size_t sz_mdc=1+1+SHA_DIGEST_LENGTH; @@ -165,9 +168,9 @@ ops_boolean_t ops_write_se_ip_pktset(const unsigned char *data, ops_memory_t *mem_mdc; ops_create_info_t *cinfo_mdc; - if (!ops_write_ptag(OPS_PTAG_CT_SE_IP_DATA,cinfo) - || !ops_write_length(1+sz_buf,cinfo) - || !ops_write_scalar(SE_IP_DATA_VERSION,1,cinfo)) + if (!ops_write_ptag(OPS_PTAG_CT_SE_IP_DATA, cinfo) + || !ops_write_length(1+sz_buf, cinfo) + || !ops_write_scalar(SE_IP_DATA_VERSION, 1, cinfo)) { free (preamble); return 0; @@ -190,7 +193,7 @@ ops_boolean_t ops_write_se_ip_pktset(const unsigned char *data, ops_setup_memory_write(&cinfo_mdc, &mem_mdc,sz_mdc); - ops_calc_mdc_hash(preamble,sz_preamble,data,len,&hashed[0]); + ops_calc_mdc_hash(preamble, sz_preamble, data, len, &hashed[0]); ops_write_mdc(hashed, cinfo_mdc); @@ -203,13 +206,13 @@ ops_boolean_t ops_write_se_ip_pktset(const unsigned char *data, fprintf(stderr,"\nplaintext: "); for (i=0; i +#include + +#ifndef WIN32 +#include +#endif + +#include +#include +#include + +#define MIN_PARTIAL_DATA_LENGTH 512 +#define MAX_PARTIAL_DATA_LENGTH 1073741824 + + +ops_boolean_t write_literal_header(ops_create_info_t *info, + void *header_data) + { + OPS_USED(header_data); + // \todo add the literal type as a header_data argument + // \todo add filename + // \todo add date + // \todo do we need to check text data for line endings ? + + ops_write_scalar(OPS_LDT_BINARY, 1, info); // data type + ops_write_scalar(0, 1, info); // Filename (length = 0) + ops_write_scalar(0, 4, info); // Date (unspecified) + return ops_true; + } + +/** + * \ingroup InternalAPI + * \brief Pushes a literal writer onto the stack. + * \param cinfo the writer info + * \param buf_size the size of the internal buffer. For best + * throughput, write data in multiples of buf_size + */ +void ops_writer_push_literal_with_opts(ops_create_info_t *cinfo, + unsigned int buf_size) + { + // The literal writer doesn't need to transform the data, so we just + // push a partial packet writer onto the stack. This will handle + // the packet length encoding. All we need to provide is a function + // to write the header. + ops_writer_push_partial(buf_size, cinfo, OPS_PTAG_CT_LITERAL_DATA, + write_literal_header, NULL); + +} + +/** + * \ingroup InternalAPI + * \brief Pushes a literal writer onto the stack. + * \param cinfo the writer info + */ +void ops_writer_push_literal(ops_create_info_t *cinfo) + { + ops_writer_push_literal_with_opts(cinfo, 0); + } + +// EOF diff --git a/openpgpsdk/src/writer_partial.c b/openpgpsdk/src/writer_partial.c new file mode 100644 index 000000000..4e9c62a84 --- /dev/null +++ b/openpgpsdk/src/writer_partial.c @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2005-2009 Nominet UK (www.nic.uk) + * All rights reserved. + * Contributors: Ben Laurie, Rachel Willmer, Alasdair Mackintosh. + * The Contributors have asserted their moral rights under the + * UK Copyright Design and Patents Act 1988 to + * be recorded as the authors of this copyright work. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. + * + * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** Writes data using a series of partial body length headers. + * (See RFC 4880 4.2.2.4). This is normally used in conjunction + * with a streaming writer of some kind that needs to write out + * data packets of unknown length. + */ + +#include +#include + +#ifndef WIN32 +#include +#endif + +#include +#include +#include +#include + +static const int debug = 0; + +#define PACKET_SIZE 2048 +#define MIN_PARTIAL_DATA_LENGTH 512 +#define MAX_PARTIAL_DATA_LENGTH 1073741824 + +typedef struct + { + size_t packet_size; // size of packets + ops_memory_t *buffer; // Data is buffered here until written + ops_content_tag_t tag; // Packet tag + ops_memory_t *header; // Header is written here + ops_boolean_t written_first; // Has the first packet been written? + ops_write_partial_trailer_t *trailer_fn; // Custom end-of-packet fn + void *trailer_data; // data for end-of-packet fn + } stream_partial_arg_t; + + + +static unsigned int ops_calc_partial_data_length(unsigned int len) + { + int i; + unsigned int mask = MAX_PARTIAL_DATA_LENGTH; + assert( len > 0 ); + + if (len > MAX_PARTIAL_DATA_LENGTH) + return MAX_PARTIAL_DATA_LENGTH; + + for (i = 0 ; i <= 30 ; i++) + { + if (mask & len) + break; + mask >>= 1; + } + + return mask; + } + +static ops_boolean_t ops_write_partial_data_length(unsigned int len, + ops_create_info_t *info) + { + // len must be a power of 2 from 0 to 30 + unsigned i; + unsigned char c[1]; + + for (i = 0 ; i <= 30 ; i++) + if ((len >> i) & 1) + break; + + assert((1u << i) == len); + + c[0] = 224 + i; + + return ops_write(c, 1, info); + } + +static ops_boolean_t write_partial_data(const unsigned char *data, + size_t len, + ops_create_info_t *info) + { + if (debug) + fprintf(stderr, "Writing %zu bytes\n", len); + while (len > 0) + { + size_t pdlen = ops_calc_partial_data_length(len); + ops_write_partial_data_length(pdlen, info); + ops_write(data, pdlen, info); + data += pdlen; + len -= pdlen; + } + return ops_true; + } + +static ops_boolean_t write_partial_data_first(stream_partial_arg_t *arg, + const unsigned char *data, + unsigned int len, + ops_create_info_t *info) + { + size_t header_len = ops_memory_get_length(arg->header); + + size_t sz_towrite = len + header_len; + size_t sz_pd = ops_calc_partial_data_length(sz_towrite); + size_t first_data_len = (sz_pd - header_len); + assert(sz_pd >= MIN_PARTIAL_DATA_LENGTH); + + if (debug) + fprintf(stderr, "Writing first packet of len %zu (%zu + %u)\n", + sz_towrite, header_len, len); + + // Write the packet tag, the partial size and the header, followed + // by the first chunk of data and then the remainder of the data. + // (We have to do this in two chunks, as the partial length may not + // match the number of bytes to write.) + return ops_write_ptag(arg->tag, info) && + ops_write_partial_data_length(sz_pd, info) && + ops_write(ops_memory_get_data(arg->header), header_len, info) && + ops_write(data, first_data_len, info) && + write_partial_data(data + first_data_len, len - first_data_len, info); + } + +/* + * Writes out the last packet. The length is encoded as a fixed-length + * packet. Note that even if there is no data accumulated in the + * buffer, we stil lneed to write out a packet, as the final packet in + * a partially-encoded stream must be a fixed-lngth packet. + */ +static ops_boolean_t write_partial_data_last(stream_partial_arg_t *arg, + ops_create_info_t *info) + { + size_t buffer_length = ops_memory_get_length(arg->buffer); + if (debug) + fprintf(stderr, "writing final packet of %zu bytes\n", buffer_length); + return ops_write_length(buffer_length, info) && + ops_write(ops_memory_get_data(arg->buffer), buffer_length, info); + } + +/* + * Writes out the data accumulated in the in-memory buffer. + */ +static ops_boolean_t flush_buffer(stream_partial_arg_t *arg, + ops_create_info_t *info) + { + ops_boolean_t result = ops_true; + size_t buffer_length = ops_memory_get_length(arg->buffer); + if (buffer_length > 0) + { + if (debug) + fprintf(stderr, "Flushing %zu bytes\n", buffer_length); + + result = write_partial_data(ops_memory_get_data(arg->buffer), + buffer_length, + info); + ops_memory_clear(arg->buffer); + } + return result; + } + +static ops_boolean_t stream_partial_writer(const unsigned char *src, + unsigned length, + ops_error_t **errors, + ops_writer_info_t *winfo) + { + stream_partial_arg_t *arg = ops_writer_get_arg(winfo); + + // For the first write operation, we need to write out the header + // plus the data. The total size that we write out must be at least + // MIN_PARTIAL_DATA_LENGTH bytes. (See RFC 4880, sec 4.2.2.4, + // Partial Body Lengths.) If we are given less than this, + // then we need to store the data in the buffer until we have the + // minumum + if (!arg->written_first) + { + ops_memory_add(arg->buffer, src, length); + size_t buffer_length = ops_memory_get_length(arg->buffer); + size_t header_length = ops_memory_get_length(arg->header); + if (header_length + buffer_length < MIN_PARTIAL_DATA_LENGTH) + { + if (debug) + fprintf(stderr, "Storing %zu (%zu + %zu) bytes\n", + header_length + buffer_length, header_length, + buffer_length); + return ops_true; // will wait for more data or end of stream + } + arg->written_first = ops_true; + + // Create a writer that will write to the parent stream. Allows + // useage of ops_write_ptag, etc. + ops_create_info_t parent_info; + ops_prepare_parent_info(&parent_info, winfo); + ops_boolean_t result = + write_partial_data_first(arg, ops_memory_get_data(arg->buffer), + buffer_length, &parent_info); + ops_memory_clear(arg->buffer); + ops_move_errors(&parent_info, errors); + return result; + } + else + { + size_t buffer_length = ops_memory_get_length(arg->buffer); + if (buffer_length + length < arg->packet_size) + { + ops_memory_add(arg->buffer, src, length); + if (debug) + fprintf(stderr, "Storing %u bytes (total %zu)\n", + length, buffer_length); + return ops_true; + } + else + { + ops_create_info_t parent_info; + parent_info.winfo = *winfo->next; + parent_info.errors = *errors; + return flush_buffer(arg, &parent_info) && + write_partial_data(src, length, &parent_info); + } + } + return ops_true; + } + +/* + * Invoked when the total packet size is less than + * MIN_PARTIAL_DATA_LENGTH. In that case, we write out the whole + * packet in a single operation, without using partial body length + * packets. + */ +static ops_boolean_t write_complete_packet(stream_partial_arg_t *arg, + ops_create_info_t *info) + { + size_t data_len = ops_memory_get_length(arg->buffer); + size_t header_len = ops_memory_get_length(arg->header); + + // Write the header tag, the length of the packet, and the + // packet. Note that the packet includes the header + // bytes. + size_t total = data_len + header_len; + if (debug) + fprintf(stderr, "writing entire packet with length %zu (%zu + %zu)\n", + total, data_len, header_len); + return ops_write_ptag(arg->tag, info) && + ops_write_length(total, info) && + ops_write(ops_memory_get_data(arg->header), header_len, info) && + ops_write(ops_memory_get_data(arg->buffer), data_len, info); + } + +static ops_boolean_t stream_partial_finaliser(ops_error_t **errors, + ops_writer_info_t *winfo) + { + stream_partial_arg_t *arg = ops_writer_get_arg(winfo); + // write last chunk of data + + // Create a writer that will write to the parent stream. Allows + // useage of ops_write_ptag, etc. + ops_create_info_t parent_info; + ops_prepare_parent_info(&parent_info, winfo); + ops_boolean_t result; + if (!arg->written_first) + result = write_complete_packet(arg, &parent_info); + else + // finish writing + result = write_partial_data_last(arg, &parent_info); + if (result && arg->trailer_fn != NULL) + result = arg->trailer_fn(&parent_info, arg->trailer_data); + ops_move_errors(&parent_info, errors); + return result; + } + +static void stream_partial_destroyer(ops_writer_info_t *winfo) + { + stream_partial_arg_t *arg = ops_writer_get_arg(winfo); + ops_memory_free(arg->buffer); + ops_memory_free(arg->header); + free(arg); + } + +/** + * \ingroup InternalAPI + * \brief Pushes a partial packet writer onto the stack. + * + * This writer is used in conjunction with another writer that + * generates streaming data of unknown length. The partial writer + * handles the various partial body length packets. When writing the + * initial packet header, the partial writer will write out the given + * tag, write out an initial length, and then invoke the 'header' + * function to write the remainder of the header. Note that the header + * function should not write a packet tag or a length. + * + * \param packet_size the expected size of the incoming packets. Must + * be >= 512 bytes. Must be a power of 2. The partial writer + * will buffer incoming writes into packets of this size. Note + * that writes will be most efficient if done in chunks of + * packet_size. If the packet size is unknown, specify 0, and + * the default size will be used. + * \param cinfo the writer info + * \param tag the packet tag + * \param header_writer a function that writes the packet header. + * \param header_data passed into header_writer + */ +void ops_writer_push_partial(size_t packet_size, + ops_create_info_t *cinfo, + ops_content_tag_t tag, + ops_write_partial_header_t *header_writer, + void *header_data) + { + ops_writer_push_partial_with_trailer(packet_size, cinfo, tag, header_writer, + header_data, NULL, NULL); + } + +/** + * \ingroup InternalAPI + * \brief Pushes a partial packet writer onto the stack. Adds a trailer + * function that will be invoked after writing out the partial + * packet. + * + * This writer is primarily used by the signature writer, which needs + * to append a signature packet after the literal data packet. + * + * \param trailer_writer a function that writes the trailer + * \param trailer_data passed into trailer_data + * \see ops_writer_push_partial + * \see ops_writer_push_signed + */ +void ops_writer_push_partial_with_trailer( + size_t packet_size, + ops_create_info_t *cinfo, + ops_content_tag_t tag, + ops_write_partial_header_t *header_writer, + void *header_data, + ops_write_partial_trailer_t *trailer_writer, + void *trailer_data) + { + if (packet_size == 0) + packet_size = PACKET_SIZE; + assert(packet_size >= MIN_PARTIAL_DATA_LENGTH); + // Verify that the packet size is a valid power of 2. + assert(ops_calc_partial_data_length(packet_size) == packet_size); + + // Create arg to be used with this writer + // Remember to free this in the destroyer + stream_partial_arg_t *arg = ops_mallocz(sizeof *arg); + arg->tag = tag; + arg->written_first = ops_false; + arg->packet_size = packet_size; + arg->buffer = ops_memory_new(); + ops_memory_init(arg->buffer, arg->packet_size); + arg->trailer_fn = trailer_writer; + arg->trailer_data = trailer_data; + + // Write out the header into the memory buffer. Later we will write + // this buffer to the underlying output stream. + ops_create_info_t *header_info; + ops_setup_memory_write(&header_info, &arg->header, 128); + header_writer(header_info, header_data); + ops_writer_close(header_info); + ops_create_info_delete(header_info); + + // And push writer on stack + ops_writer_push(cinfo, stream_partial_writer, stream_partial_finaliser, + stream_partial_destroyer, arg); + } + +// EOF diff --git a/openpgpsdk/src/writer_stream_encrypt_se_ip.c b/openpgpsdk/src/writer_stream_encrypt_se_ip.c index 08be27253..5cda68fe2 100644 --- a/openpgpsdk/src/writer_stream_encrypt_se_ip.c +++ b/openpgpsdk/src/writer_stream_encrypt_se_ip.c @@ -1,8 +1,9 @@ /* - * Copyright (c) 2005-2008 Nominet UK (www.nic.uk) + * Copyright (c) 2005-2009 Nominet UK (www.nic.uk) * All rights reserved. - * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted - * their moral rights under the UK Copyright Design and Patents Act 1988 to + * Contributors: Ben Laurie, Rachel Willmer, Alasdair Mackintosh. + * The Contributors have asserted their moral rights under the + * UK Copyright Design and Patents Act 1988 to * be recorded as the authors of this copyright work. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not @@ -34,46 +35,60 @@ #include "keyring_local.h" #include #include +#include #include -#include - -#define MAX_PARTIAL_DATA_LENGTH 1073741824 +#include typedef struct { ops_crypt_t*crypt; - ops_memory_t *mem_data; - ops_memory_t *mem_literal; - ops_create_info_t *cinfo_literal; ops_memory_t *mem_se_ip; ops_create_info_t *cinfo_se_ip; ops_hash_t hash; } stream_encrypt_se_ip_arg_t; +static ops_boolean_t write_encrypt_se_ip_header(ops_create_info_t *info, + void *header_data); + static ops_boolean_t stream_encrypt_se_ip_writer(const unsigned char *src, unsigned length, ops_error_t **errors, ops_writer_info_t *winfo); -static ops_boolean_t stream_encrypt_se_ip_finaliser(ops_error_t** errors, - ops_writer_info_t* winfo); +static ops_boolean_t stream_encrypt_se_ip_finaliser(ops_error_t **errors, + ops_writer_info_t *winfo); static void stream_encrypt_se_ip_destroyer (ops_writer_info_t *winfo); -// /** \ingroup Core_WritersNext +\brief Pushes a streaming encryption writer onto the stack. + +Data written to the stream will be encoded in a Symmetrically +Encrypted Integrity Protected packet. Note that this writer must be +used in conjunction with a literal writer or a signed writer. + \param cinfo \param pub_key +Example Code: +\code + ops_writer_push_stream_encrypt_se_ip(cinfo, public_key); + if (compress) + ops_writer_push_compressed(cinfo); + if (sign) + ops_writer_push_signed(cinfo, OPS_SIG_BINARY, secret_key); + else + ops_writer_push_literal(cinfo); +\endcode */ + void ops_writer_push_stream_encrypt_se_ip(ops_create_info_t *cinfo, const ops_keydata_t *pub_key) { - ops_crypt_t* encrypt; + ops_crypt_t *encrypt; unsigned char *iv=NULL; - const unsigned int bufsz=1024; // initial value; gets expanded as necessary // Create arg to be used with this writer @@ -81,9 +96,9 @@ void ops_writer_push_stream_encrypt_se_ip(ops_create_info_t *cinfo, stream_encrypt_se_ip_arg_t *arg=ops_mallocz(sizeof *arg); // Create and write encrypted PK session key - ops_pk_session_key_t* encrypted_pk_session_key; + ops_pk_session_key_t *encrypted_pk_session_key; encrypted_pk_session_key=ops_create_pk_session_key(pub_key); - ops_write_pk_session_key(cinfo,encrypted_pk_session_key); + ops_write_pk_session_key(cinfo, encrypted_pk_session_key); // Setup the arg encrypt=ops_mallocz(sizeof *encrypt); @@ -95,144 +110,50 @@ void ops_writer_push_stream_encrypt_se_ip(ops_create_info_t *cinfo, arg->crypt=encrypt; - arg->mem_data=ops_memory_new(); - ops_memory_init(arg->mem_data,bufsz); - - arg->mem_literal = NULL; - arg->cinfo_literal = NULL; - ops_setup_memory_write(&arg->cinfo_se_ip, &arg->mem_se_ip, bufsz); - // And push writer on stack + ops_hash_any(&arg->hash, OPS_HASH_SHA1); + arg->hash.init(&arg->hash); + + // This is a streaming writer, so we don't know the length in + // advance. Use a partial writer to handle the partial body + // packet lengths. + ops_writer_push_partial(2048, cinfo, OPS_PTAG_CT_SE_IP_DATA, + write_encrypt_se_ip_header, arg); + + // And push encryption writer on stack ops_writer_push(cinfo, - stream_encrypt_se_ip_writer, - stream_encrypt_se_ip_finaliser, - stream_encrypt_se_ip_destroyer,arg); + stream_encrypt_se_ip_writer, + stream_encrypt_se_ip_finaliser, + stream_encrypt_se_ip_destroyer, arg); // tidy up + ops_pk_session_key_free(encrypted_pk_session_key); free(encrypted_pk_session_key); free(iv); } - - -unsigned int ops_calc_partial_data_length(unsigned int len) +static ops_boolean_t ops_stream_write_se_ip(const unsigned char *data, + unsigned int len, + stream_encrypt_se_ip_arg_t *arg, + ops_create_info_t *cinfo) { - int i; - unsigned int mask = MAX_PARTIAL_DATA_LENGTH; - assert( len > 0 ); - - if ( len > MAX_PARTIAL_DATA_LENGTH ) { - return MAX_PARTIAL_DATA_LENGTH; - } - - for ( i = 0; i <= 30; i++ ) { - if ( mask & len) break; - mask >>= 1; - } - - return mask; - } - -ops_boolean_t ops_write_partial_data_length(unsigned int len, - ops_create_info_t *info) - { - // len must be a power of 2 from 0 to 30 - int i; - unsigned char c[1]; - - for ( i = 0; i <= 30; i++ ) { - if ( (len >> i) & 1) break; - } - - c[0] = 224 + i; - return ops_write(c,1,info); - } - -ops_boolean_t ops_stream_write_literal_data(const unsigned char *data, - unsigned int len, - ops_create_info_t *info) - { - while (len > 0) { - size_t pdlen = ops_calc_partial_data_length(len); - ops_write_partial_data_length(pdlen, info); - ops_write(data, pdlen, info); - data += pdlen; - len -= pdlen; - } + ops_writer_push_encrypt_crypt(cinfo, arg->crypt); + ops_write(data, len, cinfo); + ops_writer_pop(cinfo); + arg->hash.add(&arg->hash, data, len); return ops_true; } -ops_boolean_t ops_stream_write_literal_data_first(const unsigned char *data, - unsigned int len, - const ops_literal_data_type_t type, - ops_create_info_t *info) - { - // \todo add filename - // \todo add date - // \todo do we need to check text data for line endings ? - - size_t sz_towrite = 1 + 1 + 4 + len; - size_t sz_pd = ops_calc_partial_data_length(sz_towrite); - assert(sz_pd >= 512); - - ops_write_ptag(OPS_PTAG_CT_LITERAL_DATA, info); - ops_write_partial_data_length(sz_pd, info); - ops_write_scalar(type, 1, info); - ops_write_scalar(0, 1, info); - ops_write_scalar(0, 4, info); - ops_write(data, sz_pd - 6, info); - - data += (sz_pd - 6); - sz_towrite -= sz_pd; - - ops_stream_write_literal_data(data, sz_towrite, info); - return ops_true; - } - -ops_boolean_t ops_stream_write_literal_data_last(const unsigned char *data, - unsigned int len, - ops_create_info_t *info) - { - ops_write_length(len, info); - ops_write(data, len, info); - return ops_true; - } - -ops_boolean_t ops_stream_write_se_ip(const unsigned char *data, - unsigned int len, - stream_encrypt_se_ip_arg_t *arg, - ops_create_info_t *cinfo) - { - while (len > 0) { - size_t pdlen = ops_calc_partial_data_length(len); - ops_write_partial_data_length(pdlen, cinfo); - - ops_writer_push_encrypt_crypt(cinfo, arg->crypt); - ops_write(data, pdlen, cinfo); - ops_writer_pop(cinfo); - - arg->hash.add(&arg->hash, data, pdlen); - - data += pdlen; - len -= pdlen; - } - return ops_true; - } - -ops_boolean_t ops_stream_write_se_ip_first(const unsigned char *data, - unsigned int len, - stream_encrypt_se_ip_arg_t *arg, - ops_create_info_t *cinfo) +// Writes out the header for the encrypted packet. Invoked by the +// partial stream writer. Note that writing the packet tag and the +// packet length is handled by the partial stream writer. +static ops_boolean_t write_encrypt_se_ip_header(ops_create_info_t *cinfo, + void *data) { + stream_encrypt_se_ip_arg_t *arg = data; size_t sz_preamble = arg->crypt->blocksize + 2; - size_t sz_towrite = sz_preamble + 1 + len; unsigned char* preamble = ops_mallocz(sz_preamble); - size_t sz_pd = ops_calc_partial_data_length(sz_towrite); - assert(sz_pd >= 512); - - ops_write_ptag(OPS_PTAG_CT_SE_IP_DATA, cinfo); - ops_write_partial_data_length(sz_pd, cinfo); ops_write_scalar(SE_IP_DATA_VERSION, 1, cinfo); ops_writer_push_encrypt_crypt(cinfo, arg->crypt); @@ -241,42 +162,25 @@ ops_boolean_t ops_stream_write_se_ip_first(const unsigned char *data, preamble[arg->crypt->blocksize]=preamble[arg->crypt->blocksize-2]; preamble[arg->crypt->blocksize+1]=preamble[arg->crypt->blocksize-1]; - ops_hash_any(&arg->hash, OPS_HASH_SHA1); - arg->hash.init(&arg->hash); - ops_write(preamble, sz_preamble, cinfo); arg->hash.add(&arg->hash, preamble, sz_preamble); - - ops_write(data, sz_pd - sz_preamble - 1, cinfo); - arg->hash.add(&arg->hash, data, sz_pd - sz_preamble - 1); - - data += (sz_pd - sz_preamble -1); - sz_towrite -= sz_pd; - ops_writer_pop(cinfo); - - ops_stream_write_se_ip(data, sz_towrite, arg, cinfo); - free(preamble); return ops_true; } -ops_boolean_t ops_stream_write_se_ip_last(const unsigned char *data, - unsigned int len, - stream_encrypt_se_ip_arg_t *arg, - ops_create_info_t *cinfo) +static ops_boolean_t +ops_stream_write_se_ip_last(stream_encrypt_se_ip_arg_t *arg, + ops_create_info_t *cinfo) { unsigned char c[1]; unsigned char hashed[SHA_DIGEST_LENGTH]; const size_t sz_mdc = 1 + 1 + SHA_DIGEST_LENGTH; - size_t sz_buf = len + sz_mdc; ops_memory_t *mem_mdc; ops_create_info_t *cinfo_mdc; - arg->hash.add(&arg->hash, data, len); - // MDC packet tag c[0]=0xD3; arg->hash.add(&arg->hash, &c[0], 1); @@ -291,14 +195,11 @@ ops_boolean_t ops_stream_write_se_ip_last(const unsigned char *data, ops_setup_memory_write(&cinfo_mdc, &mem_mdc, sz_mdc); ops_write_mdc(hashed, cinfo_mdc); - // write length of last se_ip chunk - ops_write_length(sz_buf, cinfo); - - // encode everting + // encode everthing ops_writer_push_encrypt_crypt(cinfo, arg->crypt); - ops_write(data, len, cinfo); - ops_write(ops_memory_get_data(mem_mdc), ops_memory_get_length(mem_mdc), cinfo); + ops_write(ops_memory_get_data(mem_mdc), ops_memory_get_length(mem_mdc), + cinfo); ops_writer_pop(cinfo); @@ -316,97 +217,40 @@ static ops_boolean_t stream_encrypt_se_ip_writer(const unsigned char *src, ops_boolean_t rtn=ops_true; - if ( arg->cinfo_literal == NULL ) { // first literal data chunk is not yet written - size_t datalength; - - ops_memory_add(arg->mem_data,src,length); - datalength = ops_memory_get_length(arg->mem_data); - - // 4.2.2.4. Partial Body Lengths - // The first partial length MUST be at least 512 octets long. - if ( datalength < 512 ) { - return ops_true; // will wait for more data or end of stream - } - - ops_setup_memory_write(&arg->cinfo_literal,&arg->mem_literal,datalength+32); - ops_stream_write_literal_data_first(ops_memory_get_data(arg->mem_data), - datalength, - OPS_LDT_BINARY, - arg->cinfo_literal); - - ops_stream_write_se_ip_first(ops_memory_get_data(arg->mem_literal), - ops_memory_get_length(arg->mem_literal), - arg, arg->cinfo_se_ip); - } else { - ops_stream_write_literal_data(src, length, arg->cinfo_literal); - ops_stream_write_se_ip(ops_memory_get_data(arg->mem_literal), - ops_memory_get_length(arg->mem_literal), - arg, arg->cinfo_se_ip); - } - + ops_stream_write_se_ip(src, length, + arg, arg->cinfo_se_ip); // now write memory to next writer rtn=ops_stacked_write(ops_memory_get_data(arg->mem_se_ip), ops_memory_get_length(arg->mem_se_ip), errors, winfo); - ops_memory_clear(arg->mem_literal); ops_memory_clear(arg->mem_se_ip); return rtn; } -static ops_boolean_t stream_encrypt_se_ip_finaliser(ops_error_t** errors, - ops_writer_info_t* winfo) +static ops_boolean_t stream_encrypt_se_ip_finaliser(ops_error_t **errors, + ops_writer_info_t *winfo) { stream_encrypt_se_ip_arg_t *arg=ops_writer_get_arg(winfo); - // write last chunk of data - - if ( arg->cinfo_literal == NULL ) { - // first literal data chunk was not written - // so we know the total length of data, write a simple packet - - // create literal data packet from buffered data - ops_setup_memory_write(&arg->cinfo_literal, - &arg->mem_literal, - ops_memory_get_length(arg->mem_data)+32); - - ops_write_literal_data_from_buf(ops_memory_get_data(arg->mem_data), - ops_memory_get_length(arg->mem_data), - OPS_LDT_BINARY, arg->cinfo_literal); - - // create SE IP packet set from this literal data - ops_write_se_ip_pktset(ops_memory_get_data(arg->mem_literal), - ops_memory_get_length(arg->mem_literal), - arg->crypt, arg->cinfo_se_ip); - - } else { - // finish writing - ops_stream_write_literal_data_last(NULL, 0, arg->cinfo_literal); - ops_stream_write_se_ip_last(ops_memory_get_data(arg->mem_literal), - ops_memory_get_length(arg->mem_literal), - arg, arg->cinfo_se_ip); - } - + // write trailer + ops_stream_write_se_ip_last(arg, arg->cinfo_se_ip); // now write memory to next writer return ops_stacked_write(ops_memory_get_data(arg->mem_se_ip), ops_memory_get_length(arg->mem_se_ip), errors, winfo); } -static void stream_encrypt_se_ip_destroyer (ops_writer_info_t *winfo) +static void stream_encrypt_se_ip_destroyer(ops_writer_info_t *winfo) { stream_encrypt_se_ip_arg_t *arg=ops_writer_get_arg(winfo); - ops_memory_free(arg->mem_data); - ops_teardown_memory_write(arg->cinfo_literal, arg->mem_literal); ops_teardown_memory_write(arg->cinfo_se_ip, arg->mem_se_ip); - arg->crypt->decrypt_finish(arg->crypt); free(arg->crypt); free(arg); } - // EOF