/*
 * COPYRIGHT (c) International Business Machines Corp. 2014-2017
 *
 * This program is provided under the terms of the Common Public License,
 * version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
 * software constitutes recipient's acceptance of CPL-1.0 terms which can be
 * found in the file LICENSE file or at
 * https://opensource.org/licenses/cpl1.0.php
 */

/*
 * pkcscca - A tool for PKCS#11 CCA token.
 * Currently, only migrates CCA private token objects from using a
 * CCA cipher to using a software cipher.
 *
 */

#ifndef __PKCSCCA_H_
#define __PKCSCCA_H_

#include <stdint.h>

#define CCA_LIBRARY "libcsulcca.so"
#define TOK_DATASTORE   CONFIG_PATH "/ccatok"
#define MASTER_KEY_SIZE     64
#define SHA1_HASH_SIZE      20
#define MD5_HASH_SIZE       16
#define DES_BLOCK_SIZE      8
#define DES_KEY_SIZE        8
#define CCA_SUCCESS         0

#define AES_NAME    "AES"
#define DES_NAME    "DES"
#define DES2_NAME   "2DES"
#define DES3_NAME   "3DES"
#define ECC_NAME    "ECC"
#define HMAC_NAME   "HMAC"
#define RSA_NAME    "RSA"
#define BAD_NAME    "Unknown"

#define MK_AES      1
#define MK_APKA     2
#define MK_ASYM     3
#define MK_SYM      4

int compute_hash(int hash_type, int buf_size, char *buf, char *digest);

#define compute_sha1(a,b,c)     compute_hash(HASH_SHA1,b,a,c)
#define compute_md5(a,b,c)      compute_hash(HASH_MD5,b,a,c)
#define HASH_SHA1   1
#define HASH_MD5    2

CK_RV sw_des3_cbc(CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_BYTE *,
                  CK_BYTE *, CK_BYTE);

#define sw_des3_cbc_encrypt(clear, len, cipher, len2, iv, key) \
                sw_des3_cbc(clear, len, cipher, len2, iv, key, 1)

#define sw_des3_cbc_decrypt(clear, len, cipher, len2, iv, key) \
                sw_des3_cbc(clear, len, cipher, len2, iv, key, 0)

#define EVP_SUCCESS 1
#define print_openssl_errors() \
        do { \
                ERR_load_crypto_strings(); \
                ERR_print_errors_fp(stderr); \
        } while (0)

char *p11strerror(CK_RV);

#define p11_error(s,rc) fprintf(stderr, "%s:%d %s failed: rc=0x%lX (%s)\n", \
                                __FILE__, __LINE__, s, rc, p11strerror(rc))

static inline void _print_error(const char *file, int line,
                                const char *fmt, ...) {
    char buf[512];
    size_t off;
    va_list ap;

    snprintf(buf, sizeof(buf), "%s:%d ", file, line);
    off = strlen("%s:%d ");

    va_start(ap, fmt);
    vsnprintf(buf + off, sizeof(buf) - off, fmt, ap);
    va_end(ap);

    fprintf(stderr, "%s", buf);
}
#define print_error(...) _print_error(__FILE__, __LINE__, __VA_ARGS__)

#define cca_error(f,rc,rsn) fprintf(stderr, "%s:%d " f " failed. return code: "\
                                    "%ld, reason code: %ld\n", __FILE__, \
                                    __LINE__, rc, rsn)
#define print_hex(x, y) \
        do { \
            unsigned char *hex = x; \
            int i; \
            for (i = 0; i < y; i++) { \
                printf("%02x", hex[i]); \
                if (((i+1) % 32) == 0) \
                    printf("\n"); \
                else if (((i+1) % 4) == 0) \
                    printf(" "); \
            } \
        } while (0)


typedef struct _MASTER_KEY_FILE_T {
    CK_BYTE key[MASTER_KEY_SIZE];
    CK_BYTE sha_hash[SHA1_HASH_SIZE];
} MASTER_KEY_FILE_T;

/* from host_defs.h */
#include "pkcs32.h"
typedef struct _TWEAK_VEC {
    int allow_weak_des;
    int check_des_parity;
    int allow_key_mods;
    int netscape_mods;
} TWEAK_VEC;

typedef struct _TOKEN_DATA_VERSION {
    uint32_t version; /* major<<16|minor */
    /* --- PBKDF2 --- */
    /* SO login */
    uint64_t so_login_it;
    unsigned char so_login_salt[64];
    unsigned char so_login_key[32];
    /* User login */
    uint64_t user_login_it;
    unsigned char user_login_salt[64];
    unsigned char user_login_key[32];
    /* SO MK wrap */
    uint64_t so_wrap_it;
    unsigned char so_wrap_salt[64];
    /* User MK wrap */
    uint64_t user_wrap_it;
    unsigned char user_wrap_salt[64];
} TOKEN_DATA_VERSION;

typedef struct _TOKEN_DATA {
    CK_TOKEN_INFO_32 token_info;

    CK_BYTE user_pin_sha[3 * DES_BLOCK_SIZE];
    CK_BYTE so_pin_sha[3 * DES_BLOCK_SIZE];
    CK_BYTE next_token_object_name[8];
    TWEAK_VEC tweak_vector;

    /* new for tokversion >= 3.12 */
    TOKEN_DATA_VERSION dat;
} TOKEN_DATA;

typedef struct _TOKEN_DATA_OLD {
    CK_TOKEN_INFO_32 token_info;

    CK_BYTE user_pin_sha[3 * DES_BLOCK_SIZE];
    CK_BYTE so_pin_sha[3 * DES_BLOCK_SIZE];
    CK_BYTE next_token_object_name[8];
    TWEAK_VEC tweak_vector;
} TOKEN_DATA_OLD;

struct key {
    CK_OBJECT_HANDLE handle;
    CK_ULONG type;
    CK_BYTE *opaque_attr;
    CK_ULONG attr_len;
    CK_CHAR_PTR label;

    struct key *next;
};

struct algo {
    unsigned char *rule_array;
    unsigned char *name;
    long rule_array_count;
};

struct key_count {
    int aes;
    int des;
    int des2;
    int des3;
    int ecc;
    int hmac;
    int rsa;
};

typedef struct _DL_NODE
{
    struct _DL_NODE   *next;
    struct _DL_NODE   *prev;
    void              *data;
} DL_NODE;

typedef struct _TEMPLATE
{
    DL_NODE  *attribute_list;
} TEMPLATE;

typedef void *SESSION;

typedef struct _OBJECT
{
    CK_OBJECT_CLASS   class;
    CK_BYTE           name[8];   // for token objects

    SESSION          *session;   // creator; only for session objects
    TEMPLATE         *template;
    CK_ULONG          count_hi;  // only significant for token objects
    CK_ULONG          count_lo;  // only significant for token objects
    CK_ULONG      index;  // SAB  Index into the SHM
    CK_OBJECT_HANDLE  map_handle;
} OBJECT;

struct secaeskeytoken {
    unsigned char  type;     /* 0x01 for internal key token */
    unsigned char  res0[3];
    unsigned char  version;  /* should be 0x04 */
    unsigned char  res1[1];
    unsigned char  flag;     /* key flags */
    unsigned char  res2[1];
    unsigned long  mkvp;     /* master key verification pattern */
    unsigned char  key[32];  /* key value (encrypted) */
    unsigned char  cv[8];    /* control vector */
    unsigned short bitsize;  /* key bit size */
    unsigned short keysize;  /* key byte size */
    unsigned char  tvv[4];   /* token validation value */
} __packed;

#endif
