/**********************************************************************
 
	Copyright (C) 2003-2005
	Hirohisa MORI <joshua@nichibun.ac.jp>
	Tomohito Nakajima <nakajima@zeta.co.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/

#ifndef ___OSSL_H___
#define ___OSSL_H___

#include "openssl/evp.h"
#include "openssl/bio.h"
#include "openssl/x509v3.h"
#include "openssl/ssl.h"

typedef int OSSL_BOOL;

typedef struct oSSL_data {
#define OSSL_RAW 0
#define OSSL_RSA_PUBLICKEY 1
#define OSSL_RSA_PRIVATEKEY 2
#define OSSL_RC4KEY 3
#define OSSL_CERTIFICATE 4
#define OSSL_CSR 5

	int type;
	int len;
	int buff_size;
	unsigned char *data;
	int own_data;
} oSSL_data;


typedef struct oSSL_RC4_key{
	unsigned char *data;
	int len;
#define OSSL_ENCODE_USE 1
#define OSSL_DECODE_USE -1
	int use;
	EVP_CIPHER_CTX ctx;
} oSSL_RC4_key;

typedef struct oSSL_pkey{
	EVP_PKEY *pkey;
/*	RSA *rsa; */
	int refcnt;
} oSSL_pkey;

struct oSSL_object;
struct oSSL_data;

typedef struct oSSL_method {
	int type;
	void (*free)(struct oSSL_object*);
	struct oSSL_data * (*object2data)(struct oSSL_object * obj);
	struct oSSL_object * (*data2object)(struct oSSL_data * data);
	OSSL_BOOL (*save_pem)(struct oSSL_object*, const char* file, const char* password);
	OSSL_BOOL (*load_pem)(struct oSSL_object*, const char* file, const char* password);
}oSSL_method;

#define MAX_OSSL_OBJECT_TYPE 10

extern oSSL_method *oSSL_types[MAX_OSSL_OBJECT_TYPE];

typedef struct oSSL_object {
	int type;
	oSSL_method *method;
	int refcnt;
	
	union {
		oSSL_RC4_key rc4_key;
		oSSL_pkey pkey;
		X509 *x509;
		X509_REQ *csr;
	}obj;
} oSSL_object;

void oSSL_init();
void oSSL_close();

oSSL_object *oSSL_object_new(int type);
void oSSL_object_free(oSSL_object * obj);

oSSL_data *oSSL_data_new(int type, unsigned char *data, int len, int own_data, int buff_size);
void oSSL_data_ensure_buff_size(oSSL_data *data, int size);
void oSSL_data_free(oSSL_data * data);
oSSL_data *oSSL_object2data(oSSL_object * obj);
oSSL_object *oSSL_data2object(oSSL_data * data);

OSSL_BOOL oSSL_object_save_pem(oSSL_object * obj, const char* file, const char* password/* egnored if obj is not private key */);
OSSL_BOOL oSSL_object_load_pem(oSSL_object * obj, const char* file, const char* password/* egnored if obj is not private key */);

oSSL_data *oSSL_RSA_decode(oSSL_object * private_key, oSSL_data * data);
oSSL_data *oSSL_RSA_encode(oSSL_object * public_key, oSSL_data * data);
int oSSL_RSA_genkey(oSSL_object ** public_key, oSSL_object ** private_key, int size);

int oSSL_RC4_decode(oSSL_data *decoded, oSSL_object * key, oSSL_data *org);
int oSSL_RC4_encode(oSSL_data *encoded, oSSL_object * key, oSSL_data *org);
oSSL_object *oSSL_RC4_genkey(oSSL_data * key_data);

/*
#define OSSL_DATA_FORMAT_DER 0
#define OSSL_DATA_FORMAT_PEM 1
*/


void oSSL_RC4_init();
void oSSL_RSA_init();
void oSSL_cert_init();
void oSSL_csr_init();

#ifndef TRUE 
#define TRUE 1
#endif

#ifndef FALSE 
#define FALSE 0
#endif

#ifndef NULL
#define NULL (0)
#endif

/*
#ifdef GBSSL_TEST
#define d_alloc malloc
#define d_f_ree free
#define SEM void*
#define lock_task(SEM)
#define unlock_task(SEM, str)
#define get_tid() 1

#define LL_OSSL 1;
#define new_lock(lock_level) (0)
#define close_lock(SEM) (0)
#else
*/
#include "memory_debug.h"
#include "task.h"
#include "lock_level.h"
/*#endif*/

typedef struct oSSL_object_list{
	struct oSSL_object_list *next;
	oSSL_object *obj;
}oSSL_object_list;

typedef struct {
	SSL_CTX *ctx;
	oSSL_object_list *root_certs;
}oSSL_context;

#include "stream.h"

#define OSSL_CTX_CLIENT 1
#define OSSL_CTX_SERVER 2
oSSL_context *oSSL_context_new(
	oSSL_object *certificate, 
	oSSL_object *privatekey,
	int flags);
void oSSL_context_free(oSSL_context *);

BIO *s_bio_new(STREAM *st);

/* open ssl stream as client */
#define OSSL_FLAG_CONNECT 1
/* open ssl stream as server */
#define OSSL_FLAG_ACCEPT 2
/* verify peer */
#define OSSL_FLAG_VERIFY 4
STREAM * s_open_oSSL(STREAM * st, oSSL_context *ctx, int flags, L_CHAR *peer_host_name_for_verify);

void ___ossl_error(const char *msg, const char *file, int line);
#define ossl_error(msg) ___ossl_error(msg, __FILE__, __LINE__)

OSSL_BOOL oSSL_add_root_certificate(oSSL_context * ctx, oSSL_object *certificate);
oSSL_object_list *oSSL_get_root_certificates(oSSL_context * ctx);
OSSL_BOOL oSSL_private_key_load_pem(oSSL_object *obj, const char* file, char* password);

typedef struct oSSL_cert_extension {
	L_CHAR *name;
	L_CHAR *value;
} oSSL_cert_extension;

oSSL_object *oSSL_create_csr(
	L_CHAR* country_name,
	L_CHAR* state_or_province_name,
	L_CHAR* locality_name,
	L_CHAR* organization_name,
	L_CHAR* organizational_unit_name,
	L_CHAR* common_name,
	L_CHAR* email_address,
	oSSL_object *private_key,
	oSSL_cert_extension *extensions,
	int extension_count);
/*
void oSSL_set_csr_ex_data(oSSL_object *csr, L_CHAR *name, L_CHAR *value);
*/
L_CHAR *oSSL_get_ext_cert_data(L_CHAR *name, oSSL_object *cert);

#define OSSL_KEY_USAGE_CA (X509v3_KU_KEY_CERT_SIGN|X509v3_KU_CRL_SIGN)
#define OSSL_KEY_USAGE_SERVER (X509v3_KU_KEY_ENCIPHERMENT)
#define OSSL_KEY_USAGE_CLIENT (X509v3_KU_DIGITAL_SIGNATURE)
oSSL_object *oSSL_create_certificate(
	oSSL_object *csr, 
	oSSL_object *ca_private_key, 
	oSSL_object *ca_certificate, 
	int serial,
	long expire_secs,
	int ossl_key_usage_flag);

void oSSL_print_all_error();

const EVP_MD *oSSL_get_MD_by_pkey(EVP_PKEY *pkey);

#define SN_gb_comment		"gbComment"
#define LN_gb_comment		"Global Base Comment"
extern int NID_gb_comment;
#define OID_gb_comment      "1.2.3.4"

#endif
