added compilable version of openpgp sdk

git-svn-id: http://svn.code.sf.net/p/retroshare/code/branches/v0.5-OpenPGP@5048 b45a01b8-16f6-495d-af2f-9b41ad6348cc
This commit is contained in:
csoler 2012-03-24 15:58:18 +00:00
parent 8cb15bdbef
commit 7d06d19e40
67 changed files with 20945 additions and 0 deletions

View File

@ -0,0 +1,33 @@
/*
* 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
*/
#ifndef OPS_ACCUMULATE_H
#define OPS_ACCUMULATE_H
#endif
#include "keyring.h"
#include "packet-parse.h"
int ops_parse_and_accumulate(ops_keyring_t *keyring,
ops_parse_info_t *parse_info);

View File

@ -0,0 +1,54 @@
/*
* 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.
*/
#ifndef __OPS_ARMOUR_H__
#define __OPS_ARMOUR_H__
#include "packet-parse.h"
#include "signature.h"
unsigned ops_crc24(unsigned checksum,unsigned char c);
void ops_reader_push_dearmour(ops_parse_info_t *parse_info);
void ops_reader_pop_dearmour(ops_parse_info_t *parse_info);
ops_boolean_t ops_writer_push_clearsigned(ops_create_info_t *info,
ops_create_signature_t *sig);
void ops_writer_push_armoured_message(ops_create_info_t *info);
ops_boolean_t ops_writer_switch_to_armoured_signature(ops_create_info_t *info);
typedef enum
{
OPS_PGP_MESSAGE=1,
OPS_PGP_PUBLIC_KEY_BLOCK,
OPS_PGP_PRIVATE_KEY_BLOCK,
OPS_PGP_MULTIPART_MESSAGE_PART_X_OF_Y,
OPS_PGP_MULTIPART_MESSAGE_PART_X,
OPS_PGP_SIGNATURE
} ops_armor_type_t;
void ops_writer_push_armoured(ops_create_info_t *info, ops_armor_type_t type);
#define CRC24_INIT 0xb704ceL
#endif /* __OPS_ARMOUR_H__ */
// EOF

View File

@ -0,0 +1,37 @@
/*
* 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.
*/
#ifndef __OPS_CALLBACK_H__
#define __OPS_CALLBACK_H__
#define CB(cbinfo,t,pc) do { (pc)->tag=(t); if(ops_parse_cb((pc),(cbinfo)) == OPS_RELEASE_MEMORY) ops_parser_content_free(pc); } while(0)
/*#define CB(cbinfo,t,pc) do { (pc)->tag=(t); if((cbinfo)->cb(pc,(cbinfo)) == OPS_RELEASE_MEMORY) ops_parser_content_free(pc); } while(0)*/
//#define CB(cbinfo,t,pc) do { (pc)->tag=(t); if((cbinfo)->cb(pc,(cbinfo)) == OPS_RELEASE_MEMORY) ops_parser_content_free(pc); } while(0)
#define CBP(info,t,pc) CB(&(info)->cbinfo,t,pc)
#define ERR(cbinfo,err,code) do { content.content.error.error=err; content.tag=OPS_PARSER_ERROR; ops_parse_cb(&content,(cbinfo)); OPS_ERROR(errors,code,err); return -1; } while(0)
/*#define ERR(err) do { content.content.error.error=err; content.tag=OPS_PARSER_ERROR; ops_parse_cb(&content,cbinfo); return -1; } while(0)*/
#define ERRP(info,err) do { C.error.error=err; CBP(info,OPS_PARSER_ERROR,&content); return ops_false; } while(0)
#endif /*__OPS_CALLBACK_H__*/

View File

@ -0,0 +1,32 @@
/*
* 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 "packet-parse.h"
int ops_decompress(ops_region_t *region,ops_parse_info_t *parse_info,
ops_compression_type_t type);
ops_boolean_t ops_write_compressed(const unsigned char* data,
const unsigned int len,
ops_create_info_t *cinfo);

View File

@ -0,0 +1,7 @@
/* generated by configure from include/openpgpsdk/configure.h.template. Don't edit. */
#define HAVE_ALLOCA_H 0
#define TIME_T_FMT "%ld"
/* for silencing unused parameter warnings */
#define OPS_USED(x) (x)=(x)

View File

@ -0,0 +1,82 @@
/*
* 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
*/
#ifndef OPS_CREATE_H
#define OPS_CREATE_H
#include <openpgpsdk/types.h>
#include <openpgpsdk/packet.h>
#include <openpgpsdk/crypto.h>
#include <openpgpsdk/memory.h>
#include <openpgpsdk/errors.h>
#include <openpgpsdk/keyring.h>
#include <openpgpsdk/writer.h>
/**
* \ingroup Create
* This struct contains the required information about how to write this stream
*/
struct ops_create_info
{
ops_writer_info_t winfo;
ops_error_t *errors; /*!< an error stack */
};
ops_create_info_t *ops_create_info_new(void);
void ops_create_info_delete(ops_create_info_t *info);
ops_memory_t* ops_write_mem_from_file(const char *filename, int* errnum);
int ops_write_file_from_buf(const char *filename, const char* buf, const size_t len, const ops_boolean_t overwrite);
ops_boolean_t ops_calc_session_key_checksum(ops_pk_session_key_t *session_key, unsigned char *cs);
void ops_build_public_key(ops_memory_t *out,const ops_public_key_t *key,
ops_boolean_t make_packet);
ops_boolean_t ops_write_struct_user_id(ops_user_id_t *id,
ops_create_info_t *info);
ops_boolean_t ops_write_struct_public_key(const ops_public_key_t *key,
ops_create_info_t *info);
ops_boolean_t ops_write_ss_header(unsigned length,ops_content_tag_t type,
ops_create_info_t *info);
ops_boolean_t ops_write_struct_secret_key(const ops_secret_key_t *key,
const unsigned char* passphrase,
const size_t pplen,
ops_create_info_t *info);
ops_boolean_t ops_write_one_pass_sig(const ops_secret_key_t* skey,
const ops_hash_algorithm_t hash_alg,
const ops_sig_type_t sig_type,
ops_create_info_t* info);
ops_boolean_t ops_write_literal_data_from_buf(const unsigned char *data,
const int maxlen,
const ops_literal_data_type_t type,
ops_create_info_t *info);
ops_pk_session_key_t *ops_create_pk_session_key(const ops_keydata_t *key);
ops_boolean_t ops_write_pk_session_key(ops_create_info_t *info,
ops_pk_session_key_t *pksk);
ops_boolean_t ops_write_transferable_public_key(const ops_keydata_t *key, ops_boolean_t armoured, ops_create_info_t *info);
ops_boolean_t ops_write_transferable_secret_key(const ops_keydata_t *key, const unsigned char* passphrase, const size_t pplen, ops_boolean_t armoured, ops_create_info_t *info);
#endif /*OPS_CREATE_H*/
// eof

View File

@ -0,0 +1,176 @@
/*
* 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
*/
#ifndef OPS_CRYPTO_H
#define OPS_CRYPTO_H
#include "keyring.h"
#include "util.h"
#include "packet.h"
#include "packet-parse.h"
#include <openssl/dsa.h>
#define OPS_MIN_HASH_SIZE 16
typedef void ops_hash_init_t(ops_hash_t *hash);
typedef void ops_hash_add_t(ops_hash_t *hash,const unsigned char *data,
unsigned length);
typedef unsigned ops_hash_finish_t(ops_hash_t *hash,unsigned char *out);
/** _ops_hash_t */
struct _ops_hash_t
{
ops_hash_algorithm_t algorithm;
size_t size;
const char *name;
ops_hash_init_t *init;
ops_hash_add_t *add;
ops_hash_finish_t *finish;
void *data;
};
typedef void ops_crypt_set_iv_t(ops_crypt_t *crypt,
const unsigned char *iv);
typedef void ops_crypt_set_key_t(ops_crypt_t *crypt,
const unsigned char *key);
typedef void ops_crypt_init_t(ops_crypt_t *crypt);
typedef void ops_crypt_resync_t(ops_crypt_t *crypt);
typedef void ops_crypt_block_encrypt_t(ops_crypt_t *crypt,void *out,
const void *in);
typedef void ops_crypt_block_decrypt_t(ops_crypt_t *crypt,void *out,
const void *in);
typedef void ops_crypt_cfb_encrypt_t(ops_crypt_t *crypt,void *out,
const void *in, size_t count);
typedef void ops_crypt_cfb_decrypt_t(ops_crypt_t *crypt,void *out,
const void *in, size_t count);
typedef void ops_crypt_finish_t(ops_crypt_t *crypt);
/** _ops_crypt_t */
struct _ops_crypt_t
{
ops_symmetric_algorithm_t algorithm;
size_t blocksize;
size_t keysize;
ops_crypt_set_iv_t *set_iv; /* Call this before decrypt init! */
ops_crypt_set_key_t *set_key; /* Call this before init! */
ops_crypt_init_t *base_init;
ops_crypt_resync_t *decrypt_resync;
// encrypt/decrypt one block
ops_crypt_block_encrypt_t *block_encrypt;
ops_crypt_block_decrypt_t *block_decrypt;
// Standard CFB encrypt/decrypt (as used by Sym Enc Int Prot packets)
ops_crypt_cfb_encrypt_t *cfb_encrypt;
ops_crypt_cfb_decrypt_t *cfb_decrypt;
ops_crypt_finish_t *decrypt_finish;
unsigned char iv[OPS_MAX_BLOCK_SIZE];
unsigned char civ[OPS_MAX_BLOCK_SIZE];
unsigned char siv[OPS_MAX_BLOCK_SIZE]; /* Needed for weird v3 resync */
unsigned char key[OPS_MAX_KEY_SIZE];
size_t num; /* Offset - see openssl _encrypt doco */
void *encrypt_key;
void *decrypt_key;
};
void ops_crypto_init(void);
void ops_crypto_finish(void);
void ops_hash_md5(ops_hash_t *hash);
void ops_hash_sha1(ops_hash_t *hash);
void ops_hash_sha256(ops_hash_t *hash);
void ops_hash_sha512(ops_hash_t *hash);
void ops_hash_sha384(ops_hash_t *hash);
void ops_hash_sha224(ops_hash_t *hash);
void ops_hash_any(ops_hash_t *hash,ops_hash_algorithm_t alg);
ops_hash_algorithm_t ops_hash_algorithm_from_text(const char *hash);
const char *ops_text_from_hash(ops_hash_t *hash);
unsigned ops_hash_size(ops_hash_algorithm_t alg);
unsigned ops_hash(unsigned char *out,ops_hash_algorithm_t alg,const void *in,
size_t length);
void ops_hash_add_int(ops_hash_t *hash,unsigned n,unsigned length);
ops_boolean_t ops_dsa_verify(const unsigned char *hash,size_t hash_length,
const ops_dsa_signature_t *sig,
const ops_dsa_public_key_t *dsa);
int ops_rsa_public_decrypt(unsigned char *out,const unsigned char *in,
size_t length,const ops_rsa_public_key_t *rsa);
int ops_rsa_public_encrypt(unsigned char *out,const unsigned char *in,
size_t length,const ops_rsa_public_key_t *rsa);
int ops_rsa_private_encrypt(unsigned char *out,const unsigned char *in,
size_t length,const ops_rsa_secret_key_t *srsa,
const ops_rsa_public_key_t *rsa);
int ops_rsa_private_decrypt(unsigned char *out,const unsigned char *in,
size_t length,const ops_rsa_secret_key_t *srsa,
const ops_rsa_public_key_t *rsa);
unsigned ops_block_size(ops_symmetric_algorithm_t alg);
unsigned ops_key_size(ops_symmetric_algorithm_t alg);
int ops_decrypt_data(ops_content_tag_t tag,ops_region_t *region,
ops_parse_info_t *parse_info);
int ops_crypt_any(ops_crypt_t *decrypt,ops_symmetric_algorithm_t alg);
void ops_decrypt_init(ops_crypt_t *decrypt);
void ops_encrypt_init(ops_crypt_t *encrypt);
size_t ops_decrypt_se(ops_crypt_t *decrypt,void *out,const void *in,
size_t count);
size_t ops_encrypt_se(ops_crypt_t *encrypt,void *out,const void *in,
size_t count);
size_t ops_decrypt_se_ip(ops_crypt_t *decrypt,void *out,const void *in,
size_t count);
size_t ops_encrypt_se_ip(ops_crypt_t *encrypt,void *out,const void *in,
size_t count);
ops_boolean_t ops_is_sa_supported(ops_symmetric_algorithm_t alg);
void ops_reader_push_decrypt(ops_parse_info_t *pinfo,ops_crypt_t *decrypt,
ops_region_t *region);
void ops_reader_pop_decrypt(ops_parse_info_t *pinfo);
// Hash everything that's read
void ops_reader_push_hash(ops_parse_info_t *pinfo,ops_hash_t *hash);
void ops_reader_pop_hash(ops_parse_info_t *pinfo);
int ops_decrypt_and_unencode_mpi(unsigned char *buf,unsigned buflen,const BIGNUM *encmpi,
const ops_secret_key_t *skey);
ops_boolean_t ops_rsa_encrypt_mpi(const unsigned char *buf, const size_t buflen,
const ops_public_key_t *pkey,
ops_pk_session_key_parameters_t *spk);
// Encrypt everything that's written
struct ops_key_data;
void ops_writer_push_encrypt(ops_create_info_t *info,
const struct ops_key_data *key);
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);
// Keys
ops_boolean_t ops_rsa_generate_keypair(const int numbits, const unsigned long e, ops_keydata_t* keydata);
ops_keydata_t* ops_rsa_create_selfsigned_keypair(const int numbits, const unsigned long e, ops_user_id_t * userid);
int ops_dsa_size(const ops_dsa_public_key_t *dsa);
DSA_SIG* ops_dsa_sign(unsigned char* hashbuf, unsigned hashsize, const ops_dsa_secret_key_t *sdsa, const ops_dsa_public_key_t *dsa);
#endif

View File

@ -0,0 +1,37 @@
/*
* 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
*/
#ifndef OPS_DEFS_H
#define OPS_DEFS_H
#define OPS_ARMOURED ops_true
#define OPS_UNARMOURED ops_false
#define OPS_OVERWRITE_YES ops_true
#define OPS_OVERWRITE_NO ops_false
#define OPS_ACCUMULATE_YES ops_true
#define OPS_ACCUMULATE_NO ops_false
#endif /* OPS_DEFS_H */

View File

@ -0,0 +1,125 @@
/*
* 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
*/
#ifndef OPS_ERRORS
#define OPS_ERRORS
#include "openpgpsdk/types.h"
#include <errno.h>
/** error codes */
// Remember to add names to map in errors.c
typedef enum
{
OPS_E_OK=0x0000, /* no error */
OPS_E_FAIL=0x0001, /* general error */
OPS_E_SYSTEM_ERROR=0x0002, /* system error, look at errno for details */
OPS_E_UNIMPLEMENTED=0x0003, /* feature not yet implemented */
/* reader errors */
OPS_E_R=0x1000, /* general reader error */
OPS_E_R_READ_FAILED =OPS_E_R+1,
OPS_E_R_EARLY_EOF =OPS_E_R+2,
OPS_E_R_BAD_FORMAT =OPS_E_R+3, // For example, malformed armour
OPS_E_R_UNSUPPORTED =OPS_E_R+4,
OPS_E_R_UNCONSUMED_DATA =OPS_E_R+5,
/* writer errors */
OPS_E_W=0x2000, /* general writer error */
OPS_E_W_WRITE_FAILED = OPS_E_W+1,
OPS_E_W_WRITE_TOO_SHORT = OPS_E_W+2,
/* parser errors */
OPS_E_P=0x3000, /* general parser error */
OPS_E_P_NOT_ENOUGH_DATA =OPS_E_P+1,
OPS_E_P_UNKNOWN_TAG =OPS_E_P+2,
OPS_E_P_PACKET_CONSUMED =OPS_E_P+3,
OPS_E_P_MPI_FORMAT_ERROR =OPS_E_P+4,
OPS_E_P_PACKET_NOT_CONSUMED =OPS_E_P+5,
OPS_E_P_DECOMPRESSION_ERROR =OPS_E_P+6,
OPS_E_P_NO_USERID =OPS_E_P+7,
/* creator errors */
OPS_E_C=0x4000, /* general creator error */
/* validation errors */
OPS_E_V=0x5000, /* general validation error */
OPS_E_V_BAD_SIGNATURE =OPS_E_V+1,
OPS_E_V_NO_SIGNATURE =OPS_E_V+2,
OPS_E_V_UNKNOWN_SIGNER =OPS_E_V+3,
OPS_E_V_BAD_HASH =OPS_E_V+4,
/* Algorithm support errors */
OPS_E_ALG=0x6000, /* general algorithm error */
OPS_E_ALG_UNSUPPORTED_SYMMETRIC_ALG =OPS_E_ALG+1,
OPS_E_ALG_UNSUPPORTED_PUBLIC_KEY_ALG =OPS_E_ALG+2,
OPS_E_ALG_UNSUPPORTED_SIGNATURE_ALG =OPS_E_ALG+3,
OPS_E_ALG_UNSUPPORTED_HASH_ALG =OPS_E_ALG+4,
OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG =OPS_E_ALG+5,
/* Protocol errors */
OPS_E_PROTO=0x7000, /* general protocol error */
OPS_E_PROTO_BAD_SYMMETRIC_DECRYPT =OPS_E_PROTO+2,
OPS_E_PROTO_UNKNOWN_SS =OPS_E_PROTO+3,
OPS_E_PROTO_CRITICAL_SS_IGNORED =OPS_E_PROTO+4,
OPS_E_PROTO_BAD_PUBLIC_KEY_VRSN =OPS_E_PROTO+5,
OPS_E_PROTO_BAD_SIGNATURE_VRSN =OPS_E_PROTO+6,
OPS_E_PROTO_BAD_ONE_PASS_SIG_VRSN =OPS_E_PROTO+7,
OPS_E_PROTO_BAD_PKSK_VRSN =OPS_E_PROTO+8,
OPS_E_PROTO_DECRYPTED_MSG_WRONG_LEN =OPS_E_PROTO+9,
OPS_E_PROTO_BAD_SK_CHECKSUM =OPS_E_PROTO+10,
} ops_errcode_t;
/** ops_errcode_name_map_t */
typedef ops_map_t ops_errcode_name_map_t;
/** one entry in a linked list of errors */
typedef struct ops_error
{
ops_errcode_t errcode;
int sys_errno; /*!< irrelevent unless errcode == OPS_E_SYSTEM_ERROR */
char *comment;
const char *file;
int line;
struct ops_error *next;
} ops_error_t;
char *ops_errcode(const ops_errcode_t errcode);
void ops_push_error(ops_error_t **errstack,ops_errcode_t errcode,int sys_errno,
const char *file,int line,const char *comment,...);
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);
#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
#define OPS_ERROR(err,code,fmt) do { ops_push_error(err,code,0,__FILE__,__LINE__,fmt); } while(0)
#define OPS_ERROR_1(err,code,fmt,arg) do { ops_push_error(err,code,0,__FILE__,__LINE__,fmt,arg); } while(0)
#define OPS_ERROR_2(err,code,fmt,arg,arg2) do { ops_push_error(err,code,0,__FILE__,__LINE__,fmt,arg,arg2); } while(0)
#define OPS_ERROR_3(err,code,fmt,arg,arg2,arg3) do { ops_push_error(err,code,0,__FILE__,__LINE__,fmt,arg,arg2,arg3); } while(0)
#define OPS_ERROR_4(err,code,fmt,arg,arg2,arg3,arg4) do { ops_push_error(err,code,0,__FILE__,__LINE__,fmt,arg,arg2,arg3,arg4); } while(0)
#endif /* OPS_ERRORS */

View File

@ -0,0 +1,27 @@
/*
* 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.
*/
/* A header that is always included last, for things that need to come last */
#ifdef DMALLOC
# include <dmalloc.h>
#endif

View File

@ -0,0 +1,29 @@
/*
* 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.
*/
#ifndef __OPS_HASH_H__
#define __OPS_HASH_H__
#include "openpgpsdk/packet.h"
void ops_calc_mdc_hash(const unsigned char* preamble, const size_t sz_preamble, const unsigned char* plaintext, const unsigned int sz_plaintext, unsigned char *hashed);
ops_boolean_t ops_is_hash_alg_supported(const ops_hash_algorithm_t *hash_alg);
#endif /*__OPS_HASH_H__*/

View File

@ -0,0 +1,88 @@
/*
* 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
*/
#ifndef OPS_KEYRING_H
#define OPS_KEYRING_H
#include "packet.h"
#include "memory.h"
typedef struct ops_keydata ops_keydata_t;
/** \struct ops_keyring_t
* A keyring
*/
typedef struct
{
int nkeys; // while we are constructing a key, this is the offset
int nkeys_allocated;
ops_keydata_t *keys;
} ops_keyring_t;
const ops_keydata_t *
ops_keyring_find_key_by_id(const ops_keyring_t *keyring,
const unsigned char keyid[OPS_KEY_ID_SIZE]);
const ops_keydata_t *
ops_keyring_find_key_by_userid(const ops_keyring_t *keyring,
const char* userid);
void ops_keydata_free(ops_keydata_t *key);
void ops_keyring_free(ops_keyring_t *keyring);
void ops_dump_keyring(const ops_keyring_t *keyring);
const ops_public_key_t *
ops_get_public_key_from_data(const ops_keydata_t *data);
ops_boolean_t ops_is_key_secret(const ops_keydata_t *data);
const ops_secret_key_t *
ops_get_secret_key_from_data(const ops_keydata_t *data);
ops_secret_key_t *
ops_get_writable_secret_key_from_data(ops_keydata_t *data);
ops_secret_key_t *ops_decrypt_secret_key_from_data(const ops_keydata_t *key,
const char *pphrase);
ops_boolean_t ops_keyring_read_from_file(ops_keyring_t *keyring, const ops_boolean_t armour, const char *filename);
ops_boolean_t ops_keyring_read_from_mem(ops_keyring_t *keyring, const ops_boolean_t armour, ops_memory_t *mem);
char *ops_malloc_passphrase(char *passphrase);
char *ops_get_passphrase(void);
void ops_keyring_list(const ops_keyring_t* keyring);
void ops_set_secret_key(ops_parser_content_union_t* content,const ops_keydata_t *key);
const unsigned char* ops_get_key_id(const ops_keydata_t *key);
unsigned ops_get_user_id_count(const ops_keydata_t *key);
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 *key);
const ops_keydata_t* ops_keyring_get_key_by_index(const ops_keyring_t *keyring, int index);
ops_user_id_t* ops_add_userid_to_keydata(ops_keydata_t* keydata, const ops_user_id_t* userid);
ops_packet_t* ops_add_packet_to_keydata(ops_keydata_t* keydata, const ops_packet_t* packet);
void ops_add_signed_userid_to_keydata(ops_keydata_t* keydata, const ops_user_id_t* userid, const ops_packet_t* packet);
ops_boolean_t ops_add_selfsigned_userid_to_keydata(ops_keydata_t* keydata, ops_user_id_t* userid);
ops_keydata_t *ops_keydata_new(void);
void ops_keydata_init(ops_keydata_t* keydata, const ops_content_tag_t type);
#endif

View File

@ -0,0 +1,40 @@
/*
* 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
*/
#ifndef OPS_LISTS_H
#define OPS_LISTS_H
/** ops_ulong_list_t */
typedef struct
{
unsigned int size;/* num of array slots allocated */
unsigned int used; /* num of array slots currently used */
unsigned long *ulongs;
} ops_ulong_list_t;
void ops_ulong_list_init(ops_ulong_list_t *list);
void ops_ulong_list_free(ops_ulong_list_t *list);
unsigned int ops_ulong_list_add(ops_ulong_list_t *list, unsigned long *ulong);
#endif /* OPS_LISTS_H */

View File

@ -0,0 +1,52 @@
/*
* 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 <sys/types.h>
#include <openssl/bn.h>
#include "packet.h"
#ifndef OPS_MEMORY_H
#define OPS_MEMORY_H
/** ops_memory_t
*/
typedef struct ops_memory ops_memory_t;
ops_memory_t *ops_memory_new(void);
void ops_memory_free(ops_memory_t *mem);
void ops_memory_init(ops_memory_t *mem,size_t initial_size);
void ops_memory_pad(ops_memory_t *mem,size_t length);
void ops_memory_add(ops_memory_t *mem,const unsigned char *src,size_t length);
void ops_memory_place_int(ops_memory_t *mem,unsigned offset,unsigned n,
size_t length);
void ops_memory_make_packet(ops_memory_t *out,ops_content_tag_t tag);
void ops_memory_clear(ops_memory_t *mem);
void ops_memory_release(ops_memory_t *mem);
void ops_writer_set_memory(ops_create_info_t *info,ops_memory_t *mem);
size_t ops_memory_get_length(const ops_memory_t *mem);
void *ops_memory_get_data(ops_memory_t *mem);
#endif

View File

@ -0,0 +1,170 @@
/*
* 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
* Parser for OpenPGP packets - headers.
*/
#ifndef OPS_PACKET_PARSE_H
#define OPS_PACKET_PARSE_H
#include "types.h"
#include "packet.h"
#include "lists.h"
/** ops_region_t */
typedef struct ops_region
{
struct ops_region *parent;
unsigned length;
unsigned length_read;
unsigned last_read; /*!< length of last read, only valid in deepest child */
ops_boolean_t indeterminate:1;
} ops_region_t;
void ops_init_subregion(ops_region_t *subregion,ops_region_t *region);
#if 0
/** Return values for reader functions e.g. ops_packet_reader_t() */
enum ops_reader_ret_t
{
OPS_R_OK =0, /*!< success */
OPS_R_EOF =1, /*!< reached end of file, no data has been returned */
OPS_R_EARLY_EOF =2, /*!< could not read the requested
number of bytes and either
OPS_RETURN_LENGTH was not set and at
least 1 byte was read, or there was
an abnormal end to the file (or
armoured block) */
OPS_R_PARTIAL_READ =3, /*!< if OPS_RETURN_LENGTH is set and
the buffer was not filled */
OPS_R_ERROR =4, /*!< if there was an error reading */
};
#endif
/** ops_parse_callback_return_t */
typedef enum
{
OPS_RELEASE_MEMORY,
OPS_KEEP_MEMORY,
OPS_FINISHED
} ops_parse_cb_return_t;
typedef struct ops_parse_cb_info ops_parse_cb_info_t;
typedef ops_parse_cb_return_t
ops_parse_cb_t(const ops_parser_content_t *content,
ops_parse_cb_info_t *cbinfo);
typedef struct ops_parse_info ops_parse_info_t;
typedef struct ops_reader_info ops_reader_info_t;
typedef struct ops_crypt_info ops_crypt_info_t;
/*
A reader MUST read at least one byte if it can, and should read up
to the number asked for. Whether it reads more for efficiency is
its own decision, but if it is a stacked reader it should never
read more than the length of the region it operates in (which it
would have to be given when it is stacked).
If a read is short because of EOF, then it should return the short
read (obviously this will be zero on the second attempt, if not the
first). Because a reader is not obliged to do a full read, only a
zero return can be taken as an indication of EOF.
If there is an error, then the callback should be notified, the
error stacked, and -1 should be returned.
Note that although length is a size_t, a reader will never be asked
to read more than INT_MAX in one go.
*/
typedef int ops_reader_t(void *dest,size_t length,ops_error_t **errors,
ops_reader_info_t *rinfo,ops_parse_cb_info_t *cbinfo);
typedef void ops_reader_destroyer_t(ops_reader_info_t *rinfo);
ops_parse_info_t *ops_parse_info_new(void);
void ops_parse_info_delete(ops_parse_info_t *pinfo);
ops_error_t *ops_parse_info_get_errors(ops_parse_info_t *pinfo);
ops_crypt_t *ops_parse_get_decrypt(ops_parse_info_t *pinfo);
void ops_parse_cb_set(ops_parse_info_t *pinfo,ops_parse_cb_t *cb,void *arg);
void ops_parse_cb_push(ops_parse_info_t *pinfo,ops_parse_cb_t *cb,void *arg);
void *ops_parse_cb_get_arg(ops_parse_cb_info_t *cbinfo);
void *ops_parse_cb_get_errors(ops_parse_cb_info_t *cbinfo);
void ops_reader_set(ops_parse_info_t *pinfo,ops_reader_t *reader,ops_reader_destroyer_t *destroyer,void *arg);
void ops_reader_push(ops_parse_info_t *pinfo,ops_reader_t *reader,ops_reader_destroyer_t *destroyer,void *arg);
void ops_reader_pop(ops_parse_info_t *pinfo);
void *ops_reader_get_arg_from_pinfo(ops_parse_info_t *pinfo);
void *ops_reader_get_arg(ops_reader_info_t *rinfo);
ops_parse_cb_return_t ops_parse_cb(const ops_parser_content_t *content,
ops_parse_cb_info_t *cbinfo);
ops_parse_cb_return_t ops_parse_stacked_cb(const ops_parser_content_t *content,
ops_parse_cb_info_t *cbinfo);
ops_reader_info_t *ops_parse_get_rinfo(ops_parse_info_t *pinfo);
int ops_parse(ops_parse_info_t *parse_info);
int ops_parse_and_print_errors(ops_parse_info_t *parse_info);
int ops_parse_and_save_errs(ops_parse_info_t *parse_info,ops_ulong_list_t *errs);
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);
/** Used to specify whether subpackets should be returned raw, parsed or ignored.
*/
enum ops_parse_type_t
{
OPS_PARSE_RAW, /*!< Callback Raw */
OPS_PARSE_PARSED, /*!< Callback Parsed */
OPS_PARSE_IGNORE, /*!< Don't callback */
};
void ops_parse_options(ops_parse_info_t *pinfo,ops_content_tag_t tag,
ops_parse_type_t type);
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_region_t *region,
ops_error_t **errors,
ops_reader_info_t *rinfo,
ops_parse_cb_info_t *cbinfo);
void ops_parse_hash_init(ops_parse_info_t *pinfo,ops_hash_algorithm_t type,
const unsigned char *keyid);
void ops_parse_hash_data(ops_parse_info_t *pinfo,const void *data,
size_t length);
void ops_parse_hash_finish(ops_parse_info_t *pinfo);
ops_hash_t *ops_parse_hash_find(ops_parse_info_t *pinfo,
const unsigned char keyid[OPS_KEY_ID_SIZE]);
ops_reader_t ops_stacked_read;
/* vim:set textwidth=120: */
/* vim:set ts=8: */
#endif

View File

@ -0,0 +1,38 @@
/* Generated from packet-show.cast by ../../util/caster.pl, do not edit. */
#include "types.h"
/* (line 4) char *show_packet_tag(ops_packet_tag_t packet_tag, packet_tag_map_t *packet_tag_map) -> char *ops_str_from_map(int packet_tag, ops_map_t *packet_tag_map) */
char *ops_str_from_map(int packet_tag, ops_map_t *packet_tag_map);
#define show_packet_tag(packet_tag,packet_tag_map) ops_str_from_map(CHECKED_INSTANCE_OF(ops_packet_tag_t , packet_tag),CHECKED_INSTANCE_OF( packet_tag_map_t *, packet_tag_map))
typedef char * show_packet_tag_t(ops_packet_tag_t , packet_tag_map_t *);
/* (line 5) char *show_sig_type(ops_sig_type_t sig_type, sig_type_map_t *sig_type_map) -> char *ops_str_from_map(int sig_type, ops_map_t *sig_type_map) */
char *ops_str_from_map(int sig_type, ops_map_t *sig_type_map);
#define show_sig_type(sig_type,sig_type_map) ops_str_from_map(CHECKED_INSTANCE_OF(ops_sig_type_t , sig_type),CHECKED_INSTANCE_OF( sig_type_map_t *, sig_type_map))
typedef char * show_sig_type_t(ops_sig_type_t , sig_type_map_t *);
/* (line 6) char *show_pka(ops_public_key_algorithm_t pka, public_key_algorithm_map_t *pka_map) -> char *ops_str_from_map(int pka, ops_map_t *pka_map) */
char *ops_str_from_map(int pka, ops_map_t *pka_map);
#define show_pka(pka,pka_map) ops_str_from_map(CHECKED_INSTANCE_OF(ops_public_key_algorithm_t , pka),CHECKED_INSTANCE_OF( public_key_algorithm_map_t *, pka_map))
typedef char * show_pka_t(ops_public_key_algorithm_t , public_key_algorithm_map_t *);
/* (line 7) char *show_ss_type(ops_ss_type_t ss_type, ss_type_map_t *ss_type_map) -> char *ops_str_from_map(int ss_type, ops_map_t *ss_type_map) */
char *ops_str_from_map(int ss_type, ops_map_t *ss_type_map);
#define show_ss_type(ss_type,ss_type_map) ops_str_from_map(CHECKED_INSTANCE_OF(ops_ss_type_t , ss_type),CHECKED_INSTANCE_OF( ss_type_map_t *, ss_type_map))
typedef char * show_ss_type_t(ops_ss_type_t , ss_type_map_t *);
/* (line 8) char *show_ss_rr_code(ops_ss_rr_code_t ss_rr_code, ss_rr_code_map_t *ss_rr_code_map) -> char *ops_str_from_map(int ss_rr_code, ops_map_t *ss_rr_code_map) */
char *ops_str_from_map(int ss_rr_code, ops_map_t *ss_rr_code_map);
#define show_ss_rr_code(ss_rr_code,ss_rr_code_map) ops_str_from_map(CHECKED_INSTANCE_OF(ops_ss_rr_code_t , ss_rr_code),CHECKED_INSTANCE_OF( ss_rr_code_map_t *, ss_rr_code_map))
typedef char * show_ss_rr_code_t(ops_ss_rr_code_t , ss_rr_code_map_t *);
/* (line 9) char *show_hash_algorithm(unsigned char hash,+ops_map_t *hash_algorithm_map) -> char *ops_str_from_map(int hash,ops_map_t *hash_algorithm_map) */
char *ops_str_from_map(int hash,ops_map_t *hash_algorithm_map);
#define show_hash_algorithm(hash) ops_str_from_map(CHECKED_INSTANCE_OF(unsigned char , hash),CHECKED_INSTANCE_OF(ops_map_t *, hash_algorithm_map))
typedef char * show_hash_algorithm_t(unsigned char );
/* (line 10) char *show_symmetric_algorithm(unsigned char hash,+ops_map_t *symmetric_algorithm_map) -> char *ops_str_from_map(int hash,ops_map_t *symmetric_algorithm_map) */
char *ops_str_from_map(int hash,ops_map_t *symmetric_algorithm_map);
#define show_symmetric_algorithm(hash) ops_str_from_map(CHECKED_INSTANCE_OF(unsigned char , hash),CHECKED_INSTANCE_OF(ops_map_t *, symmetric_algorithm_map))
typedef char * show_symmetric_algorithm_t(unsigned char );

