

  buf_mem_st		= record
    length		: Integer;	(* current number of bytes *)
    data		: PChar;
    max 		: Integer;	(* size of buffer *)
  end;

  stack_func		= function(a,b:Pointer):Integer;
  stack_proc		= procedure;
  stack_st		= record
    num 		: Integer;
    data		:^Pointer;
    sorted		: Integer;
    num_alloc		: Integer;
    comp		: stack_func;
  end;

  lhash_node_st 	= record
    data		: Pointer;
    next		: LHASH_NODE;
    hash		: Cardinal;
  end;

  lhash_comp_func	= function(a,b:Pointer):Integer;
  lhash_hash_func	= function(a:Pointer):Cardinal;
  lhash_st		= record
    b			:^LHASH_NODE;
    comp		: lhash_comp_func;
    hash		: lhash_hash_func;
    num_nodes		: Word;
    num_alloc_nodes	: Word;
    p			: Integer;
    pmax		: Integer;
    up_load		: LongInt; (* load times 256 *)
    down_load		: LongInt; (* load times 256 *)
    num_items		: LongInt;

    num_expands 	: Cardinal;
    num_expand_reallocs : Cardinal;
    num_contracts	: Cardinal;
    num_contract_reallocs:Cardinal;
    num_hash_calls	: Cardinal;
    num_comp_calls	: Cardinal;
    num_insert		: Cardinal;
    num_replace 	: Cardinal;
    num_delete		: Cardinal;
    num_no_delete	: Cardinal;
    num_retrieve	: Cardinal;
    num_retrieve_miss	: Cardinal;
    num_hash_comps	: Cardinal;
  end;

  lhash_doall_proc	= Procedure;
  lhash_doall_arg_proc	= Procedure(arg:Pointer);

  err_state_st		= record
    pid 		: Cardinal;
    err_buffer		: Array[0..15] of Cardinal;
    err_data		: Array[0..15] of PChar;
    err_data_flags	: Array[0..15] of Integer;
    err_file		: Array[0..15] of PChar;
    err_line		: Array[0..15] of Integer;
    top,bottom		: Integer;
  end;

  ERR_string_data_st	= record
    error		: Cardinal;
    str 		: PChar;
  end;

  MD2state_st		= record
    num 		: Integer;
    data		: Array[0..15] of Byte;
    cksm		: Array[0..15] of Word;
    state		: Array[0..15] of Word;
  end;
  MD2_CTX		= MD2state_st;

  MD5state_st		= record
    A,B,C,D		: Cardinal;
    Nl,Nh		: Cardinal;
    data		: Array[0..15] of Cardinal;
    num 		: Integer;
  end;
  MD5_CTX		= MD5state_st;

  SHAstate_st		= record
    h0,h1,h2,h3,h4	: Cardinal;
    Nl,Nh		: Cardinal;
    data		: Array[0..15] of Cardinal;
    num 		: Integer;
  end;
  SHA_CTX		= SHAstate_st;

  des_cblock		= Array[0..7] of Byte;
  des_key_schedule	= record
    ks			: record
    case byte of
      0:(_		: des_cblock);
      1:(pad		: Array[0..1] of Cardinal);
    end;
  end;
  bit_64		= des_key_schedule;

  rc2_key_st		= record
    data		: Array[0..63] of Word;
  end;
  RC2_KEY		= rc2_key_st;

  rc4_key_st		= record
    x,y 		: Word;
    data		: Array[0..255] of Word;
  end;
  RC4_KEY		= rc4_key_st;

  idea_key_st		= record
    data		: Array[0..8,0..5] of Word;
  end;
  IDEA_KEY_SCHEDULE	= idea_key_st;

  bignum_st		= record
    s			:^Cardinal;	(* Pointer to an array of 'BN_BITS2' bit chunks. *)
    top 		: Integer;	(* Index of last used d +1. *)
	(* The next are internal book keeping for bn_expand. *)
    max 		: Integer;	(* Size of the d array. *)
    neg 		: Integer;	(* one if the number is negative *)
  end;

  bignum_ctx		= record
    tos 		: Integer;
    bn			: Array[0..12] of BIGNUM;
  end;

  bn_blinding_st	= record
    init		: Integer;
    A			: BIGNUM;
    Ai			: BIGNUM;
    _mod		: BIGNUM;     (* just a reference *)
  end;