View File

@ -0,0 +1,94 @@
/*
* 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
*/
#ifndef OPS_PACKET_TO_TEXT_H
#define OPS_PACKET_TO_TEXT_H
#ifndef OPS_PACKET_H
#include "packet.h"
#endif
/** ops_list_t
*/
typedef struct
{
unsigned int size;/* num of array slots allocated */
unsigned int used; /* num of array slots currently used */
char **strings;
} ops_list_t;
/** ops_text_t
*/
typedef struct
{
ops_list_t known;
ops_list_t unknown;
} ops_text_t;
/** ops_bit_map_t
*/
typedef struct
{
unsigned char mask;
char *string;
} ops_bit_map_t;
void ops_text_init(ops_text_t *text);
void ops_text_free(ops_text_t *text);
const char *ops_show_packet_tag(ops_packet_tag_t packet_tag);
const char *ops_show_ss_type(ops_ss_type_t ss_type);
const char *ops_show_sig_type(ops_sig_type_t sig_type);
const char *ops_show_pka(ops_public_key_algorithm_t pka);
ops_text_t *ops_showall_ss_preferred_compression(ops_ss_preferred_compression_t ss_preferred_compression);
const char *ops_show_ss_preferred_compression(unsigned char octet);
ops_text_t *ops_showall_ss_preferred_hash(ops_ss_preferred_hash_t ss_preferred_hash);
const char *ops_show_hash_algorithm(unsigned char octet);
const char *ops_show_symmetric_algorithm(unsigned char hash);
ops_text_t *ops_showall_ss_preferred_ska(ops_ss_preferred_ska_t ss_preferred_ska);
const char *ops_show_ss_preferred_ska(unsigned char octet);
const char *ops_show_ss_rr_code(ops_ss_rr_code_t ss_rr_code);
ops_text_t *ops_showall_ss_features(ops_ss_features_t ss_features);
ops_text_t *ops_showall_ss_key_flags(ops_ss_key_flags_t ss_key_flags);
const char *ops_show_ss_key_flag(unsigned char octet, ops_bit_map_t *map);
ops_text_t *ops_showall_ss_key_server_prefs(ops_ss_key_server_prefs_t ss_key_server_prefs);
const char *ops_show_ss_key_server_prefs(unsigned char octet,
ops_bit_map_t *map);
ops_text_t *ops_showall_ss_notation_data_flags(ops_ss_notation_data_t ss_notation_data);
char *ops_str_from_map(int code, ops_map_t *map);
/* vim:set textwidth=120: */
/* vim:set ts=8: */
#endif /* OPS_PACKET_TO_TEXT_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,28 @@
/*
* 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.
*/
#ifdef WIN32
#include <malloc.h>
#else
#include <unistd.h>
#endif
void ops_random(void *dest,size_t length);

View File

@ -0,0 +1,93 @@
/*
* 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.
*/
#ifndef __OPS_READERWRITER_H__
#define __OPS_READERWRITER_H__
#include <openpgpsdk/memory.h>
#include <openpgpsdk/create.h>
void ops_reader_set_fd(ops_parse_info_t *pinfo,int fd);
void ops_reader_set_memory(ops_parse_info_t *pinfo,const void *buffer,
size_t length);
// Do a sum mod 65536 of all bytes read (as needed for secret keys)
void ops_reader_push_sum16(ops_parse_info_t *pinfo);
unsigned short ops_reader_pop_sum16(ops_parse_info_t *pinfo);
void ops_reader_push_se_ip_data(ops_parse_info_t *pinfo, ops_crypt_t *decrypt,
ops_region_t *region);
void ops_reader_pop_se_ip_data(ops_parse_info_t* pinfo);
//
ops_boolean_t ops_write_mdc(const unsigned char *hashed,
ops_create_info_t* info);
ops_boolean_t ops_write_se_ip_pktset(const unsigned char *data,
const unsigned int len,
ops_crypt_t *crypt,
ops_create_info_t *info);
void ops_writer_push_encrypt_crypt(ops_create_info_t *cinfo,
ops_crypt_t *crypt);
void ops_writer_push_encrypt_se_ip(ops_create_info_t *cinfo,
const ops_keydata_t *pub_key);
// Secret Key checksum
void ops_push_skey_checksum_writer(ops_create_info_t *cinfo, ops_secret_key_t *skey);
ops_boolean_t ops_pop_skey_checksum_writer(ops_create_info_t *cinfo);
// memory writing
void ops_setup_memory_write(ops_create_info_t **cinfo, ops_memory_t **mem, size_t bufsz);
void ops_teardown_memory_write(ops_create_info_t *cinfo, ops_memory_t *mem);
// memory reading
void ops_setup_memory_read(ops_parse_info_t **pinfo, ops_memory_t *mem,
void* arg,
ops_parse_cb_return_t callback(const ops_parser_content_t *, ops_parse_cb_info_t *),ops_boolean_t accumulate);
void ops_teardown_memory_read(ops_parse_info_t *pinfo, ops_memory_t *mem);
// file writing
int ops_setup_file_write(ops_create_info_t **cinfo, const char* filename, ops_boolean_t allow_overwrite);
void ops_teardown_file_write(ops_create_info_t *cinfo, int fd);
// file appending
int ops_setup_file_append(ops_create_info_t **cinfo, const char* filename);
void ops_teardown_file_append(ops_create_info_t *cinfo, int fd);
// file reading
int ops_setup_file_read(ops_parse_info_t **pinfo, const char *filename, void* arg,
ops_parse_cb_return_t callback(const ops_parser_content_t *, ops_parse_cb_info_t *), ops_boolean_t accumulate);
void ops_teardown_file_read(ops_parse_info_t *pinfo, int fd);
ops_boolean_t ops_reader_set_accumulate(ops_parse_info_t* pinfo, ops_boolean_t state);
// useful callbacks
ops_parse_cb_return_t
callback_literal_data(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo);
ops_parse_cb_return_t
callback_pk_session_key(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo);
ops_parse_cb_return_t
callback_cmd_get_secret_key(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo);
ops_parse_cb_return_t
callback_cmd_get_passphrase_from_cmdline(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo);
#endif /*OPS_READERWRITER_H__*/

View File

@ -0,0 +1,95 @@
/*
* 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
*/
#ifndef OPS_SIGNATURE_H
#define OPS_SIGNATURE_H
#include "packet.h"
#include "util.h"
#include "create.h"
typedef struct ops_create_signature ops_create_signature_t;
ops_create_signature_t *ops_create_signature_new(void);
void ops_create_signature_delete(ops_create_signature_t *sig);
ops_boolean_t
ops_check_user_id_certification_signature(const ops_public_key_t *key,
const ops_user_id_t *id,
const ops_signature_t *sig,
const ops_public_key_t *signer,
const unsigned char *raw_packet);
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);
ops_boolean_t
ops_check_subkey_signature(const ops_public_key_t *key,
const ops_public_key_t *subkey,
const ops_signature_t *sig,
const ops_public_key_t *signer,
const unsigned char *raw_packet);
ops_boolean_t
ops_check_direct_signature(const ops_public_key_t *key,
const ops_signature_t *sig,
const ops_public_key_t *signer,
const unsigned char *raw_packet);
ops_boolean_t
ops_check_hash_signature(ops_hash_t *hash,
const ops_signature_t *sig,
const ops_public_key_t *signer);
void ops_signature_start_key_signature(ops_create_signature_t *sig,
const ops_public_key_t *key,
const ops_user_id_t *id,
ops_sig_type_t type);
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);
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);
void ops_signature_add_data(ops_create_signature_t *sig,const void *buf,
size_t length);
ops_hash_t *ops_signature_get_hash(ops_create_signature_t *sig);
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 *opt);
ops_boolean_t ops_signature_add_creation_time(ops_create_signature_t *sig,time_t when);
ops_boolean_t ops_signature_add_issuer_key_id(ops_create_signature_t *sig,
const unsigned char keyid[OPS_KEY_ID_SIZE]);
void ops_signature_add_primary_user_id(ops_create_signature_t *sig,
ops_boolean_t primary);
// Standard Interface
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_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);
#endif

View File

@ -0,0 +1,47 @@
/*
* 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
*/
#ifndef OPS_STD_PRINT_H
#define OPS_STD_PRINT_H
#include "openpgpsdk/packet.h"
#include "openpgpsdk/packet-parse.h"
#include "openpgpsdk/keyring.h"
void print_bn( const char *name,
const BIGNUM *bn);
void ops_print_pk_session_key(ops_content_tag_t tag,
const ops_pk_session_key_t *key);
void ops_print_public_keydata(const ops_keydata_t *key);
void ops_print_public_keydata_verbose(const ops_keydata_t *key);
void ops_print_public_key(const ops_public_key_t *pkey);
void ops_print_secret_keydata(const ops_keydata_t *key);
void ops_print_secret_keydata_verbose(const ops_keydata_t *key);
//void ops_print_secret_key(const ops_content_tag_t type, const ops_secret_key_t* skey);
int ops_print_packet(const ops_parser_content_t *content_);
void ops_list_packets(char *filename, ops_boolean_t armour, ops_keyring_t* pubring, ops_parse_cb_t* cb_get_passphrase);
#endif

View File

@ -0,0 +1,30 @@
/*
* 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.
*/
#ifndef __OPS_STREAMWRITER_H__
#define __OPS_STREAMWRITER_H__
#include <openpgpsdk/readerwriter.h>
void ops_writer_push_stream_encrypt_se_ip(ops_create_info_t *cinfo,
const ops_key_data_t *pub_key);
#endif /*__OPS_STREAMWRITER_H__*/

View File

@ -0,0 +1,96 @@
/*
* 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
*/
#ifndef OPS_TYPES_H
#define OPS_TYPES_H
/** Special type for intermediate function casting, avoids warnings on
some platforms
*/
typedef void (*ops_void_fptr)(void);
#define ops_fcast(f) ((ops_void_fptr)f)
/** ops_map_t
*/
typedef struct
{
int type;
char *string;
} ops_map_t;
/** Boolean type */
typedef unsigned ops_boolean_t;
/** ops_content_tag_t */
typedef enum ops_content_tag_t ops_content_tag_t;
typedef struct _ops_crypt_t ops_crypt_t;
/** ops_hash_t */
typedef struct _ops_hash_t ops_hash_t;
/**
keep both ops_content_tag_t and ops_packet_tag_t because we might
want to introduce some bounds checking i.e. is this really a valid value
for a packet tag?
*/
typedef enum ops_content_tag_t ops_packet_tag_t;
/** SS types are a subset of all content types.
*/
typedef enum ops_content_tag_t ops_ss_type_t;
/* typedef enum ops_sig_type_t ops_sig_type_t; */
/** Revocation Reason type */
typedef unsigned char ops_ss_rr_code_t;
/** ops_parse_type_t */
typedef enum ops_parse_type_t ops_parse_type_t;
/** ops_parser_content_t */
typedef struct ops_parser_content_t ops_parser_content_t;
/** Reader Flags */
/*
typedef enum
{
OPS_RETURN_LENGTH=1,
} ops_reader_flags_t;
typedef enum ops_reader_ret_t ops_reader_ret_t;
*/
/** Writer flags */
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
* Contains the required information about how to write
*/
typedef struct ops_create_info ops_create_info_t;
#endif

View File

@ -0,0 +1,54 @@
/*
* 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
*/
#ifndef OPS_UTIL_H
#define OPS_UTIL_H
#include "openpgpsdk/types.h"
#include "openpgpsdk/create.h"
#include "openpgpsdk/packet-parse.h"
#include <stdlib.h>
#define ops_false 0
#define ops_true 1
void hexdump(const unsigned char *src,size_t length);
/*
* These macros code ensures that you are casting what you intend to cast.
* It works because in "a ? b : c", b and c must have the same type.
* This is a copy of the macro defined in openssl/asn1.h.
*/
#ifndef CHECKED_PTR_OF
#define CHECKED_PTR_OF(type, p) ((void*) (1 ? p : (type *)0))
#endif
#define CHECKED_INSTANCE_OF(type, p) (1 ? p : (type)0)
#define DECONST(type,p) ((type *)CHECKED_PTR_OF(const type, p))
/* number of elements in an array */
#define OPS_ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a)))
void *ops_mallocz(size_t n);
#endif

View File

@ -0,0 +1,102 @@
/*
* 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.
*/
typedef struct
{
unsigned int valid_count;
ops_signature_info_t * valid_sigs;
unsigned int invalid_count;
ops_signature_info_t * invalid_sigs;
unsigned int unknown_signer_count;
ops_signature_info_t * unknown_sigs;
} ops_validate_result_t;
void ops_validate_result_free(ops_validate_result_t *result);
ops_boolean_t ops_validate_key_signatures(ops_validate_result_t *result,
const ops_keydata_t* keydata,
const ops_keyring_t *ring,
ops_parse_cb_return_t cb (const ops_parser_content_t *, ops_parse_cb_info_t *));
ops_boolean_t ops_validate_all_signatures(ops_validate_result_t *result,
const ops_keyring_t *ring,
ops_parse_cb_return_t (const ops_parser_content_t *, ops_parse_cb_info_t *));
void ops_keydata_reader_set(ops_parse_info_t *pinfo,
const ops_keydata_t *key);
typedef struct
{
const ops_keydata_t *key;
unsigned packet;
unsigned offset;
} validate_reader_arg_t;
/** Struct used with the validate_key_cb callback */
typedef struct
{
ops_public_key_t pkey;
ops_public_key_t subkey;
ops_secret_key_t skey;
enum
{
ATTRIBUTE=1,
ID,
} last_seen;
ops_user_id_t user_id;
ops_user_attribute_t user_attribute;
unsigned char hash[OPS_MAX_HASH_SIZE];
const ops_keyring_t *keyring;
validate_reader_arg_t *rarg;
ops_validate_result_t *result;
ops_parse_cb_return_t (*cb_get_passphrase) (const ops_parser_content_t *, ops_parse_cb_info_t *);
} validate_key_cb_arg_t;
/** Struct use with the validate_data_cb callback */
typedef struct
{
enum
{
LITERAL_DATA,
SIGNED_CLEARTEXT
} use; /*<! this is set to indicate what kind of data we have */
union
{
ops_literal_data_body_t literal_data_body; /*<! Used to hold Literal Data */
ops_signed_cleartext_body_t signed_cleartext_body; /*<! Used to hold Signed Cleartext */
} data; /*<! the data itself */
unsigned char hash[OPS_MAX_HASH_SIZE]; /*<! the hash */
const ops_keyring_t *keyring; /*<! keyring to use */
validate_reader_arg_t *rarg; /*<! reader-specific arg */
ops_validate_result_t *result; /*<! where to put the result */
} validate_data_cb_arg_t; /*<! used with validate_data_cb callback */
ops_boolean_t ops_check_signature(const unsigned char *hash,
unsigned length,
const ops_signature_t *sig,
const ops_public_key_t *signer);
ops_parse_cb_return_t
ops_validate_key_cb(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo);
ops_boolean_t ops_validate_file(ops_validate_result_t* result, const char* filename, const int armoured, const ops_keyring_t* keyring);
ops_boolean_t ops_validate_mem(ops_validate_result_t *result, ops_memory_t* mem, const int armoured, const ops_keyring_t* keyring);
// EOF

View File

@ -0,0 +1,39 @@
/*
* 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.
*/
#define OPS_VERSION_MAJOR 0
/* Set to the version next to be released */
#define OPS_VERSION_MINOR 9
/* 0 for development version, 1 for release */
#define OPS_VERSION_RELEASE 1
#define OPS_VERSION ((OPS_VERSION_MAJOR << 16)+(OPS_VERSION_MINOR << 1)+OPS_VERSION_RELEASE)
#if OPS_VERSION_RELEASE
# define OPS_DEV_STRING ""
#else
# define OPS_DEV_STRING " (dev)"
#endif
#define OPS_VERSION_CAT(a,b) "OpenPGP:SDK v" #a "." #b OPS_DEV_STRING
#define OPS_VERSION_CAT2(a,b) OPS_VERSION_CAT(a,b)
#define OPS_VERSION_STRING OPS_VERSION_CAT2(OPS_VERSION_MAJOR,OPS_VERSION_MINOR)

View File

@ -0,0 +1,100 @@
/*
* 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
*/
#ifndef OPS_WRITER_H
#define OPS_WRITER_H
#include "types.h"
#include "packet.h"
#include "crypto.h"
#include "memory.h"
#include "errors.h"
#include "keyring.h"
/**
* \ingroup Create
* This struct contains the required information about one writer
*/
/**
* \ingroup Writer
* the writer function prototype
*/
typedef struct ops_writer_info ops_writer_info_t;
typedef ops_boolean_t ops_writer_t(const unsigned char *src,
unsigned length,
ops_error_t **errors,
ops_writer_info_t *winfo);
typedef ops_boolean_t ops_writer_finaliser_t(ops_error_t **errors,
ops_writer_info_t *winfo);
typedef void ops_writer_destroyer_t(ops_writer_info_t *winfo);
/** Writer settings */
struct ops_writer_info
{
ops_writer_t *writer; /*!< the writer itself */
ops_writer_finaliser_t *finaliser; /*!< the writer's finaliser */
ops_writer_destroyer_t *destroyer; /*!< the writer's destroyer */
void *arg; /* writer-specific argument */
ops_writer_info_t *next; /*!< next writer in the stack */
};
void *ops_writer_get_arg(ops_writer_info_t *winfo);
ops_boolean_t ops_stacked_write(const void *src,unsigned length,
ops_error_t **errors,
ops_writer_info_t *winfo);
void ops_writer_set(ops_create_info_t *info,
ops_writer_t *writer,
ops_writer_finaliser_t *finaliser,
ops_writer_destroyer_t *destroyer,
void *arg);
void ops_writer_push(ops_create_info_t *info,
ops_writer_t *writer,
ops_writer_finaliser_t *finaliser,
ops_writer_destroyer_t *destroyer,
void *arg);
void ops_writer_pop(ops_create_info_t *info);
void ops_writer_generic_destroyer(ops_writer_info_t *winfo);
ops_boolean_t ops_writer_passthrough(const unsigned char *src,
unsigned length,
ops_error_t **errors,
ops_writer_info_t *winfo);
void ops_writer_set_fd(ops_create_info_t *info,int fd);
ops_boolean_t ops_writer_close(ops_create_info_t *info);
ops_boolean_t ops_write(const void *src,unsigned length,
ops_create_info_t *opt);
ops_boolean_t ops_write_length(unsigned length,ops_create_info_t *opt);
ops_boolean_t ops_write_ptag(ops_content_tag_t tag,ops_create_info_t *opt);
ops_boolean_t ops_write_scalar(unsigned n,unsigned length,
ops_create_info_t *opt);
ops_boolean_t ops_write_mpi(const BIGNUM *bn,ops_create_info_t *opt);
ops_boolean_t ops_write_encrypted_mpi(const BIGNUM *bn, ops_crypt_t* crypt, ops_create_info_t *info);
void writer_info_delete(ops_writer_info_t *winfo);
ops_boolean_t writer_info_finalise(ops_error_t **errors, ops_writer_info_t *winfo);
#endif

View File

@ -0,0 +1,31 @@
/*
* 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.
*/
#include <openpgpsdk/armour.h>
ops_boolean_t ops_writer_push_clearsigned(ops_create_info_t *info,
ops_create_signature_t *sig);
void ops_writer_push_armoured_message(ops_create_info_t *info);
ops_boolean_t ops_writer_switch_to_armoured_signature(ops_create_info_t *info);
void ops_writer_push_armoured(ops_create_info_t *info, ops_armor_type_t type);
// EOF

195
openpgpsdk/src/accumulate.c Normal file
View File

@ -0,0 +1,195 @@
/*
* 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 <openpgpsdk/packet.h>
#include <openpgpsdk/packet-parse.h>
#include <openpgpsdk/util.h>
#include <openpgpsdk/accumulate.h>
#include "keyring_local.h"
#include "parse_local.h"
#include <openpgpsdk/signature.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <openpgpsdk/final.h>
typedef struct
{
ops_keyring_t *keyring;
} accumulate_arg_t;
/**
* \ingroup Core_Callbacks
*/
static ops_parse_cb_return_t
accumulate_cb(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo)
{
accumulate_arg_t *arg=ops_parse_cb_get_arg(cbinfo);
const ops_parser_content_union_t *content=&content_->content;
ops_keyring_t *keyring=arg->keyring;
ops_keydata_t *cur=NULL;
const ops_public_key_t *pkey;
if(keyring->nkeys >= 0)
cur=&keyring->keys[keyring->nkeys];
switch(content_->tag)
{
case OPS_PTAG_CT_PUBLIC_KEY:
case OPS_PTAG_CT_SECRET_KEY:
case OPS_PTAG_CT_ENCRYPTED_SECRET_KEY:
// printf("New key\n");
++keyring->nkeys;
EXPAND_ARRAY(keyring,keys);
if(content_->tag == OPS_PTAG_CT_PUBLIC_KEY)
pkey=&content->public_key;
else
pkey=&content->secret_key.public_key;
memset(&keyring->keys[keyring->nkeys],'\0',
sizeof keyring->keys[keyring->nkeys]);
ops_keyid(keyring->keys[keyring->nkeys].key_id,pkey);
ops_fingerprint(&keyring->keys[keyring->nkeys].fingerprint,pkey);
keyring->keys[keyring->nkeys].type=content_->tag;
if(content_->tag == OPS_PTAG_CT_PUBLIC_KEY)
keyring->keys[keyring->nkeys].key.pkey=*pkey;
else
keyring->keys[keyring->nkeys].key.skey=content->secret_key;
return OPS_KEEP_MEMORY;
case OPS_PTAG_CT_USER_ID:
// printf("User ID: %s\n",content->user_id.user_id);
if (!cur)
{
OPS_ERROR(cbinfo->errors,OPS_E_P_NO_USERID, "No user id found");
return OPS_KEEP_MEMORY;
}
// assert(cur);
ops_add_userid_to_keydata(cur, &content->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);
return OPS_KEEP_MEMORY;
case OPS_PARSER_ERROR:
fprintf(stderr,"Error: %s\n",content->error.error);
assert(0);
break;
case OPS_PARSER_ERRCODE:
switch(content->errcode.errcode)
{
default:
fprintf(stderr,"parse error: %s\n",
ops_errcode(content->errcode.errcode));
//assert(0);
}
break;
default:
break;
}
// XXX: we now exclude so many things, we should either drop this or
// do something to pass on copies of the stuff we keep
return ops_parse_stacked_cb(content_,cbinfo);
}
/**
* \ingroup Core_Parse
*
* Parse packets from an input stream until EOF or error.
*
* Key data found in the parsed data is added to #keyring.
*
* \param keyring Pointer to an existing keyring
* \param parse_info Options to use when parsing
*/
int ops_parse_and_accumulate(ops_keyring_t *keyring,
ops_parse_info_t *parse_info)
{
int rtn;
accumulate_arg_t arg;
assert(!parse_info->rinfo.accumulate);
memset(&arg,'\0',sizeof arg);
arg.keyring=keyring;
/* Kinda weird, but to do with counting, and we put it back after */
--keyring->nkeys;
ops_parse_cb_push(parse_info,accumulate_cb,&arg);
parse_info->rinfo.accumulate=ops_true;
rtn=ops_parse(parse_info);
++keyring->nkeys;
return rtn;
}
static void dump_one_keydata(const ops_keydata_t *key)
{
unsigned n;
printf("Key ID: ");
hexdump(key->key_id,8);
printf("\nFingerpint: ");
hexdump(key->fingerprint.fingerprint,key->fingerprint.length);
printf("\n\nUIDs\n====\n\n");
for(n=0 ; n < key->nuids ; ++n)
printf("%s\n",key->uids[n].user_id);
printf("\nPackets\n=======\n");
for(n=0 ; n < key->npackets ; ++n)
{
printf("\n%03d: ",n);
hexdump(key->packets[n].raw,key->packets[n].length);
}
printf("\n\n");
}
// XXX: not a maintained part of the API - use ops_keyring_list()
/** ops_dump_keyring
*/
void ops_dump_keyring(const ops_keyring_t *keyring)
{
int n;
for(n=0 ; n < keyring->nkeys ; ++n)
dump_one_keydata(&keyring->keys[n]);
}

405
openpgpsdk/src/compress.c Normal file
View File

@ -0,0 +1,405 @@
/*
* 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 <zlib.h>
#include <bzlib.h>
#include <assert.h>
#include <string.h>
#include <openpgpsdk/compress.h>
#include <openpgpsdk/packet-parse.h>
#include <openpgpsdk/crypto.h>
#include <openpgpsdk/errors.h>
#include "parse_local.h"
#include <openpgpsdk/final.h>
#define DECOMPRESS_BUFFER 1024
typedef struct
{
ops_compression_type_t type;
ops_region_t *region;
unsigned char in[DECOMPRESS_BUFFER];
unsigned char out[DECOMPRESS_BUFFER];
z_stream zstream; // ZIP and ZLIB
size_t offset;
int inflate_ret;
} z_decompress_arg_t;
typedef struct
{
ops_compression_type_t type;
ops_region_t *region;
char in[DECOMPRESS_BUFFER];
char out[DECOMPRESS_BUFFER];
bz_stream bzstream; // BZIP2
size_t offset;
int inflate_ret;
} bz_decompress_arg_t;
typedef struct
{
z_stream stream;
unsigned char *src;
unsigned char *dst;
} 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)
{
z_decompress_arg_t *arg=ops_reader_get_arg(rinfo);
assert(arg->type==OPS_C_ZIP || arg->type==OPS_C_ZLIB);
//ops_parser_content_t content;
int saved=length;
if(/*arg->region->indeterminate && */ arg->inflate_ret == Z_STREAM_END
&& arg->zstream.next_out == &arg->out[arg->offset])
return 0;
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.");
/*
else
return 0;
www.zlib.org
*/
}
while(length > 0)
{
unsigned len;
if(&arg->out[arg->offset] == arg->zstream.next_out)
{
int ret;
arg->zstream.next_out=arg->out;
arg->zstream.avail_out=sizeof arg->out;
arg->offset=0;
if(arg->zstream.avail_in == 0)
{
unsigned n=arg->region->length;
if(!arg->region->indeterminate)
{
n-=arg->region->length_read;
if(n > sizeof arg->in)
n=sizeof arg->in;
}
else
n=sizeof arg->in;
if(!ops_stacked_limited_read(arg->in,n,arg->region,
errors,rinfo,cbinfo))
return -1;
arg->zstream.next_in=arg->in;
arg->zstream.avail_in=arg->region->indeterminate
? arg->region->last_read : n;
}
ret=inflate(&arg->zstream,Z_SYNC_FLUSH);
if(ret == Z_STREAM_END)
{
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.");
}
else if(ret != Z_OK)
{
fprintf(stderr,"ret=%d\n",ret);
OPS_ERROR(cbinfo->errors,OPS_E_P_DECOMPRESSION_ERROR, arg->zstream.msg);
}
arg->inflate_ret=ret;
}
assert(arg->zstream.next_out > &arg->out[arg->offset]);
len=arg->zstream.next_out-&arg->out[arg->offset];
if(len > length)
len=length;
memcpy(dest,&arg->out[arg->offset],len);
arg->offset+=len;
length-=len;
}
return saved;
}
// \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)
{
bz_decompress_arg_t *arg=ops_reader_get_arg(rinfo);
assert(arg->type==OPS_C_BZIP2);
//ops_parser_content_t content;
int saved=length;
if(arg->inflate_ret == BZ_STREAM_END
&& arg->bzstream.next_out == &arg->out[arg->offset])
return 0;
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.");
}
while(length > 0)
{
unsigned len;
if(&arg->out[arg->offset] == arg->bzstream.next_out)
{
int ret;
arg->bzstream.next_out=(char *) arg->out;
arg->bzstream.avail_out=sizeof arg->out;
arg->offset=0;
if(arg->bzstream.avail_in == 0)
{
unsigned n=arg->region->length;
if(!arg->region->indeterminate)
{
n-=arg->region->length_read;
if(n > sizeof arg->in)
n=sizeof arg->in;
}
else
n=sizeof arg->in;
if(!ops_stacked_limited_read((unsigned char *)arg->in,n,arg->region,
errors,rinfo,cbinfo))
return -1;
arg->bzstream.next_in=arg->in;
arg->bzstream.avail_in=arg->region->indeterminate
? arg->region->last_read : n;
}
ret=BZ2_bzDecompress(&arg->bzstream);
if(ret == BZ_STREAM_END)
{
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.");
}
else if(ret != BZ_OK)
{
OPS_ERROR_1(cbinfo->errors,OPS_E_P_DECOMPRESSION_ERROR,"Invalid return %d from BZ2_bzDecompress", ret);
}
arg->inflate_ret=ret;
}
assert(arg->bzstream.next_out > &arg->out[arg->offset]);
len=arg->bzstream.next_out-&arg->out[arg->offset];
if(len > length)
len=length;
memcpy(dest,&arg->out[arg->offset],len);
arg->offset+=len;
length-=len;
}
return saved;
}
/**
* \ingroup Core_Compress
*
* \param *region Pointer to a region
* \param *parse_info How to parse
* \param type Which compression type to expect
*/
int ops_decompress(ops_region_t *region,ops_parse_info_t *parse_info,
ops_compression_type_t type)
{
z_decompress_arg_t z_arg;
bz_decompress_arg_t bz_arg;
int ret;
switch (type)
{
case OPS_C_ZIP:
case OPS_C_ZLIB:
memset(&z_arg,'\0',sizeof z_arg);
z_arg.region=region;
z_arg.offset=0;
z_arg.type=type;
z_arg.zstream.next_in=Z_NULL;
z_arg.zstream.avail_in=0;
z_arg.zstream.next_out=z_arg.out;
z_arg.zstream.zalloc=Z_NULL;
z_arg.zstream.zfree=Z_NULL;
z_arg.zstream.opaque=Z_NULL;
break;
case OPS_C_BZIP2:
memset(&bz_arg,'\0',sizeof bz_arg);
bz_arg.region=region;
bz_arg.offset=0;
bz_arg.type=type;
bz_arg.bzstream.next_in=NULL;
bz_arg.bzstream.avail_in=0;
bz_arg.bzstream.next_out=bz_arg.out;
bz_arg.bzstream.bzalloc=NULL;
bz_arg.bzstream.bzfree=NULL;
bz_arg.bzstream.opaque=NULL;
break;
default:
OPS_ERROR_1(&parse_info->errors, OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG, "Compression algorithm %d is not yet supported", type);
return 0;
}
switch(type)
{
case OPS_C_ZIP:
ret=inflateInit2(&z_arg.zstream,-15);
break;
case OPS_C_ZLIB:
ret=inflateInit(&z_arg.zstream);
break;
case OPS_C_BZIP2:
/*
OPS_ERROR_1(&parse_info->errors, OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG, "Compression algorithm %s is not yet supported", "BZIP2");
return 0;
*/
ret=BZ2_bzDecompressInit(&bz_arg.bzstream, 1, 0);
break;
default:
OPS_ERROR_1(&parse_info->errors, OPS_E_ALG_UNSUPPORTED_COMPRESS_ALG, "Compression algorithm %d is not yet supported", type);
return 0;
}
switch (type)
{
case OPS_C_ZIP:
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);
return 0;
}
ops_reader_push(parse_info,zlib_compressed_data_reader,NULL,&z_arg);
break;
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);
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);
return 0;
}
ret=ops_parse(parse_info);
ops_reader_pop(parse_info);
return ret;
}
/**
\ingroup Core_WritePackets
\brief Writes Compressed packet
\param data Data to write out
\param len Length of data
\param cinfo Write settings
\return ops_true if OK; else ops_false
*/
ops_boolean_t ops_write_compressed(const unsigned char *data,
const unsigned int len,
ops_create_info_t *cinfo)
{
int r=0;
int sz_in=0;
int sz_out=0;
compress_arg_t* compress=ops_mallocz(sizeof *compress);
// compress the data
const int level=Z_DEFAULT_COMPRESSION; // \todo allow varying levels
compress->stream.zalloc=Z_NULL;
compress->stream.zfree=Z_NULL;
compress->stream.opaque=NULL;
// all other fields set to zero by use of ops_mallocz
if (deflateInit(&compress->stream,level) != Z_OK)
{
// can't initialise
assert(0);
}
// do necessary transformation
// copy input to maintain const'ness of src
assert(compress->src==NULL);
assert(compress->dst==NULL);
sz_in=len * sizeof (unsigned char);
sz_out= (sz_in * 1.01) + 12; // from zlib webpage
compress->src=ops_mallocz(sz_in);
compress->dst=ops_mallocz(sz_out);
memcpy(compress->src,data,len);
// setup stream
compress->stream.next_in=compress->src;
compress->stream.avail_in=sz_in;
compress->stream.total_in=0;
compress->stream.next_out=compress->dst;
compress->stream.avail_out=sz_out;
compress->stream.total_out=0;
r=deflate(&compress->stream, Z_FINISH);
assert(r==Z_STREAM_END); // need to loop if not
// write it out
return (ops_write_ptag(OPS_PTAG_CT_COMPRESSED, cinfo)
&& ops_write_length(1+compress->stream.total_out, cinfo)
&& ops_write_scalar(OPS_C_ZLIB,1,cinfo)
&& ops_write(compress->dst, compress->stream.total_out,cinfo));
}
// EOF

1258
openpgpsdk/src/create.c Normal file

File diff suppressed because it is too large Load Diff

400
openpgpsdk/src/crypto.c Normal file
View File

@ -0,0 +1,400 @@
/*
* 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.
*/
#include <openpgpsdk/crypto.h>
#include <openpgpsdk/random.h>
#include <openpgpsdk/readerwriter.h>
#include <openpgpsdk/writer_armoured.h>
#include "parse_local.h"
#include <assert.h>
#include <string.h>
#include <fcntl.h>
#include <openpgpsdk/final.h>
/**
\ingroup Core_MPI
\brief Decrypt and unencode MPI
\param buf Buffer in which to write decrypted unencoded MPI
\param buflen Length of buffer
\param encmpi
\param skey
\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)
{
unsigned char encmpibuf[8192];
unsigned char mpibuf[8192];
unsigned mpisize;
int n;
int i;
mpisize=BN_num_bytes(encmpi);
/* MPI can't be more than 65,536 */
assert(mpisize <= sizeof encmpibuf);
BN_bn2bin(encmpi,encmpibuf);
assert(skey->public_key.algorithm == OPS_PKA_RSA);
/*
fprintf(stderr,"\nDECRYPTING\n");
fprintf(stderr,"encrypted data : ");
for (i=0; i<16; i++)
fprintf(stderr,"%2x ", encmpibuf[i]);
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);
/*
fprintf(stderr,"decrypted encoded m buf : ");
for (i=0; i<16; i++)
fprintf(stderr,"%2x ", mpibuf[i]);
fprintf(stderr,"\n");
*/
if(n <= 0)
return -1;
/*
printf(" decrypted=%d ",n);
hexdump(mpibuf,n);
printf("\n");
*/
// Decode EME-PKCS1_V1_5 (RFC 2437).
if(mpibuf[0] != 0 || mpibuf[1] != 2)
return ops_false;
// Skip the random bytes.
for(i=2 ; i < n && mpibuf[i] ; ++i)
;
if(i == n || i < 10)
return ops_false;
// Skip the zero
++i;
// this is the unencoded m buf
if((unsigned)(n-i) <= buflen)
memcpy(buf,mpibuf+i,n-i);
/*
printf("decoded m buf:\n");
int j;
for (j=0; j<n-i; j++)
printf("%2x ",buf[j]);
printf("\n");
*/
return n-i;
}
/**
\ingroup Core_MPI
\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)
{
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);
assert(n!=-1);
if(n <= 0)
return ops_false;
skp->rsa.encrypted_m=BN_bin2bn(encmpibuf, n, NULL);
/*
fprintf(stderr,"encrypted mpi buf : ");
int i;
for (i=0; i<16; i++)
fprintf(stderr,"%2x ", encmpibuf[i]);
fprintf(stderr,"\n");
*/
return ops_true;
}
#define MAXBUF 1024
static ops_parse_cb_return_t
callback_write_parsed(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo);
/**
\ingroup HighLevel_Crypto
Encrypt a file
\param input_filename Name of file to be encrypted
\param output_filename Name of file to write to. If NULL, name is constructed from input_filename
\param pub_key Public Key to encrypt file for
\param use_armour Write armoured text, if set
\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)
{
int fd_in=0;
int fd_out=0;
ops_create_info_t *cinfo;
#ifdef WIN32
fd_in=open(input_filename,O_RDONLY | O_BINARY);
#else
fd_in=open(input_filename,O_RDONLY);
#endif
if(fd_in < 0)
{
perror(input_filename);
return ops_false;
}
fd_out=ops_setup_file_write(&cinfo, output_filename, allow_overwrite);
if (fd_out < 0)
return ops_false;
// set armoured/not armoured here
if (use_armour)
ops_writer_push_armoured_message(cinfo);
// Push the encrypted writer
ops_writer_push_encrypt_se_ip(cinfo,pub_key);
// Do the writing
unsigned char* buf=NULL;
size_t bufsz=16;
int done=0;
for (;;)
{
buf=realloc(buf,done+bufsz);
int n=0;
n=read(fd_in,buf+done,bufsz);
if (!n)
break;
assert(n>=0);
done+=n;
}
// This does the writing
ops_write(buf,done,cinfo);
// tidy up
close(fd_in);
free(buf);
ops_teardown_file_write(cinfo,fd_out);
return ops_true;
}
/**
\ingroup HighLevel_Crypto
\brief Decrypt a file.
\param input_filename Name of file to be decrypted
\param output_filename Name of file to write to. If NULL, the filename is constructed from the input filename, following GPG conventions.
\param keyring Keyring to use
\param use_armour Expect armoured text, if set
\param allow_overwrite Allow output file to overwritten, if set.
\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)
{
int fd_in=0;
int fd_out=0;
char* myfilename=NULL;
//
ops_parse_info_t *pinfo=NULL;
// setup for reading from given input file
fd_in=ops_setup_file_read(&pinfo, input_filename,
NULL,
callback_write_parsed,
ops_false);
if (fd_in < 0)
{
perror(input_filename);
return ops_false;
}
// setup output filename
if (output_filename)
{
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);
return ops_false;
}
}
else
{
int suffixlen=4;
char *defaultsuffix=".decrypted";
const char *suffix=input_filename+strlen((char *)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);
}
else
{
unsigned filenamelen=strlen(input_filename)+strlen(defaultsuffix)+1;
myfilename=ops_mallocz(filenamelen);
snprintf(myfilename,filenamelen,"%s%s",input_filename,defaultsuffix);
}
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);
return ops_false;
}
free (myfilename);
}
// \todo check for suffix matching armour param
// setup for writing decrypted contents to given output file
// setup keyring and passphrase callback
pinfo->cbinfo.cryptinfo.keyring=keyring;
pinfo->cbinfo.cryptinfo.cb_get_passphrase=cb_get_passphrase;
// Set up armour/passphrase options
if (use_armour)
ops_reader_push_dearmour(pinfo);
// Do it
ops_parse_and_print_errors(pinfo);
// Unsetup
if (use_armour)
ops_reader_pop_dearmour(pinfo);
ops_teardown_file_write(pinfo->cbinfo.cinfo, fd_out);
ops_teardown_file_read(pinfo, fd_in);
// \todo cleardown crypt
return ops_true;
}
static ops_parse_cb_return_t
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;
static ops_boolean_t skipping;
// ops_boolean_t write=ops_true;
OPS_USED(cbinfo);
// ops_print_packet(content_);
if(content_->tag != OPS_PTAG_CT_UNARMOURED_TEXT && skipping)
{
puts("...end of skip");
skipping=ops_false;
}
switch(content_->tag)
{
case OPS_PTAG_CT_UNARMOURED_TEXT:
printf("OPS_PTAG_CT_UNARMOURED_TEXT\n");
if(!skipping)
{
puts("Skipping...");
skipping=ops_true;
}
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);
break;
case OPS_PARSER_CMD_GET_SECRET_KEY:
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);
break;
case OPS_PTAG_CT_LITERAL_DATA_BODY:
return callback_literal_data(content_,cbinfo);
break;
case OPS_PTAG_CT_ARMOUR_HEADER:
case OPS_PTAG_CT_ARMOUR_TRAILER:
case OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY:
case OPS_PTAG_CT_COMPRESSED:
case OPS_PTAG_CT_LITERAL_DATA_HEADER:
case OPS_PTAG_CT_SE_IP_DATA_BODY:
case OPS_PTAG_CT_SE_IP_DATA_HEADER:
case OPS_PTAG_CT_SE_DATA_BODY:
case OPS_PTAG_CT_SE_DATA_HEADER:
// Ignore these packets
// They're handled in ops_parse_one_packet()
// and nothing else needs to be done
break;
default:
// return callback_general(content_,cbinfo);
break;
// fprintf(stderr,"Unexpected packet tag=%d (0x%x)\n",content_->tag,
// content_->tag);
// assert(0);
}
return OPS_RELEASE_MEMORY;
}
// EOF

211
openpgpsdk/src/errors.c Normal file
View File

@ -0,0 +1,211 @@
/*
* 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
* \brief Error Handling
*/
#include <openpgpsdk/errors.h>
#include <openpgpsdk/util.h>
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#define vsnprintf _vsnprintf
#endif
#include <openpgpsdk/packet-show.h>
#include <openpgpsdk/final.h>
#define ERRNAME(code) { code, #code }
static ops_errcode_name_map_t errcode_name_map[] =
{
ERRNAME(OPS_E_OK),
ERRNAME(OPS_E_FAIL),
ERRNAME(OPS_E_SYSTEM_ERROR),
ERRNAME(OPS_E_UNIMPLEMENTED),
ERRNAME(OPS_E_R),
ERRNAME(OPS_E_R_READ_FAILED),
ERRNAME(OPS_E_R_EARLY_EOF),
ERRNAME(OPS_E_R_BAD_FORMAT),
ERRNAME(OPS_E_R_UNCONSUMED_DATA),
ERRNAME(OPS_E_W),
ERRNAME(OPS_E_W_WRITE_FAILED),
ERRNAME(OPS_E_W_WRITE_TOO_SHORT),
ERRNAME(OPS_E_P),
ERRNAME(OPS_E_P_NOT_ENOUGH_DATA),
ERRNAME(OPS_E_P_UNKNOWN_TAG),
ERRNAME(OPS_E_P_PACKET_CONSUMED),
ERRNAME(OPS_E_P_MPI_FORMAT_ERROR),
ERRNAME(OPS_E_C),
ERRNAME(OPS_E_V),
ERRNAME(OPS_E_V_BAD_SIGNATURE),
ERRNAME(OPS_E_V_NO_SIGNATURE),
ERRNAME(OPS_E_V_UNKNOWN_SIGNER),
ERRNAME(OPS_E_ALG),
ERRNAME(OPS_E_ALG_UNSUPPORTED_SYMMETRIC_ALG),
ERRNAME(OPS_E_ALG_UNSUPPORTED_PUBLIC_KEY_ALG),
ERRNAME(OPS_E_ALG_UNSUPPORTED_SIGNATURE_ALG),
ERRNAME(OPS_E_ALG_UNSUPPORTED_HASH_ALG),
ERRNAME(OPS_E_PROTO),
ERRNAME(OPS_E_PROTO_BAD_SYMMETRIC_DECRYPT),
ERRNAME(OPS_E_PROTO_UNKNOWN_SS),
ERRNAME(OPS_E_PROTO_CRITICAL_SS_IGNORED),
ERRNAME(OPS_E_PROTO_BAD_PUBLIC_KEY_VRSN),
ERRNAME(OPS_E_PROTO_BAD_SIGNATURE_VRSN),
ERRNAME(OPS_E_PROTO_BAD_ONE_PASS_SIG_VRSN),
ERRNAME(OPS_E_PROTO_BAD_PKSK_VRSN),
ERRNAME(OPS_E_PROTO_DECRYPTED_MSG_WRONG_LEN),
ERRNAME(OPS_E_PROTO_BAD_SK_CHECKSUM),
{ 0x00, NULL }, /* this is the end-of-array marker */
};
/**
* \ingroup Core_Errors
* \brief returns error code name
* \param errcode
* \return error code name or "Unknown"
*/
char *ops_errcode(const ops_errcode_t errcode)
{
return(ops_str_from_map((int) errcode, (ops_map_t *) errcode_name_map));
}
/**
* \ingroup Core_Errors
* \brief Pushes the given error on the given errorstack
* \param errstack Error stack to use
* \param errcode Code of error to push
* \param sys_errno System errno (used if errcode=OPS_E_SYSTEM_ERROR)
* \param file Source filename where error occurred
* \param line Line in source file where error occurred
* \param fmt Comment
*
*/
void ops_push_error(ops_error_t **errstack,ops_errcode_t errcode,int sys_errno,
const char *file,int line,const char *fmt,...)
{
// first get the varargs and generate the comment
char *comment;
int maxbuf=128;
va_list args;
ops_error_t *err;
comment=malloc(maxbuf+1);
assert(comment);
va_start(args, fmt);
vsnprintf(comment,maxbuf+1,fmt,args);
va_end(args);
// alloc a new error and add it to the top of the stack
err=malloc(sizeof(ops_error_t));
assert(err);
err->next=*errstack;
*errstack=err;
// fill in the details
err->errcode=errcode;
err->sys_errno=sys_errno;
err->file=file;
err->line=line;
err->comment=comment;
}
/**
\ingroup Core_Errors
\brief print this error
\param err Error to print
*/
void ops_print_error(ops_error_t *err)
{
printf("%s:%d: ",err->file,err->line);
if(err->errcode==OPS_E_SYSTEM_ERROR)
printf("system error %d returned from %s()\n",err->sys_errno,
err->comment);
else
printf("%s, %s\n",ops_errcode(err->errcode),err->comment);
}
/**
\ingroup Core_Errors
\brief Print all errors on stack
\param errstack Error stack to print
*/
void ops_print_errors(ops_error_t *errstack)
{
ops_error_t *err;
for(err=errstack ; err!=NULL ; err=err->next)
ops_print_error(err);
}
/**
\ingroup Core_Errors
\brief Return true if given error is present anywhere on stack
\param errstack Error stack to check
\param errcode Error code to look for
\return 1 if found; else 0
*/
int ops_has_error(ops_error_t *errstack, ops_errcode_t errcode)
{
ops_error_t *err;
for (err=errstack; err!=NULL; err=err->next)
{
if (err->errcode==errcode)
return 1;
}
return 0;
}
/**
\ingroup Core_Errors
\brief Frees all errors on stack
\param errstack Error stack to free
*/
void ops_free_errors(ops_error_t *errstack)
{
ops_error_t *next;
while(errstack!=NULL) {
next=errstack->next;
free(errstack->comment);
free(errstack);
errstack=next;
}
}
// EOF

View File

@ -0,0 +1,139 @@
/*
* 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 <openpgpsdk/packet.h>
#include <openpgpsdk/crypto.h>
#include <openpgpsdk/create.h>
#include <assert.h>
#include <string.h>
#include <openpgpsdk/configure.h>
#ifdef HAVE_ALLOCA_H
# include <alloca.h>
#endif
#ifdef WIN32
#define alloca _alloca
#endif
#include <openpgpsdk/final.h>
static int debug=0;
/**
* \ingroup Core_Keys
* \brief Calculate a public key fingerprint.
* \param fp Where to put the calculated fingerprint
* \param key The key for which the fingerprint is calculated
*/
void ops_fingerprint(ops_fingerprint_t *fp,const ops_public_key_t *key)
{
if(key->version == 2 || key->version == 3)
{
unsigned char *bn;
int n;
ops_hash_t md5;
assert(key->algorithm == OPS_PKA_RSA
|| key->algorithm == OPS_PKA_RSA_ENCRYPT_ONLY
|| key->algorithm == OPS_PKA_RSA_SIGN_ONLY );
ops_hash_md5(&md5);
md5.init(&md5);
n=BN_num_bytes(key->key.rsa.n);
bn=alloca(n);
BN_bn2bin(key->key.rsa.n,bn);
md5.add(&md5,bn,n);
n=BN_num_bytes(key->key.rsa.e);
bn=alloca(n);
BN_bn2bin(key->key.rsa.e,bn);
md5.add(&md5,bn,n);
md5.finish(&md5,fp->fingerprint);
fp->length=16;
}
else
{
ops_memory_t *mem=ops_memory_new();
ops_hash_t sha1;
size_t l;
ops_build_public_key(mem,key,ops_false);
if (debug)
{ fprintf(stderr,"--- creating key fingerprint\n"); }
ops_hash_sha1(&sha1);
sha1.init(&sha1);
l=ops_memory_get_length(mem);
ops_hash_add_int(&sha1,0x99,1);
ops_hash_add_int(&sha1,l,2);
sha1.add(&sha1,ops_memory_get_data(mem),l);
sha1.finish(&sha1,fp->fingerprint);
if (debug)
{ fprintf(stderr,"--- finished creating key fingerprint\n"); }
fp->length=20;
ops_memory_free(mem);
}
}
/**
* \ingroup Core_Keys
* \brief Calculate the Key ID from the public key.
* \param keyid Space for the calculated ID to be stored
* \param key The key for which the ID is calculated
*/
void ops_keyid(unsigned char keyid[8],const ops_public_key_t *key)
{
if(key->version == 2 || key->version == 3)
{
unsigned char bn[8192];
unsigned n=BN_num_bytes(key->key.rsa.n);
assert(n <= sizeof bn);
assert(key->algorithm == OPS_PKA_RSA
|| key->algorithm == OPS_PKA_RSA_ENCRYPT_ONLY
|| key->algorithm == OPS_PKA_RSA_SIGN_ONLY );
BN_bn2bin(key->key.rsa.n,bn);
memcpy(keyid,bn+n-8,8);
}
else
{
ops_fingerprint_t fingerprint;
ops_fingerprint(&fingerprint,key);
memcpy(keyid,fingerprint.fingerprint+fingerprint.length-8,8);
}
}
// EOF

249
openpgpsdk/src/hash.c Normal file
View File

@ -0,0 +1,249 @@
/*
* 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 <openpgpsdk/crypto.h>
#include <assert.h>
#include <string.h>
#include <openpgpsdk/final.h>
static int debug=0;
/**
\ingroup Core_Hashes
\brief Add to the hash
\param hash Hash to add to
\param n Int to add
\param length Length of int in bytes
*/
void ops_hash_add_int(ops_hash_t *hash,unsigned n,unsigned length)
{
while(length--)
{
unsigned char c[1];
c[0]=n >> (length*8);
hash->add(hash,c,1);
}
}
/**
\ingroup Core_Hashes
\brief Setup hash for given hash algorithm
\param hash Hash to set up
\param alg Hash algorithm to use
*/
void ops_hash_any(ops_hash_t *hash,ops_hash_algorithm_t alg)
{
switch(alg)
{
case OPS_HASH_MD5:
ops_hash_md5(hash);
break;
case OPS_HASH_SHA1:
ops_hash_sha1(hash);
break;
case OPS_HASH_SHA256:
ops_hash_sha256(hash);
break;
case OPS_HASH_SHA384:
ops_hash_sha384(hash);
break;
case OPS_HASH_SHA512:
ops_hash_sha512(hash);
break;
case OPS_HASH_SHA224:
ops_hash_sha224(hash);
break;
default:
assert(0);
}
}
/**
\ingroup Core_Hashes
\brief Returns size of hash for given hash algorithm
\param alg Hash algorithm to use
\return Size of hash algorithm in bytes
*/
unsigned ops_hash_size(ops_hash_algorithm_t alg)
{
switch(alg)
{
case OPS_HASH_MD5:
return 16;
case OPS_HASH_SHA1:
return 20;
case OPS_HASH_SHA256:
return 32;
case OPS_HASH_SHA224:
return 28;
case OPS_HASH_SHA512:
return 64;
case OPS_HASH_SHA384:
return 48;
default:
assert(0);
}
return 0;
}
/**
\ingroup Core_Hashes
\brief Returns hash enum corresponding to given string
\param hash Text name of hash algorithm i.e. "SHA1"
\returns Corresponding enum i.e. OPS_HASH_SHA1
*/
ops_hash_algorithm_t ops_hash_algorithm_from_text(const char *hash)
{
if(!strcmp(hash,"SHA1"))
return OPS_HASH_SHA1;
else if(!strcmp(hash,"MD5"))
return OPS_HASH_MD5;
else if (!strcmp(hash,"SHA256"))
return OPS_HASH_SHA256;
/*
else if (!strcmp(hash,"SHA224"))
return OPS_HASH_SHA224;
*/
else if (!strcmp(hash,"SHA512"))
return OPS_HASH_SHA512;
else if (!strcmp(hash,"SHA384"))
return OPS_HASH_SHA384;
return OPS_HASH_UNKNOWN;
}
/**
\ingroup Core_Hashes
\brief Hash given data
\param out Where to write the hash
\param alg Hash algorithm to use
\param in Data to hash
\param length Length of data
\return Size of hash created
*/
unsigned ops_hash(unsigned char *out,ops_hash_algorithm_t alg,const void *in,
size_t length)
{
ops_hash_t hash;
ops_hash_any(&hash,alg);
hash.init(&hash);
hash.add(&hash,in,length);
return hash.finish(&hash,out);
}
/**
\ingroup Core_Hashes
\brief Calculate hash for MDC packet
\param preamble Preamble to hash
\param sz_preamble Size of preamble
\param plaintext Plaintext to hash
\param sz_plaintext Size of plaintext
\param hashed Resulting hash
*/
void ops_calc_mdc_hash(const unsigned char* preamble, const size_t sz_preamble, const unsigned char* plaintext, const unsigned int sz_plaintext, unsigned char *hashed)
{
ops_hash_t hash;
unsigned char c[1];
if (debug)
{
unsigned int i=0;
fprintf(stderr,"ops_calc_mdc_hash():\n");
fprintf(stderr,"\npreamble: ");
for (i=0; i<sz_preamble;i++)
fprintf(stderr," 0x%02x", preamble[i]);
fprintf(stderr,"\n");
fprintf(stderr,"\nplaintext (len=%d): ",sz_plaintext);
for (i=0; i<sz_plaintext;i++)
fprintf(stderr," 0x%02x", plaintext[i]);
fprintf(stderr,"\n");
}
// init
ops_hash_any(&hash, OPS_HASH_SHA1);
hash.init(&hash);
// preamble
hash.add(&hash,preamble,sz_preamble);
// plaintext
hash.add(&hash,plaintext,sz_plaintext);
// MDC packet tag
c[0]=0xD3;
hash.add(&hash,&c[0],1);
// MDC packet len
c[0]=0x14;
hash.add(&hash,&c[0],1);
//finish
hash.finish(&hash,hashed);
if (debug)
{
unsigned int i=0;
fprintf(stderr,"\nhashed (len=%d): ",OPS_SHA1_HASH_SIZE);
for (i=0; i<OPS_SHA1_HASH_SIZE;i++)
fprintf(stderr," 0x%02x", hashed[i]);
fprintf(stderr,"\n");
}
}
/**
\ingroup HighLevel_Supported
\brief Is this Hash Algorithm supported?
\param hash_alg Hash Algorithm to check
\return ops_true if supported; else ops_false
*/
ops_boolean_t ops_is_hash_alg_supported(const ops_hash_algorithm_t *hash_alg)
{
switch (*hash_alg)
{
case OPS_HASH_MD5:
case OPS_HASH_SHA1:
case OPS_HASH_SHA256:
return ops_true;
default:
return ops_false;
}
}
// EOF

906
openpgpsdk/src/keyring.c Normal file
View File

@ -0,0 +1,906 @@
/*
* 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 <openpgpsdk/armour.h>
#include <openpgpsdk/std_print.h>
#include <openpgpsdk/keyring.h>
#include <openpgpsdk/packet-parse.h>
#include <openpgpsdk/util.h>
#include <openpgpsdk/accumulate.h>
#include <openpgpsdk/validate.h>
#include <openpgpsdk/signature.h>
#include <openpgpsdk/readerwriter.h>
#include <openpgpsdk/defs.h>
#include "keyring_local.h"
#include "parse_local.h"
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#include <termios.h>
#endif
#include <fcntl.h>
#include <assert.h>
#include <openpgpsdk/final.h>
/**
\ingroup HighLevel_Keyring
\brief Creates a new ops_keydata_t struct
\return A new ops_keydata_t struct, initialised to zero.
\note The returned ops_keydata_t struct must be freed after use with ops_keydata_free.
*/
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)
{
unsigned n;
for(n=0 ; n < keydata->nuids ; ++n)
ops_user_id_free(&keydata->uids[n]);
free(keydata->uids);
keydata->uids=NULL;
keydata->nuids=0;
for(n=0 ; n < keydata->npackets ; ++n)
ops_packet_free(&keydata->packets[n]);
free(keydata->packets);
keydata->packets=NULL;
keydata->npackets=0;
if(keydata->type == OPS_PTAG_CT_PUBLIC_KEY)
ops_public_key_free(&keydata->key.pkey);
else
ops_secret_key_free(&keydata->key.skey);
free(keydata);
}
/**
\ingroup HighLevel_KeyGeneral
\brief Returns the public key in the given keydata.
\param keydata
\return Pointer to public key
\note This is not a copy, do not free it after use.
*/
const ops_public_key_t *
ops_get_public_key_from_data(const ops_keydata_t *keydata)
{
if(keydata->type == OPS_PTAG_CT_PUBLIC_KEY)
return &keydata->key.pkey;
return &keydata->key.skey.public_key;
}
/**
\ingroup HighLevel_KeyGeneral
\brief Check whether this is a secret key or not.
*/
ops_boolean_t ops_is_key_secret(const ops_keydata_t *data)
{ return data->type != OPS_PTAG_CT_PUBLIC_KEY; }
/**
\ingroup HighLevel_KeyGeneral
\brief Returns the secret key in the given keydata.
\note This is not a copy, do not free it after use.
\note This returns a const. If you need to be able to write to this pointer, use ops_get_writable_secret_key_from_data
*/
const ops_secret_key_t *
ops_get_secret_key_from_data(const ops_keydata_t *data)
{
if(data->type != OPS_PTAG_CT_SECRET_KEY)
return NULL;
return &data->key.skey;
}
/**
\ingroup HighLevel_KeyGeneral
\brief Returns the secret key in the given keydata.
\note This is not a copy, do not free it after use.
\note If you do not need to be able to modify this key, there is an equivalent read-only function ops_get_secret_key_from_data.
*/
ops_secret_key_t *
ops_get_writable_secret_key_from_data(ops_keydata_t *data)
{
if (data->type != OPS_PTAG_CT_SECRET_KEY)
return NULL;
return &data->key.skey;
}
typedef struct
{
const ops_keydata_t *key;
char *pphrase;
ops_secret_key_t *skey;
} decrypt_arg_t;
static ops_parse_cb_return_t decrypt_cb(const ops_parser_content_t *content_,
ops_parse_cb_info_t *cbinfo)
{
const ops_parser_content_union_t *content=&content_->content;
decrypt_arg_t *arg=ops_parse_cb_get_arg(cbinfo);
OPS_USED(cbinfo);
switch(content_->tag)
{
case OPS_PARSER_PTAG:
case OPS_PTAG_CT_USER_ID:
case OPS_PTAG_CT_SIGNATURE:
case OPS_PTAG_CT_SIGNATURE_HEADER:
case OPS_PTAG_CT_SIGNATURE_FOOTER:
case OPS_PTAG_CT_TRUST:
break;
case OPS_PARSER_CMD_GET_SK_PASSPHRASE:
*content->secret_key_passphrase.passphrase=arg->pphrase;
return OPS_KEEP_MEMORY;
case OPS_PARSER_ERRCODE:
switch(content->errcode.errcode)
{
case OPS_E_P_MPI_FORMAT_ERROR:
/* Generally this means a bad passphrase */
fprintf(stderr,"Bad passphrase!\n");
goto done;
case OPS_E_P_PACKET_CONSUMED:
/* And this is because of an error we've accepted */
goto done;
default:
fprintf(stderr,"parse error: %s\n",
ops_errcode(content->errcode.errcode));
assert(0);
break;
}
break;
case OPS_PARSER_ERROR:
printf("parse error: %s\n",content->error.error);
assert(0);
break;
case OPS_PTAG_CT_SECRET_KEY:
arg->skey=malloc(sizeof *arg->skey);
*arg->skey=content->secret_key;
return OPS_KEEP_MEMORY;
case OPS_PARSER_PACKET_END:
// nothing to do
break;
default:
fprintf(stderr,"Unexpected tag %d (0x%x)\n",content_->tag,
content_->tag);
assert(0);
}
done:
return OPS_RELEASE_MEMORY;
}
/**
\ingroup Core_Keys
\brief Decrypts secret key from given keydata with given passphrase
\param key Key from which to get secret key
\param pphrase Passphrase to use to decrypt secret key
\return secret key
*/
ops_secret_key_t *ops_decrypt_secret_key_from_data(const ops_keydata_t *key,
const char *pphrase)
{
ops_parse_info_t *pinfo;
decrypt_arg_t arg;
memset(&arg,'\0',sizeof arg);
arg.key=key;
arg.pphrase=strdup(pphrase);
pinfo=ops_parse_info_new();
ops_keydata_reader_set(pinfo,key);
ops_parse_cb_set(pinfo,decrypt_cb,&arg);
pinfo->rinfo.accumulate=ops_true;
ops_parse(pinfo);
return arg.skey;
}
/**
\ingroup Core_Keys
\brief Set secret key in content
\param content Content to be set
\param key Keydata to get secret key from
*/
void ops_set_secret_key(ops_parser_content_union_t* content,const ops_keydata_t *key)
{
*content->get_secret_key.secret_key=&key->key.skey;
}
/**
\ingroup Core_Keys
\brief Get Key ID from keydata
\param key Keydata to get Key ID from
\return Pointer to Key ID inside keydata
*/
const unsigned char* ops_get_key_id(const ops_keydata_t *key)
{
return key->key_id;
}
/**
\ingroup Core_Keys
\brief How many User IDs in this key?
\param key Keydata to check
\return Num of user ids
*/
unsigned ops_get_user_id_count(const ops_keydata_t *key)
{
return key->nuids;
}
/**
\ingroup Core_Keys
\brief Get indexed user id from key
\param key Key to get user id from
\param index Which key to get
\return Pointer to requested user id
*/
const unsigned char* ops_get_user_id(const ops_keydata_t *key, unsigned index)
{
return key->uids[index].user_id;
}
/**
\ingroup HighLevel_Supported
\brief Checks whether key's algorithm and type are supported by OpenPGP::SDK
\param keydata Key to be checked
\return ops_true if key algorithm and type are supported by OpenPGP::SDK; ops_false if not
*/
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 ) {
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;
}
/**
\ingroup HighLevel_KeyringFind
\brief Returns key inside a keyring, chosen by index
\param keyring Pointer to existing keyring
\param index Index of required key
\note Index starts at 0
\note This returns a pointer to the original key, not a copy. You do not need to free the key after use.
\return Pointer to the required key; or NULL if index too large.
Example code:
\code
void example(const ops_keyring_t* keyring)
{
ops_keydata_t* keydata=NULL;
keydata=ops_keyring_get_key_by_index(keyring, 0);
...
}
\endcode
*/
const ops_keydata_t* ops_keyring_get_key_by_index(const ops_keyring_t *keyring, int index)
{
if (index >= keyring->nkeys)
return NULL;
return &keyring->keys[index];
}
// \todo check where userid pointers are copied
/**
\ingroup Core_Keys
\brief Copy user id, including contents
\param dst Destination User ID
\param src Source User ID
\note If dst already has a user_id, it will be freed.
*/
void ops_copy_userid(ops_user_id_t* dst, const ops_user_id_t* src)
{
int len=strlen((char *)src->user_id);
if (dst->user_id)
free(dst->user_id);
dst->user_id=ops_mallocz(len+1);
memcpy(dst->user_id, src->user_id, len);
}
// \todo check where pkt pointers are copied
/**
\ingroup Core_Keys
\brief Copy packet, including contents
\param dst Destination packet
\param src Source packet
\note If dst already has a packet, it will be freed.
*/
void ops_copy_packet(ops_packet_t* dst, const ops_packet_t* src)
{
if (dst->raw)
free(dst->raw);
dst->raw=ops_mallocz(src->length);
dst->length=src->length;
memcpy(dst->raw, src->raw, src->length);
}
/**
\ingroup Core_Keys
\brief Add User ID to keydata
\param keydata Key to which to add User ID
\param userid User ID to add
\return Pointer to new User ID
*/
ops_user_id_t* ops_add_userid_to_keydata(ops_keydata_t* keydata, const ops_user_id_t* userid)
{
ops_user_id_t* new_uid=NULL;
EXPAND_ARRAY(keydata, uids);
// initialise new entry in array
new_uid=&keydata->uids[keydata->nuids];
new_uid->user_id=NULL;
// now copy it
ops_copy_userid(new_uid,userid);
keydata->nuids++;
return new_uid;
}
/**
\ingroup Core_Keys
\brief Add packet to key
\param keydata Key to which to add packet
\param packet Packet to add
\return Pointer to new packet
*/
ops_packet_t* ops_add_packet_to_keydata(ops_keydata_t* keydata, const ops_packet_t* packet)
{
ops_packet_t* new_pkt=NULL;
EXPAND_ARRAY(keydata, packets);
// initialise new entry in array
new_pkt=&keydata->packets[keydata->npackets];
new_pkt->length=0;
new_pkt->raw=NULL;
// now copy it
ops_copy_packet(new_pkt, packet);
keydata->npackets++;
return new_pkt;
}
/**
\ingroup Core_Keys
\brief Add signed User ID to key
\param keydata Key to which to add signed User ID
\param user_id User ID to add
\param sigpacket Packet to add
*/
void ops_add_signed_userid_to_keydata(ops_keydata_t* keydata, const ops_user_id_t* user_id, const ops_packet_t* sigpacket)
{
//int i=0;
ops_user_id_t * uid=NULL;
ops_packet_t * pkt=NULL;
uid=ops_add_userid_to_keydata(keydata, user_id);
pkt=ops_add_packet_to_keydata(keydata, sigpacket);
/*
* add entry in sigs array to link the userid and sigpacket
*/
// and add ptr to it from the sigs array
EXPAND_ARRAY(keydata, sigs);
// setup new entry in array
keydata->sigs[keydata->nsigs].userid=uid;
keydata->sigs[keydata->nsigs].packet=pkt;
keydata->nsigs++;
}
/**
\ingroup Core_Keys
\brief Add selfsigned User ID to key
\param keydata Key to which to add user ID
\param userid Self-signed User ID to add
\return ops_true if OK; else ops_false
*/
ops_boolean_t ops_add_selfsigned_userid_to_keydata(ops_keydata_t* keydata, ops_user_id_t* userid)
{
ops_packet_t sigpacket;
ops_memory_t* mem_userid=NULL;
ops_create_info_t* cinfo_userid=NULL;
ops_memory_t* mem_sig=NULL;
ops_create_info_t* cinfo_sig=NULL;
ops_create_signature_t *sig=NULL;
/*
* create signature packet for this userid
*/
// create userid pkt
ops_setup_memory_write(&cinfo_userid, &mem_userid, 128);
ops_write_struct_user_id(userid, cinfo_userid);
// create sig for this pkt
sig=ops_create_signature_new();
ops_signature_start_key_signature(sig, &keydata->key.skey.public_key, userid, OPS_CERT_POSITIVE);
ops_signature_add_creation_time(sig,time(NULL));
ops_signature_add_issuer_key_id(sig,keydata->key_id);
ops_signature_add_primary_user_id(sig, ops_true);
ops_signature_hashed_subpackets_end(sig);
ops_setup_memory_write(&cinfo_sig, &mem_sig, 128);
ops_write_signature(sig,&keydata->key.skey.public_key,&keydata->key.skey, cinfo_sig);
// add this packet to keydata
sigpacket.length=ops_memory_get_length(mem_sig);
sigpacket.raw=ops_memory_get_data(mem_sig);
// add userid to keydata
ops_add_signed_userid_to_keydata(keydata, userid, &sigpacket);
// cleanup
ops_create_signature_delete(sig);
ops_create_info_delete(cinfo_userid);
ops_create_info_delete(cinfo_sig);
ops_memory_free(mem_userid);
ops_memory_free(mem_sig);
return ops_true;
}
/**
\ingroup Core_Keys
\brief Initialise ops_keydata_t
\param keydata Keydata to initialise
\param type OPS_PTAG_CT_PUBLIC_KEY or OPS_PTAG_CT_SECRET_KEY
*/
void ops_keydata_init(ops_keydata_t* keydata, const ops_content_tag_t type)
{
assert(keydata->type==OPS_PTAG_CT_RESERVED);
assert(type==OPS_PTAG_CT_PUBLIC_KEY || type==OPS_PTAG_CT_SECRET_KEY);
keydata->type=type;
}
/**
Example Usage:
\code
// definition of variables
ops_keyring_t keyring;
char* filename="~/.gnupg/pubring.gpg";
// Read keyring from file
ops_keyring_read_from_file(&keyring,filename);
// do actions using keyring
...
// Free memory alloc-ed in ops_keyring_read_from_file()
ops_keyring_free(keyring);
\endcode
*/
static ops_parse_cb_return_t
cb_keyring_read(const ops_parser_content_t *content_,
ops_parse_cb_info_t *cbinfo);
/**
\ingroup HighLevel_KeyringRead
\brief Reads a keyring from a file
\param keyring Pointer to an existing ops_keyring_t struct
\param armour ops_true if file is armoured; else ops_false
\param filename Filename of keyring to be read
\return ops true if OK; ops_false on error
\note Keyring struct must already exist.
\note Can be used with either a public or secret keyring.
\note You must call ops_keyring_free() after usage to free alloc-ed memory.
\note If you call this twice on the same keyring struct, without calling
ops_keyring_free() between these calls, you will introduce a memory leak.
\sa ops_keyring_read_from_mem()
\sa ops_keyring_free()
Example code:
\code
ops_keyring_t* keyring=ops_mallocz(sizeof *keyring);
ops_boolean_t armoured=ops_false;
ops_keyring_read_from_file(keyring, armoured, "~/.gnupg/pubring.gpg");
...
ops_keyring_free(keyring);
free (keyring);
\endcode
*/
ops_boolean_t ops_keyring_read_from_file(ops_keyring_t *keyring, const ops_boolean_t armour, const char *filename)
{
ops_parse_info_t *pinfo;
int fd;
ops_boolean_t res = ops_true;
pinfo=ops_parse_info_new();
// add this for the moment,
// \todo need to fix the problems with reading signature subpackets later
// 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);
#else
fd=open(filename,O_RDONLY);
#endif
if(fd < 0)
{
ops_parse_info_delete(pinfo);
perror(filename);
return ops_false;
}
ops_reader_set_fd(pinfo,fd);
ops_parse_cb_set(pinfo,cb_keyring_read,NULL);
if (armour)
{ ops_reader_push_dearmour(pinfo); }
if ( ops_parse_and_accumulate(keyring,pinfo) == 0 ) {
res = ops_false;
}
else
{
res = ops_true;
}
ops_print_errors(ops_parse_info_get_errors(pinfo));
if (armour)
ops_reader_pop_dearmour(pinfo);
close(fd);
ops_parse_info_delete(pinfo);
return res;
}
/**
\ingroup HighLevel_KeyringRead
\brief Reads a keyring from memory
\param keyring Pointer to existing ops_keyring_t struct
\param armour ops_true if file is armoured; else ops_false
\param mem Pointer to a ops_memory_t struct containing keyring to be read
\return ops true if OK; ops_false on error
\note Keyring struct must already exist.
\note Can be used with either a public or secret keyring.
\note You must call ops_keyring_free() after usage to free alloc-ed memory.
\note If you call this twice on the same keyring struct, without calling
ops_keyring_free() between these calls, you will introduce a memory leak.
\sa ops_keyring_read_from_file
\sa ops_keyring_free
Example code:
\code
ops_memory_t* mem; // Filled with keyring packets
ops_keyring_t* keyring=ops_mallocz(sizeof *keyring);
ops_boolean_t armoured=ops_false;
ops_keyring_read_from_mem(keyring, armoured, mem);
...
ops_keyring_free(keyring);
free (keyring);
\endcode
*/
ops_boolean_t ops_keyring_read_from_mem(ops_keyring_t *keyring, const ops_boolean_t armour, ops_memory_t* mem)
{
ops_parse_info_t *pinfo=NULL;
ops_boolean_t res = ops_true;
pinfo=ops_parse_info_new();
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); }
if ( ops_parse_and_accumulate(keyring,pinfo) == 0 )
{
res = ops_false;
}
else
{
res = ops_true;
}
ops_print_errors(ops_parse_info_get_errors(pinfo));
if (armour)
ops_reader_pop_dearmour(pinfo);
// don't call teardown_memory_read because memory was passed in
ops_parse_info_delete(pinfo);
return res;
}
/**
\ingroup HighLevel_KeyringRead
\brief Frees keyring's contents (but not keyring itself)
\param keyring Keyring whose data is to be freed
\note This does not free keyring itself, just the memory alloc-ed in it.
*/
void ops_keyring_free(ops_keyring_t *keyring)
{
free(keyring->keys);
keyring->keys=NULL;
keyring->nkeys=0;
keyring->nkeys_allocated=0;
}
/**
\ingroup HighLevel_KeyringFind
\brief Finds key in keyring from its Key ID
\param keyring Keyring to be searched
\param keyid ID of required key
\return Pointer to key, if found; NULL, if not found
\note This returns a pointer to the key inside the given keyring, not a copy. Do not free it after use.
Example code:
\code
void example(ops_keyring_t* keyring)
{
ops_keydata_t* keydata=NULL;
unsigned char keyid[OPS_KEY_ID_SIZE]; // value set elsewhere
keydata=ops_keyring_find_key_by_id(keyring,keyid);
...
}
\endcode
*/
const ops_keydata_t *
ops_keyring_find_key_by_id(const ops_keyring_t *keyring,
const unsigned char keyid[OPS_KEY_ID_SIZE])
{
int n;
if (!keyring)
return NULL;
for(n=0 ; n < keyring->nkeys ; ++n)
{
if(!memcmp(keyring->keys[n].key_id,keyid,OPS_KEY_ID_SIZE))
return &keyring->keys[n];
}
return NULL;
}
/**
\ingroup HighLevel_KeyringFind
\brief Finds key from its User ID
\param keyring Keyring to be searched
\param userid User ID of required key
\return Pointer to Key, if found; NULL, if not found
\note This returns a pointer to the key inside the keyring, not a copy. Do not free it.
Example code:
\code
void example(ops_keyring_t* keyring)
{
ops_keydata_t* keydata=NULL;
keydata=ops_keyring_find_key_by_userid(keyring,"user@domain.com");
...
}
\endcode
*/
const ops_keydata_t *
ops_keyring_find_key_by_userid(const ops_keyring_t *keyring,
const char *userid)
{
int n=0;
unsigned int i=0;
if (!keyring)
return NULL;
for(n=0 ; n < keyring->nkeys ; ++n)
{
for(i=0; i<keyring->keys[n].nuids; i++)
{
//printf("[%d][%d] userid %s\n",n,i,keyring->keys[n].uids[i].user_id);
if(!strncmp((char *)keyring->keys[n].uids[i].user_id,userid,strlen(userid)))
return &keyring->keys[n];
}
}
//printf("end: n=%d,i=%d\n",n,i);
return NULL;
}
/**
\ingroup HighLevel_KeyringList
\brief Prints all keys in keyring to stdout.
\param keyring Keyring to use
\return none
Example code:
\code
void example()
{
ops_keyring_t* keyring=ops_mallocz(sizeof *keyring);
ops_boolean_t armoured=ops_false;
ops_keyring_read_from_file(keyring, armoured, "~/.gnupg/pubring.gpg");
ops_keyring_list(keyring);
ops_keyring_free(keyring);
free (keyring);
}
\endcode
*/
void
ops_keyring_list(const ops_keyring_t* keyring)
{
int n;
unsigned int i;
ops_keydata_t* key;
printf ("%d keys\n", keyring->nkeys);
for(n=0,key=&keyring->keys[n] ; n < keyring->nkeys ; ++n,++key)
{
for(i=0; i<key->nuids; i++)
{
if (ops_is_key_secret(key))
ops_print_secret_keydata(key);
else
ops_print_public_keydata(key);
}
}
}
/* Static functions */
static ops_parse_cb_return_t
cb_keyring_read(const ops_parser_content_t *content_,
ops_parse_cb_info_t *cbinfo)
{
OPS_USED(cbinfo);
switch(content_->tag)
{
case OPS_PARSER_PTAG:
case OPS_PTAG_CT_ENCRYPTED_SECRET_KEY: // we get these because we didn't prompt
case OPS_PTAG_CT_SIGNATURE_HEADER:
case OPS_PTAG_CT_SIGNATURE_FOOTER:
case OPS_PTAG_CT_SIGNATURE:
case OPS_PTAG_CT_TRUST:
case OPS_PARSER_ERRCODE:
break;
default:
;
}
return OPS_RELEASE_MEMORY;
}
/*\@}*/
// eof