(* Used for montgomery multiplication *)
  bn_mont_ctx_st	= record
    ri			: Integer;    (* number of bits in R *)
    RR			: BIGNUM;     (* used to convert to montgomery form *)
    N			: BIGNUM;     (* The modulus *)
    Ni			: BIGNUM;     (* The inverse of N *)
    n0			: Cardinal;   (* word form of inverse, normally only one of
					 Ni or n0 is defined *)
  end;

  bn_gen_prime_cb	= procedure(a,b:Integer;p:PChar);

  dh_st 		= record
	(* This first argument is used to pick up errors when
	  a DH is passed instead of a EVP_PKEY *)
    pad 		: Integer;
    version		: Integer;
    p,g 		: BIGNUM;
    length		: Integer; (* optional *)
    pub_key		: BIGNUM;	 (* y *)
    priv_key		: BIGNUM;	 (* x *)
  end;
  dh_gen_parm_cb	= procedure(a,b:Integer;p:PChar);

  crypto_ex_data_st	= record
    sk			: STACK;
    dummy		: Integer;	(* gcc is screwing up this data structure :-( *)
  end;
  CRYPTO_EX_DATA	= crypto_ex_data_st;

  crypto_ex_new_func	= function(obj,item:Byte;idx:Integer;argl:LongInt;argp:PChar):Integer;
  crypto_ex_free_func	= procedure(obj,item:Byte;idx:Integer;argl:LongInt;argp:PChar);
  crypto_ex_dup_func	= function(obj_to,obj_from,neu:Byte;idx:Integer;argl:LongInt;argp:PChar):Integer;

  crypto_ex_data_func_st= record
    argl		: LongInt;	(* Arbitary long *)
    argp		: PChar;	(* Arbitary char  *)
	(* Called when a new object is created *)
    new_func		: crypto_ex_new_func;
	(* Called when this object is free()ed *)
    free_func		: crypto_ex_free_func;
	(* Called when we need to dup this one *)
    dup_func		: crypto_ex_dup_func;
  end;
  CRYPTO_EX_DATA_FUNCS	= crypto_ex_data_func_st;

  crypto_lock_cb	= procedure(mode,typ:Integer;fname:PChar;line:Integer);
  crypto_add_lock_cb	= function(var num:Integer;mount,typ:Integer;fname:PChar;line:Integer):Integer;
  crypto_id_cb		= function:Cardinal;
  crypto_leaks_cb	= procedure(order:Cardinal;fname:PChar;line,num_bytes:Integer;addr:Pointer);
  crypto_malloc_func	= function(size:Integer):Pointer;
  crypto_realloc_func	= function(p:Pointer;size:Integer):Pointer;
  crypto_free_func	= procedure(p:Pointer);

  rsa_pub_enc_func	= function:Integer;
  rsa_pub_dec_func	= function:Integer;
  rsa_priv_enc_func	= function:Integer;
  rsa_priv_dec_func	= function:Integer;
  rsa_mod_exp_func	= function:Integer;
  rsa_bn_exp_func	= function:Integer;
  rsa_meth_init_func	= function:Integer;
  rsa_meth_fini_func	= function:Integer;
  rsa_meth_st		= record
    name		: PChar;
    rsa_pub_enc 	: rsa_pub_enc_func;
    rsa_pub_dec 	: rsa_pub_dec_func;
    rsa_priv_enc	: rsa_priv_enc_func;
    rsa_priv_dec	: rsa_priv_dec_func;
    rsa_mod_exp 	: rsa_mod_exp_func;	      (* Can be null *)
    bn_mod_exp		: rsa_bn_exp_func;	      (* Can be null *)
    init		: rsa_meth_init_func;	      (* called at new *)
    finish		: rsa_meth_fini_func;	      (* called at free *)
    flags		: Integer;		      (* RSA_METHOD_FLAG_ things *)
    app_data		: PChar;		      (* may be needed! *)
  end;

  rsa_st		= record
	(* The first parameter is used to pickup errors where
	  this is passed instead of aEVP_PKEY, it is set to 0 *)
    pad 		: Integer;
    version		: Integer;
    meth		: RSA_METHOD;
    n			: BIGNUM;
    e			: BIGNUM;
    d			: BIGNUM;
    p			: BIGNUM;
    q			: BIGNUM;
    dmp1		: BIGNUM;
    dmq1		: BIGNUM;
    iqmp		: BIGNUM;
	(* be carefull using this if the RSA structure is shared *)
    ex_data		: CRYPTO_EX_DATA;
    references		: Integer;
    flags		: Integer;

	(* Normally used to cached montgomery values *)
    method_mod_n	: PChar;
    method_mod_p	: PChar;
    method_mod_q	: PChar;

    blinding		: BN_BLINDING;
  end;

  rsa_gen_key_cb	= procedure(a,b:Integer;p:PChar);

  dsa_st		= record
	(* This first variable is used to pick up errors where
	  a DSA is passed instead of of a EVP_PKEY *)
    pad 		: Integer;
    version		: Integer;
    write_params	: Integer;
    p			: BIGNUM;
    q			: BIGNUM;	(* == 20 *)
    g			: BIGNUM;

    pub_key		: BIGNUM;	(* y public key *)
    priv_key		: BIGNUM;	(* x private key *)

    kinv		: BIGNUM;	(* Signing pre-calc *)
    r			: BIGNUM;	(* Signing pre-calc *)

    references		: Integer;
  end;

  dsa_cb_func		= procedure;

  CONF_VALUE		= record
    section		: PChar;
    name		: PChar;
    value		: PChar;
  end;

  txt_db_qual_func	= function:Integer;
  txt_db_st		= record
    num_fields		: Integer;
    data		: STACK;
    index		:^LHASH;
    qual		:^txt_db_qual_func;
    error		: LongInt;
    arg1, arg2		: LongInt;
    arg_row		:^PChar;
  end;

  RIPEMD160state_st	= record
    A,B,C,D,E		: Cardinal;
    Nl,Nh		: Cardinal;
    data		: Array[0..15] of Cardinal;
    num 		: Integer;
  end;
  RIPEMD160_CTX 	= RIPEMD160state_st;

  rc5_key_st		= record
	(* Number of rounds *)
    rounds		: Integer;
    data		: Array[0..2*(16+1)-1] of Cardinal;
  end;
  RC5_32_KEY		= rc5_key_st;

  bf_key_st		= record
    P			: Array[0..16+2-1] of Cardinal;
    S			: Array[0..4*256-1] of Cardinal;
  end;
  BF_KEY		= bf_key_st;

  cast_key_st		= record
    data		: Array[0..31] of Cardinal;
  end;
  CAST_KEY		= cast_key_st;

  mdc2_ctx_st		= record
    num 		: Integer;
    data		: Array[0..7] of Byte;
    h,hh		: des_cblock;
    pad_type		: Integer; (* either 1 or 2, default 1 *)
  end;
  MDC2_CTX		= mdc2_ctx_st;

  bio_bwrite_func	= function(h:BIO;var buf;num:Integer):Integer;
  bio_bread_func	= function(h:BIO;var buf;num:Integer):Integer;
  bio_bputs_func	= function(h:BIO;str:PChar):Integer;
  bio_bgets_func	= function(h:BIO;str:PChar;size:Integer):Integer;
  bio_ctrl_func 	= function(h:BIO;cmd:Integer;arg1:LongInt;arg2:Pointer):LongInt;
  bio_create_func	= function(h:BIO):Integer;
  bio_destroy_func	= function(h:BIO):Integer;
  bio_method_st 	= record
    typ 		: Integer;
    name		: PChar;
    bwrite		: bio_bwrite_func;
    bread		: bio_bread_func;
    bputs		: bio_bputs_func;
    bgets		: bio_bgets_func;
    ctrl		: bio_ctrl_func;
    create		: bio_create_func;
    destroy		: bio_destroy_func;
  end;

  bio_callback_func	= function(h:BIO;mode:Integer;argp:Pointer;argi:Integer;argl,ret:LongInt):LongInt;
  bio_st		= record
    method		: BIO_METHOD;
    callback		: bio_callback_func;
    cb_arg		: Pointer;	    (* first argument for the callback *)
    init		: Integer;
    shutdown		: Integer;
    flags		: Integer;	    (* extra storage *)
    retry_reason	: Integer;
    num 		: Integer;
    ptr 		: PChar;
    next_bio		: BIO;		    (* used by filter BIOs *)
    prev_bio		: BIO;		    (* used by filter BIOs *)
    references		: Integer;
    num_read		: Cardinal;
    num_write		: Cardinal;

    ex_data		: CRYPTO_EX_DATA;
  end;

  bio_f_buffer_ctx_struct=record
	(* BIO bio; *) (* this is now in the BIO struct *)
    ibuf_size		: Integer;  (* how big is the input buffer *)
    obuf_size		: Integer;  (* how big is the output buffer *)

    ibuf		: PChar;    (* the char array *)
    ibuf_len		: Integer;  (* how many bytes are in it *)
    ibuf_off		: Integer;  (* write/read offset *)

    obuf		: PChar;    (* the char array *)
    obuf_len		: Integer;  (* how many bytes are in it *)
    obuf_off		: Integer;  (* write/read offset *)
  end;

  asn1_ctx_st		= record
    p			: Pointer;	(* work char pointer *)
    eos 		: Integer;	(* end of sequence read for indefinite encoding *)
    error		: Integer;	(* error code to use when returning an error *)
    inf 		: Integer;	(* constructed if $20, indefinite is $21 *)
    tag 		: Integer;	(* tag from last 'get object' *)
    xclass		: Integer;	(* class from last 'get object' *)
    slen		: LongInt;	(* length of last 'get object' *)
    max 		: Pointer;	(* largest value of p alowed *)
    q			: Pointer;	(* temporary variable *)
    pp			:^Pointer;	(* variable *)
  end;

  asn1_object_st	= record
    sn,ln		: PChar;
    nid 		: Integer;
    length		: Integer;
    data		: Pointer;
    flags		: Integer;	(* Should we free this one *)
  end;

  asn1_string_st	= record
    length		: Integer;
    typ 		: Integer;
    data		: Pointer;
  end;

  asn1_type_st		= record
    typ 		: Integer;
    value		: record
    case Integer of
      0 :(ptr		: PChar);
      1 :(str		: ASN1_STRING);
      2 :(obj		: ASN1_OBJECT);
      3 :(int		: ASN1_INTEGER);
      4 :(bit_string	: ASN1_BIT_STRING);
      5 :(octet_string	: ASN1_OCTET_STRING);
      6 :(printablestring:ASN1_PRINTABLESTRING);
      7 :(t61string	: ASN1_T61STRING);
      8 :(ia5string	: ASN1_IA5STRING);
      9 :(generalstring : ASN1_GENERALSTRING);
      10:(bmpstring	: ASN1_BMPSTRING);
      11:(universalstring:ASN1_UNIVERSALSTRING);
      12:(utctime	: ASN1_UTCTIME);
      13:(generalizedtime:ASN1_GENERALIZEDTIME);
		(* set and sequence are left complete and still
		  contain the set or sequence bytes *)
      14:(aset		: ASN1_STRING);
      15:(sequence	: ASN1_STRING);
    end;
  end;

  asn1_i2d_func 	= function(a:Pointer;var b:Pointer):Integer;
  asn1_d2i_func 	= function(var a,b:Pointer;l:LongInt):Pointer;
  asn1_create_func	= function:Pointer;
  asn1_destroy_func	= procedure;
  asn1_method_st	= record
    i2d 		: asn1_i2d_func;
    d2i 		: asn1_d2i_func;
    create		: asn1_create_func;
    destroy		: asn1_destroy_func;
  end;

  asn1_header_st	= record
    header		: ASN1_OCTET_STRING;
    data		: PChar;
    meth		: ASN1_METHOD;
  end;

  evp_pkey_st		= record
    typ 		: Integer;
    save_type		: Integer;
    references		: Integer;
    pkey		: record
    case byte of
      0 : (ptr		: PChar);
      1 : (rsa		: RSA); 	(* RSA *)
      2 : (dsa		: DSA); 	(* DSA *)
      3 : (dh		: DH);		(* DH *)
    end;
    save_parameters	: Integer;
    attributes		: STACK;	(* X509_ATTRIBUTE *)
  end;

  env_md_init_func	= procedure;
  env_md_update_func	= procedure;
  env_md_final_func	= procedure;
  env_md_sign_func	= function:Integer;
  env_md_verify_func	= function:Integer;
  env_md_st		= record
    typ 		: Integer;
    pkey_type		: Integer;
    md_size		: Integer;
    init		: env_md_init_func;
    update		: env_md_update_func;
    final		: env_md_final_func;

    sign		: env_md_sign_func;
    verify		: env_md_verify_func;
    required_pkey_type	: Array[0..4] of Integer; (*EVP_PKEY_xxx *)
    block_size		: Integer;
    ctx_size		: Integer; (* how big does the ctx need to be *)
  end;

  env_md_ctx_st 	= record
    digest		: EVP_MD;
    md			: record
    case Integer of
      0 : (base 	: Array[0..3] of Byte);
      1 : (md2		: MD2_CTX);
      2 : (md5		: MD5_CTX);
      3 : (ripemd160	: RIPEMD160_CTX);
      4 : (sha		: SHA_CTX);
      5 : (mdc2 	: MDC2_CTX);
    end;
  end;
  EVP_MD_CTX		= env_md_ctx_st;

  evp_cipher_ctx_st	= record
    cipher		: EVP_CIPHER;
    encrypt		: Integer;			(* encrypt or decrypt *)
    buf_len		: Integer;			(* number we have left *)

    oiv 		: Array[0..7] of Byte;		(* original iv *)
    iv			: Array[0..7] of Byte;		(* working iv *)
    buf 		: Array[0..7] of Byte;		(* saved partial block *)
    num 		: Integer;			(* used by cfb/ofb mode *)

    app_data		: PChar;			(* aplication stuff *)
    c			: record
    case Integer of
      0:(rc4		: record
	   key		: Array[0..15] of Byte;
	   ks		: RC4_KEY;			(* working key *)
	 end);
      1:(des_ks 	: des_key_schedule);		(* key schedule *)
      2:(desx_cbc	: record
	   ks		: des_key_schedule;		(* key schedule *)
	   inw		: des_cblock;
	   outw 	: des_cblock;
	 end);
      3:(des_ede	: record
	   ks1		: des_key_schedule;		(* key schedule *)
	   ks2		: des_key_schedule;		(* key schedule (for ede) *)
	   ks3		: des_key_schedule;		(* key schedule (for ede3) *)
	 end);
      4:(idea_ks	: IDEA_KEY_SCHEDULE);		(* key schedule *)
      5:(rc2_ks 	: RC2_KEY);			(* key schedule *)
      6:(rc5_ks 	: RC5_32_KEY);			(* key schedule *)
      7:(bf_ks		: BF_KEY);			(* key schedule *)
      8:(cast_ks	: CAST_KEY);			(* key schedule *)
    end;
  end;
  EVP_CIPHER_CTX	= evp_cipher_ctx_st;

  evp_ciph_init_func	= procedure;
  evp_ciph_do_func	= procedure;
  evp_ciph_cleanup_func = procedure;
  evp_set_asn1_parm_func= function(var ctx:EVP_CIPHER_CTX;a:ASN1_TYPE):Integer;
  evp_get_asn1_parm_func= function(var ctx:EVP_CIPHER_CTX;a:ASN1_TYPE):Integer;
  evp_cipher_st 	= record
    nid 		: Integer;
    block_size		: Integer;
    key_len		: Integer;
    iv_len		: Integer;
    init		: evp_ciph_init_func;		(* init for encryption *)
    do_cipher		: evp_ciph_do_func;		(* encrypt data *)
    cleanup		: evp_ciph_cleanup_func;	(* used by cipher method *)
    ctx_size		: Integer;			(* how big the ctx needs to be *)
	(* int set_asn1_parameters(EVP_CIPHER_CTX,ASN1_TYPE ); *)
    set_asn1_parameters : evp_set_asn1_parm_func;	(* Populate a ASN1_TYPE with parameters *)
	(* int get_asn1_parameters(EVP_CIPHER_CTX,ASN1_TYPE ); *)
    get_asn1_parameters : evp_get_asn1_parm_func;	(* Get parameters from a ASN1_TYPE *)
  end;

  evp_cipher_info_st	= record
    cipher		: EVP_CIPHER;
    iv			: Array[0..7] of Byte;
  end;
  EVP_CIPHER_INFO	= evp_cipher_info_st;

  evp_Encode_Ctx_st	= record
    num 		: Integer;	(* number saved in a partial encode/decode *)
    length		: Integer;	(* The length is either the output line length
			  (in input bytes) or the shortest input line
			  length that is ok.  Once decoding begins,
			  the length is adjusted up each time a longer
			  line is decoded *)
    enc_data		: array[0..79] of Byte; (* data to encode *)
    line_num		: Integer;	(* number read on current line *)
    expect_nl		: Integer;
  end;
  EVP_ENCODE_CTX	= evp_Encode_Ctx_st;

  x509_a2i_func 	= function:Integer;
  x509_i2a_func 	= function:Integer;
  X509_objects_st	= record
    nid 		: Integer;
    a2i 		: x509_a2i_func;
    i2a 		: x509_i2a_func;
  end;
  X509_OBJECTS		= X509_objects_st;

  X509_algor_st 	= record
    algorithm		: ASN1_OBJECT;
    parameter		: ASN1_TYPE;
  end;

  X509_val_st		= record
    notBefore		: ASN1_UTCTIME;
    notAfter		: ASN1_UTCTIME;
  end;

  X509_pubkey_st	= record
    algor		: X509_ALGOR;
    public_key		: ASN1_BIT_STRING;
    pkey		: EVP_PKEY;
  end;

  X509_sig_st		= record
    algor		: X509_ALGOR;
    digest		: ASN1_OCTET_STRING;
  end;

  X509_name_entry_st	= record
    obj 		: ASN1_OBJECT;
    val 		: ASN1_STRING;
    set_		: Integer;
    size		: Integer;	(* temp variable *)
  end;

(* we always keep X509_NAMEs in 2 forms. *)
  X509_name_st		= record
    entries		: STACK;	(* of X509_NAME_ENTRY *)
    modified		: Integer;	(* true if 'bytes' needs to be built *)

    bytes		: BUF_MEM;

    hash		: Cardinal;	(* Keep the hash around for lookups *)
  end;

  x509_ex_free_func	= procedure;
  X509_extension_st	= record
    obj 		: ASN1_OBJECT;
    critical		: SmallInt;
    netscape_hack	: SmallInt;
    value		: ASN1_OCTET_STRING;
    argl		: LongInt;		(* used when decoding *)
    argp		: PChar;		(* used when decoding *)
    ex_free		: x509_ex_free_func;	(* clear argp stuff *)
  end;
  X509_EXTENSION	= X509_extension_st;

  x509_ex_clear_func	= function:Integer;
  x509_ex_get_bool_func = function:Integer;
  x509_ex_set_bool_func = function:Integer;
  x509_ex_get_str_func	= function:Integer;
  x509_ex_set_str_func	= function:Integer;
  x509_ex_get_struc_func= function:Pointer;
  x509_ex_set_struc_func= function:Integer;
  x509_extension_method_st=record
    nid 		: Integer;
    data_type		: Integer;
    pack_type		: Integer;
    ex_clear		: x509_ex_clear_func;
    ex_get_bool 	: x509_ex_get_bool_func;
    ex_set_bool 	: x509_ex_set_bool_func;
    ex_get_str		: x509_ex_get_str_func;
    ex_set_str		: x509_ex_set_str_func;
    ex_get_struct	: x509_ex_get_struc_func;
    ex_set_struct	: x509_ex_set_struc_func;
    a2i 		: x509_a2i_func;
    i2a 		: x509_i2a_func;
  end;

  X509_req_info_st	= record
    version		: ASN1_INTEGER;
    subject		: X509_NAME;
    pubkey		: X509_PUBKEY;
	(*  d=2 hl=2 l=  0 cons: cont: 00 *)
    attributes		: STACK; (* X509_ATTRIBUTE *)
    req_kludge		: Integer;
  end;

  X509_req_st		= record
    req_info		: X509_REQ_INFO;
    sig_alg		: X509_ALGOR;
    signature		: ASN1_BIT_STRING;
    references		: Integer;
  end;

  x509_cinf_st		= record
    version		: ASN1_INTEGER; 		(* [ 0 ] default of v1 *)
    serialNumber	: ASN1_INTEGER;
    signature		: X509_ALGOR;
    issuer		: X509_NAME;
    validity		: X509_VAL;
    subject		: X509_NAME;
    key 		: X509_PUBKEY;
    issuerUID		: ASN1_BIT_STRING;		(* [ 1 ] optional in v2 *)
    subjectUID		: ASN1_BIT_STRING;		(* [ 2 ] optional in v2 *)
    extensions		: STACK; (* X509_EXTENSION *)	(* [ 3 ] optional in v3 *)
  end;

  x509_st		= record
    cert_info		: X509_CINF;
    sig_alg		: X509_ALGOR;
    signature		: ASN1_BIT_STRING;
    valid		: Integer;
    references		: Integer;
    name		: PChar;
  end;

  X509_revoked_st	= record
    serialNumber	: ASN1_INTEGER;
    revocationDate	: ASN1_UTCTIME;
    extensions		: STACK;       (* optional X509_EXTENSION *)
    sequence		: Integer;     (* load sequence *)
  end;

  X509_crl_info_st	= record
    version		: ASN1_INTEGER;
    sig_alg		: X509_ALGOR;
    issuer		: X509_NAME;
    lastUpdate		: ASN1_UTCTIME;
    nextUpdate		: ASN1_UTCTIME;
    revoked		: STACK;       (* X509_REVOKED *)
    extensions		: STACK;       (* [0] X509_EXTENSION *)
  end;

  X509_crl_st		= record
	(* actual signature *)
    crl 		: X509_CRL_INFO;
    sig_alg		: X509_ALGOR;
    signature		: ASN1_BIT_STRING;
    references		: Integer;
  end;

(* a sequence of these are used *)
  x509_attributes_st	= record
    obj 		: ASN1_OBJECT;
    set_		: Integer;	(* 1 for a set, 0 for a single item (which is wrong) *)
    value		: record
    case Integer of
      0:(ptr		: PChar);
      1:(sset		: STACK);	(* 1 *) (* ASN1_TYPE *)
      2:(single 	: ASN1_TYPE);	(* 0 *)
    end;
  end;

  private_key_st	= record
    version		: Integer;
	(* The PKCS#8 data types *)
    enc_algor		: X509_ALGOR;
    enc_pkey		: ASN1_OCTET_STRING;	(* encrypted pub key *)

	(* When decrypted, the following will not be NULL *)
    dec_pkey		: EVP_PKEY;

	(* used to encrypt and decrypt *)
    key_length		: Integer;
    key_data		: PChar;
    key_free		: Integer;	(* true if we should auto free key_data *)

	(* expanded version of 'enc_algor' *)
    cipher		: EVP_CIPHER_INFO;

    references		: Integer;
  end;

  X509_info_st		= record
    x509		: X509;
    crl 		: X509_CRL;
    x_pkey		: X509_PKEY;

    enc_cipher		: EVP_CIPHER_INFO;
    enc_len		: Integer;
    enc_data		: PChar;

    references		: Integer;
  end;


(* The next 2 structures and their 8 routines were sent to me by
  Pat Richard <patr@x509.com> and are used to manipulate
  Netscapes spki strucutres - usefull if you are writing a CA web page
 *)
  Netscape_spkac_st	= record
    pubkey		: X509_PUBKEY;
    challenge		: ASN1_IA5STRING;	(* challenge sent in atlas >= PR2 *)
  end;

  Netscape_spki_st	= record
    spkac		: NETSCAPE_SPKAC;	(* signed public key and challenge *)
    sig_algor		: X509_ALGOR;
    signature		: ASN1_BIT_STRING;
  end;

  CBCParameter_st	= record
    iv			: Array[0..7] of Byte;
  end;
  CBC_PARAM		= CBCParameter_st;

(* Outer object *)
  x509_hash_dir_st	= record
    num_dirs		: Integer;
    dirs		:^PChar;
    dirs_type		:^Integer;
    num_dirs_alloced	: Integer;
  end;
  X509_HASH_DIR_CTX	= x509_hash_dir_st;

  x509_file_st		= record
    num_paths		: Integer;	(* number of paths to files or directories *)
    num_alloced 	: Integer;
    paths		:^PChar;	(* the list of paths or directories *)
    path_type		:^Integer;
  end;
  X509_CERT_FILE_CTX	= x509_file_st;

  x509_object_st	= record
	(* one of the above types *)
    typ 		: Integer;
    data		: record
    case Integer of
      0:(ptr		: PChar);
      1:(x509		: X509);
      2:(crl		: X509_CRL);
      3:(pkey		: EVP_PKEY);
    end;
  end;

(* This is a static that defines the function interface *)
  x509_new_item_func	= function:Integer;
  x509_free_func	= procedure;
  x509_init_func	= function:Integer;	(* meth, char  *)
  x509_shutdown_func	= function:Integer;	(* meth, char  *)
  x509_ctrl_func	= function:Integer;	(* meth, char , int cmd, char argp, int argi *)
  x509_get_by_subj_func = function:Integer;	(* meth, char , XNAME , X509 ret *)
  x509_get_by_issn_func = function:Integer;
  x509_get_by_fngrp_func= function:Integer;
  x509_get_by_alias_func= function:Integer;
  x509_lookup_method_st = record
    name		: PChar;
    new_item		: x509_new_item_func;
    free		: x509_free_func;
    init		: x509_init_func;
    shutdown		: x509_shutdown_func;
    ctrl		: x509_ctrl_func;
    get_by_subject	: x509_get_by_subj_func;
    get_by_issuer_serial: x509_get_by_issn_func;
    get_by_fingerprint	: x509_get_by_fngrp_func;
    get_by_alias	: x509_get_by_alias_func;
  end;

  x509_verify_func	= function:Integer;
  x509_verify_cb_func	= function:Integer;
  x509_store_st 	= record
	(* The following is a cache of trusted certs *)
    cache		: Integer;		  (* if true, stash any hits *)

    certs		: LHASH;		  (* cached certs; *)

	(* These are external lookup methods *)
    get_cert_methods	: STACK;		   (* X509_LOOKUP *)
    verify		: x509_verify_func;	   (* called to verify a certificate *)
    verify_cb		: x509_verify_cb_func;	   (* error callback *)

    ex_data		: CRYPTO_EX_DATA;
    references		: Integer;
    depth		: Integer;		   (* how deep to look *)
  end;

  x509_lookup_st	= record
    init		: Integer;		(* have we been started *)
    skip		: Integer;		(* don't use us. *)
    method		: X509_LOOKUP_METHOD;	(* the functions *)
    method_data 	: PChar;		(* method data *)

    store_ctx		: X509_STORE;		(* who owns us *)
  end;

  x509_store_state_st	= record
    ctx 		: X509_STORE;
    current_method	: Integer;		(* used when looking up certs *)

	(* The following are set by the caller *)
    cert		: X509; 		(* The cert to check *)
    untrusted		: STACK;		(* chain of X509s - untrusted - passed in *)

	(* The following is built up *)
    depth		: Integer;		(* how far to go looking up certs *)
    valid		: Integer;		(* if 0, rebuild chain *)
    last_untrusted	: Integer;		(* index of last untrusted cert *)
    chain		: STACK;		(* chain of X509s - built up and trusted *)

	(* When something goes wrong, this is why *)
    error_depth 	: Integer;
    error		: Integer;
    current_cert	: X509;

    ex_data		: CRYPTO_EX_DATA;
  end;
  X509_STORE_CTX	= x509_store_state_st;

  pkcs7_issuer_and_serial_st	= record
    issuer		: X509_NAME;
    serial		: ASN1_INTEGER;
  end;

  pkcs7_signer_info_st	= record
    version		: ASN1_INTEGER; 		(* version 1 *)
    issuer_and_serial	: PKCS7_ISSUER_AND_SERIAL;
    digest_alg		: X509_ALGOR;
    auth_attr		: STACK;(* X509_ATTRIBUTE *)	(* [ 0 ] *)
    digest_enc_alg	: X509_ALGOR;
    enc_digest		: ASN1_OCTET_STRING;
    unauth_attr 	: STACK;(* X509_ATTRIBUTE *)	(* [ 1 ] *)

	(* The private key to sign with *)
    pkey		: EVP_PKEY;
  end;

  pkcs7_recip_info_st	= record
    version		: ASN1_INTEGER; 	(* version 0 *)
    issuer_and_serial	: PKCS7_ISSUER_AND_SERIAL;
    key_enc_algor	: X509_ALGOR;
    enc_key		: ASN1_STRING;
    cert		: X509; 		(* get the pub-key from this *)
  end;

  pkcs7_signed_st	= record
    version		: ASN1_INTEGER; 	(* version 1 *)
    md_algs		: STACK;(* X509_ALGOR's *)(* md used *)
    cert		: STACK;(* X509 *)	(* [ 0 ] *)
    crl 		: STACK;(* X509_CRL *)	(* [ 1 ] *)
    signer_info 	: STACK;(* PKCS7_SIGNER_INFO *)

    contents		: PKCS7;
  end;
(* The above structure is very very similar to PKCS7_SIGN_ENVELOPE.
  How about merging the two *)

  pkcs7_enc_content_st	= record
    content_type	: ASN1_OBJECT;
    algorithm		: X509_ALGOR;
    enc_data		: ASN1_OCTET_STRING;	(* [ 0 ] *)
  end;

  pkcs7_enveloped_st	= record
    version		: ASN1_INTEGER; 	(* version 0 *)
    recipientinfo	: STACK;(* PKCS7_RECIP_INFO *)
    enc_data		: PKCS7_ENC_CONTENT;
  end;

  pkcs7_signedandenveloped_st=record
    version		: ASN1_INTEGER; 	(* version 1 *)
    md_algs		: STACK;(* X509_ALGOR's *)(* md used *)
    cert		: STACK;(* X509 *)	(* [ 0 ] *)
    crl 		: STACK;(* X509_CRL *)	(* [ 1 ] *)
    signer_info 	: STACK;(* PKCS7_SIGNER_INFO *)

    enc_data		: PKCS7_ENC_CONTENT;
    recipientinfo	: STACK;(* PKCS7_RECIP_INFO *)
  end;

  pkcs7_digest_st	= record
    version		: ASN1_INTEGER; 	(* version 0 *)
    md			: X509_ALGOR;		(* md used *)
    contents		: PKCS7;
    digest		: ASN1_OCTET_STRING;
  end;

  pkcs7_encrypted_st	= record
    version		: ASN1_INTEGER; 	(* version 0 *)
    enc_data		: PKCS7_ENC_CONTENT;
  end;

  pkcs7_st		= record
	(* The following is non NULL if it contains ASN1 encoding of
	  this structure *)
    asn1		: Pointer;
    length		: LongInt;

    state		: Integer;	(* used during processing *)

    detached		: Integer;

    typ 		: ASN1_OBJECT;
	(* content as defined by the type *)
	(* all encryption/message digests are applied to the 'contents',
	  leaving out the 'type' field. *)
    d			: record
    case Integer of
      0:(ptr		: Pointer);
      1:(data		: ASN1_OCTET_STRING);	(* NID_pkcs7_data *)
      2:(sign		: PKCS7_SIGNED);	(* NID_pkcs7_signed *)
      3:(enveloped	: PKCS7_ENVELOPE);	(* NID_pkcs7_enveloped *)
      4:(signed_and_enveloped:PKCS7_SIGN_ENVELOPE);(* NID_pkcs7_signedAndEnveloped *)
      5:(digest 	: PKCS7_DIGEST);	(* NID_pkcs7_digest *)
      6:(encrypted	: PKCS7_ENCRYPT);	(* NID_pkcs7_encrypted *)
    end;
  end;

  PEM_Encode_Seal_st	= record
    encode		: EVP_ENCODE_CTX;
    md			: EVP_MD_CTX;
    cipher		: EVP_CIPHER_CTX;
  end;
  PEM_ENCODE_SEAL_CTX	= PEM_Encode_Seal_st;

  pem_recip_st		= record
    name		: PChar;
    dn			: X509_NAME;

    cipher		: Integer;
    key_enc		: Integer;
    iv			: Array[0..7] of Char;
  end;

  pem_ctx_st		= record
    typ 		: Integer;	(* what type of object *)
    proc_type		: record
      version		: Integer;
      mode		: Integer;
    end;
    domain		: PChar;

    DEK_info		: record
      cipher		: Integer;
      iv		: Array[0..7] of Byte;
    end;

    originator		: PEM_USER;

    num_recipient	: Integer;
    recipient		:^PEM_USER;

    x509_chain		: STACK;	(* certificate chain *)

    md			: EVP_MD;	(* signature type *)

    md_enc		: Integer;	(* is the md encrypted or not? *)
    md_len		: Integer;	(* length of md_data *)
    md_data		: PChar;	(* message digest, could be pkey encrypted *)

    dec 		: EVP_CIPHER;	(* date encryption cipher *)
    key_len		: Integer;	(* key length *)
    key 		: Pointer;	(* key *)
    iv			: Array[0..7] of Byte;(* the iv *)

    data_enc		: Integer;	(* is the data encrypted *)
    data_len		: Integer;
    data		: Pointer;
  end;
  PEM_CTX		= pem_ctx_st;

  pem_callback_func	= function:Integer;

  hmac_ctx_st		= record
    md			: EVP_MD;
    md_ctx		: EVP_MD_CTX;
    i_ctx		: EVP_MD_CTX;
    o_ctx		: EVP_MD_CTX;
    key_length		: Word;
    key 		: Array[0..63] of Byte;
  end;
  HMAC_CTX		= hmac_ctx_st;