View File

@ -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 <openpgpsdk/packet.h>
#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;
};

107
openpgpsdk/src/lists.c Normal file
View File

@ -0,0 +1,107 @@
/*
* 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
*
* Set of functions to manage a dynamic list
*/
#include <openpgpsdk/lists.h>
#include <stdlib.h>
#include <openpgpsdk/final.h>
/**
* \ingroup Core_Lists
* \brief Initialises ulong list
* \param *list Pointer to existing list structure
*/
void ops_ulong_list_init(ops_ulong_list_t *list)
{
list->size=0;
list->used=0;
list->ulongs=NULL;
}
/**
* \ingroup Core_Lists
* \brief Frees allocated memory in ulong list. Does not free *list itself.
* \param *list
*/
void ops_ulong_list_free(ops_ulong_list_t *list)
{
if (list->ulongs)
free(list->ulongs);
ops_ulong_list_init(list);
}
/**
* \ingroup Core_Lists
* \brief Resizes ulong list.
*
* We only resize in one direction - upwards.
* Algorithm used : double the current size then add 1
*
* \param *list Pointer to list
* \return 1 if success, else 0
*/
static unsigned int ops_ulong_list_resize(ops_ulong_list_t *list)
{
int newsize=0;
newsize=list->size*2 + 1;
list->ulongs=realloc(list->ulongs,newsize*sizeof *list->ulongs);
if (list->ulongs)
{
list->size=newsize;
return 1;
}
else
{
/* xxx - realloc failed. error message? - rachel */
return 0;
}
}
/**
* \ingroup Core_Lists
* Adds entry to ulong list
*
* \param *list
* \param *ulong
*
* \return 1 if success, else 0
*/
unsigned int ops_ulong_list_add(ops_ulong_list_t *list, unsigned long *ulong)
{
if (list->size==list->used)
if (!ops_ulong_list_resize(list))
return 0;
list->ulongs[list->used]=*ulong;
list->used++;
return 1;
}

204
openpgpsdk/src/memory.c Normal file
View File

@ -0,0 +1,204 @@
/*
* 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 <openpgpsdk/create.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <openpgpsdk/final.h>
struct ops_memory
{
unsigned char *buf;
size_t length;
size_t allocated;
};
/**
\ingroup HighLevel_Memory
\brief Memory to initialise
\param mem memory to initialise
\param initial_size Size to initialise to
*/
void ops_memory_init(ops_memory_t *mem,size_t initial_size)
{
mem->length=0;
if(mem->buf)
{
if(mem->allocated < initial_size)
{
mem->buf=realloc(mem->buf,initial_size);
mem->allocated=initial_size;
}
return;
}
mem->buf=malloc(initial_size);
mem->allocated=initial_size;
}
/**
\ingroup HighLevel_Memory
\brief Pad memory to required length
\param mem Memory to use
\param length New size
*/
void ops_memory_pad(ops_memory_t *mem,size_t length)
{
assert(mem->allocated >= mem->length);
if(mem->allocated < mem->length+length)
{
mem->allocated=mem->allocated*2+length;
mem->buf=realloc(mem->buf,mem->allocated);
}
assert(mem->allocated >= mem->length+length);
}
/**
\ingroup HighLevel_Memory
\brief Add data to memory
\param mem Memory to which to add
\param src Data to add
\param length Length of data to add
*/
void ops_memory_add(ops_memory_t *mem,const unsigned char *src,size_t length)
{
ops_memory_pad(mem,length);
memcpy(mem->buf+mem->length,src,length);
mem->length+=length;
}
// XXX: this could be refactored via the writer, but an awful lot of
// hoops to jump through for 2 lines of code!
void ops_memory_place_int(ops_memory_t *mem,unsigned offset,unsigned n,
size_t length)
{
assert(mem->allocated >= offset+length);
while(length--)
mem->buf[offset++]=n >> (length*8);
}
/**
* \ingroup HighLevel_Memory
* \brief Retains allocated memory and set length of stored data to zero.
* \param mem Memory to clear
* \sa ops_memory_release()
* \sa ops_memory_free()
*/
void ops_memory_clear(ops_memory_t *mem)
{ mem->length=0; }
/**
\ingroup HighLevel_Memory
\brief Free memory and associated data
\param mem Memory to free
\note This does not free mem itself
\sa ops_memory_clear()
\sa ops_memory_free()
*/
void ops_memory_release(ops_memory_t *mem)
{
free(mem->buf);
mem->buf=NULL;
mem->length=0;
}
void ops_memory_make_packet(ops_memory_t *out,ops_content_tag_t tag)
{
size_t extra;
if(out->length < 192)
extra=1;
else if(out->length < 8384)
extra=2;
else
extra=5;
ops_memory_pad(out,extra+1);
memmove(out->buf+extra+1,out->buf,out->length);
out->buf[0]=OPS_PTAG_ALWAYS_SET|OPS_PTAG_NEW_FORMAT|tag;
if(out->length < 192)
out->buf[1]=out->length;
else if(out->length < 8384)
{
out->buf[1]=((out->length-192) >> 8)+192;
out->buf[2]=out->length-192;
}
else
{
out->buf[1]=0xff;
out->buf[2]=out->length >> 24;
out->buf[3]=out->length >> 16;
out->buf[4]=out->length >> 8;
out->buf[5]=out->length;
}
out->length+=extra+1;
}
/**
\ingroup HighLevel_Memory
\brief Create a new zeroed ops_memory_t
\return Pointer to new ops_memory_t
\note Free using ops_memory_free() after use.
\sa ops_memory_free()
*/
ops_memory_t *ops_memory_new()
{ return ops_mallocz(sizeof(ops_memory_t)); }
/**
\ingroup HighLevel_Memory
\brief Free memory ptr and associated memory
\param mem Memory to be freed
\sa ops_memory_release()
\sa ops_memory_clear()
*/
void ops_memory_free(ops_memory_t *mem)
{
ops_memory_release(mem);
free(mem);
}
/**
\ingroup HighLevel_Memory
\brief Get length of data stored in ops_memory_t struct
\return Number of bytes in data
*/
size_t ops_memory_get_length(const ops_memory_t *mem)
{ return mem->length; }
/**
\ingroup HighLevel_Memory
\brief Get data stored in ops_memory_t struct
\return Pointer to data
*/
void *ops_memory_get_data(ops_memory_t *mem)
{ return mem->buf; }
// EOF

View File

@ -0,0 +1,792 @@
/*
* 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 <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/dsa.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
#include <assert.h>
#include <stdlib.h>
#include <openpgpsdk/configure.h>
#include <openpgpsdk/crypto.h>
#include <openpgpsdk/keyring.h>
#include <openpgpsdk/readerwriter.h>
#include "keyring_local.h"
#include <openpgpsdk/std_print.h>
#include <openpgpsdk/final.h>
static int debug=0;
void test_secret_key(const ops_secret_key_t *skey)
{
RSA* test=RSA_new();
test->n=BN_dup(skey->public_key.key.rsa.n);
test->e=BN_dup(skey->public_key.key.rsa.e);
test->d=BN_dup(skey->key.rsa.d);
test->p=BN_dup(skey->key.rsa.p);
test->q=BN_dup(skey->key.rsa.q);
assert(RSA_check_key(test)==1);
RSA_free(test);
}
static void md5_init(ops_hash_t *hash)
{
assert(!hash->data);
hash->data=malloc(sizeof(MD5_CTX));
MD5_Init(hash->data);
}
static void md5_add(ops_hash_t *hash,const unsigned char *data,unsigned length)
{
MD5_Update(hash->data,data,length);
}
static unsigned md5_finish(ops_hash_t *hash,unsigned char *out)
{
MD5_Final(out,hash->data);
free(hash->data);
hash->data=NULL;
return 16;
}
static ops_hash_t md5={OPS_HASH_MD5,MD5_DIGEST_LENGTH,"MD5",md5_init,md5_add,
md5_finish,NULL};
/**
\ingroup Core_Crypto
\brief Initialise to MD5
\param hash Hash to initialise
*/
void ops_hash_md5(ops_hash_t *hash)
{
*hash=md5;
}
static void sha1_init(ops_hash_t *hash)
{
if (debug)
{
fprintf(stderr,"***\n***\nsha1_init\n***\n");
}
assert(!hash->data);
hash->data=malloc(sizeof(SHA_CTX));
SHA1_Init(hash->data);
}
static void sha1_add(ops_hash_t *hash,const unsigned char *data,
unsigned length)
{
if (debug)
{
unsigned int i=0;
fprintf(stderr,"adding %d to hash:\n ", length);
for (i=0; i<length; i++)
{
fprintf(stderr,"0x%02x ", data[i]);
if (!((i+1) % 16))
fprintf(stderr,"\n");
else if (!((i+1) % 8))
fprintf(stderr," ");
}
fprintf(stderr,"\n");
}
SHA1_Update(hash->data,data,length);
}
static unsigned sha1_finish(ops_hash_t *hash,unsigned char *out)
{
SHA1_Final(out,hash->data);
if (debug)
{
unsigned i=0;
fprintf(stderr,"***\n***\nsha1_finish\n***\n");
for (i=0; i<SHA_DIGEST_LENGTH; i++)
fprintf(stderr,"0x%02x ",out[i]);
fprintf(stderr,"\n");
}
free(hash->data);
hash->data=NULL;
return SHA_DIGEST_LENGTH;
}
static ops_hash_t sha1={OPS_HASH_SHA1,SHA_DIGEST_LENGTH,"SHA1",sha1_init,
sha1_add,sha1_finish,NULL};
/**
\ingroup Core_Crypto
\brief Initialise to SHA1
\param hash Hash to initialise
*/
void ops_hash_sha1(ops_hash_t *hash)
{
*hash=sha1;
}
static void sha256_init(ops_hash_t *hash)
{
if (debug)
{
fprintf(stderr,"***\n***\nsha256_init\n***\n");
}
assert(!hash->data);
hash->data=malloc(sizeof(SHA256_CTX));
SHA256_Init(hash->data);
}
static void sha256_add(ops_hash_t *hash,const unsigned char *data,
unsigned length)
{
if (debug)
{
unsigned int i=0;
fprintf(stderr,"adding %d to hash:\n ", length);
for (i=0; i<length; i++)
{
fprintf(stderr,"0x%02x ", data[i]);
if (!((i+1) % 16))
fprintf(stderr,"\n");
else if (!((i+1) % 8))
fprintf(stderr," ");
}
fprintf(stderr,"\n");
}
SHA256_Update(hash->data,data,length);
}
static unsigned sha256_finish(ops_hash_t *hash,unsigned char *out)
{
SHA256_Final(out,hash->data);
if (debug)
{
unsigned i=0;
fprintf(stderr,"***\n***\nsha1_finish\n***\n");
for (i=0; i<SHA256_DIGEST_LENGTH; i++)
fprintf(stderr,"0x%02x ",out[i]);
fprintf(stderr,"\n");
}
free(hash->data);
hash->data=NULL;
return SHA256_DIGEST_LENGTH;
}
static ops_hash_t sha256={OPS_HASH_SHA256,SHA256_DIGEST_LENGTH,"SHA256",sha256_init,
sha256_add,sha256_finish,NULL};
void ops_hash_sha256(ops_hash_t *hash)
{
*hash=sha256;
}
/*
* SHA384
*/
static void sha384_init(ops_hash_t *hash)
{
if (debug)
{
fprintf(stderr,"***\n***\nsha384_init\n***\n");
}
assert(!hash->data);
hash->data=malloc(sizeof(SHA512_CTX));
SHA384_Init(hash->data);
}
static void sha384_add(ops_hash_t *hash,const unsigned char *data,
unsigned length)
{
if (debug)
{
unsigned int i=0;
fprintf(stderr,"adding %d to hash:\n ", length);
for (i=0; i<length; i++)
{
fprintf(stderr,"0x%02x ", data[i]);
if (!((i+1) % 16))
fprintf(stderr,"\n");
else if (!((i+1) % 8))
fprintf(stderr," ");
}
fprintf(stderr,"\n");
}
SHA384_Update(hash->data,data,length);
}
static unsigned sha384_finish(ops_hash_t *hash,unsigned char *out)
{
SHA384_Final(out,hash->data);
if (debug)
{
unsigned i=0;
fprintf(stderr,"***\n***\nsha1_finish\n***\n");
for (i=0; i<SHA384_DIGEST_LENGTH; i++)
fprintf(stderr,"0x%02x ",out[i]);
fprintf(stderr,"\n");
}
free(hash->data);
hash->data=NULL;
return SHA384_DIGEST_LENGTH;
}
static ops_hash_t sha384={OPS_HASH_SHA384,SHA384_DIGEST_LENGTH,"SHA384",sha384_init,
sha384_add,sha384_finish,NULL};
void ops_hash_sha384(ops_hash_t *hash)
{
*hash=sha384;
}
/*
* SHA512
*/
static void sha512_init(ops_hash_t *hash)
{
if (debug)
{
fprintf(stderr,"***\n***\nsha512_init\n***\n");
}
assert(!hash->data);
hash->data=malloc(sizeof(SHA512_CTX));
SHA512_Init(hash->data);
}
static void sha512_add(ops_hash_t *hash,const unsigned char *data,
unsigned length)
{
if (debug)
{
unsigned int i=0;
fprintf(stderr,"adding %d to hash:\n ", length);
for (i=0; i<length; i++)
{
fprintf(stderr,"0x%02x ", data[i]);
if (!((i+1) % 16))
fprintf(stderr,"\n");
else if (!((i+1) % 8))
fprintf(stderr," ");
}
fprintf(stderr,"\n");
}
SHA512_Update(hash->data,data,length);
}
static unsigned sha512_finish(ops_hash_t *hash,unsigned char *out)
{
SHA512_Final(out,hash->data);
if (debug)
{
unsigned i=0;
fprintf(stderr,"***\n***\nsha1_finish\n***\n");
for (i=0; i<SHA512_DIGEST_LENGTH; i++)
fprintf(stderr,"0x%02x ",out[i]);
fprintf(stderr,"\n");
}
free(hash->data);
hash->data=NULL;
return SHA512_DIGEST_LENGTH;
}
static ops_hash_t sha512={OPS_HASH_SHA512,SHA512_DIGEST_LENGTH,"SHA512",sha512_init,
sha512_add,sha512_finish,NULL};
void ops_hash_sha512(ops_hash_t *hash)
{
*hash=sha512;
}
/*
* SHA224
*/
static void sha224_init(ops_hash_t *hash)
{
if (debug)
{
fprintf(stderr,"***\n***\nsha1_init\n***\n");
}
assert(!hash->data);
hash->data=malloc(sizeof(SHA256_CTX));
SHA224_Init(hash->data);
}
static void sha224_add(ops_hash_t *hash,const unsigned char *data,
unsigned length)
{
if (debug)
{
unsigned int i=0;
fprintf(stderr,"adding %d to hash:\n ", length);
for (i=0; i<length; i++)
{
fprintf(stderr,"0x%02x ", data[i]);
if (!((i+1) % 16))
fprintf(stderr,"\n");
else if (!((i+1) % 8))
fprintf(stderr," ");
}
fprintf(stderr,"\n");
}
SHA224_Update(hash->data,data,length);
}
static unsigned sha224_finish(ops_hash_t *hash,unsigned char *out)
{
SHA224_Final(out,hash->data);
if (debug)
{
unsigned i=0;
fprintf(stderr,"***\n***\nsha1_finish\n***\n");
for (i=0; i<SHA224_DIGEST_LENGTH; i++)
fprintf(stderr,"0x%02x ",out[i]);
fprintf(stderr,"\n");
}
free(hash->data);
hash->data=NULL;
return SHA224_DIGEST_LENGTH;
}
static ops_hash_t sha224={OPS_HASH_SHA224,SHA224_DIGEST_LENGTH,"SHA224",sha224_init,
sha224_add,sha224_finish,NULL};
void ops_hash_sha224(ops_hash_t *hash)
{
*hash=sha224;
}
ops_boolean_t ops_dsa_verify(const unsigned char *hash,size_t hash_length,
const ops_dsa_signature_t *sig,
const ops_dsa_public_key_t *dsa)
{
DSA_SIG *osig;
DSA *odsa;
int ret;
osig=DSA_SIG_new();
osig->r=sig->r;
osig->s=sig->s;
odsa=DSA_new();
odsa->p=dsa->p;
odsa->q=dsa->q;
odsa->g=dsa->g;
odsa->pub_key=dsa->y;
if (debug)
{
fprintf(stderr,"hash passed in:\n");
unsigned i;
for (i=0; i<hash_length; i++)
{
fprintf(stderr,"%02x ", hash[i]);
}
fprintf(stderr,"\n");
}
//printf("hash_length=%ld\n", hash_length);
//printf("Q=%d\n", BN_num_bytes(odsa->q));
unsigned int qlen=BN_num_bytes(odsa->q);
if (qlen < hash_length)
hash_length=qlen;
// ret=DSA_do_verify(hash,hash_length,osig,odsa);
ret=DSA_do_verify(hash,hash_length,osig,odsa);
if (debug)
{
fprintf(stderr,"ret=%d\n",ret);
}
assert(ret >= 0);
odsa->p=odsa->q=odsa->g=odsa->pub_key=NULL;
DSA_free(odsa);
osig->r=osig->s=NULL;
DSA_SIG_free(osig);
return ret != 0;
}
/**
\ingroup Core_Crypto
\brief Recovers message digest from the signature
\param out Where to write decrypted data to
\param in Encrypted data
\param length Length of encrypted data
\param rsa RSA public key
\return size of recovered message digest
*/
int ops_rsa_public_decrypt(unsigned char *out,const unsigned char *in,
size_t length,const ops_rsa_public_key_t *rsa)
{
RSA *orsa;
int n;
orsa=RSA_new();
orsa->n=rsa->n;
orsa->e=rsa->e;
n=RSA_public_decrypt(length,in,out,orsa,RSA_NO_PADDING);
orsa->n=orsa->e=NULL;
RSA_free(orsa);
return n;
}
/**
\ingroup Core_Crypto
\brief Signs data with RSA
\param out Where to write signature
\param in Data to sign
\param length Length of data
\param srsa RSA secret key
\param rsa RSA public key
\return number of bytes decrypted
*/
int ops_rsa_private_encrypt(unsigned char *out,const unsigned char *in,
size_t length,const ops_rsa_secret_key_t *srsa,
const ops_rsa_public_key_t *rsa)
{
RSA *orsa;
int n;
orsa=RSA_new();
orsa->n=rsa->n; // XXX: do we need n?
orsa->d=srsa->d;
orsa->p=srsa->q;
orsa->q=srsa->p;
/* debug */
orsa->e=rsa->e;
// If this isn't set, it's very likely that the programmer hasn't
// decrypted the secret key. RSA_check_key segfaults in that case.
// Use ops_decrypt_secret_key_from_data() to do that.
assert(orsa->d);
assert(RSA_check_key(orsa) == 1);
orsa->e=NULL;
/* end debug */
n=RSA_private_encrypt(length,in,out,orsa,RSA_NO_PADDING);
orsa->n=orsa->d=orsa->p=orsa->q=NULL;
RSA_free(orsa);
return n;
}
/**
\ingroup Core_Crypto
\brief Decrypts RSA-encrypted data
\param out Where to write the plaintext
\param in Encrypted data
\param length Length of encrypted data
\param srsa RSA secret key
\param rsa RSA public key
\return size of recovered plaintext
*/
int ops_rsa_private_decrypt(unsigned char *out,const unsigned char *in,
size_t length,const ops_rsa_secret_key_t *srsa,
const ops_rsa_public_key_t *rsa)
{
RSA *orsa;
int n;
char errbuf[1024];
orsa=RSA_new();
orsa->n=rsa->n; // XXX: do we need n?
orsa->d=srsa->d;
orsa->p=srsa->q;
orsa->q=srsa->p;
/* debug */
orsa->e=rsa->e;
assert(RSA_check_key(orsa) == 1);
orsa->e=NULL;
/* end debug */
n=RSA_private_decrypt(length,in,out,orsa,RSA_NO_PADDING);
// printf("ops_rsa_private_decrypt: n=%d\n",n);
errbuf[0]='\0';
if (n==-1)
{
unsigned long err=ERR_get_error();
ERR_error_string(err,&errbuf[0]);
fprintf(stderr,"openssl error : %s\n",errbuf);
}
orsa->n=orsa->d=orsa->p=orsa->q=NULL;
RSA_free(orsa);
return n;
}
/**
\ingroup Core_Crypto
\brief RSA-encrypts data
\param out Where to write the encrypted data
\param in Plaintext
\param length Size of plaintext
\param rsa RSA Public Key
*/
int ops_rsa_public_encrypt(unsigned char *out,const unsigned char *in,
size_t length,const ops_rsa_public_key_t *rsa)
{
RSA *orsa;
int n;
// printf("ops_rsa_public_encrypt: length=%ld\n", length);
orsa=RSA_new();
orsa->n=rsa->n;
orsa->e=rsa->e;
// printf("len: %ld\n", length);
// ops_print_bn("n: ", orsa->n);
// ops_print_bn("e: ", orsa->e);
n=RSA_public_encrypt(length,in,out,orsa,RSA_NO_PADDING);
if (n==-1)
{
BIO *fd_out;
fd_out=BIO_new_fd(fileno(stderr), BIO_NOCLOSE);
ERR_print_errors(fd_out);
}
orsa->n=orsa->e=NULL;
RSA_free(orsa);
return n;
}
/**
\ingroup Core_Crypto
\brief initialises openssl
\note Would usually call ops_init() instead
\sa ops_init()
*/
void ops_crypto_init()
{
#ifdef DMALLOC
CRYPTO_malloc_debug_init();
CRYPTO_dbg_set_options(V_CRYPTO_MDEBUG_ALL);
CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
#endif
}
/**
\ingroup Core_Crypto
\brief Finalise openssl
\note Would usually call ops_finish() instead
\sa ops_finish()
*/
void ops_crypto_finish()
{
CRYPTO_cleanup_all_ex_data();
ERR_remove_state(0);
#ifdef DMALLOC
CRYPTO_mem_leaks_fp(stderr);
#endif
}
/**
\ingroup Core_Hashes
\brief Get Hash name
\param hash Hash struct
\return Hash name
*/
const char *ops_text_from_hash(ops_hash_t *hash)
{ return hash->name; }
/**
\ingroup HighLevel_KeyGenerate
\brief Generates an RSA keypair
\param numbits Modulus size
\param e Public Exponent
\param keydata Pointer to keydata struct to hold new key
\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_secret_key_t *skey=NULL;
RSA *rsa=NULL;
BN_CTX *ctx=BN_CTX_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);
// populate ops key from ssl key
skey->public_key.version=4;
skey->public_key.creation_time=time(NULL);
skey->public_key.days_valid=0;
skey->public_key.algorithm= OPS_PKA_RSA;
skey->public_key.key.rsa.n=BN_dup(rsa->n);
skey->public_key.key.rsa.e=BN_dup(rsa->e);
skey->s2k_usage=OPS_S2KU_ENCRYPTED_AND_HASHED;
skey->s2k_specifier=OPS_S2KS_SALTED;
//skey->s2k_specifier=OPS_S2KS_SIMPLE;
skey->algorithm=OPS_SA_CAST5; // \todo make param
skey->hash_algorithm=OPS_HASH_SHA1; // \todo make param
skey->octet_count=0;
skey->checksum=0;
skey->key.rsa.d=BN_dup(rsa->d);
skey->key.rsa.p=BN_dup(rsa->p);
skey->key.rsa.q=BN_dup(rsa->q);
skey->key.rsa.u=BN_mod_inverse(NULL,rsa->p, rsa->q, ctx);
assert(skey->key.rsa.u);
BN_CTX_free(ctx);
RSA_free(rsa);
ops_keyid(keydata->key_id, &keydata->key.skey.public_key);
ops_fingerprint(&keydata->fingerprint, &keydata->key.skey.public_key);
// Generate checksum
ops_create_info_t *cinfo=NULL;
ops_memory_t *mem=NULL;
ops_setup_memory_write(&cinfo, &mem, 128);
ops_push_skey_checksum_writer(cinfo, skey);
switch(skey->public_key.algorithm)
{
// case OPS_PKA_DSA:
// return ops_write_mpi(key->key.dsa.x,info);
case OPS_PKA_RSA:
case OPS_PKA_RSA_ENCRYPT_ONLY:
case OPS_PKA_RSA_SIGN_ONLY:
if(!ops_write_mpi(skey->key.rsa.d,cinfo)
|| !ops_write_mpi(skey->key.rsa.p,cinfo)
|| !ops_write_mpi(skey->key.rsa.q,cinfo)
|| !ops_write_mpi(skey->key.rsa.u,cinfo))
return ops_false;
break;
// case OPS_PKA_ELGAMAL:
// return ops_write_mpi(key->key.elgamal.x,info);
default:
assert(0);
break;
}
// close rather than pop, since its the only one on the stack
ops_writer_close(cinfo);
ops_teardown_memory_write(cinfo, mem);
// should now have checksum in skey struct
// test
if (debug)
test_secret_key(skey);
return ops_true;
}
/**
\ingroup HighLevel_KeyGenerate
\brief Creates a self-signed RSA keypair
\param numbits Modulus size
\param e Public Exponent
\param userid User ID
\return The new keypair or NULL
\note It is the caller's responsibility to call ops_keydata_free(keydata)
\sa ops_rsa_generate_keypair()
\sa ops_keydata_free()
*/
ops_keydata_t* ops_rsa_create_selfsigned_keypair(const int numbits, const unsigned long e, ops_user_id_t * userid)
{
ops_keydata_t *keydata=NULL;
keydata=ops_keydata_new();
if (ops_rsa_generate_keypair(numbits, e, keydata) != ops_true
|| ops_add_selfsigned_userid_to_keydata(keydata, userid) != ops_true)
{
ops_keydata_free(keydata);
return NULL;
}
return keydata;
}
/*
int ops_dsa_size(const ops_dsa_public_key_t *dsa)
{
int size;
DSA *odsa;
odsa=DSA_new();
odsa->p=dsa->p;
odsa->q=dsa->q;
odsa->g=dsa->g;
odsa->pub_key=dsa->y;
DSAparams_print_fp(stderr, odsa);
size=DSA_size(odsa);
odsa->p=odsa->q=odsa->g=odsa->pub_key=odsa->priv_key=NULL;
DSA_free(odsa);
return size;
}
*/
DSA_SIG* ops_dsa_sign(unsigned char* hashbuf, unsigned hashsize, const ops_dsa_secret_key_t *sdsa, const ops_dsa_public_key_t *dsa)
{
DSA *odsa;
DSA_SIG *dsasig;
odsa=DSA_new();
odsa->p=dsa->p;
odsa->q=dsa->q;
odsa->g=dsa->g;
odsa->pub_key=dsa->y;
odsa->priv_key=sdsa->x;
dsasig=DSA_do_sign(hashbuf,hashsize,odsa);
odsa->p=odsa->q=odsa->g=odsa->pub_key=odsa->priv_key=NULL;
DSA_free(odsa);
return dsasig;
}
// eof

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,854 @@
/*
* 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
*
* Creates printable text strings from packet contents
*
*/
#include <openpgpsdk/configure.h>
#include <stdlib.h>
#include <string.h>
#include <openpgpsdk/packet-show.h>
#include <openpgpsdk/util.h>
#include <openpgpsdk/final.h>
/*
* Arrays of value->text maps
*/
static ops_map_t packet_tag_map[] =
{
{ OPS_PTAG_CT_RESERVED, "Reserved" },
{ OPS_PTAG_CT_PK_SESSION_KEY, "Public-Key Encrypted Session Key" },
{ OPS_PTAG_CT_SIGNATURE, "Signature" },
{ OPS_PTAG_CT_SK_SESSION_KEY, "Symmetric-Key Encrypted Session Key" },
{ OPS_PTAG_CT_ONE_PASS_SIGNATURE, "One-Pass Signature" },
{ OPS_PTAG_CT_SECRET_KEY, "Secret Key" },
{ OPS_PTAG_CT_PUBLIC_KEY, "Public Key" },
{ OPS_PTAG_CT_SECRET_SUBKEY, "Secret Subkey" },
{ OPS_PTAG_CT_COMPRESSED, "Compressed Data" },
{ OPS_PTAG_CT_SE_DATA, "Symmetrically Encrypted Data" },
{ OPS_PTAG_CT_MARKER, "Marker" },
{ OPS_PTAG_CT_LITERAL_DATA, "Literal Data" },
{ OPS_PTAG_CT_TRUST, "Trust" },
{ OPS_PTAG_CT_USER_ID, "User ID" },
{ OPS_PTAG_CT_PUBLIC_SUBKEY, "Public Subkey" },
{ OPS_PTAG_CT_RESERVED2, "reserved" },
{ OPS_PTAG_CT_RESERVED3, "reserved" },
{ OPS_PTAG_CT_USER_ATTRIBUTE, "User Attribute" },
{ OPS_PTAG_CT_SE_IP_DATA, "Sym. Encrypted and Integrity Protected Data" },
{ OPS_PTAG_CT_MDC, "Modification Detection Code" },
{ OPS_PARSER_PTAG, "OPS_PARSER_PTAG" },
{ OPS_PTAG_RAW_SS, "OPS_PTAG_RAW_SS" },
{ OPS_PTAG_SS_ALL, "OPS_PTAG_SS_ALL" },
{ OPS_PARSER_PACKET_END, "OPS_PARSER_PACKET_END" },
{ OPS_PTAG_SIGNATURE_SUBPACKET_BASE, "OPS_PTAG_SIGNATURE_SUBPACKET_BASE" },
{ OPS_PTAG_SS_CREATION_TIME, "SS: Signature Creation Time" },
{ OPS_PTAG_SS_EXPIRATION_TIME, "SS: Signature Expiration Time" },
{ OPS_PTAG_SS_EXPORTABLE_CERTIFICATION, "SS: Exportable Certification" },
{ OPS_PTAG_SS_TRUST, "SS: Trust Signature" },
{ OPS_PTAG_SS_REGEXP, "SS: Regular Expression" },
{ OPS_PTAG_SS_REVOCABLE, "SS: Revocable" },
{ OPS_PTAG_SS_KEY_EXPIRATION_TIME, "SS: Key Expiration Time" },
{ OPS_PTAG_SS_RESERVED, "SS: Reserved" },
{ OPS_PTAG_SS_PREFERRED_SKA, "SS: Preferred Secret Key Algorithm" },
{ OPS_PTAG_SS_REVOCATION_KEY, "SS: Revocation Key" },
{ OPS_PTAG_SS_ISSUER_KEY_ID, "SS: Issuer Key Id" },
{ OPS_PTAG_SS_NOTATION_DATA, "SS: Notation Data" },
{ OPS_PTAG_SS_PREFERRED_HASH, "SS: Preferred Hash Algorithm" },
{ OPS_PTAG_SS_PREFERRED_COMPRESSION,"SS: Preferred Compression Algorithm" },
{ OPS_PTAG_SS_KEY_SERVER_PREFS, "SS: Key Server Preferences" },
{ OPS_PTAG_SS_PREFERRED_COMPRESSION,"SS: Preferred Key Server" },
{ OPS_PTAG_SS_PRIMARY_USER_ID, "SS: Primary User ID" },
{ OPS_PTAG_SS_POLICY_URI, "SS: Policy URI" },
{ OPS_PTAG_SS_KEY_FLAGS, "SS: Key Flags" },
{ OPS_PTAG_SS_SIGNERS_USER_ID, "SS: Signer's User ID" },
{ OPS_PTAG_SS_REVOCATION_REASON, "SS: Reason for Revocation" },
{ OPS_PTAG_SS_FEATURES, "SS: Features" },
{ OPS_PTAG_SS_SIGNATURE_TARGET, "SS: Signature Target" },
{ OPS_PTAG_SS_EMBEDDED_SIGNATURE, "SS: Embedded Signature" },
{ OPS_PTAG_CT_LITERAL_DATA_HEADER, "CT: Literal Data Header" },
{ OPS_PTAG_CT_LITERAL_DATA_BODY, "CT: Literal Data Body" },
{ OPS_PTAG_CT_SIGNATURE_HEADER, "CT: Signature Header" },
{ OPS_PTAG_CT_SIGNATURE_FOOTER, "CT: Signature Footer" },
{ OPS_PTAG_CT_ARMOUR_HEADER, "CT: Armour Header" },
{ OPS_PTAG_CT_ARMOUR_TRAILER, "CT: Armour Trailer" },
{ OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER, "CT: Signed Cleartext Header" },
{ OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY, "CT: Signed Cleartext Body" },
{ OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER, "CT: Signed Cleartext Trailer" },
{ OPS_PTAG_CT_UNARMOURED_TEXT, "CT: Unarmoured Text" },
{ OPS_PTAG_CT_ENCRYPTED_SECRET_KEY, "CT: Encrypted Secret Key" },
{ OPS_PTAG_CT_SE_DATA_HEADER, "CT: Sym Encrypted Data Header" },
{ OPS_PTAG_CT_SE_DATA_BODY, "CT: Sym Encrypted Data Body" },
{ OPS_PTAG_CT_SE_IP_DATA_HEADER, "CT: Sym Encrypted IP Data Header" },
{ OPS_PTAG_CT_SE_IP_DATA_BODY, "CT: Sym Encrypted IP Data Body" },
{ OPS_PTAG_CT_ENCRYPTED_PK_SESSION_KEY, "CT: Encrypted PK Session Key" },
{ OPS_PARSER_CMD_GET_SK_PASSPHRASE, "CMD: Get Secret Key Passphrase" },
{ OPS_PARSER_CMD_GET_SECRET_KEY, "CMD: Get Secret Key" },
{ OPS_PARSER_ERROR, "OPS_PARSER_ERROR" },
{ OPS_PARSER_ERRCODE, "OPS_PARSER_ERRCODE" },
{ 0x00, NULL }, /* this is the end-of-array marker */
};
typedef ops_map_t packet_tag_map_t;
static ops_map_t ss_type_map[] =
{
{ OPS_PTAG_SS_CREATION_TIME, "Signature Creation Time" },
{ OPS_PTAG_SS_EXPIRATION_TIME, "Signature Expiration Time" },
{ OPS_PTAG_SS_TRUST, "Trust Signature" },
{ OPS_PTAG_SS_REGEXP, "Regular Expression" },
{ OPS_PTAG_SS_REVOCABLE, "Revocable" },
{ OPS_PTAG_SS_KEY_EXPIRATION_TIME, "Key Expiration Time" },
{ OPS_PTAG_SS_PREFERRED_SKA, "Preferred Symmetric Algorithms" },
{ OPS_PTAG_SS_REVOCATION_KEY, "Revocation Key" },
{ OPS_PTAG_SS_ISSUER_KEY_ID, "Issuer key ID" },
{ OPS_PTAG_SS_NOTATION_DATA, "Notation Data" },
{ OPS_PTAG_SS_PREFERRED_HASH, "Preferred Hash Algorithms" },
{ OPS_PTAG_SS_PREFERRED_COMPRESSION,"Preferred Compression Algorithms" },
{ OPS_PTAG_SS_KEY_SERVER_PREFS, "Key Server Preferences" },
{ OPS_PTAG_SS_PREFERRED_KEY_SERVER, "Preferred Key Server" },
{ OPS_PTAG_SS_PRIMARY_USER_ID, "Primary User ID" },
{ OPS_PTAG_SS_POLICY_URI, "Policy URI" },
{ OPS_PTAG_SS_KEY_FLAGS, "Key Flags" },
{ OPS_PTAG_SS_REVOCATION_REASON, "Reason for Revocation" },
{ OPS_PTAG_SS_FEATURES, "Features" },
{ 0x00, NULL }, /* this is the end-of-array marker */
};
typedef ops_map_t ss_type_map_t;
static ops_map_t ss_rr_code_map[] =
{
{ 0x00, "No reason specified" },
{ 0x01, "Key is superseded" },
{ 0x02, "Key material has been compromised" },
{ 0x03, "Key is retired and no longer used" },
{ 0x20, "User ID information is no longer valid" },
{ 0x00, NULL }, /* this is the end-of-array marker */
};
typedef ops_map_t ss_rr_code_map_t;
static ops_map_t sig_type_map[] =
{
{ OPS_SIG_BINARY, "Signature of a binary document" },
{ OPS_SIG_TEXT, "Signature of a canonical text document" },
{ OPS_SIG_STANDALONE, "Standalone signature" },
{ OPS_CERT_GENERIC, "Generic certification of a User ID and Public Key packet" },
{ OPS_CERT_PERSONA, "Persona certification of a User ID and Public Key packet" },
{ OPS_CERT_CASUAL, "Casual certification of a User ID and Public Key packet" },
{ OPS_CERT_POSITIVE, "Positive certification of a User ID and Public Key packet" },
{ OPS_SIG_SUBKEY, "Subkey Binding Signature" },
{ OPS_SIG_PRIMARY, "Primary Key Binding Signature" },
{ OPS_SIG_DIRECT, "Signature directly on a key" },
{ OPS_SIG_REV_KEY, "Key revocation signature" },
{ OPS_SIG_REV_SUBKEY, "Subkey revocation signature" },
{ OPS_SIG_REV_CERT, "Certification revocation signature" },
{ OPS_SIG_TIMESTAMP, "Timestamp signature" },
{ OPS_SIG_3RD_PARTY, "Third-Party Confirmation signature" },
{ 0x00, NULL }, /* this is the end-of-array marker */
};
typedef ops_map_t sig_type_map_t;
static ops_map_t public_key_algorithm_map[] =
{
{ OPS_PKA_RSA, "RSA (Encrypt or Sign)" },
{ OPS_PKA_RSA_ENCRYPT_ONLY, "RSA Encrypt-Only" },
{ OPS_PKA_RSA_SIGN_ONLY, "RSA Sign-Only" },
{ OPS_PKA_ELGAMAL, "Elgamal (Encrypt-Only)" },
{ OPS_PKA_DSA, "DSA" },
{ OPS_PKA_RESERVED_ELLIPTIC_CURVE, "Reserved for Elliptic Curve" },
{ OPS_PKA_RESERVED_ECDSA, "Reserved for ECDSA" },
{ OPS_PKA_ELGAMAL_ENCRYPT_OR_SIGN, "Reserved (formerly Elgamal Encrypt or Sign" },
{ OPS_PKA_RESERVED_DH, "Reserved for Diffie-Hellman (X9.42)" },
{ OPS_PKA_PRIVATE00, "Private/Experimental" },
{ OPS_PKA_PRIVATE01, "Private/Experimental" },
{ OPS_PKA_PRIVATE02, "Private/Experimental" },
{ OPS_PKA_PRIVATE03, "Private/Experimental" },
{ OPS_PKA_PRIVATE04, "Private/Experimental" },
{ OPS_PKA_PRIVATE05, "Private/Experimental" },
{ OPS_PKA_PRIVATE06, "Private/Experimental" },
{ OPS_PKA_PRIVATE07, "Private/Experimental" },
{ OPS_PKA_PRIVATE08, "Private/Experimental" },
{ OPS_PKA_PRIVATE09, "Private/Experimental" },
{ OPS_PKA_PRIVATE10, "Private/Experimental" },
{ 0x00, NULL }, /* this is the end-of-array marker */
};
typedef ops_map_t public_key_algorithm_map_t;
static ops_map_t symmetric_algorithm_map[] =
{
{ OPS_SA_PLAINTEXT, "Plaintext or unencrypted data" },
{ OPS_SA_IDEA, "IDEA" },
{ OPS_SA_TRIPLEDES, "TripleDES" },
{ OPS_SA_CAST5, "CAST5" },
{ OPS_SA_BLOWFISH, "Blowfish" },
{ OPS_SA_AES_128, "AES (128-bit key)" },
{ OPS_SA_AES_192, "AES (192-bit key)" },
{ OPS_SA_AES_256, "AES (256-bit key)" },
{ OPS_SA_TWOFISH, "Twofish(256-bit key)" },
{ 0x00, NULL }, /* this is the end-of-array marker */
};
static ops_map_t hash_algorithm_map[] =
{
{ OPS_HASH_MD5, "MD5" },
{ OPS_HASH_SHA1, "SHA1" },
{ OPS_HASH_RIPEMD, "RIPEMD160" },
{ OPS_HASH_SHA256, "SHA256" },
{ OPS_HASH_SHA384, "SHA384" },
{ OPS_HASH_SHA512, "SHA512" },
{ OPS_HASH_SHA224, "SHA224" },
{ 0x00, NULL }, /* this is the end-of-array marker */
};
static ops_map_t compression_algorithm_map[] =
{
{ OPS_C_NONE, "Uncompressed" },
{ OPS_C_ZIP, "ZIP(RFC1951)" },
{ OPS_C_ZLIB, "ZLIB(RFC1950)" },
{ OPS_C_BZIP2, "Bzip2(BZ2)" },
{ 0x00, NULL }, /* this is the end-of-array marker */
};
static ops_bit_map_t ss_notation_data_map_byte0[] =
{
{ 0x80, "Human-readable" },
{ 0x00, NULL },
};
static ops_bit_map_t *ss_notation_data_map[] =
{
ss_notation_data_map_byte0,
};
static ops_bit_map_t ss_feature_map_byte0[] =
{
{ 0x01, "Modification Detection" },
{ 0x00, NULL },
};
static ops_bit_map_t *ss_feature_map[] =
{
ss_feature_map_byte0,
};
static ops_bit_map_t ss_key_flags_map[] =
{
{ 0x01, "May be used to certify other keys" },
{ 0x02, "May be used to sign data" },
{ 0x04, "May be used to encrypt communications" },
{ 0x08, "May be used to encrypt storage" },
{ 0x10, "Private component may have been split by a secret-sharing mechanism"},
{ 0x80, "Private component may be in possession of more than one person"},
{ 0x00, NULL },
};
static ops_bit_map_t ss_key_server_prefs_map[] =
{
{ 0x80, "Key holder requests that this key only be modified or updated by the key holder or an administrator of the key server" },
{ 0x00, NULL },
};
#include <openpgpsdk/packet-show-cast.h>
/*
* Private functions
*/
static void list_init(ops_list_t *list)
{
list->size=0;
list->used=0;
list->strings=NULL;
}
static void list_free_strings(ops_list_t *list)
{
unsigned i;
for(i=0; i < list->used ; i++)
{
free(list->strings[i]);
list->strings[i]=NULL;
}
}
static void list_free(ops_list_t *list)
{
if (list->strings)
free(list->strings);
list_init(list);
}
static unsigned int list_resize(ops_list_t *list)
{
/* We only resize in one direction - upwards.
Algorithm used : double the current size then add 1
*/
int newsize=0;
newsize=list->size*2 + 1;
list->strings=realloc(list->strings,newsize*sizeof(char *));
if (list->strings)
{
list->size=newsize;
return 1;
}
else
{
/* xxx - realloc failed. error message? - rachel */
return 0;
}
}
static unsigned int add_str(ops_list_t *list,char *str)
{
if (list->size==list->used)
if (!list_resize(list))
return 0;
list->strings[list->used]=str;
list->used++;
return 1;
}
static char *str_from_bitfield_or_null(unsigned char octet, ops_bit_map_t *map)
{
ops_bit_map_t *row;
for ( row=map; row->string != NULL; row++ )
if (row->mask == octet)
return row->string;
return NULL;
}
static char *str_from_bitfield(unsigned char octet, ops_bit_map_t *map)
{
char *str;
str=str_from_bitfield_or_null(octet,map);
if (str)
return str;
else
return "Unknown";
}
/*! generic function to initialise ops_text_t structure */
void ops_text_init(ops_text_t *text)
{
list_init(&text->known);
list_init(&text->unknown);
}
/**
* \ingroup Core_Print
*
* ops_text_free() frees the memory used by an ops_text_t structure
*
* \param text Pointer to a previously allocated structure. This structure and its contents will be freed.
*/
void ops_text_free(ops_text_t *text)
{
/* Strings in "known" array will be constants, so don't free them */
list_free(&text->known);
/* Strings in "unknown" array will be dynamically allocated, so do free them */
list_free_strings(&text->unknown);
list_free(&text->unknown);
/* finally, free the text structure itself */
free(text);
}
// XXX: should this (and many others) be ops_boolean_t?
/*! generic function which adds text derived from single octet map to text */
static unsigned int add_str_from_octet_map(ops_text_t *text,char *str,
unsigned char octet)
{
if (str && !add_str(&text->known,str))
{
/* value recognised, but there was a problem adding it to the list */
/* XXX - should print out error msg here, Ben? - rachel */
return 0;
}
else if (!str)
{
/* value not recognised and there was a problem adding it to the unknown list */
unsigned len=2+2+1; /* 2 for "0x", 2 for single octet in hex format, 1 for NULL */
str=malloc(len);
snprintf(str,len,"0x%x",octet);
if (!add_str(&text->unknown,str))
return 0;
}
return 1;
}
/*! generic function which adds text derived from single bit map to text */
static unsigned int add_str_from_bit_map(ops_text_t *text, char *str, unsigned char bit)
{
char *fmt_unknown="Unknown bit(0x%x)";
if (str && !add_str(&text->known,str))
{
/* value recognised, but there was a problem adding it to the list */
/* XXX - should print out error msg here, Ben? - rachel */
return 0;
}
else if (!str)
{
/* value not recognised and there was a problem adding it to the unknown list */
/* 2 chars of the string are the format definition,
this will be replaced in the output by 2 chars of hex,
so the length will be correct */
unsigned len=strlen(fmt_unknown)+1;
str=malloc(len);
snprintf(str,len,fmt_unknown,bit);
if (!add_str(&text->unknown,str))
return 0;
}
return 1;
}
/**
* Produce a structure containing human-readable textstrings
* representing the recognised and unrecognised contents
* of this byte array. text_fn() will be called on each octet in turn.
* Each octet will generate one string representing the whole byte.
*
*/
static ops_text_t *text_from_bytemapped_octets(ops_data_t *data,
const char *(*text_fn)(unsigned char octet))
{
ops_text_t *text=NULL;
const char *str;
unsigned i;
/*! allocate and initialise ops_text_t structure to store derived strings */
text=malloc(sizeof(ops_text_t));
if (!text)
return NULL;
ops_text_init(text);
/*! for each octet in field ... */
for(i=0 ; i < data->len ; i++)
{
/*! derive string from octet */
str=(*text_fn)(data->contents[i]);
/*! and add to text */
if (!add_str_from_octet_map(text,strdup(str),data->contents[i]))
{
ops_text_free(text);
return NULL;
}
}
/*! All values have been added to either the known or the unknown list */
/*! Return text */
return text;
}
/**
* Produce a structure containing human-readable textstrings
* representing the recognised and unrecognised contents
* of this byte array, derived from each bit of each octet.
*
*/
static ops_text_t *showall_octets_bits(ops_data_t *data,ops_bit_map_t **map,
size_t nmap)
{
ops_text_t *text=NULL;
char *str;
unsigned i;
int j=0;
unsigned char mask, bit;
/*! allocate and initialise ops_text_t structure to store derived strings */
text=malloc(sizeof(ops_text_t));
if (!text)
return NULL;
ops_text_init(text);
/*! for each octet in field ... */
for(i=0 ; i < data->len ; i++)
{
/*! for each bit in octet ... */
for (j=0, mask=0x80; j<8; j++, mask = mask>>1 )
{
bit = data->contents[i]&mask;
if (bit)
{
if(i >= nmap)
str="Unknown";
else
str=str_from_bitfield ( bit, map[i] );
if (!add_str_from_bit_map( text, str, bit))
{
ops_text_free(text);
return NULL;
}
}
}
}
return text;
}
/*
* Public Functions
*/
/**
* \ingroup Core_Print
* returns description of the Packet Tag
* \param packet_tag
* \return string or "Unknown"
*/
const char *ops_show_packet_tag(ops_packet_tag_t packet_tag)
{
char *rtn=NULL;
rtn=show_packet_tag(packet_tag,packet_tag_map);
if (!rtn)
rtn="Unknown Tag";
return rtn;
}
/**
* \ingroup Core_Print
*
* returns description of the Signature Sub-Packet type
* \param ss_type Signature Sub-Packet type
* \return string or "Unknown"
*/
const char *ops_show_ss_type(ops_ss_type_t ss_type)
{
return show_ss_type(ss_type,ss_type_map);
}
/**
* \ingroup Core_Print
*
* returns description of the Revocation Reason code
* \param ss_rr_code Revocation Reason code
* \return string or "Unknown"
*/
const char *ops_show_ss_rr_code(ops_ss_rr_code_t ss_rr_code)
{
return show_ss_rr_code(ss_rr_code,ss_rr_code_map);
}
/**
* \ingroup Core_Print
*
* returns description of the given Signature type
* \param sig_type Signature type
* \return string or "Unknown"
*/
const char *ops_show_sig_type(ops_sig_type_t sig_type)
{
return show_sig_type(sig_type, sig_type_map);
}
/**
* \ingroup Core_Print
*
* returns description of the given Public Key Algorithm
* \param pka Public Key Algorithm type
* \return string or "Unknown"
*/
const char *ops_show_pka(ops_public_key_algorithm_t pka)
{
return show_pka(pka, public_key_algorithm_map);
}
/**
* \ingroup Core_Print
* returns description of the Preferred Compression
* \param octet Preferred Compression
* \return string or "Unknown"
*/
const char *ops_show_ss_preferred_compression(unsigned char octet)
{
return ops_str_from_map(octet,compression_algorithm_map);
}
/**
* \ingroup Core_Print
*
* returns set of descriptions of the given Preferred Compression Algorithms
* \param ss_preferred_compression Array of Preferred Compression Algorithms
* \return NULL if cannot allocate memory or other error
* \return pointer to structure, if no error
*/
ops_text_t *ops_showall_ss_preferred_compression(ops_ss_preferred_compression_t ss_preferred_compression)
{
return text_from_bytemapped_octets(&ss_preferred_compression.data,
&ops_show_ss_preferred_compression);
}
/**
* \ingroup Core_Print
*
* returns description of the Hash Algorithm type
* \param hash Hash Algorithm type
* \return string or "Unknown"
*/
const char *ops_show_hash_algorithm(unsigned char hash)
{
return show_hash_algorithm(hash);
}
/**
* \ingroup Core_Print
*
* returns set of descriptions of the given Preferred Hash Algorithms
* \param ss_preferred_hash Array of Preferred Hash Algorithms
* \return NULL if cannot allocate memory or other error
* \return pointer to structure, if no error
*/
ops_text_t *ops_showall_ss_preferred_hash(ops_ss_preferred_hash_t ss_preferred_hash)
{
return text_from_bytemapped_octets(&ss_preferred_hash.data,
&ops_show_hash_algorithm);
}
const char *ops_show_symmetric_algorithm(unsigned char hash)
{
return show_symmetric_algorithm(hash);
}
/**
* \ingroup Core_Print
* returns description of the given Preferred Symmetric Key Algorithm
* \param octet
* \return string or "Unknown"
*/
const char *ops_show_ss_preferred_ska(unsigned char octet)
{
return ops_str_from_map(octet,symmetric_algorithm_map);
}
/**
* \ingroup Core_Print
*
* returns set of descriptions of the given Preferred Symmetric Key Algorithms
* \param ss_preferred_ska Array of Preferred Symmetric Key Algorithms
* \return NULL if cannot allocate memory or other error
* \return pointer to structure, if no error
*/
ops_text_t *ops_showall_ss_preferred_ska(ops_ss_preferred_ska_t ss_preferred_ska)
{
return text_from_bytemapped_octets(&ss_preferred_ska.data,
&ops_show_ss_preferred_ska);
}
/**
* \ingroup Core_Print
* returns description of one SS Feature
* \param octet
* \return string or "Unknown"
*/
static char *ops_show_ss_feature(unsigned char octet,unsigned offset)
{
if(offset >= OPS_ARRAY_SIZE(ss_feature_map))
return "Unknown";
return str_from_bitfield(octet,ss_feature_map[offset]);
}
/**
* \ingroup Core_Print
*
* returns set of descriptions of the given SS Features
* \param ss_features Signature Sub-Packet Features
* \return NULL if cannot allocate memory or other error
* \return pointer to structure, if no error
*/
/* XXX: shouldn't this use show_all_octets_bits? */
ops_text_t *ops_showall_ss_features(ops_ss_features_t ss_features)
{
ops_text_t *text=NULL;
char *str;
unsigned i;
int j=0;
unsigned char mask, bit;
text=malloc(sizeof(ops_text_t));
if (!text)
return NULL;
ops_text_init(text);
for(i=0 ; i < ss_features.data.len ; i++)
{
for (j=0, mask=0x80; j<8; j++, mask = mask>>1 )
{
bit = ss_features.data.contents[i]&mask;
if (bit)
{
str=ops_show_ss_feature ( bit, i );
if (!add_str_from_bit_map( text, str, bit))
{
ops_text_free(text);
return NULL;
}
}
}
}
return text;
}
/**
* \ingroup Core_Print
* returns description of SS Key Flag
* \param octet
* \param map
* \return
*/
const char *ops_show_ss_key_flag(unsigned char octet, ops_bit_map_t *map)
{
return str_from_bitfield(octet,map);
}
/**
* \ingroup Core_Print
*
* returns set of descriptions of the given Preferred Key Flags
* \param ss_key_flags Array of Key Flags
* \return NULL if cannot allocate memory or other error
* \return pointer to structure, if no error
*/
ops_text_t *ops_showall_ss_key_flags(ops_ss_key_flags_t ss_key_flags)
{
ops_text_t *text=NULL;
const char *str;
int i=0;
unsigned char mask, bit;
text=malloc(sizeof(ops_text_t));
if (!text)
return NULL;
ops_text_init(text);
/* xxx - TBD: extend to handle multiple octets of bits - rachel */
for (i=0,mask=0x80 ; i < 8 ; i++,mask=mask >> 1)
{
bit=ss_key_flags.data.contents[0]&mask;
if(bit)
{
str=ops_show_ss_key_flag(bit,&ss_key_flags_map[0]);
if(!add_str_from_bit_map(text,strdup(str),bit))
{
ops_text_free(text);
return NULL;
}
}
}
/* xxx - must add error text if more than one octet. Only one currently specified -- rachel */
return text;
}
/**
* \ingroup Core_Print
*
* returns description of one given Key Server Preference
*
* \param prefs Byte containing bitfield of preferences
* \param map
* \return string or "Unknown"
*/
const char *ops_show_ss_key_server_prefs(unsigned char prefs,
ops_bit_map_t *map)
{
return str_from_bitfield(prefs,map);
}
/**
* \ingroup Core_Print
* returns set of descriptions of given Key Server Preferences
* \param ss_key_server_prefs
* \return NULL if cannot allocate memory or other error
* \return pointer to structure, if no error
*
*/
ops_text_t *ops_showall_ss_key_server_prefs(ops_ss_key_server_prefs_t ss_key_server_prefs)
{
ops_text_t *text=NULL;
const char *str;
int i=0;
unsigned char mask, bit;
text=malloc(sizeof(ops_text_t));
if (!text)
return NULL;
ops_text_init(text);
/* xxx - TBD: extend to handle multiple octets of bits - rachel */
for (i=0,mask=0x80 ; i < 8 ; i++,mask=mask >> 1)
{
bit=ss_key_server_prefs.data.contents[0]&mask;
if (bit)
{
str=ops_show_ss_key_server_prefs(bit,
&ss_key_server_prefs_map[0]);
if(!add_str_from_bit_map( text, strdup(str), bit))
{
ops_text_free(text);
return NULL;
}
}
}
/* xxx - must add error text if more than one octet. Only one currently specified -- rachel */
return text;
}
/**
* \ingroup Core_Print
*
* returns set of descriptions of the given SS Notation Data Flags
* \param ss_notation_data Signature Sub-Packet Notation Data
* \return NULL if cannot allocate memory or other error
* \return pointer to structure, if no error
*/
ops_text_t *ops_showall_ss_notation_data_flags(ops_ss_notation_data_t ss_notation_data)
{
return showall_octets_bits(&ss_notation_data.flags,ss_notation_data_map,
OPS_ARRAY_SIZE(ss_notation_data_map));
}

View File

@ -0,0 +1,118 @@
/*
* 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 <openpgpsdk/types.h>
#include <openpgpsdk/crypto.h>
/** ops_reader_info */
struct ops_reader_info
{
ops_reader_t *reader; /*!< the reader function to use to get the
data to be parsed */
ops_reader_destroyer_t *destroyer;
void *arg; /*!< the args to pass to the reader function */
ops_boolean_t accumulate:1; /*!< set to accumulate packet data */
unsigned char *accumulated; /*!< the accumulated data */
unsigned asize; /*!< size of the buffer */
unsigned alength; /*!< used buffer */
/* XXX: what do we do about offsets into compressed packets? */
unsigned position; /*!< the offset from the beginning (with this reader) */
ops_reader_info_t *next;
ops_parse_info_t *pinfo; /*!< A pointer back to the parent parse_info structure */
};
/** ops_crypt_info
Encrypt/decrypt settings
*/
struct ops_crypt_info
{
char *passphrase; /*<! passphrase to use, this is set by cb_get_passphrase */
ops_keyring_t *keyring; /*<! keyring to use */
const ops_keydata_t *keydata; /*<! keydata to use */
ops_parse_cb_t *cb_get_passphrase; /*<! callback to use to get the passphrase */
};
/** ops_parse_cb_info */
struct ops_parse_cb_info
{
ops_parse_cb_t *cb; /*!< the callback function to use when parsing */
void *arg; /*!< the args to pass to the callback function */
ops_error_t** errors; /*!< the address of the error stack to use */
ops_parse_cb_info_t *next;
ops_create_info_t *cinfo; /*!< used if writing out parsed info */
ops_crypt_info_t cryptinfo; /*!< used when decrypting */
};
/** ops_parse_hash_info_t */
typedef struct
{
ops_hash_t hash; /*!< hashes we should hash data with */
unsigned char keyid[OPS_KEY_ID_SIZE];
} ops_parse_hash_info_t;
#define NTAGS 0x100
/** \brief Structure to hold information about a packet parse.
*
* This information includes options about the parse:
* - whether the packet contents should be accumulated or not
* - whether signature subpackets should be parsed or left raw
*
* It contains options specific to the parsing of armoured data:
* - whether headers are allowed in armoured data without a gap
* - whether a blank line is allowed at the start of the armoured data
*
* It also specifies :
* - the callback function to use and its arguments
* - the reader function to use and its arguments
*
* It also contains information about the current state of the parse:
* - offset from the beginning
* - the accumulated data, if any
* - the size of the buffer, and how much has been used
*
* It has a linked list of errors.
*/
struct ops_parse_info
{
unsigned char ss_raw[NTAGS/8]; /*!< one bit per signature-subpacket type;
set to get raw data */
unsigned char ss_parsed[NTAGS/8]; /*!< one bit per signature-subpacket type;
set to get parsed data */
ops_reader_info_t rinfo;
ops_parse_cb_info_t cbinfo;
ops_error_t *errors;
ops_crypt_t decrypt;
ops_crypt_info_t cryptinfo;
size_t nhashes;
ops_parse_hash_info_t *hashes;
ops_boolean_t reading_v3_secret:1;
ops_boolean_t reading_mpi_length:1;
ops_boolean_t exact_read:1;
};

29
openpgpsdk/src/random.c Normal file
View File

@ -0,0 +1,29 @@
/*
* 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.
*/
#include <openpgpsdk/random.h>
#include <openssl/rand.h>
void ops_random(void *dest,size_t length)
{
RAND_bytes(dest,length);
}

107
openpgpsdk/src/reader.c Normal file
View File

@ -0,0 +1,107 @@
/*
* 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.
*/
#include <fcntl.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <direct.h>
#endif
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <openpgpsdk/readerwriter.h>
#include <openpgpsdk/callback.h>
#include "parse_local.h"
/**
* \ingroup Internal_Readers_Generic
* \brief Starts reader stack
* \param pinfo Parse settings
* \param reader Reader to use
* \param destroyer Destroyer to use
* \param arg Reader-specific arg
*/
void ops_reader_set(ops_parse_info_t *pinfo,ops_reader_t *reader,ops_reader_destroyer_t *destroyer,void *arg)
{
pinfo->rinfo.reader=reader;
pinfo->rinfo.destroyer=destroyer;
pinfo->rinfo.arg=arg;
}
/**
* \ingroup Internal_Readers_Generic
* \brief Adds to reader stack
* \param pinfo Parse settings
* \param reader Reader to use
* \param destroyer Reader's destroyer
* \param arg Reader-specific arg
*/
void ops_reader_push(ops_parse_info_t *pinfo,ops_reader_t *reader,ops_reader_destroyer_t *destroyer,void *arg)
{
ops_reader_info_t *rinfo=malloc(sizeof *rinfo);
*rinfo=pinfo->rinfo;
memset(&pinfo->rinfo,'\0',sizeof pinfo->rinfo);
pinfo->rinfo.next=rinfo;
pinfo->rinfo.pinfo=pinfo;
// should copy accumulate flags from other reader? RW
pinfo->rinfo.accumulate=rinfo->accumulate;
ops_reader_set(pinfo,reader,destroyer,arg);
}
/**
* \ingroup Internal_Readers_Generic
* \brief Removes from reader stack
* \param pinfo Parse settings
*/
void ops_reader_pop(ops_parse_info_t *pinfo)
{
ops_reader_info_t *next=pinfo->rinfo.next;
pinfo->rinfo=*next;
free(next);
}
/**
* \ingroup Internal_Readers_Generic
* \brief Gets arg from reader
* \param rinfo Reader info
* \return Pointer to reader info's arg
*/
void *ops_reader_get_arg(ops_reader_info_t *rinfo)
{ return rinfo->arg; }
/**
* \ingroup Internal_Readers_Generic
* \brief Gets reader's arg from parse_info
* \param pinfo
* \return Pointer to parse_info's reader_info's arg
*/
void *ops_reader_get_arg_from_pinfo(ops_parse_info_t *pinfo)
{ return pinfo->rinfo.arg; }
// EOF

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,217 @@
/*
* 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.
*/
#include <openpgpsdk/crypto.h>
#include <string.h>
#include <assert.h>
#include <openssl/cast.h>
#ifndef OPENSSL_NO_IDEA
#include <openssl/idea.h>
#endif
#include <openssl/aes.h>
#include <openssl/des.h>
#include "parse_local.h"
#include <openpgpsdk/packet-show.h>
#include <openpgpsdk/final.h>
static int debug=0;
#ifndef ATTRIBUTE_UNUSED
#ifndef WIN32
#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#else
#define ATTRIBUTE_UNUSED
#endif // #ifndef WIN32
#endif /* ATTRIBUTE_UNUSED */
// \todo there's also a encrypted_arg_t in adv_create.c
// which is used for *encrypting* whereas this is used
// for *decrypting*
typedef struct
{
unsigned char decrypted[1024];
size_t decrypted_count;
size_t decrypted_offset;
ops_crypt_t *decrypt;
ops_region_t *region;
ops_boolean_t prev_read_was_plain:1;
} encrypted_arg_t;
static int encrypted_data_reader(void *dest,size_t length,ops_error_t **errors,
ops_reader_info_t *rinfo,
ops_parse_cb_info_t *cbinfo)
{
encrypted_arg_t *arg=ops_reader_get_arg(rinfo);
int saved=length;
// V3 MPIs have the count plain and the cipher is reset after each count
if(arg->prev_read_was_plain && !rinfo->pinfo->reading_mpi_length)
{
assert(rinfo->pinfo->reading_v3_secret);
arg->decrypt->decrypt_resync(arg->decrypt);
arg->prev_read_was_plain=ops_false;
}
else if(rinfo->pinfo->reading_v3_secret
&& rinfo->pinfo->reading_mpi_length)
{
arg->prev_read_was_plain=ops_true;
}
while(length > 0)
{
if(arg->decrypted_count)
{
unsigned n;
// if we are reading v3 we should never read more than
// we're asked for
assert(length >= arg->decrypted_count
|| (!rinfo->pinfo->reading_v3_secret
&& !rinfo->pinfo->exact_read));
if(length > arg->decrypted_count)
n=arg->decrypted_count;
else
n=length;
memcpy(dest,arg->decrypted+arg->decrypted_offset,n);
arg->decrypted_count-=n;
arg->decrypted_offset+=n;
length-=n;
#ifdef WIN32
(char*)dest+=n;
#else
dest+=n;
#endif
}
else
{
unsigned n=arg->region->length;
unsigned char buffer[1024];
if(!n)
{
return -1;
}
if(!arg->region->indeterminate)
{
n-=arg->region->length_read;
if(n == 0)
return saved-length;
if(n > sizeof buffer)
n=sizeof buffer;
}
else
{
n=sizeof buffer;
}
// we can only read as much as we're asked for in v3 keys
// because they're partially unencrypted!
if((rinfo->pinfo->reading_v3_secret || rinfo->pinfo->exact_read)
&& n > length)
n=length;
if(!ops_stacked_limited_read(buffer,n,arg->region,errors,rinfo,
cbinfo))
{
return -1;
}
if(!rinfo->pinfo->reading_v3_secret
|| !rinfo->pinfo->reading_mpi_length)
{
arg->decrypted_count=ops_decrypt_se_ip(arg->decrypt,
arg->decrypted,
buffer,n);
if (debug)
{
fprintf(stderr,"READING:\nencrypted: ");
int i=0;
for (i=0; i<16; i++)
fprintf(stderr,"%2x ", buffer[i]);
fprintf(stderr,"\n");
fprintf(stderr,"decrypted: ");
for (i=0; i<16; i++)
fprintf(stderr,"%2x ", arg->decrypted[i]);
fprintf(stderr,"\n");
}
}
else
{
memcpy(arg->decrypted,buffer,n);
arg->decrypted_count=n;
}
assert(arg->decrypted_count > 0);
arg->decrypted_offset=0;
}
}
return saved;
}
static void encrypted_data_destroyer(ops_reader_info_t *rinfo)
{ free(ops_reader_get_arg(rinfo)); }
/**
* \ingroup Core_Readers_SE
* \brief Pushes decryption reader onto stack
* \sa ops_reader_pop_decrypt()
*/
void ops_reader_push_decrypt(ops_parse_info_t *pinfo,ops_crypt_t *decrypt,
ops_region_t *region)
{
encrypted_arg_t *arg=ops_mallocz(sizeof *arg);
arg->decrypt=decrypt;
arg->region=region;
ops_decrypt_init(arg->decrypt);
ops_reader_push(pinfo,encrypted_data_reader,encrypted_data_destroyer,arg);
}
/**
* \ingroup Core_Readers_Encrypted
* \brief Pops decryption reader from stack
* \sa ops_reader_push_decrypt()
*/
void ops_reader_pop_decrypt(ops_parse_info_t *pinfo)
{
encrypted_arg_t *arg=ops_reader_get_arg(ops_parse_get_rinfo(pinfo));
arg->decrypt->decrypt_finish(arg->decrypt);
free(arg);
ops_reader_pop(pinfo);
}
// eof

View File

@ -0,0 +1,248 @@
/*
* 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
* \brief Parser for OpenPGP packets
*/
#include <openssl/cast.h>
#include <openpgpsdk/callback.h>
#include <openpgpsdk/packet.h>
#include <openpgpsdk/packet-parse.h>
#include <openpgpsdk/keyring.h>
#include <openpgpsdk/util.h>
#include <openpgpsdk/compress.h>
#include <openpgpsdk/errors.h>
#include <openpgpsdk/readerwriter.h>
#include <openpgpsdk/packet-show.h>
#include <openpgpsdk/std_print.h>
#include <openpgpsdk/create.h>
#include <openpgpsdk/hash.h>
#include "parse_local.h"
#include <assert.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <errno.h>
#include <limits.h>
#include <openpgpsdk/final.h>
static int debug=0;
typedef struct
{
// boolean: false once we've done the preamble/MDC checks
// and are reading from the plaintext
int passed_checks;
unsigned char *plaintext;
size_t plaintext_available;
size_t plaintext_offset;
ops_region_t *region;
ops_crypt_t *decrypt;
} decrypt_se_ip_arg_t;
static int se_ip_data_reader(void *dest_, size_t len, ops_error_t **errors,
ops_reader_info_t *rinfo,
ops_parse_cb_info_t *cbinfo)
{
/*
Gets entire SE_IP data packet.
Verifies leading preamble
Verifies trailing MDC packet
Then passes up plaintext as requested
*/
unsigned int n=0;
ops_region_t decrypted_region;
decrypt_se_ip_arg_t *arg=ops_reader_get_arg(rinfo);
if (!arg->passed_checks)
{
unsigned char*buf=NULL;
ops_hash_t hash;
unsigned char hashed[SHA_DIGEST_LENGTH];
size_t b;
size_t sz_preamble;
size_t sz_mdc_hash;
size_t sz_mdc;
size_t sz_plaintext;
unsigned char* preamble;
unsigned char* plaintext;
unsigned char* mdc;
unsigned char* mdc_hash;
ops_hash_any(&hash,OPS_HASH_SHA1);
hash.init(&hash);
ops_init_subregion(&decrypted_region,NULL);
decrypted_region.length = arg->region->length - arg->region->length_read;
buf=ops_mallocz(decrypted_region.length);
// read entire SE IP packet
if (!ops_stacked_limited_read(buf,decrypted_region.length, &decrypted_region,errors,rinfo,cbinfo))
{
free (buf);
return -1;
}
if (debug)
{
unsigned int i=0;
fprintf(stderr,"\n\nentire SE IP packet (len=%d):\n",decrypted_region.length);
for (i=0; i<decrypted_region.length; i++)
{
fprintf(stderr,"0x%02x ", buf[i]);
if (!((i+1)%8))
fprintf(stderr,"\n");
}
fprintf(stderr,"\n");
fprintf(stderr,"\n");
}
// verify leading preamble
if (debug)
{
unsigned int i=0;
fprintf(stderr,"\npreamble: ");
for (i=0; i<arg->decrypt->blocksize+2;i++)
fprintf(stderr," 0x%02x", buf[i]);
fprintf(stderr,"\n");
}
b=arg->decrypt->blocksize;
if(buf[b-2] != buf[b] || buf[b-1] != buf[b+1])
{
fprintf(stderr,"Bad symmetric decrypt (%02x%02x vs %02x%02x)\n",
buf[b-2],buf[b-1],buf[b],buf[b+1]);
OPS_ERROR(errors, OPS_E_PROTO_BAD_SYMMETRIC_DECRYPT,"Bad symmetric decrypt when parsing SE IP packet");
free(buf);
return -1;
}
// Verify trailing MDC hash
sz_preamble=arg->decrypt->blocksize+2;
sz_mdc_hash=OPS_SHA1_HASH_SIZE;
sz_mdc=1+1+sz_mdc_hash;
sz_plaintext=decrypted_region.length-sz_preamble-sz_mdc;
preamble=buf;
plaintext=buf+sz_preamble;
mdc=plaintext+sz_plaintext;
mdc_hash=mdc+2;
#ifdef DEBUG
if (debug)
{
unsigned int i=0;
fprintf(stderr,"\nplaintext (len=%ld): ",sz_plaintext);
for (i=0; i<sz_plaintext;i++)
fprintf(stderr," 0x%02x", plaintext[i]);
fprintf(stderr,"\n");
fprintf(stderr,"\nmdc (len=%ld): ",sz_mdc);
for (i=0; i<sz_mdc;i++)
fprintf(stderr," 0x%02x", mdc[i]);
fprintf(stderr,"\n");
}
#endif /*DEBUG*/
ops_calc_mdc_hash(preamble,sz_preamble,plaintext,sz_plaintext,&hashed[0]);
if (memcmp(mdc_hash,hashed,OPS_SHA1_HASH_SIZE))
{
OPS_ERROR(errors, OPS_E_V_BAD_HASH, "Bad hash in MDC packet");
free(buf);
return 0;
}
// all done with the checks
// now can start reading from the plaintext
assert(!arg->plaintext);
arg->plaintext=ops_mallocz(sz_plaintext);
memcpy(arg->plaintext, plaintext, sz_plaintext);
arg->plaintext_available=sz_plaintext;
arg->passed_checks=1;
free(buf);
}
n=len;
if (n > arg->plaintext_available)
n=arg->plaintext_available;
memcpy(dest_, arg->plaintext+arg->plaintext_offset, n);
arg->plaintext_available-=n;
arg->plaintext_offset+=n;
len-=n;
return n;
}
static void se_ip_data_destroyer(ops_reader_info_t *rinfo)
{
decrypt_se_ip_arg_t* arg=ops_reader_get_arg(rinfo);
free (arg->plaintext);
free (arg);
// free(ops_reader_get_arg(rinfo));
}
/**
\ingroup Internal_Readers_SEIP
*/
void ops_reader_push_se_ip_data(ops_parse_info_t *pinfo, ops_crypt_t *decrypt,
ops_region_t *region)
{
decrypt_se_ip_arg_t *arg=ops_mallocz(sizeof *arg);
arg->region=region;
arg->decrypt=decrypt;
ops_reader_push(pinfo, se_ip_data_reader, se_ip_data_destroyer,arg);
}
/**
\ingroup Internal_Readers_SEIP
*/
void ops_reader_pop_se_ip_data(ops_parse_info_t* pinfo)
{
// decrypt_se_ip_arg_t *arg=ops_reader_get_arg(ops_parse_get_rinfo(pinfo));
// free(arg);
ops_reader_pop(pinfo);
}
// eof

109
openpgpsdk/src/reader_fd.c Normal file
View File

@ -0,0 +1,109 @@
/*
* 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 <openpgpsdk/util.h>
#include <openpgpsdk/packet-parse.h>
#include <openpgpsdk/crypto.h>
#include <openpgpsdk/create.h>
#include <openpgpsdk/errors.h>
#include <stdio.h>
#include <assert.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <string.h>
#include <openpgpsdk/final.h>
/** Arguments for reader_fd
*/
typedef struct
{
int fd; /*!< file descriptor */
} reader_fd_arg_t;
/**
* \ingroup Core_Readers
*
* ops_reader_fd() attempts to read up to "plength" bytes from the file
* descriptor in "parse_info" into the buffer starting at "dest" using the
* rules contained in "flags"
*
* \param dest Pointer to previously allocated buffer
* \param plength Number of bytes to try to read
* \param flags Rules about reading to use
* \param parse_info Gets cast to ops_reader_fd_arg_t
*
* \return OPS_R_EOF if no bytes were read
* \return OPS_R_PARTIAL_READ if not enough bytes were read, and OPS_RETURN_LENGTH is set in "flags"
* \return OPS_R_EARLY_EOF if not enough bytes were read, and OPS_RETURN_LENGTH was not set in "flags"
* \return OPS_R_OK if expected length was read
* \return OPS_R_ERROR if cannot read
*
* OPS_R_EARLY_EOF and OPS_R_ERROR push errors on the stack
*
* \sa enum opt_reader_ret_t
*
* \todo change arg_ to typesafe?
*/
static int fd_reader(void *dest,size_t length,ops_error_t **errors,
ops_reader_info_t *rinfo,ops_parse_cb_info_t *cbinfo)
{
reader_fd_arg_t *arg=ops_reader_get_arg(rinfo);
int n=read(arg->fd,dest,length);
OPS_USED(cbinfo);
if(n == 0)
return 0;
if(n < 0)
{
OPS_SYSTEM_ERROR_1(errors,OPS_E_R_READ_FAILED,"read",
"file descriptor %d",arg->fd);
return -1;
}
return n;
}
static void fd_destroyer(ops_reader_info_t *rinfo)
{ free(ops_reader_get_arg(rinfo)); }
/**
\ingroup Core_Readers_First
\brief Starts stack with file reader
*/
void ops_reader_set_fd(ops_parse_info_t *pinfo,int fd)
{
reader_fd_arg_t *arg=malloc(sizeof *arg);
arg->fd=fd;
ops_reader_set(pinfo,fd_reader,fd_destroyer,arg);
}
// eof

View File

@ -0,0 +1,62 @@
/*
* 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 <openpgpsdk/crypto.h>
#include <assert.h>
#include <string.h>
#include <openpgpsdk/final.h>
static int hash_reader(void *dest,size_t length,ops_error_t **errors,
ops_reader_info_t *rinfo,ops_parse_cb_info_t *cbinfo)
{
ops_hash_t *hash=ops_reader_get_arg(rinfo);
int r=ops_stacked_read(dest,length,errors,rinfo,cbinfo);
if(r <= 0)
return r;
hash->add(hash,dest,r);
return r;
}
/**
\ingroup Internal_Readers_Hash
\brief Push hashed data reader on stack
*/
void ops_reader_push_hash(ops_parse_info_t *pinfo,ops_hash_t *hash)
{
hash->init(hash);
ops_reader_push(pinfo,hash_reader,NULL,hash);
}
/**
\ingroup Internal_Readers_Hash
\brief Pop hashed data reader from stack
*/
void ops_reader_pop_hash(ops_parse_info_t *pinfo)
{ ops_reader_pop(pinfo); }
// EOF

View File

@ -0,0 +1,90 @@
/*
* 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 <openpgpsdk/util.h>
#include <openpgpsdk/packet-parse.h>
#include <openpgpsdk/crypto.h>
#include <openpgpsdk/create.h>
#include <openpgpsdk/errors.h>
#include <stdio.h>
#include <assert.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <string.h>
#include <openpgpsdk/final.h>
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)); }
/**
\ingroup Core_Readers_First
\brief Starts stack with memory reader
*/
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);
}
/* eof */

View File

@ -0,0 +1,451 @@
/*
* 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.
*/
#include <fcntl.h>
#ifndef WIN32
#include <unistd.h>
#else
#include <direct.h>
#endif
#include <termios.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <openpgpsdk/readerwriter.h>
#include <openpgpsdk/callback.h>
#include "parse_local.h"
/**
\ingroup Core_Writers
\brief Create and initialise cinfo and mem; Set for writing to mem
\param cinfo Address where new cinfo pointer will be set
\param mem Address when new mem pointer will be set
\param bufsz Initial buffer size (will automatically be increased when necessary)
\note It is the caller's responsiblity to free cinfo and mem.
\sa ops_teardown_memory_write()
*/
void ops_setup_memory_write(ops_create_info_t **cinfo, ops_memory_t **mem, size_t bufsz)
{
/*
* initialise needed structures for writing to memory
*/
*cinfo=ops_create_info_new();
*mem=ops_memory_new();
ops_memory_init(*mem,bufsz);
ops_writer_set_memory(*cinfo,*mem);
}
/**
\ingroup Core_Writers
\brief Closes writer and frees cinfo and mem
\param cinfo
\param mem
\sa ops_setup_memory_write()
*/
void ops_teardown_memory_write(ops_create_info_t *cinfo, ops_memory_t *mem)
{
ops_writer_close(cinfo); // new
ops_create_info_delete(cinfo);
ops_memory_free(mem);
}
/**
\ingroup Core_Readers
\brief Create parse_info and sets to read from memory
\param pinfo Address where new parse_info will be set
\param mem Memory to read from
\param arg Reader-specific arg
\param callback Callback to use with reader
\param accumulate Set if we need to accumulate as we read. (Usually false unless doing signature verification)
\note It is the caller's responsiblity to free parse_info
\sa ops_teardown_memory_read()
*/
void ops_setup_memory_read(ops_parse_info_t **pinfo, ops_memory_t *mem,
void* arg,
ops_parse_cb_return_t callback(const ops_parser_content_t *, ops_parse_cb_info_t *),
ops_boolean_t accumulate)
{
/*
* initialise needed uctures for reading
*/
*pinfo=ops_parse_info_new();
ops_parse_cb_set(*pinfo,callback,arg);
ops_reader_set_memory(*pinfo,
ops_memory_get_data(mem),
ops_memory_get_length(mem));
if (accumulate)
(*pinfo)->rinfo.accumulate=ops_true;
}
/**
\ingroup Core_Readers
\brief Frees pinfo and mem
\param pinfo
\param mem
\sa ops_setup_memory_read()
*/
void ops_teardown_memory_read(ops_parse_info_t *pinfo, ops_memory_t *mem)
{
ops_parse_info_delete(pinfo);
ops_memory_free(mem);
}
/**
\ingroup Core_Writers
\brief Create and initialise cinfo and mem; Set for writing to file
\param cinfo Address where new cinfo pointer will be set
\param filename File to write to
\param allow_overwrite Allows file to be overwritten, if set.
\return Newly-opened file descriptor
\note It is the caller's responsiblity to free cinfo and to close fd.
\sa ops_teardown_file_write()
*/
int ops_setup_file_write(ops_create_info_t **cinfo, const char* filename, ops_boolean_t allow_overwrite)
{
int fd=0;
int flags=0;
/*
* initialise needed structures for writing to file
*/
flags=O_WRONLY | O_CREAT;
if (allow_overwrite==ops_true)
flags |= O_TRUNC;
else
flags |= O_EXCL;
#ifdef WIN32
flags |= O_BINARY;
#endif
fd=open(filename, flags, 0600);
if(fd < 0)
{
perror(filename);
return fd;
}
*cinfo=ops_create_info_new();
ops_writer_set_fd(*cinfo,fd);
return fd;
}
/**
\ingroup Core_Writers
\brief Closes writer, frees info, closes fd
\param cinfo
\param fd
*/
void ops_teardown_file_write(ops_create_info_t *cinfo, int fd)
{
ops_writer_close(cinfo);
close(fd);
ops_create_info_delete(cinfo);
}
/**
\ingroup Core_Writers
\brief As ops_setup_file_write, but appends to file
*/
int ops_setup_file_append(ops_create_info_t **cinfo, const char* filename)
{
int fd;
/*
* initialise needed structures for writing to file
*/
#ifdef WIN32
fd=open(filename,O_WRONLY | O_APPEND | O_BINARY, 0600);
#else
fd=open(filename,O_WRONLY | O_APPEND, 0600);
#endif
if(fd < 0)
{
perror(filename);
return fd;
}
*cinfo=ops_create_info_new();
ops_writer_set_fd(*cinfo,fd);
return fd;
}
/**
\ingroup Core_Writers
\brief As ops_teardown_file_write()
*/
void ops_teardown_file_append(ops_create_info_t *cinfo, int fd)
{
ops_teardown_file_write(cinfo,fd);
}
/**
\ingroup Core_Readers
\brief Creates parse_info, opens file, and sets to read from file
\param pinfo Address where new parse_info will be set
\param filename Name of file to read
\param arg Reader-specific arg
\param callback Callback to use when reading
\param accumulate Set if we need to accumulate as we read. (Usually false unless doing signature verification)
\note It is the caller's responsiblity to free parse_info and to close fd
\sa ops_teardown_file_read()
*/
int ops_setup_file_read(ops_parse_info_t **pinfo, const char *filename,
void* arg,
ops_parse_cb_return_t callback(const ops_parser_content_t *, ops_parse_cb_info_t *),
ops_boolean_t accumulate)
{
int fd=0;
/*
* initialise needed structures for reading
*/
#ifdef WIN32
fd=open(filename,O_RDONLY | O_BINARY);
#else
fd=open(filename,O_RDONLY);
#endif
if (fd < 0)
{
perror(filename);
return fd;
}
*pinfo=ops_parse_info_new();
ops_parse_cb_set(*pinfo,callback,arg);
ops_reader_set_fd(*pinfo,fd);
if (accumulate)
(*pinfo)->rinfo.accumulate=ops_true;
return fd;
}
/**
\ingroup Core_Readers
\brief Frees pinfo and closes fd
\param pinfo
\param fd
\sa ops_setup_file_read()
*/
void ops_teardown_file_read(ops_parse_info_t *pinfo, int fd)
{
close(fd);
ops_parse_info_delete(pinfo);
}
ops_parse_cb_return_t
callback_literal_data(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_USED(cbinfo);
// ops_print_packet(content_);
// Read data from packet into static buffer
switch(content_->tag)
{
case OPS_PTAG_CT_LITERAL_DATA_BODY:
// if writer enabled, use it
if (cbinfo->cinfo)
{
ops_write(content->literal_data_body.data,
content->literal_data_body.length,
cbinfo->cinfo);
}
/*
ops_memory_add(mem_literal_data,
content->literal_data_body.data,
content->literal_data_body.length);
*/
break;
case OPS_PTAG_CT_LITERAL_DATA_HEADER:
// ignore
break;
default:
// return callback_general(content_,cbinfo);
break;
}
return OPS_RELEASE_MEMORY;
}
ops_parse_cb_return_t
callback_pk_session_key(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_USED(cbinfo);
// ops_print_packet(content_);
// Read data from packet into static buffer
switch(content_->tag)
{
case OPS_PTAG_CT_PK_SESSION_KEY:
// printf ("OPS_PTAG_CT_PK_SESSION_KEY\n");
assert(cbinfo->cryptinfo.keyring);
cbinfo->cryptinfo.keydata=ops_keyring_find_key_by_id(cbinfo->cryptinfo.keyring,
content->pk_session_key.key_id);
if(!cbinfo->cryptinfo.keydata)
break;
break;
default:
// return callback_general(content_,cbinfo);
break;
}
return OPS_RELEASE_MEMORY;
}
/**
\ingroup Core_Callbacks
\brief Callback to get secret key, decrypting if necessary.
@verbatim
This callback does the following:
* finds the session key in the keyring
* gets a passphrase if required
* decrypts the secret key, if necessary
* sets the secret_key in the content struct
@endverbatim
*/
ops_parse_cb_return_t
callback_cmd_get_secret_key(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;
const ops_secret_key_t *secret;
ops_parser_content_t pc;
OPS_USED(cbinfo);
// ops_print_packet(content_);
switch(content_->tag)
{
case OPS_PARSER_CMD_GET_SECRET_KEY:
cbinfo->cryptinfo.keydata=ops_keyring_find_key_by_id(cbinfo->cryptinfo.keyring,content->get_secret_key.pk_session_key->key_id);
if (!cbinfo->cryptinfo.keydata || !ops_is_key_secret(cbinfo->cryptinfo.keydata))
return 0;
/* now get the key from the data */
secret=ops_get_secret_key_from_data(cbinfo->cryptinfo.keydata);
while(!secret)
{
if (!cbinfo->cryptinfo.passphrase)
{
memset(&pc,'\0',sizeof pc);
pc.content.secret_key_passphrase.passphrase=&cbinfo->cryptinfo.passphrase;
CB(cbinfo,OPS_PARSER_CMD_GET_SK_PASSPHRASE,&pc);
if (!cbinfo->cryptinfo.passphrase)
{
fprintf(stderr,"can't get passphrase\n");
assert(0);
}
}
/* then it must be encrypted */
secret=ops_decrypt_secret_key_from_data(cbinfo->cryptinfo.keydata,cbinfo->cryptinfo.passphrase);
}
*content->get_secret_key.secret_key=secret;
break;
default:
// return callback_general(content_,cbinfo);
break;
}
return OPS_RELEASE_MEMORY;
}
char *ops_get_passphrase(void)
{
return ops_malloc_passphrase(getpass("Passphrase: "));
}
char *ops_malloc_passphrase(char *pp)
{
char *passphrase;
size_t n;
n=strlen(pp);
passphrase=malloc(n+1);
strncpy(passphrase,pp,n+1);
return passphrase;
}
/**
\ingroup HighLevel_Callbacks
\brief Callback to use when you need to prompt user for passphrase
\param content_
\param cbinfo
*/
ops_parse_cb_return_t
callback_cmd_get_passphrase_from_cmdline(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_USED(cbinfo);
// ops_print_packet(content_);
switch(content_->tag)
{
case OPS_PARSER_CMD_GET_SK_PASSPHRASE:
*(content->secret_key_passphrase.passphrase)=ops_get_passphrase();
return OPS_KEEP_MEMORY;
break;
default:
// return callback_general(content_,cbinfo);
break;
}
return OPS_RELEASE_MEMORY;
}
ops_boolean_t ops_reader_set_accumulate(ops_parse_info_t* pinfo, ops_boolean_t state)
{
pinfo->rinfo.accumulate=state;
return state;
}
// EOF

1322
openpgpsdk/src/signature.c Normal file

File diff suppressed because it is too large Load Diff

49
openpgpsdk/src/src.pro Normal file
View File

@ -0,0 +1,49 @@
TEMPLATE = lib
CONFIG = staticlib
DEFINES *= OPENSSL_NO_IDEA
QMAKE_CXXFLAGS *= -Wall -Werror -W
TARGET = ops
DESTDIR = ../lib
DEPENDPATH += .
INCLUDEPATH += . ../include
# Input
HEADERS += keyring_local.h parse_local.h
SOURCES += accumulate.c \
compress.c \
create.c \
crypto.c \
errors.c \
fingerprint.c \
hash.c \
keyring.c \
lists.c \
memory.c \
openssl_crypto.c \
packet-parse.c \
packet-print.c \
packet-show.c \
random.c \
reader.c \
reader_armoured.c \
reader_encrypted_se.c \
reader_encrypted_seip.c \
reader_fd.c \
reader_hashed.c \
reader_mem.c \
readerwriter.c \
signature.c \
symmetric.c \
util.c \
validate.c \
writer.c \
writer_armour.c \
writer_encrypt.c \
writer_encrypt_se_ip.c \
writer_fd.c \
writer_memory.c \
writer_skey_checksum.c \
writer_stream_encrypt_se_ip.c

525
openpgpsdk/src/symmetric.c Normal file
View File

@ -0,0 +1,525 @@
/*
* 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.
*/
#include <openpgpsdk/crypto.h>
#include <string.h>
#include <assert.h>
#include <openssl/cast.h>
#ifndef OPENSSL_NO_IDEA
#include <openssl/idea.h>
#endif
#include <openssl/aes.h>
#include <openssl/des.h>
#include "parse_local.h"
#include <openpgpsdk/packet-show.h>
#include <openpgpsdk/final.h>
//static int debug=0;
#ifndef ATTRIBUTE_UNUSED
#ifndef WIN32
#define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#else
#define ATTRIBUTE_UNUSED
#endif // #ifndef WIN32
#endif /* ATTRIBUTE_UNUSED */
static void std_set_iv(ops_crypt_t *crypt,const unsigned char *iv)
{
memcpy(crypt->iv,iv,crypt->blocksize);
crypt->num=0;
}
static void std_set_key(ops_crypt_t *crypt,const unsigned char *key)
{ memcpy(crypt->key,key,crypt->keysize); }
static void std_resync(ops_crypt_t *decrypt)
{
if(decrypt->num == decrypt->blocksize)
return;
memmove(decrypt->civ+decrypt->blocksize-decrypt->num,decrypt->civ,
decrypt->num);
memcpy(decrypt->civ,decrypt->siv+decrypt->num,
decrypt->blocksize-decrypt->num);
decrypt->num=0;
}
static void std_finish(ops_crypt_t *crypt)
{
if (crypt->encrypt_key)
{
free(crypt->encrypt_key);
crypt->encrypt_key=NULL;
}
if (crypt->decrypt_key)
{
free(crypt->decrypt_key);
crypt->decrypt_key=NULL;
}
}
static void cast5_init(ops_crypt_t *crypt)
{
if (crypt->encrypt_key)
free(crypt->encrypt_key);
crypt->encrypt_key=malloc(sizeof(CAST_KEY));
CAST_set_key(crypt->encrypt_key,crypt->keysize,crypt->key);
crypt->decrypt_key=malloc(sizeof(CAST_KEY));
CAST_set_key(crypt->decrypt_key,crypt->keysize,crypt->key);
}
static void cast5_block_encrypt(ops_crypt_t *crypt,void *out,const void *in)
{ CAST_ecb_encrypt(in,out,crypt->encrypt_key,CAST_ENCRYPT); }
static void cast5_block_decrypt(ops_crypt_t *crypt,void *out,const void *in)
{ CAST_ecb_encrypt(in,out,crypt->encrypt_key,CAST_DECRYPT); }
static void cast5_cfb_encrypt(ops_crypt_t *crypt,void *out,const void *in, size_t count)
{
CAST_cfb64_encrypt(in,out,count,
crypt->encrypt_key, crypt->iv, (int *)&crypt->num,
CAST_ENCRYPT);
}
static void cast5_cfb_decrypt(ops_crypt_t *crypt,void *out,const void *in, size_t count)
{
CAST_cfb64_encrypt(in,out,count,
crypt->encrypt_key, crypt->iv, (int *)&crypt->num,
CAST_DECRYPT);
}
#define TRAILER "","","","",0,NULL,NULL
static ops_crypt_t cast5=
{
OPS_SA_CAST5,
CAST_BLOCK,
CAST_KEY_LENGTH,
std_set_iv,
std_set_key,
cast5_init,
std_resync,
cast5_block_encrypt,
cast5_block_decrypt,
cast5_cfb_encrypt,
cast5_cfb_decrypt,
std_finish,
TRAILER
};
#ifndef OPENSSL_NO_IDEA
static void idea_init(ops_crypt_t *crypt)
{
assert(crypt->keysize == IDEA_KEY_LENGTH);
if (crypt->encrypt_key)
free(crypt->encrypt_key);
crypt->encrypt_key=malloc(sizeof(IDEA_KEY_SCHEDULE));
// note that we don't invert the key when decrypting for CFB mode
idea_set_encrypt_key(crypt->key,crypt->encrypt_key);
if (crypt->decrypt_key)
free(crypt->decrypt_key);
crypt->decrypt_key=malloc(sizeof(IDEA_KEY_SCHEDULE));
idea_set_decrypt_key(crypt->encrypt_key,crypt->decrypt_key);
}
static void idea_block_encrypt(ops_crypt_t *crypt,void *out,const void *in)
{ idea_ecb_encrypt(in,out,crypt->encrypt_key); }
static void idea_block_decrypt(ops_crypt_t *crypt,void *out,const void *in)
{ idea_ecb_encrypt(in,out,crypt->decrypt_key); }
static void idea_cfb_encrypt(ops_crypt_t *crypt,void *out,const void *in, size_t count)
{
idea_cfb64_encrypt(in,out,count,
crypt->encrypt_key, crypt->iv, (int *)&crypt->num,
CAST_ENCRYPT);
}
static void idea_cfb_decrypt(ops_crypt_t *crypt,void *out,const void *in, size_t count)
{
idea_cfb64_encrypt(in,out,count,
crypt->decrypt_key, crypt->iv, (int *)&crypt->num,
CAST_DECRYPT);
}
static const ops_crypt_t idea=
{
OPS_SA_IDEA,
IDEA_BLOCK,
IDEA_KEY_LENGTH,
std_set_iv,
std_set_key,
idea_init,
std_resync,
idea_block_encrypt,
idea_block_decrypt,
idea_cfb_encrypt,
idea_cfb_decrypt,
std_finish,
TRAILER
};
#endif /* OPENSSL_NO_IDEA */
// AES with 128-bit key (AES)
#define KEYBITS_AES128 128
static void aes128_init(ops_crypt_t *crypt)
{
if (crypt->encrypt_key)
free(crypt->encrypt_key);
crypt->encrypt_key=malloc(sizeof(AES_KEY));
if (AES_set_encrypt_key(crypt->key,KEYBITS_AES128,crypt->encrypt_key))
fprintf(stderr,"aes128_init: Error setting encrypt_key\n");
if (crypt->decrypt_key)
free(crypt->decrypt_key);
crypt->decrypt_key=malloc(sizeof(AES_KEY));
if (AES_set_decrypt_key(crypt->key,KEYBITS_AES128,crypt->decrypt_key))
fprintf(stderr,"aes128_init: Error setting decrypt_key\n");
}
static void aes_block_encrypt(ops_crypt_t *crypt,void *out,const void *in)
{ AES_encrypt(in,out,crypt->encrypt_key); }
static void aes_block_decrypt(ops_crypt_t *crypt,void *out,const void *in)
{ AES_decrypt(in,out,crypt->decrypt_key); }
static void aes_cfb_encrypt(ops_crypt_t *crypt,void *out,const void *in, size_t count)
{
AES_cfb128_encrypt(in,out,count,
crypt->encrypt_key, crypt->iv, (int *)&crypt->num,
AES_ENCRYPT);
}
static void aes_cfb_decrypt(ops_crypt_t *crypt,void *out,const void *in, size_t count)
{
AES_cfb128_encrypt(in,out,count,
crypt->encrypt_key, crypt->iv, (int *)&crypt->num,
AES_DECRYPT);
}
static const ops_crypt_t aes128=
{
OPS_SA_AES_128,
AES_BLOCK_SIZE,
KEYBITS_AES128/8,
std_set_iv,
std_set_key,
aes128_init,
std_resync,
aes_block_encrypt,
aes_block_decrypt,
aes_cfb_encrypt,
aes_cfb_decrypt,
std_finish,
TRAILER
};
// AES with 256-bit key
#define KEYBITS_AES256 256
static void aes256_init(ops_crypt_t *crypt)
{
if (crypt->encrypt_key)
free(crypt->encrypt_key);
crypt->encrypt_key=malloc(sizeof(AES_KEY));
if (AES_set_encrypt_key(crypt->key,KEYBITS_AES256,crypt->encrypt_key))
fprintf(stderr,"aes256_init: Error setting encrypt_key\n");
if (crypt->decrypt_key)
free(crypt->decrypt_key);
crypt->decrypt_key=malloc(sizeof(AES_KEY));
if (AES_set_decrypt_key(crypt->key,KEYBITS_AES256,crypt->decrypt_key))
fprintf(stderr,"aes256_init: Error setting decrypt_key\n");
}
static const ops_crypt_t aes256=
{
OPS_SA_AES_256,
AES_BLOCK_SIZE,
KEYBITS_AES256/8,
std_set_iv,
std_set_key,
aes256_init,
std_resync,
aes_block_encrypt,
aes_block_decrypt,
aes_cfb_encrypt,
aes_cfb_decrypt,
std_finish,
TRAILER
};
// Triple DES
static void tripledes_init(ops_crypt_t *crypt)
{
DES_key_schedule *keys;
int n;
if (crypt->encrypt_key)
free(crypt->encrypt_key);
keys=crypt->encrypt_key=malloc(3*sizeof(DES_key_schedule));
for(n=0 ; n < 3 ; ++n)
DES_set_key((DES_cblock *)(crypt->key+n*8),&keys[n]);
}
static void tripledes_block_encrypt(ops_crypt_t *crypt,void *out,
const void *in)
{
DES_key_schedule *keys=crypt->encrypt_key;
DES_ecb3_encrypt((void *)in,out,&keys[0],&keys[1],&keys[2],DES_ENCRYPT);
}
static void tripledes_block_decrypt(ops_crypt_t *crypt,void *out,
const void *in)
{
DES_key_schedule *keys=crypt->encrypt_key;
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)
{
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);
}
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);
}
static const ops_crypt_t tripledes=
{
OPS_SA_TRIPLEDES,
8,
24,
std_set_iv,
std_set_key,
tripledes_init,
std_resync,
tripledes_block_encrypt,
tripledes_block_decrypt,
tripledes_cfb_encrypt,
tripledes_cfb_decrypt,
std_finish,
TRAILER
};
static const ops_crypt_t *get_proto(ops_symmetric_algorithm_t alg)
{
switch(alg)
{
case OPS_SA_CAST5:
return &cast5;
#ifndef OPENSSL_NO_IDEA
case OPS_SA_IDEA:
return &idea;
#endif /* OPENSSL_NO_IDEA */
case OPS_SA_AES_128:
return &aes128;
case OPS_SA_AES_256:
return &aes256;
case OPS_SA_TRIPLEDES:
return &tripledes;
default:
fprintf(stderr,"Unknown algorithm: %d (%s)\n",alg,ops_show_symmetric_algorithm(alg));
// assert(0);
}
return NULL;
}
int ops_crypt_any(ops_crypt_t *crypt,ops_symmetric_algorithm_t alg)
{
const ops_crypt_t *ptr=get_proto(alg);
if (ptr)
{
*crypt=*ptr;
return 1;
}
else
{
memset(crypt,'\0',sizeof *crypt);
return 0;
}
}
unsigned ops_block_size(ops_symmetric_algorithm_t alg)
{
const ops_crypt_t *p=get_proto(alg);
if(!p)
return 0;
return p->blocksize;
}
unsigned ops_key_size(ops_symmetric_algorithm_t alg)
{
const ops_crypt_t *p=get_proto(alg);
if(!p)
return 0;
return p->keysize;
}
void ops_encrypt_init(ops_crypt_t * encrypt)
{
// \todo should there be a separate ops_encrypt_init?
ops_decrypt_init(encrypt);
}
void ops_decrypt_init(ops_crypt_t *decrypt)
{
decrypt->base_init(decrypt);
decrypt->block_encrypt(decrypt,decrypt->siv,decrypt->iv);
memcpy(decrypt->civ,decrypt->siv,decrypt->blocksize);
decrypt->num=0;
}
size_t ops_decrypt_se
(ops_crypt_t *decrypt,void *out_,const void *in_,
size_t count)
{
unsigned char *out=out_;
const unsigned char *in=in_;
int saved=count;
/* in order to support v3's weird resyncing we have to implement CFB mode
ourselves */
while(count-- > 0)
{
unsigned char t;
if(decrypt->num == decrypt->blocksize)
{
memcpy(decrypt->siv,decrypt->civ,decrypt->blocksize);
decrypt->block_decrypt(decrypt,decrypt->civ,decrypt->civ);
decrypt->num=0;
}
t=decrypt->civ[decrypt->num];
*out++=t^(decrypt->civ[decrypt->num++]=*in++);
}
return saved;
}
size_t ops_encrypt_se(ops_crypt_t *encrypt,void *out_,const void *in_,
size_t count)
{
unsigned char *out=out_;
const unsigned char *in=in_;
int saved=count;
/* in order to support v3's weird resyncing we have to implement CFB mode
ourselves */
while(count-- > 0)
{
if(encrypt->num == encrypt->blocksize)
{
memcpy(encrypt->siv,encrypt->civ,encrypt->blocksize);
encrypt->block_encrypt(encrypt,encrypt->civ,encrypt->civ);
encrypt->num=0;
}
encrypt->civ[encrypt->num]=*out++=encrypt->civ[encrypt->num]^*in++;
++encrypt->num;
}
return saved;
}
/**
\ingroup HighLevel_Supported
\brief Is this Symmetric Algorithm supported?
\param alg Symmetric Algorithm to check
\return ops_true if supported; else ops_false
*/
ops_boolean_t ops_is_sa_supported(ops_symmetric_algorithm_t alg)
{
switch (alg)
{
case OPS_SA_AES_128:
case OPS_SA_AES_256:
case OPS_SA_CAST5:
case OPS_SA_TRIPLEDES:
#ifndef OPENSSL_NO_IDEA
case OPS_SA_IDEA:
#endif
return ops_true;
break;
default:
fprintf(stderr,"\nWarning: %s not supported\n",
ops_show_symmetric_algorithm(alg));
return ops_false;
}
}
size_t ops_encrypt_se_ip(ops_crypt_t *crypt,void *out_,const void *in_,
size_t count)
{
if (!ops_is_sa_supported(crypt->algorithm))
return -1;
crypt->cfb_encrypt(crypt, out_, in_, count);
// \todo test this number was encrypted
return count;
}
size_t ops_decrypt_se_ip(ops_crypt_t *crypt,void *out_,const void *in_,
size_t count)
{
if (!ops_is_sa_supported(crypt->algorithm))
return -1;
crypt->cfb_decrypt(crypt, out_, in_, count);
// \todo check this number was in fact decrypted
return count;
}
// EOF

222
openpgpsdk/src/util.c Normal file
View File

@ -0,0 +1,222 @@
/*
* 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 <openpgpsdk/util.h>
#include <openpgpsdk/packet-parse.h>
#include <openpgpsdk/crypto.h>
#include <openpgpsdk/create.h>
#include <openpgpsdk/errors.h>
#include <stdio.h>
#include <assert.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <string.h>
#include <openpgpsdk/final.h>
/**
* Searches the given map for the given type.
* Returns a human-readable descriptive string if found,
* returns NULL if not found
*
* It is the responsibility of the calling function to handle the
* error case sensibly (i.e. don't just print out the return string.
*
*/
static char *str_from_map_or_null(int type, ops_map_t *map)
{
ops_map_t *row;
for ( row=map; row->string != NULL; row++ )
if (row->type == type)
return row->string;
return NULL;
}
/**
* \ingroup Core_Print
*
* Searches the given map for the given type.
* Returns a readable string if found, "Unknown" if not.
*/
char *ops_str_from_map(int type, ops_map_t *map)
{
char *str;
str=str_from_map_or_null(type,map);
if (str)
return(str);
else
return("Unknown");
}
void hexdump(const unsigned char *src,size_t length)
{
while(length--)
printf("%02X",*src++);
}
/**
* \ingroup HighLevel_Functions
* \brief Initialises OpenPGP::SDK. To be called before any other OPS function.
*
* Initialises OpenPGP::SDK and the underlying openssl library.
*/
void ops_init(void)
{
ops_crypto_init();
}
/**
* \ingroup HighLevel_Functions
* \brief Closes down OpenPGP::SDK.
*
* Close down OpenPGP:SDK, release any resources under the control of
* the library. No OpenPGP:SDK function other than ops_init() should
* be called after this function.
*/
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
\param n Number of bytes to be alloc-ed.
\return Pointer to new memory.
\note Should be freed after use with free().
*/
void *ops_mallocz(size_t n)
{
void *m=malloc(n);
memset(m,'\0',n);
return m;
}
typedef struct
{
unsigned short sum;
} sum16_arg_t;
static int sum16_reader(void *dest_,size_t length,ops_error_t **errors,
ops_reader_info_t *rinfo,ops_parse_cb_info_t *cbinfo)
{
const unsigned char *dest=dest_;
sum16_arg_t *arg=ops_reader_get_arg(rinfo);
int r=ops_stacked_read(dest_,length,errors,rinfo,cbinfo);
int n;
if(r < 0)
return r;
for(n=0 ; n < r ; ++n)
arg->sum=(arg->sum+dest[n])&0xffff;
return r;
}
static void sum16_destroyer(ops_reader_info_t *rinfo)
{ free(ops_reader_get_arg(rinfo)); }
/**
\ingroup Internal_Readers_Sum16
\param pinfo Parse settings
*/
void ops_reader_push_sum16(ops_parse_info_t *pinfo)
{
sum16_arg_t *arg=ops_mallocz(sizeof *arg);
ops_reader_push(pinfo,sum16_reader,sum16_destroyer,arg);
}
/**
\ingroup Internal_Readers_Sum16
\param pinfo Parse settings
\return sum
*/
unsigned short ops_reader_pop_sum16(ops_parse_info_t *pinfo)
{
sum16_arg_t *arg=ops_reader_get_arg(ops_parse_get_rinfo(pinfo));
unsigned short sum=arg->sum;
ops_reader_pop(pinfo);
free(arg);
return sum;
}

746
openpgpsdk/src/validate.c Normal file
View File

@ -0,0 +1,746 @@
/*
* 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.
*/
#include <openpgpsdk/packet-parse.h>
#include <openpgpsdk/packet-show.h>
#include <openpgpsdk/keyring.h>
#include "keyring_local.h"
#include "parse_local.h"
#include <openpgpsdk/util.h>
#include <openpgpsdk/armour.h>
#include <openpgpsdk/signature.h>
#include <openpgpsdk/memory.h>
#include <openpgpsdk/validate.h>
#include <openpgpsdk/readerwriter.h>
#include <assert.h>
#include <string.h>
#include <openpgpsdk/final.h>
static int debug=0;
static ops_boolean_t check_binary_signature(const unsigned len,
const unsigned char *data,
const ops_signature_t *sig,
const ops_public_key_t *signer __attribute__((unused)))
{
// Does the signed hash match the given hash?
int n=0;
ops_hash_t hash;
unsigned char hashout[OPS_MAX_HASH_SIZE];
unsigned char trailer[6];
unsigned int hashedlen;
//common_init_signature(&hash,sig);
ops_hash_any(&hash,sig->info.hash_algorithm);
hash.init(&hash);
hash.add(&hash,data,len);
switch (sig->info.version)
{
case OPS_V3:
trailer[0]=sig->info.type;
trailer[1]=sig->info.creation_time >> 24;
trailer[2]=sig->info.creation_time >> 16;
trailer[3]=sig->info.creation_time >> 8;
trailer[4]=sig->info.creation_time;
hash.add(&hash,&trailer[0],5);
break;
case OPS_V4:
hash.add(&hash,sig->info.v4_hashed_data,sig->info.v4_hashed_data_length);
trailer[0]=0x04; // version
trailer[1]=0xFF;
hashedlen=sig->info.v4_hashed_data_length;
trailer[2]=hashedlen >> 24;
trailer[3]=hashedlen >> 16;
trailer[4]=hashedlen >> 8;
trailer[5]=hashedlen;
hash.add(&hash,&trailer[0],6);
break;
default:
fprintf(stderr,"Invalid signature version %d\n", sig->info.version);
return ops_false;
}
n=hash.finish(&hash,hashout);
// return ops_false;
return ops_check_signature(hashout,n,sig,signer);
}
static int keydata_reader(void *dest,size_t length,ops_error_t **errors,
ops_reader_info_t *rinfo,
ops_parse_cb_info_t *cbinfo)
{
validate_reader_arg_t *arg=ops_reader_get_arg(rinfo);
OPS_USED(errors);
OPS_USED(cbinfo);
if(arg->offset == arg->key->packets[arg->packet].length)
{
++arg->packet;
arg->offset=0;
}
if(arg->packet == arg->key->npackets)
return 0;
// we should never be asked to cross a packet boundary in a single read
assert(arg->key->packets[arg->packet].length >= arg->offset+length);
memcpy(dest,&arg->key->packets[arg->packet].raw[arg->offset],length);
arg->offset+=length;
return length;
}
static void free_signature_info(ops_signature_info_t *sig)
{
free (sig->v4_hashed_data);
free (sig);
}
static void copy_signature_info(ops_signature_info_t* dst, const ops_signature_info_t* src)
{
memcpy(dst,src,sizeof *src);
dst->v4_hashed_data=ops_mallocz(src->v4_hashed_data_length);
memcpy(dst->v4_hashed_data,src->v4_hashed_data,src->v4_hashed_data_length);
}
static void add_sig_to_valid_list(ops_validate_result_t * result, const ops_signature_info_t* sig)
{
size_t newsize;
size_t start;
// increment count
++result->valid_count;
// increase size of array
newsize=(sizeof *sig) * result->valid_count;
if (!result->valid_sigs)
result->valid_sigs=malloc(newsize);
else
result->valid_sigs=realloc(result->valid_sigs, newsize);
// copy key ptr to array
start=(sizeof *sig) * (result->valid_count-1);
copy_signature_info(result->valid_sigs+start,sig);
}
static void add_sig_to_invalid_list(ops_validate_result_t * result, const ops_signature_info_t *sig)
{
size_t newsize;
size_t start;
// increment count
++result->invalid_count;
// increase size of array
newsize=(sizeof *sig) * result->invalid_count;
if (!result->invalid_sigs)
result->invalid_sigs=malloc(newsize);
else
result->invalid_sigs=realloc(result->invalid_sigs, newsize);
// copy key ptr to array
start=(sizeof *sig) * (result->invalid_count-1);
copy_signature_info(result->invalid_sigs+start, sig);
}
static void add_sig_to_unknown_list(ops_validate_result_t * result, const ops_signature_info_t *sig)
{
size_t newsize;
size_t start;
// increment count
++result->unknown_signer_count;
// increase size of array
newsize=(sizeof *sig) * result->unknown_signer_count;
if (!result->unknown_sigs)
result->unknown_sigs=malloc(newsize);
else
result->unknown_sigs=realloc(result->unknown_sigs, newsize);
// copy key id to array
start=OPS_KEY_ID_SIZE * (result->unknown_signer_count-1);
copy_signature_info(result->unknown_sigs+start, sig);
}
ops_parse_cb_return_t
ops_validate_key_cb(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo)
{
const ops_parser_content_union_t *content=&content_->content;
validate_key_cb_arg_t *arg=ops_parse_cb_get_arg(cbinfo);
ops_error_t **errors=ops_parse_cb_get_errors(cbinfo);
const ops_keydata_t *signer;
ops_boolean_t valid=ops_false;
if (debug)
printf("%s\n",ops_show_packet_tag(content_->tag));
switch(content_->tag)
{
case OPS_PTAG_CT_PUBLIC_KEY:
assert(arg->pkey.version == 0);
arg->pkey=content->public_key;
return OPS_KEEP_MEMORY;
case OPS_PTAG_CT_PUBLIC_SUBKEY:
if(arg->subkey.version)
ops_public_key_free(&arg->subkey);
arg->subkey=content->public_key;
return OPS_KEEP_MEMORY;
case OPS_PTAG_CT_SECRET_KEY:
arg->skey=content->secret_key;
arg->pkey=arg->skey.public_key;
return OPS_KEEP_MEMORY;
case OPS_PTAG_CT_USER_ID:
if(arg->user_id.user_id)
ops_user_id_free(&arg->user_id);
arg->user_id=content->user_id;
arg->last_seen=ID;
return OPS_KEEP_MEMORY;
case OPS_PTAG_CT_USER_ATTRIBUTE:
assert(content->user_attribute.data.len);
printf("user attribute, length=%d\n",(int)content->user_attribute.data.len);
if(arg->user_attribute.data.len)
ops_user_attribute_free(&arg->user_attribute);
arg->user_attribute=content->user_attribute;
arg->last_seen=ATTRIBUTE;
return OPS_KEEP_MEMORY;
case OPS_PTAG_CT_SIGNATURE: // V3 sigs
case OPS_PTAG_CT_SIGNATURE_FOOTER: // V4 sigs
/*
printf(" type=%02x signer_id=",content->signature.type);
hexdump(content->signature.signer_id,
sizeof content->signature.signer_id);
*/
signer=ops_keyring_find_key_by_id(arg->keyring,
content->signature.info.signer_id);
if(!signer)
{
add_sig_to_unknown_list(arg->result, &content->signature.info);
break;
}
switch(content->signature.info.type)
{
case OPS_CERT_GENERIC:
case OPS_CERT_PERSONA:
case OPS_CERT_CASUAL:
case OPS_CERT_POSITIVE:
case OPS_SIG_REV_CERT:
if(arg->last_seen == ID)
valid=ops_check_user_id_certification_signature(&arg->pkey,
&arg->user_id,
&content->signature,
ops_get_public_key_from_data(signer),
arg->rarg->key->packets[arg->rarg->packet].raw);
else
valid=ops_check_user_attribute_certification_signature(&arg->pkey,
&arg->user_attribute,
&content->signature,
ops_get_public_key_from_data(signer),
arg->rarg->key->packets[arg->rarg->packet].raw);
break;
case OPS_SIG_SUBKEY:
// XXX: we should also check that the signer is the key we are validating, I think.
valid=ops_check_subkey_signature(&arg->pkey,&arg->subkey,
&content->signature,
ops_get_public_key_from_data(signer),
arg->rarg->key->packets[arg->rarg->packet].raw);
break;
case OPS_SIG_DIRECT:
valid=ops_check_direct_signature(&arg->pkey,&content->signature,
ops_get_public_key_from_data(signer),
arg->rarg->key->packets[arg->rarg->packet].raw);
break;
case OPS_SIG_STANDALONE:
case OPS_SIG_PRIMARY:
case OPS_SIG_REV_KEY:
case OPS_SIG_REV_SUBKEY:
case OPS_SIG_TIMESTAMP:
case OPS_SIG_3RD_PARTY:
OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
"Verification of signature type 0x%02x not yet implemented\n", content->signature.info.type);
break;
default:
OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
"Unexpected signature type 0x%02x\n", content->signature.info.type);
}
if(valid)
{
// printf(" validated\n");
//++arg->result->valid_count;
add_sig_to_valid_list(arg->result, &content->signature.info);
}
else
{
OPS_ERROR(errors,OPS_E_V_BAD_SIGNATURE,"Bad Signature");
// printf(" BAD SIGNATURE\n");
// ++arg->result->invalid_count;
add_sig_to_invalid_list(arg->result, &content->signature.info);
}
break;
// ignore these
case OPS_PARSER_PTAG:
case OPS_PTAG_CT_SIGNATURE_HEADER:
case OPS_PARSER_PACKET_END:
break;
case OPS_PARSER_CMD_GET_SK_PASSPHRASE:
if (arg->cb_get_passphrase)
{
return arg->cb_get_passphrase(content_,cbinfo);
}
break;
default:
fprintf(stderr,"unexpected tag=0x%x\n",content_->tag);
assert(0);
break;
}
return OPS_RELEASE_MEMORY;
}
ops_parse_cb_return_t
validate_data_cb(const ops_parser_content_t *content_,ops_parse_cb_info_t *cbinfo)
{
const ops_parser_content_union_t *content=&content_->content;
validate_data_cb_arg_t *arg=ops_parse_cb_get_arg(cbinfo);
ops_error_t **errors=ops_parse_cb_get_errors(cbinfo);
const ops_keydata_t *signer;
ops_boolean_t valid=ops_false;
ops_memory_t* mem=NULL;
if (debug)
printf("%s\n",ops_show_packet_tag(content_->tag));
switch(content_->tag)
{
case OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
// ignore - this gives us the "Armor Header" line "Hash: SHA1" or similar
break;
case OPS_PTAG_CT_LITERAL_DATA_HEADER:
// ignore
break;
case OPS_PTAG_CT_LITERAL_DATA_BODY:
arg->data.literal_data_body=content->literal_data_body;
arg->use=LITERAL_DATA;
return OPS_KEEP_MEMORY;
break;
case OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY:
arg->data.signed_cleartext_body=content->signed_cleartext_body;
arg->use=SIGNED_CLEARTEXT;
return OPS_KEEP_MEMORY;
break;
case OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
// this gives us an ops_hash_t struct
break;
case OPS_PTAG_CT_SIGNATURE: // V3 sigs
case OPS_PTAG_CT_SIGNATURE_FOOTER: // V4 sigs
if (debug)
{
printf("\n*** hashed data:\n");
unsigned int zzz=0;
for (zzz=0; zzz<content->signature.info.v4_hashed_data_length; zzz++)
printf("0x%02x ", content->signature.info.v4_hashed_data[zzz]);
printf("\n");
printf(" type=%02x signer_id=",content->signature.info.type);
hexdump(content->signature.info.signer_id,
sizeof content->signature.info.signer_id);
}
signer=ops_keyring_find_key_by_id(arg->keyring,
content->signature.info.signer_id);
if(!signer)
{
OPS_ERROR(errors,OPS_E_V_UNKNOWN_SIGNER,"Unknown Signer");
add_sig_to_unknown_list(arg->result, &content->signature.info);
break;
}
mem=ops_memory_new();
ops_memory_init(mem,128);
switch(content->signature.info.type)
{
case OPS_SIG_BINARY:
case OPS_SIG_TEXT:
switch(arg->use)
{
case LITERAL_DATA:
ops_memory_add(mem,
arg->data.literal_data_body.data,
arg->data.literal_data_body.length);
break;
case SIGNED_CLEARTEXT:
ops_memory_add(mem,
arg->data.signed_cleartext_body.data,
arg->data.signed_cleartext_body.length);
break;
default:
OPS_ERROR_1(errors,OPS_E_UNIMPLEMENTED,"Unimplemented Sig Use %d", arg->use);
printf(" Unimplemented Sig Use %d\n", arg->use);
break;
}
valid=check_binary_signature(ops_memory_get_length(mem),
ops_memory_get_data(mem),
&content->signature,
ops_get_public_key_from_data(signer));
break;
default:
OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
"Verification of signature type 0x%02x not yet implemented\n", content->signature.info.type);
break;
}
ops_memory_free(mem);
if(valid)
{
add_sig_to_valid_list(arg->result, &content->signature.info);
}
else
{
OPS_ERROR(errors,OPS_E_V_BAD_SIGNATURE,"Bad Signature");
add_sig_to_invalid_list(arg->result, &content->signature.info);
}
break;
// ignore these
case OPS_PARSER_PTAG:
case OPS_PTAG_CT_SIGNATURE_HEADER:
case OPS_PTAG_CT_ARMOUR_HEADER:
case OPS_PTAG_CT_ARMOUR_TRAILER:
case OPS_PTAG_CT_ONE_PASS_SIGNATURE:
case OPS_PARSER_PACKET_END:
break;
default:
fprintf(stderr,"unexpected tag=0x%x\n",content_->tag);
assert(0);
break;
}
return OPS_RELEASE_MEMORY;
}
static void keydata_destroyer(ops_reader_info_t *rinfo)
{ free(ops_reader_get_arg(rinfo)); }
void ops_keydata_reader_set(ops_parse_info_t *pinfo,const ops_keydata_t *key)
{
validate_reader_arg_t *arg=malloc(sizeof *arg);
memset(arg,'\0',sizeof *arg);
arg->key=key;
arg->packet=0;
arg->offset=0;
ops_reader_set(pinfo,keydata_reader,keydata_destroyer,arg);
}
/**
* \ingroup HighLevel_Verify
* \brief Indicicates whether any errors were found
* \param result Validation result to check
* \return ops_false if any invalid signatures or unknown signers or no valid signatures; else ops_true
*/
ops_boolean_t validate_result_status(ops_validate_result_t* result)
{
if (result->invalid_count || result->unknown_signer_count || !result->valid_count)
return ops_false;
else
return ops_true;
}
/**
* \ingroup HighLevel_Verify
* \brief Validate all signatures on a single key against the given keyring
* \param result Where to put the result
* \param key Key to validate
* \param keyring Keyring to use for validation
* \param cb_get_passphrase Callback to use to get passphrase
* \return ops_true if all signatures OK; else ops_false
* \note It is the caller's responsiblity to free result after use.
* \sa ops_validate_result_free()
Example Code:
\code
void example(const ops_keydata_t* key, const ops_keyring_t *keyring)
{
ops_validate_result_t *result=NULL;
if (ops_validate_key_signatures(result, key, keyring, callback_cmd_get_passphrase_from_cmdline)==ops_true)
printf("OK");
else
printf("ERR");
printf("valid=%d, invalid=%d, unknown=%d\n",
result->valid_count,
result->invalid_count,
result->unknown_signer_count);
ops_validate_result_free(result);
}
\endcode
*/
ops_boolean_t ops_validate_key_signatures(ops_validate_result_t *result,const ops_keydata_t *key,
const ops_keyring_t *keyring,
ops_parse_cb_return_t cb_get_passphrase (const ops_parser_content_t *, ops_parse_cb_info_t *)
)
{
ops_parse_info_t *pinfo;
validate_key_cb_arg_t carg;
memset(&carg,'\0',sizeof carg);
carg.result=result;
carg.cb_get_passphrase=cb_get_passphrase;
pinfo=ops_parse_info_new();
// ops_parse_options(&opt,OPS_PTAG_CT_SIGNATURE,OPS_PARSE_PARSED);
carg.keyring=keyring;
ops_parse_cb_set(pinfo,ops_validate_key_cb,&carg);
pinfo->rinfo.accumulate=ops_true;
ops_keydata_reader_set(pinfo,key);
// Note: Coverity incorrectly reports an error that carg.rarg
// is never used.
carg.rarg=ops_reader_get_arg_from_pinfo(pinfo);
ops_parse(pinfo);
ops_public_key_free(&carg.pkey);
if(carg.subkey.version)
ops_public_key_free(&carg.subkey);
ops_user_id_free(&carg.user_id);
ops_user_attribute_free(&carg.user_attribute);
ops_parse_info_delete(pinfo);
if (result->invalid_count || result->unknown_signer_count || !result->valid_count)
return ops_false;
else
return ops_true;
}
/**
\ingroup HighLevel_Verify
\param result Where to put the result
\param ring Keyring to use
\param cb_get_passphrase Callback to use to get passphrase
\note It is the caller's responsibility to free result after use.
\sa ops_validate_result_free()
*/
ops_boolean_t ops_validate_all_signatures(ops_validate_result_t *result,
const ops_keyring_t *ring,
ops_parse_cb_return_t cb_get_passphrase (const ops_parser_content_t *, ops_parse_cb_info_t *)
)
{
int n;
memset(result,'\0',sizeof *result);
for(n=0 ; n < ring->nkeys ; ++n)
ops_validate_key_signatures(result,&ring->keys[n],ring, cb_get_passphrase);
return validate_result_status(result);
}
/**
\ingroup HighLevel_Verify
\brief Frees validation result and associated memory
\param result Struct to be freed
\note Must be called after validation functions
*/
void ops_validate_result_free(ops_validate_result_t *result)
{
if (!result)
return;
if (result->valid_sigs)
free_signature_info(result->valid_sigs);
if (result->invalid_sigs)
free_signature_info(result->invalid_sigs);
if (result->unknown_sigs)
free_signature_info(result->unknown_sigs);
free(result);
result=NULL;
}
/**
\ingroup HighLevel_Verify
\brief Verifies the signatures in a signed file
\param result Where to put the result
\param filename Name of file to be validated
\param armoured Treat file as armoured, if set
\param keyring Keyring to use
\return ops_true if signatures validate successfully; ops_false if signatures fail or there are no signatures
\note After verification, result holds the details of all keys which
have passed, failed and not been recognised.
\note It is the caller's responsiblity to call ops_validate_result_free(result) after use.
Example code:
\code
void example(const char* filename, const int armoured, const ops_keyring_t* keyring)
{
ops_validate_result_t* result=ops_mallocz(sizeof *result);
if (ops_validate_file(result, filename, armoured, keyring)==ops_true)
{
printf("OK");
// look at result for details of keys with good signatures
}
else
{
printf("ERR");
// look at result for details of failed signatures or unknown signers
}
ops_validate_result_free(result);
}
\endcode
*/
ops_boolean_t ops_validate_file(ops_validate_result_t *result, const char* filename, const int armoured, const ops_keyring_t* keyring)
{
ops_parse_info_t *pinfo=NULL;
validate_data_cb_arg_t validate_arg;
int fd=0;
//
fd=ops_setup_file_read(&pinfo, filename, &validate_arg, validate_data_cb, ops_true);
if (fd < 0)
return ops_false;
// Set verification reader and handling options
memset(&validate_arg,'\0',sizeof validate_arg);
validate_arg.result=result;
validate_arg.keyring=keyring;
// Note: Coverity incorrectly reports an error that carg.rarg
// is never used.
validate_arg.rarg=ops_reader_get_arg_from_pinfo(pinfo);
if (armoured)
ops_reader_push_dearmour(pinfo);
// Do the verification
ops_parse(pinfo);
if (debug)
{
printf("valid=%d, invalid=%d, unknown=%d\n",
result->valid_count,
result->invalid_count,
result->unknown_signer_count);
}
// Tidy up
if (armoured)
ops_reader_pop_dearmour(pinfo);
ops_teardown_file_read(pinfo, fd);
return validate_result_status(result);
}
/**
\ingroup HighLevel_Verify
\brief Verifies the signatures in a ops_memory_t struct
\param result Where to put the result
\param mem Memory to be validated
\param armoured Treat data as armoured, if set
\param keyring Keyring to use
\return ops_true if signature validates successfully; ops_false if not
\note After verification, result holds the details of all keys which
have passed, failed and not been recognised.
\note It is the caller's responsiblity to call ops_validate_result_free(result) after use.
*/
ops_boolean_t ops_validate_mem(ops_validate_result_t *result, ops_memory_t* mem, const int armoured, const ops_keyring_t* keyring)
{
ops_parse_info_t *pinfo=NULL;
validate_data_cb_arg_t validate_arg;
//
ops_setup_memory_read(&pinfo, mem, &validate_arg, validate_data_cb, ops_true);
// Set verification reader and handling options
memset(&validate_arg,'\0',sizeof validate_arg);
validate_arg.result=result;
validate_arg.keyring=keyring;
// Note: Coverity incorrectly reports an error that carg.rarg
// is never used.
validate_arg.rarg=ops_reader_get_arg_from_pinfo(pinfo);
if (armoured)
ops_reader_push_dearmour(pinfo);
// Do the verification
ops_parse(pinfo);
if (debug)
{
printf("valid=%d, invalid=%d, unknown=%d\n",
result->valid_count,
result->invalid_count,
result->unknown_signer_count);
}
// Tidy up
if (armoured)
ops_reader_pop_dearmour(pinfo);
ops_teardown_memory_read(pinfo, mem);
return validate_result_status(result);
}
// eof

331
openpgpsdk/src/writer.c Normal file
View File

@ -0,0 +1,331 @@
/*
* 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
* This file contains the base functions used by the writers.
*/
#include <openssl/cast.h>
#include <openpgpsdk/armour.h>
#include <openpgpsdk/writer.h>
#include <openpgpsdk/keyring.h>
#include <openpgpsdk/memory.h>
#include <openpgpsdk/random.h>
#include <openpgpsdk/readerwriter.h>
#include "keyring_local.h"
#include <openpgpsdk/packet.h>
#include <openpgpsdk/util.h>
#include <openpgpsdk/std_print.h>
#include <string.h>
#include <assert.h>
#include <fcntl.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <openpgpsdk/final.h>
//static int debug=0;
/*
* return true if OK, otherwise false
*/
static ops_boolean_t base_write(const void *src,unsigned length,
ops_create_info_t *info)
{
return info->winfo.writer(src,length,&info->errors,&info->winfo);
}
/**
* \ingroup Core_WritePackets
*
* \param src
* \param length
* \param info
* \return 1 if OK, otherwise 0
*/
ops_boolean_t ops_write(const void *src,unsigned length,
ops_create_info_t *info)
{
return base_write(src,length,info);
}
/**
* \ingroup Core_WritePackets
* \param n
* \param length
* \param info
* \return ops_true if OK, otherwise ops_false
*/
ops_boolean_t ops_write_scalar(unsigned n,unsigned length,
ops_create_info_t *info)
{
while(length-- > 0)
{
unsigned char c[1];
c[0]=n >> (length*8);
if(!base_write(c,1,info))
return ops_false;
}
return ops_true;
}
/**
* \ingroup Core_WritePackets
* \param bn
* \param info
* \return 1 if OK, otherwise 0
*/
ops_boolean_t ops_write_mpi(const BIGNUM *bn,ops_create_info_t *info)
{
unsigned char buf[8192];
int bits=BN_num_bits(bn);
assert(bits <= 65535);
BN_bn2bin(bn,buf);
return ops_write_scalar(bits,2,info)
&& ops_write(buf,(bits+7)/8,info);
}
/**
* \ingroup Core_WritePackets
* \param tag
* \param info
* \return 1 if OK, otherwise 0
*/
ops_boolean_t ops_write_ptag(ops_content_tag_t tag,ops_create_info_t *info)
{
unsigned char c[1];
c[0]=tag|OPS_PTAG_ALWAYS_SET|OPS_PTAG_NEW_FORMAT;
return base_write(c,1,info);
}
/**
* \ingroup Core_WritePackets
* \param length
* \param info
* \return 1 if OK, otherwise 0
*/
ops_boolean_t ops_write_length(unsigned length,ops_create_info_t *info)
{
unsigned char c[2];
if(length < 192)
{
c[0]=length;
return base_write(c,1,info);
}
else if(length < 8384)
{
c[0]=((length-192) >> 8)+192;
c[1]=(length-192)%256;
return base_write(c,2,info);
}
return ops_write_scalar(0xff,1,info) && ops_write_scalar(length,4,info);
}
/* Note that we finalise from the top down, so we don't use writers below
* that have already been finalised
*/
ops_boolean_t writer_info_finalise(ops_error_t **errors,
ops_writer_info_t *winfo)
{
ops_boolean_t ret=ops_true;
if(winfo->finaliser)
{
ret=winfo->finaliser(errors,winfo);
winfo->finaliser=NULL;
}
if(winfo->next && !writer_info_finalise(errors,winfo->next))
{
winfo->finaliser=NULL;
return ops_false;
}
return ret;
}
void writer_info_delete(ops_writer_info_t *winfo)
{
// we should have finalised before deleting
assert(!winfo->finaliser);
if(winfo->next)
{
writer_info_delete(winfo->next);
free(winfo->next);
winfo->next=NULL;
}
if(winfo->destroyer)
{
winfo->destroyer(winfo);
winfo->destroyer=NULL;
}
winfo->writer=NULL;
}
/**
* \ingroup Core_Writers
*
* Set a writer in info. There should not be another writer set.
*
* \param info The info structure
* \param writer
* \param finaliser
* \param destroyer
* \param arg The argument for the writer and destroyer
*/
void ops_writer_set(ops_create_info_t *info,
ops_writer_t *writer,
ops_writer_finaliser_t *finaliser,
ops_writer_destroyer_t *destroyer,
void *arg)
{
assert(!info->winfo.writer);
info->winfo.writer=writer;
info->winfo.finaliser=finaliser;
info->winfo.destroyer=destroyer;
info->winfo.arg=arg;
}
/**
* \ingroup Core_Writers
*
* Push a writer in info. There must already be another writer set.
*
* \param info The info structure
* \param writer
* \param finaliser
* \param destroyer
* \param arg The argument for the writer and destroyer
*/
void ops_writer_push(ops_create_info_t *info,
ops_writer_t *writer,
ops_writer_finaliser_t *finaliser,
ops_writer_destroyer_t *destroyer,
void *arg)
{
ops_writer_info_t *copy=ops_mallocz(sizeof *copy);
assert(info->winfo.writer);
*copy=info->winfo;
info->winfo.next=copy;
info->winfo.writer=writer;
info->winfo.finaliser=finaliser;
info->winfo.destroyer=destroyer;
info->winfo.arg=arg;
}
void ops_writer_pop(ops_create_info_t *info)
{
ops_writer_info_t *next;
// Make sure the finaliser has been called.
assert(!info->winfo.finaliser);
// Make sure this is a stacked writer
assert(info->winfo.next);
if(info->winfo.destroyer)
info->winfo.destroyer(&info->winfo);
next=info->winfo.next;
info->winfo=*next;
free(next);
}
/**
* \ingroup Core_Writers
*
* Close the writer currently set in info.
*
* \param info The info structure
*/
ops_boolean_t ops_writer_close(ops_create_info_t *info)
{
ops_boolean_t ret=writer_info_finalise(&info->errors,&info->winfo);
writer_info_delete(&info->winfo);
return ret;
}
/**
* \ingroup Core_Writers
*
* Get the arg supplied to ops_create_info_set_writer().
*
* \param winfo The writer_info structure
* \return The arg
*/
void *ops_writer_get_arg(ops_writer_info_t *winfo)
{ return winfo->arg; }
/**
* \ingroup Core_Writers
*
* Write to the next writer down in the stack.
*
* \param src The data to write.
* \param length The length of src.
* \param errors A place to store errors.
* \param winfo The writer_info structure.
* \return Success - if ops_false, then errors should contain the error.
*/
ops_boolean_t ops_stacked_write(const void *src,unsigned length,
ops_error_t **errors,ops_writer_info_t *winfo)
{
return winfo->next->writer(src,length,errors,winfo->next);
}
/**
* \ingroup Core_Writers
*
* Free the arg. Many writers just have a malloc()ed lump of storage, this
* function releases it.
*
* \param winfo the info structure.
*/
void ops_writer_generic_destroyer(ops_writer_info_t *winfo)
{ free(ops_writer_get_arg(winfo)); }
/**
* \ingroup Core_Writers
*
* A writer that just writes to the next one down. Useful for when you
* want to insert just a finaliser into the stack.
*/
ops_boolean_t ops_writer_passthrough(const unsigned char *src,
unsigned length,
ops_error_t **errors,
ops_writer_info_t *winfo)
{ return ops_stacked_write(src,length,errors,winfo); }
// EOF

View File

@ -0,0 +1,488 @@
/*
* 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 <assert.h>
#include <string.h>
#include <openpgpsdk/armour.h>
#include <openpgpsdk/create.h>
#include <openpgpsdk/signature.h>
#include <openpgpsdk/version.h>
#include <openpgpsdk/final.h>
static int debug=0;
/**
* \struct dash_escaped_arg_t
*/
typedef struct
{
ops_boolean_t seen_nl:1;
ops_boolean_t seen_cr:1;
ops_create_signature_t *sig;
ops_memory_t *trailing;
} dash_escaped_arg_t;
static ops_boolean_t dash_escaped_writer(const unsigned char *src,
unsigned length,
ops_error_t **errors,
ops_writer_info_t *winfo)
{
dash_escaped_arg_t *arg=ops_writer_get_arg(winfo);
unsigned n;
if (debug)
{
unsigned int i=0;
fprintf(stderr,"dash_escaped_writer writing %d:\n", length);
for (i=0; i<length; i++)
{
fprintf(stderr,"0x%02x ", src[i]);
if (!((i+1) % 16))
fprintf(stderr,"\n");
else if (!((i+1) % 8))
fprintf(stderr," ");
}
fprintf(stderr,"\n");
}
// XXX: make this efficient
for(n=0 ; n < length ; ++n)
{
unsigned l;
if(arg->seen_nl)
{
if(src[n] == '-' && !ops_stacked_write("- ",2,errors,winfo))
return ops_false;
arg->seen_nl=ops_false;
}
arg->seen_nl=src[n] == '\n';
if(arg->seen_nl && !arg->seen_cr)
{
if(!ops_stacked_write("\r",1,errors,winfo))
return ops_false;
ops_signature_add_data(arg->sig,"\r",1);
}
arg->seen_cr=src[n] == '\r';
if(!ops_stacked_write(&src[n],1,errors,winfo))
return ops_false;
/* trailing whitespace isn't included in the signature */
if(src[n] == ' ' || src[n] == '\t')
ops_memory_add(arg->trailing,&src[n],1);
else
{
if((l=ops_memory_get_length(arg->trailing)))
{
if(!arg->seen_nl && !arg->seen_cr)
ops_signature_add_data(arg->sig,
ops_memory_get_data(arg->trailing),
l);
ops_memory_clear(arg->trailing);
}
ops_signature_add_data(arg->sig,&src[n],1);
}
}
return ops_true;
}
/**
* \param winfo
*/
static void dash_escaped_destroyer(ops_writer_info_t *winfo)
{
dash_escaped_arg_t *arg=ops_writer_get_arg(winfo);
ops_memory_free(arg->trailing);
free(arg);
}
/**
* \ingroup Core_WritersNext
* \brief Push Clearsigned Writer onto stack
* \param info
* \param sig
*/
ops_boolean_t ops_writer_push_clearsigned(ops_create_info_t *info,
ops_create_signature_t *sig)
{
static char header[]="-----BEGIN PGP SIGNED MESSAGE-----\r\nHash: ";
const char *hash=ops_text_from_hash(ops_signature_get_hash(sig));
dash_escaped_arg_t *arg=ops_mallocz(sizeof *arg);
ops_boolean_t rtn;
rtn= ( ops_write(header,sizeof header-1,info)
&& ops_write(hash,strlen(hash),info)
&& ops_write("\r\n\r\n",4,info));
if (rtn==ops_false)
{
OPS_ERROR(&info->errors, OPS_E_W, "Error pushing clearsigned header");
free(arg);
return rtn;
}
arg->seen_nl=ops_true;
arg->sig=sig;
arg->trailing=ops_memory_new();
ops_writer_push(info,dash_escaped_writer,NULL,dash_escaped_destroyer,arg);
return rtn;
}
/**
* \struct base64_arg_t
*/
typedef struct
{
unsigned pos;
unsigned char t;
unsigned checksum;
} base64_arg_t;
static char b64map[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static ops_boolean_t base64_writer(const unsigned char *src,
unsigned length,ops_error_t **errors,
ops_writer_info_t *winfo)
{
base64_arg_t *arg=ops_writer_get_arg(winfo);
unsigned n;
for(n=0 ; n < length ; )
{
arg->checksum=ops_crc24(arg->checksum,src[n]);
if(arg->pos == 0)
{
/* XXXXXX00 00000000 00000000 */
if(!ops_stacked_write(&b64map[src[n] >> 2],1,errors,winfo))
return ops_false;
/* 000000XX xxxx0000 00000000 */
arg->t=(src[n++]&3) << 4;
arg->pos=1;
}
else if(arg->pos == 1)
{
/* 000000xx XXXX0000 00000000 */
arg->t+=src[n] >> 4;
if(!ops_stacked_write(&b64map[arg->t],1,errors,winfo))
return ops_false;
/* 00000000 0000XXXX xx000000 */
arg->t=(src[n++]&0xf) << 2;
arg->pos=2;
}
else if(arg->pos == 2)
{
/* 00000000 0000xxxx XX000000 */
arg->t+=src[n] >> 6;
if(!ops_stacked_write(&b64map[arg->t],1,errors,winfo))
return ops_false;
/* 00000000 00000000 00XXXXXX */
if(!ops_stacked_write(&b64map[src[n++]&0x3f],1,errors,winfo))
return ops_false;
arg->pos=0;
}
}
return ops_true;
}
static ops_boolean_t signature_finaliser(ops_error_t **errors,
ops_writer_info_t *winfo)
{
base64_arg_t *arg=ops_writer_get_arg(winfo);
static char trailer[]="\r\n-----END PGP SIGNATURE-----\r\n";
unsigned char c[3];
if(arg->pos)
{
if(!ops_stacked_write(&b64map[arg->t],1,errors,winfo))
return ops_false;
if(arg->pos == 1 && !ops_stacked_write("==",2,errors,winfo))
return ops_false;
if(arg->pos == 2 && !ops_stacked_write("=",1,errors,winfo))
return ops_false;
}
/* Ready for the checksum */
if(!ops_stacked_write("\r\n=",3,errors,winfo))
return ops_false;
arg->pos=0; /* get ready to write the checksum */
c[0]=arg->checksum >> 16;
c[1]=arg->checksum >> 8;
c[2]=arg->checksum;
/* push the checksum through our own writer */
if(!base64_writer(c,3,errors,winfo))
return ops_false;
return ops_stacked_write(trailer,sizeof trailer-1,errors,winfo);
}
/**
* \struct linebreak_arg_t
*/
typedef struct
{
unsigned pos;
} linebreak_arg_t;
#define BREAKPOS 76
static ops_boolean_t linebreak_writer(const unsigned char *src,
unsigned length,
ops_error_t **errors,
ops_writer_info_t *winfo)
{
linebreak_arg_t *arg=ops_writer_get_arg(winfo);
unsigned n;
for(n=0 ; n < length ; ++n,++arg->pos)
{
if(src[n] == '\r' || src[n] == '\n')
arg->pos=0;
if(arg->pos == BREAKPOS)
{
if(!ops_stacked_write("\r\n",2,errors,winfo))
return ops_false;
arg->pos=0;
}
if(!ops_stacked_write(&src[n],1,errors,winfo))
return ops_false;
}
return ops_true;
}
/**
* \ingroup Core_WritersNext
* \brief Push armoured signature on stack
* \param info
*/
ops_boolean_t ops_writer_switch_to_armoured_signature(ops_create_info_t *info)
{
static char header[]="\r\n-----BEGIN PGP SIGNATURE-----\r\nVersion: "
OPS_VERSION_STRING "\r\n\r\n";
base64_arg_t *base64;
ops_writer_pop(info);
if (ops_write(header,sizeof header-1,info)==ops_false)
{
OPS_ERROR(&info->errors, OPS_E_W, "Error switching to armoured signature");
return ops_false;
}
ops_writer_push(info,linebreak_writer,NULL,ops_writer_generic_destroyer,
ops_mallocz(sizeof(linebreak_arg_t)));
base64=ops_mallocz(sizeof *base64);
if (!base64)
{
OPS_MEMORY_ERROR(&info->errors);
return ops_false;
}
base64->checksum=CRC24_INIT;
ops_writer_push(info,base64_writer,signature_finaliser,
ops_writer_generic_destroyer,base64);
return ops_true;
}
static ops_boolean_t armoured_message_finaliser(ops_error_t **errors,
ops_writer_info_t *winfo)
{
// TODO: This is same as signature_finaliser apart from trailer.
base64_arg_t *arg=ops_writer_get_arg(winfo);
static char trailer[]="\r\n-----END PGP MESSAGE-----\r\n";
unsigned char c[3];
if(arg->pos)
{
if(!ops_stacked_write(&b64map[arg->t],1,errors,winfo))
return ops_false;
if(arg->pos == 1 && !ops_stacked_write("==",2,errors,winfo))
return ops_false;
if(arg->pos == 2 && !ops_stacked_write("=",1,errors,winfo))
return ops_false;
}
/* Ready for the checksum */
if(!ops_stacked_write("\r\n=",3,errors,winfo))
return ops_false;
arg->pos=0; /* get ready to write the checksum */
c[0]=arg->checksum >> 16;
c[1]=arg->checksum >> 8;
c[2]=arg->checksum;
/* push the checksum through our own writer */
if(!base64_writer(c,3,errors,winfo))
return ops_false;
return ops_stacked_write(trailer,sizeof trailer-1,errors,winfo);
}
/**
\ingroup Core_WritersNext
\brief Write a PGP MESSAGE
\todo replace with generic function
*/
void ops_writer_push_armoured_message(ops_create_info_t *info)
// ops_create_signature_t *sig)
{
static char header[]="-----BEGIN PGP MESSAGE-----\r\n";
base64_arg_t *base64;
ops_write(header,sizeof header-1,info);
ops_write("\r\n",2,info);
base64=ops_mallocz(sizeof *base64);
base64->checksum=CRC24_INIT;
ops_writer_push(info,base64_writer,armoured_message_finaliser,ops_writer_generic_destroyer,base64);
}
static ops_boolean_t armoured_finaliser(ops_armor_type_t type, ops_error_t **errors,
ops_writer_info_t *winfo)
{
static char tail_public_key[]="\r\n-----END PGP PUBLIC KEY BLOCK-----\r\n";
static char tail_private_key[]="\r\n-----END PGP PRIVATE KEY BLOCK-----\r\n";
char* tail=NULL;
unsigned int sz_tail=0;
switch(type)
{
case OPS_PGP_PUBLIC_KEY_BLOCK:
tail=tail_public_key;
sz_tail=sizeof tail_public_key-1;
break;
case OPS_PGP_PRIVATE_KEY_BLOCK:
tail=tail_private_key;
sz_tail=sizeof tail_private_key-1;
break;
default:
assert(0);
}
base64_arg_t *arg=ops_writer_get_arg(winfo);
unsigned char c[3];
if(arg->pos)
{
if(!ops_stacked_write(&b64map[arg->t],1,errors,winfo))
return ops_false;
if(arg->pos == 1 && !ops_stacked_write("==",2,errors,winfo))
return ops_false;
if(arg->pos == 2 && !ops_stacked_write("=",1,errors,winfo))
return ops_false;
}
/* Ready for the checksum */
if(!ops_stacked_write("\r\n=",3,errors,winfo))
return ops_false;
arg->pos=0; /* get ready to write the checksum */
c[0]=arg->checksum >> 16;
c[1]=arg->checksum >> 8;
c[2]=arg->checksum;
/* push the checksum through our own writer */
if(!base64_writer(c,3,errors,winfo))
return ops_false;
return ops_stacked_write(tail,sz_tail,errors,winfo);
}
static ops_boolean_t armoured_public_key_finaliser(ops_error_t **errors,
ops_writer_info_t *winfo)
{
return armoured_finaliser(OPS_PGP_PUBLIC_KEY_BLOCK,errors,winfo);
}
static ops_boolean_t armoured_private_key_finaliser(ops_error_t **errors,
ops_writer_info_t *winfo)
{
return armoured_finaliser(OPS_PGP_PRIVATE_KEY_BLOCK,errors,winfo);
}
// \todo use this for other armoured types
/**
\ingroup Core_WritersNext
\brief Push Armoured Writer on stack (generic)
*/
void ops_writer_push_armoured(ops_create_info_t *info, ops_armor_type_t type)
{
static char hdr_public_key[]="-----BEGIN PGP PUBLIC KEY BLOCK-----\r\nVersion: "
OPS_VERSION_STRING "\r\n\r\n";
static char hdr_private_key[]="-----BEGIN PGP PRIVATE KEY BLOCK-----\r\nVersion: "
OPS_VERSION_STRING "\r\n\r\n";
char* header=NULL;
unsigned int sz_hdr=0;
ops_boolean_t (* finaliser)(ops_error_t **errors, ops_writer_info_t *winfo);
switch(type)
{
case OPS_PGP_PUBLIC_KEY_BLOCK:
header=hdr_public_key;
sz_hdr=sizeof hdr_public_key-1;
finaliser=armoured_public_key_finaliser;
break;
case OPS_PGP_PRIVATE_KEY_BLOCK:
header=hdr_private_key;
sz_hdr=sizeof hdr_private_key-1;
finaliser=armoured_private_key_finaliser;
break;
default:
assert(0);
}
ops_write(header,sz_hdr,info);
ops_writer_push(info,linebreak_writer,NULL,ops_writer_generic_destroyer,
ops_mallocz(sizeof(linebreak_arg_t)));
base64_arg_t *arg=ops_mallocz(sizeof *arg);
arg->checksum=CRC24_INIT;
ops_writer_push(info,base64_writer,finaliser,ops_writer_generic_destroyer,arg);
}
// EOF

View File

@ -0,0 +1,122 @@
/*
* 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 <assert.h>
#include <string.h>
#include <openpgpsdk/readerwriter.h>
static int debug=0;
typedef struct
{
ops_crypt_t* crypt;
int free_crypt;
} crypt_arg_t;
/*
* This writer simply takes plaintext as input,
* encrypts it with the given key
* and outputs the resulting encrypted text
*/
static ops_boolean_t encrypt_writer(const unsigned char *src,
unsigned length,
ops_error_t **errors,
ops_writer_info_t *winfo)
{
#define BUFSZ 1024 // arbitrary number
unsigned char encbuf[BUFSZ];
unsigned remaining=length;
unsigned done=0;
crypt_arg_t *arg=(crypt_arg_t *)ops_writer_get_arg(winfo);
if (!ops_is_sa_supported(arg->crypt->algorithm))
assert(0); // \todo proper error handling
while (remaining)
{
unsigned len = remaining < BUFSZ ? remaining : BUFSZ;
// memcpy(buf,src,len); // \todo copy needed here?
arg->crypt->cfb_encrypt(arg->crypt, encbuf, src+done, len);
if (debug)
{
int i=0;
fprintf(stderr,"WRITING:\nunencrypted: ");
for (i=0; i<16; i++)
fprintf(stderr,"%2x ", src[done+i]);
fprintf(stderr,"\n");
fprintf(stderr,"encrypted: ");
for (i=0; i<16; i++)
fprintf(stderr,"%2x ", encbuf[i]);
fprintf(stderr,"\n");
}
if (!ops_stacked_write(encbuf,len,errors,winfo))
{
if (debug)
{ fprintf(stderr, "encrypted_writer got error from stacked write, returning\n"); }
return ops_false;
}
remaining-=len;
done+=len;
}
return ops_true;
}
static void encrypt_destroyer (ops_writer_info_t *winfo)
{
crypt_arg_t *arg=(crypt_arg_t *)ops_writer_get_arg(winfo);
if (arg->free_crypt)
free(arg->crypt);
free (arg);
}
/**
\ingroup Core_WritersNext
\brief Push Encrypted Writer onto stack (create SE packets)
*/
void ops_writer_push_encrypt_crypt(ops_create_info_t *cinfo,
ops_crypt_t *crypt)
{
// Create arg to be used with this writer
// Remember to free this in the destroyer
crypt_arg_t *arg=ops_mallocz(sizeof *arg);
// Setup the arg
arg->crypt=crypt;
arg->free_crypt=0;
// And push writer on stack
ops_writer_push(cinfo,encrypt_writer,NULL,encrypt_destroyer,arg);
}
// EOF

View File

@ -0,0 +1,242 @@
/*
* 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 <string.h>
#include <assert.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <openssl/cast.h>
#include "keyring_local.h"
#include <openpgpsdk/compress.h>
#include <openpgpsdk/create.h>
#include <openpgpsdk/hash.h>
#include <openpgpsdk/keyring.h>
#include <openpgpsdk/random.h>
#include <openpgpsdk/readerwriter.h>
static int debug=0;
typedef struct
{
ops_crypt_t* crypt;
} encrypt_se_ip_arg_t;
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);
//
/**
\ingroup Core_WritersNext
\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)
{
ops_crypt_t* encrypt;
unsigned char *iv=NULL;
// Create arg to be used with this writer
// Remember to free this in the destroyer
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;
encrypted_pk_session_key=ops_create_pk_session_key(pub_key);
ops_write_pk_session_key(cinfo,encrypted_pk_session_key);
// Setup the arg
encrypt=ops_mallocz(sizeof *encrypt);
ops_crypt_any(encrypt, encrypted_pk_session_key->symmetric_algorithm);
iv=ops_mallocz(encrypt->blocksize);
encrypt->set_iv(encrypt, iv);
encrypt->set_key(encrypt, &encrypted_pk_session_key->key[0]);
ops_encrypt_init(encrypt);
arg->crypt=encrypt;
// And push writer on stack
ops_writer_push(cinfo,encrypt_se_ip_writer,NULL,encrypt_se_ip_destroyer,arg);
// tidy up
free(encrypted_pk_session_key);
free(iv);
}
static ops_boolean_t encrypt_se_ip_writer(const unsigned char *src,
unsigned length,
ops_error_t **errors,
ops_writer_info_t *winfo)
{
encrypt_se_ip_arg_t *arg=ops_writer_get_arg(winfo);
ops_boolean_t rtn=ops_true;
ops_memory_t *mem_literal;
ops_create_info_t *cinfo_literal;
ops_memory_t *mem_compressed;
ops_create_info_t *cinfo_compressed;
ops_memory_t *my_mem;
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);
// 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);
// create compressed packet from literal data packet
ops_write_compressed(ops_memory_get_data(mem_literal),
ops_memory_get_length(mem_literal),
cinfo_compressed);
// create SE IP packet set from this compressed literal data
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));
// now write memory to next writer
rtn=ops_stacked_write(ops_memory_get_data(my_mem),
ops_memory_get_length(my_mem),
errors, winfo);
ops_memory_free(my_mem);
ops_memory_free(mem_compressed);
ops_memory_free(mem_literal);
return rtn;
}
static void encrypt_se_ip_destroyer (ops_writer_info_t *winfo)
{
encrypt_se_ip_arg_t *arg=ops_writer_get_arg(winfo);
free(arg->crypt);
free(arg);
}
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)
{
unsigned char hashed[SHA_DIGEST_LENGTH];
const size_t sz_mdc=1+1+SHA_DIGEST_LENGTH;
size_t sz_preamble=crypt->blocksize+2;
unsigned char* preamble=ops_mallocz(sz_preamble);
size_t sz_buf=sz_preamble+len+sz_mdc;
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))
{
free (preamble);
return 0;
}
ops_random(preamble, crypt->blocksize);
preamble[crypt->blocksize]=preamble[crypt->blocksize-2];
preamble[crypt->blocksize+1]=preamble[crypt->blocksize-1];
if (debug)
{
unsigned int i=0;
fprintf(stderr,"\npreamble: ");
for (i=0; i<sz_preamble;i++)
fprintf(stderr," 0x%02x", preamble[i]);
fprintf(stderr,"\n");
}
// now construct MDC packet and add to the end of the buffer
ops_setup_memory_write(&cinfo_mdc, &mem_mdc,sz_mdc);
ops_calc_mdc_hash(preamble,sz_preamble,data,len,&hashed[0]);
ops_write_mdc(hashed, cinfo_mdc);
if (debug)
{
unsigned int i=0;
size_t sz_plaintext=len;
size_t sz_mdc=1+1+OPS_SHA1_HASH_SIZE;
unsigned char* mdc=NULL;
fprintf(stderr,"\nplaintext: ");
for (i=0; i<sz_plaintext;i++)
fprintf(stderr," 0x%02x", data[i]);
fprintf(stderr,"\n");
fprintf(stderr,"\nmdc: ");
mdc=ops_memory_get_data(mem_mdc);
for (i=0; i<sz_mdc;i++)
fprintf(stderr," 0x%02x", mdc[i]);
fprintf(stderr,"\n");
}
// and write it out
ops_writer_push_encrypt_crypt(cinfo, crypt);
#ifdef DEBUG
if (debug)
{
fprintf(stderr,"writing %ld + %d + %ld\n", sz_preamble, len, ops_memory_get_length(mem_mdc));
}
#endif /*DEBUG*/
if (!ops_write(preamble, sz_preamble,cinfo)
|| !ops_write(data, len, cinfo)
|| !ops_write(ops_memory_get_data(mem_mdc), ops_memory_get_length(mem_mdc), cinfo))
// \todo fix cleanup here and in old code functions
return 0;
ops_writer_pop(cinfo);
// cleanup
ops_teardown_memory_write(cinfo_mdc, mem_mdc);
free (preamble);
return 1;
}
// EOF

View File

@ -0,0 +1,88 @@
/*
* 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 <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <openpgpsdk/create.h>
#include <openpgpsdk/final.h>
typedef struct
{
int fd;
} writer_fd_arg_t;
static ops_boolean_t fd_writer(const unsigned char *src,unsigned length,
ops_error_t **errors,
ops_writer_info_t *winfo)
{
writer_fd_arg_t *arg=ops_writer_get_arg(winfo);
int n=write(arg->fd,src,length);
if(n == -1)
{
OPS_SYSTEM_ERROR_1(errors,OPS_E_W_WRITE_FAILED,"write",
"file descriptor %d",arg->fd);
return ops_false;
}
if((unsigned)n != length)
{
OPS_ERROR_1(errors,OPS_E_W_WRITE_TOO_SHORT,
"file descriptor %d",arg->fd);
return ops_false;
}
return ops_true;
}
static void fd_destroyer(ops_writer_info_t *winfo)
{
free(ops_writer_get_arg(winfo));
}
/**
* \ingroup Core_WritersFirst
* \brief Write to a File
*
* Set the writer in info to be a stock writer that writes to a file
* descriptor. If another writer has already been set, then that is
* first destroyed.
*
* \param info The info structure
* \param fd The file descriptor
*
*/
void ops_writer_set_fd(ops_create_info_t *info,int fd)
{
writer_fd_arg_t *arg=malloc(sizeof *arg);
arg->fd=fd;
ops_writer_set(info,fd_writer,NULL,fd_destroyer,arg);
}
// EOF

View File

@ -0,0 +1,61 @@
/*
* 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 <openpgpsdk/create.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <openpgpsdk/final.h>
static ops_boolean_t memory_writer(const unsigned char *src,unsigned length,
ops_error_t **errors,
ops_writer_info_t *winfo)
{
ops_memory_t *mem=ops_writer_get_arg(winfo);
OPS_USED(errors);
ops_memory_add(mem,src,length);
return ops_true;
}
/**
* \ingroup Core_WritersFirst
* \brief Write to memory
*
* Set a memory writer.
*
* \param info The info structure
* \param mem The memory structure
* \note It is the caller's responsiblity to call ops_memory_free(mem)
* \sa ops_memory_free()
*/
void ops_writer_set_memory(ops_create_info_t *info,ops_memory_t *mem)
{
ops_writer_set(info,memory_writer,NULL,NULL,mem);
}
// EOF

View File

@ -0,0 +1,88 @@
/*
* 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 <openpgpsdk/create.h>
#include <openpgpsdk/final.h>
//static int debug=0;
typedef struct
{
ops_hash_algorithm_t hash_algorithm;
ops_hash_t hash;
unsigned char *hashed;
} skey_checksum_arg_t;
static ops_boolean_t skey_checksum_writer(const unsigned char *src, const unsigned length, ops_error_t **errors, ops_writer_info_t *winfo)
{
skey_checksum_arg_t *arg=ops_writer_get_arg(winfo);
ops_boolean_t rtn=ops_true;
// add contents to hash
arg->hash.add(&arg->hash, src, length);
// write to next stacked writer
rtn=ops_stacked_write(src,length,errors,winfo);
// tidy up and return
return rtn;
}
static ops_boolean_t skey_checksum_finaliser(ops_error_t **errors __attribute__((unused)), ops_writer_info_t *winfo)
{
skey_checksum_arg_t *arg=ops_writer_get_arg(winfo);
arg->hash.finish(&arg->hash, arg->hashed);
return ops_true;
}
static void skey_checksum_destroyer(ops_writer_info_t* winfo)
{
skey_checksum_arg_t *arg=ops_writer_get_arg(winfo);
free(arg);
}
/**
\ingroup Core_WritersNext
\param cinfo
\param skey
*/
void ops_push_skey_checksum_writer(ops_create_info_t *cinfo, ops_secret_key_t *skey)
{
// OPS_USED(info);
// XXX: push a SHA-1 checksum writer (and change s2k to 254).
skey_checksum_arg_t *arg=ops_mallocz(sizeof *arg);
// configure the arg
arg->hash_algorithm=skey->hash_algorithm;
arg->hashed=&skey->checkhash[0];
// init the hash
ops_hash_any(&arg->hash, arg->hash_algorithm);
arg->hash.init(&arg->hash);
ops_writer_push(cinfo, skey_checksum_writer, skey_checksum_finaliser, skey_checksum_destroyer, arg);
}
// EOF

View File

@ -0,0 +1,412 @@
/*
* 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 <string.h>
#include <assert.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <openssl/cast.h>
#include "keyring_local.h"
#include <openpgpsdk/create.h>
#include <openpgpsdk/keyring.h>
#include <openpgpsdk/random.h>
#include <openpgpsdk/readerwriter.h>
#define MAX_PARTIAL_DATA_LENGTH 1073741824
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 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 void stream_encrypt_se_ip_destroyer (ops_writer_info_t *winfo);
//
/**
\ingroup Core_WritersNext
\param cinfo
\param pub_key
*/
void ops_writer_push_stream_encrypt_se_ip(ops_create_info_t *cinfo,
const ops_keydata_t *pub_key)
{
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
// Remember to free this in the destroyer
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;
encrypted_pk_session_key=ops_create_pk_session_key(pub_key);
ops_write_pk_session_key(cinfo,encrypted_pk_session_key);
// Setup the arg
encrypt=ops_mallocz(sizeof *encrypt);
ops_crypt_any(encrypt, encrypted_pk_session_key->symmetric_algorithm);
iv=ops_mallocz(encrypt->blocksize);
encrypt->set_iv(encrypt, iv);
encrypt->set_key(encrypt, &encrypted_pk_session_key->key[0]);
ops_encrypt_init(encrypt);
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_writer_push(cinfo,
stream_encrypt_se_ip_writer,
stream_encrypt_se_ip_finaliser,
stream_encrypt_se_ip_destroyer,arg);
// tidy up
free(encrypted_pk_session_key);
free(iv);
}
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;
}
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;
}
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 <cr><lf> 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)
{
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);
ops_random(preamble, arg->crypt->blocksize);
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)
{
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);
// MDC packet len
c[0]=0x14;
arg->hash.add(&arg->hash, &c[0], 1);
//finish
arg->hash.finish(&arg->hash, hashed);
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
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_writer_pop(cinfo);
ops_teardown_memory_write(cinfo_mdc, mem_mdc);
return ops_true;
}
static ops_boolean_t stream_encrypt_se_ip_writer(const unsigned char *src,
unsigned length,
ops_error_t **errors,
ops_writer_info_t *winfo)
{
stream_encrypt_se_ip_arg_t *arg=ops_writer_get_arg(winfo);
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);
}
// 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)
{
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);
}
// 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)
{
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