diff --git a/Makefile b/Makefile index 4e5da73..7ac33ac 100644 --- a/Makefile +++ b/Makefile @@ -96,6 +96,7 @@ endif ifeq (libkcapi,$(firstword $(MAKECMDGOALS))) C_SRCS += backends/backend_libkcapi.c + C_SRCS += backends/rsakeys.c LIBRARIES += kcapi endif diff --git a/backends/backend_libkcapi.c b/backends/backend_libkcapi.c new file mode 100644 index 0000000..96e5708 --- /dev/null +++ b/backends/backend_libkcapi.c @@ -0,0 +1,2428 @@ +#include +#include +#include +#include +#include +#include +#include "backend_common.h" +#include "parser_sha_mct_helper.h" +#include "logger.h" + +#define CIPHERMAXNAME 63 +#define ECDH_CURVE_STR_P192 "ecdh-nist-p192" +#define ECDH_CURVE_STR_P256 "ecdh-nist-p256" +#define ECDH_CURVE_STR_P384 "ecdh-nist-p384" +#define ECDH_CURVE_ID_P192 1 +#define ECDH_CURVE_ID_P256 2 +#define ECDH_CURVE_ID_P384 3 +#define ECDH_CURVE_NUM_P192 192 +#define ECDH_CURVE_NUM_P256 256 +#define ECDH_CURVE_NUM_P384 384 +#define ECDH_SS_KEYLEN_P192 24 +#define ECDH_SS_KEYLEN_P256 32 +#define ECDH_SS_KEYLEN_P384 48 +#define GCM_IV_SIZE 12 +#define CCM_IV_SIZE 16 + +extern char n1[]; +extern char e1[]; +extern char d1[]; +extern char p1[]; +extern char q1[]; +extern char dp1[]; +extern char dq1[]; +extern char qinv1[]; +extern char n2[]; +extern char e2[]; +extern char d2[]; +extern char p2[]; +extern char q2[]; +extern char dp2[]; +extern char dq2[]; +extern char qinv2[]; +extern char n3[]; +extern char e3[]; +extern char d3[]; +extern char p3[]; +extern char q3[]; +extern char dp3[]; +extern char dq3[]; +extern char qinv3[]; +extern char n4[]; +extern char e4[]; +extern char d4[]; +extern char p4[]; +extern char q4[]; +extern char dp4[]; +extern char dq4[]; +extern char qinv4[]; + +unsigned char * write_field(unsigned char *ptr, unsigned char *src, unsigned short int len) +{ + /* actual length of a field = 0x02 and len */ + unsigned char *tmp; + tmp = (unsigned char *)(&len); + ptr[0] = 0x02; + if(len <= 127) + { + if(tmp) + memcpy(ptr + 1, tmp, 1); + ptr = ptr + 2; + } + else if(len > 127 && len <=255) + { + ptr[1] = 0x81; + if(tmp) + memcpy(ptr + 2, tmp, 1); + ptr = ptr + 3; + } + else if(len > 255) + { + ptr[1] = 0x82; + if(tmp) + { + memcpy(ptr + 2, tmp + 1, 1); + memcpy(ptr + 3, tmp, 1); + } + ptr = ptr + 4; + } + + if(src) + memcpy(ptr, src, len); + ptr = ptr + len; + return ptr; +} + +extern int rsa_private_key_ber_encode(struct rsa_siggen_data *data, struct buffer *d, + struct buffer *p, struct buffer *q, struct buffer *dp, + struct buffer *dq, struct buffer *qinv, + struct buffer *pk); + +int rsa_public_key_ber_encode(struct rsa_sigver_data *data, struct buffer *pk) { + /* + BER encoding for public key + 1. Calculate total length of Public key + + Metadata for complete key = 0x30 and sum of length of all fields + + 2. BER encoding the length of any field + actual length of a field = 0x02 and len + + if length <= 127 - 1 byte (actual length) + if length > 127 and length <= 255 - 2 bytes (Byte1 = 0x81, Byte2 = actual length) + if length > 255 - 3 bytes (Byte1 = 0x82, Byte2 and Byte3 = actual length) + */ + + unsigned short int nlen; + unsigned short int elen, total=0, extra; + unsigned char *ptr; + unsigned char *tmp; + int ret = 0; + + if(!data) + { + logger(LOGGER_ERR, "rsa: rsa_sigver_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + + nlen = data->n.len; + elen = data->e.len; + total = nlen; + if(nlen <= 127) + total = total + 2; + else if(nlen >= 128 && nlen <= 255) + total = total + 3; + else + total = total + 4; + total = total + elen; + + if(elen <= 127) + total = total + 2; + else if(elen >= 128 && elen <= 255) + total = total + 3; + else + total = total + 4; + + if(total <= 127) + extra = 2; + else if(total >= 128 && total <= 255) + extra = 3; + else + extra = 4; + +/*Calculated total length and extra bytes*/ +/*Start Prepare buffer*/ + CKINT_LOG(alloc_buf(total + extra + 1, pk), "rsa: public key buffer could not be allocated\n"); + ptr = pk->buf; + ptr[0] = 0x30; + if(extra == 2) + memcpy(ptr + 1, &total, 1); + if(extra == 3) + { + ptr[1] = 0x81; + memcpy(ptr + 2, &total, 1); + } + if(extra == 4) + { + tmp =(unsigned char*)(&total); + ptr[1] = 0x82; + memcpy(ptr + 2, tmp + 1, 1); + memcpy(ptr + 3, tmp , 1); + } + ptr = ptr + extra; + ptr = write_field(ptr, data->n.buf, nlen); + ptr = write_field(ptr, data->e.buf, elen); +out: + return ret; +} + +static int rsa_sigver(struct rsa_sigver_data *data, flags_t parsed_flags) +{ + struct kcapi_handle *handle = NULL; + char cipher[CIPHERMAXNAME]; + struct kcapi_handle *handle1 = NULL; + char cipher1[CIPHERMAXNAME]; + int ret = 0; + int ret1 = 0; + struct buffer pk; + struct buffer dgst; + struct buffer mac; + struct buffer in; + int dgst_len=0; + pk.len = 0; + pk.buf = NULL; + dgst.len = 0; + dgst.buf = NULL; + mac.len = 0; + mac.buf = NULL; + in.len = 0; + in.buf = NULL; + + if(!data) + { + logger(LOGGER_ERR,"rsa: rsa_sigver_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + if(!(parsed_flags & FLAG_OP_RSA_SIG_PKCS15)) + { + logger(LOGGER_ERR, "rsa: invalid cipher\n"); + return -EFAULT; + } + strcpy(cipher,"pkcs1pad(rsa,"); + switch(data->cipher & ACVP_HASHMASK) + { + case ACVP_SHA1: + strcat(cipher, "sha1)"); + strcpy(cipher1, "sha1"); + dgst_len = 20; + break; + case ACVP_SHA224: + strcat(cipher, "sha224)"); + strcpy(cipher1, "sha224"); + dgst_len = 28; + break; + case ACVP_SHA256: + strcat(cipher, "sha256)"); + strcpy(cipher1, "sha256"); + dgst_len = 32; + break; + case ACVP_SHA384: + strcat(cipher, "sha384)"); + strcpy(cipher1, "sha384"); + dgst_len = 48; + break; + case ACVP_SHA512: + strcat(cipher, "sha512)"); + strcpy(cipher1, "sha512"); + dgst_len = 64; + break; + } + + if (kcapi_akcipher_init(&handle, cipher, 0)) + { + logger(LOGGER_ERR, "rsa: allocation of %s cipher failed\n", cipher); + return -EFAULT; + } + if (kcapi_md_init(&handle1, cipher1, 0)) + { + logger(LOGGER_ERR, "rsa: allocation of hash %s failed\n", cipher); + kcapi_akcipher_destroy(handle1); + ret = -EFAULT; + } + + CKINT_LOG(alloc_buf(dgst_len, &mac), "rsa: mac buffer could not be allocated\n"); + ret = kcapi_md_digest(handle1, data->msg.buf, data->msg.len, mac.buf, mac.len); + if (ret < 0) + { + logger(LOGGER_ERR, "rsa: message digest generation failed\n"); + goto out; + } + + if(rsa_public_key_ber_encode(data, &pk) < 0) + { + logger(LOGGER_ERR, "rsa: BER encoding of public key failed\n"); + ret = -EFAULT; + goto out; + } + + ret1 = kcapi_akcipher_setpubkey(handle, pk.buf, pk.len); + if (ret1 <= 0) + { + logger(LOGGER_ERR, "rsa: public key setting failed\n"); + ret = -EFAULT; + goto out; + } + + CKINT_LOG(alloc_buf(ret, &dgst), "rsa: digest buffer could not be allocated\n"); + CKINT_LOG(alloc_buf(data->sig.len + mac.len, &in), "rsa: in buffer could not be allocated\n"); + + if(data->sig.buf) + memcpy(in.buf, data->sig.buf, data->sig.len); + + if(mac.buf) + memcpy(in.buf + data->sig.len, mac.buf, mac.len); + + ret1 = kcapi_akcipher_verify(handle, + in.buf, in.len, + dgst.buf, dgst.len, 0); + + if(ret1 < 0) + { + logger(LOGGER_ERR, "rsa: signature verification failed with error = %d\n", ret1); + data->sig_result = 0; + goto out; + } + data->sig_result = 1; + +out: + if(dgst.buf) + free_buf(&dgst); + if(in.buf) + free_buf(&in); + if(pk.buf) + free_buf(&pk); + if(mac.buf) + free_buf(&mac); + + kcapi_akcipher_destroy(handle); + kcapi_md_destroy(handle1); + return ret; +} + +static int rsa_siggen(struct rsa_siggen_data *data, + flags_t parsed_flags) +{ + struct kcapi_handle *handle = NULL; + char cipher[CIPHERMAXNAME]; + struct kcapi_handle *handle1 = NULL; + char cipher1[CIPHERMAXNAME]; + int ret = 0; + int ret1 = 0; + char *n_ptr; + char *e_ptr; + char *d_ptr; + char *p_ptr; + char *q_ptr; + char *dp_ptr; + char *dq_ptr; + char *qinv_ptr; + struct buffer d; + struct buffer p; + struct buffer q; + struct buffer dp; + struct buffer dq; + struct buffer qinv; + struct buffer pk; + struct buffer dgst; + struct buffer mac; + int dgst_len=0; + pk.len = 0; + pk.buf = NULL; + dgst.len = 0; + dgst.buf = NULL; + mac.len = 0; + mac.buf = NULL; + d.len = 0; + d.buf = NULL; + p.len = 0; + p.buf = NULL; + q.len = 0; + q.buf = NULL; + dp.len = 0; + dp.buf = NULL; + dq.len = 0; + dq.buf = NULL; + qinv.len = 0; + qinv.buf = NULL; + + if(!data) + { + logger(LOGGER_ERR, "rsa: rsa_siggen_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + if(!(parsed_flags & FLAG_OP_RSA_SIG_PKCS15)) + { + logger(LOGGER_ERR, "rsa: invalid cipher\n"); + return -EFAULT; + } + + strcpy(cipher,"pkcs1pad(rsa,"); + switch(data->cipher & ACVP_HASHMASK) + { + case ACVP_SHA1: + strcat(cipher, "sha1)"); + strcpy(cipher1, "sha1"); + dgst_len = 20; + break; + case ACVP_SHA224: + strcat(cipher, "sha224)"); + strcpy(cipher1, "sha224"); + dgst_len = 28; + break; + case ACVP_SHA256: + strcat(cipher, "sha256)"); + strcpy(cipher1, "sha256"); + dgst_len = 32; + break; + case ACVP_SHA384: + strcat(cipher, "sha384)"); + strcpy(cipher1, "sha384"); + dgst_len = 48; + break; + case ACVP_SHA512: + strcat(cipher, "sha512)"); + strcpy(cipher1, "sha512"); + dgst_len = 64; + break; + } + + if (kcapi_akcipher_init(&handle, cipher, 0)) + { + logger(LOGGER_ERR, "rsa: allocation of %s cipher failed\n", cipher); + return -EFAULT; + } + if (kcapi_md_init(&handle1, cipher1, 0)) + { + logger(LOGGER_ERR, "rsa: allocation of hash %s failed\n", cipher1); + kcapi_akcipher_destroy(handle1); + ret = -EFAULT; + } + + CKINT_LOG(alloc_buf(dgst_len, &mac), "rsa: mac buffer cannot be allocated\n"); + ret = kcapi_md_digest(handle1, data->msg.buf, data->msg.len, mac.buf, mac.len); + + if (ret < 0) + { + logger(LOGGER_ERR, "rsa: message digest generation failed\n"); + goto out; + } + + /* + definition for the array n1, n1[] = "n = 00b67b1cee2ff9f99f94478a23200816e0449845....." + the actual value that is needed is starting from index 4 + therefore, we do n1 + 4 + the same logic is followed for the other attributes + */ + + if(data->modulus == 1024) + { + n_ptr = n1 + 4; + e_ptr = e1 + 4; + d_ptr = d1 + 4; + p_ptr = p1 + 4; + q_ptr = q1 + 4; + dp_ptr = dp1 + 5; + dq_ptr = dq1 + 5; + qinv_ptr = qinv1 + 7; + } + if(data->modulus == 2048) + { + n_ptr = n2 + 4; + e_ptr = e2 + 4; + d_ptr = d2 + 4; + p_ptr = p2 + 4; + q_ptr = q2 + 4; + dp_ptr = dp2 + 5; + dq_ptr = dq2 + 5; + qinv_ptr = qinv2 + 7; + } + if(data->modulus == 3072) + { + n_ptr = n3 + 4; + e_ptr = e3 + 4; + d_ptr = d3 + 4; + p_ptr = p3 + 4; + q_ptr = q3 + 4; + dp_ptr = dp3 + 5; + dq_ptr = dq3 + 5; + qinv_ptr = qinv3 + 7; + } + if(data->modulus == 4096) + { + n_ptr = n4 + 4; + e_ptr = e4 + 4; + d_ptr = d4 + 4; + p_ptr = p4 + 4; + q_ptr = q4 + 4; + dp_ptr = dp4 + 5; + dq_ptr = dq4 + 5; + qinv_ptr = qinv4 + 7; + } + + hex2bin_alloc((char*)n_ptr, strlen(n_ptr), &data->n.buf, &data->n.len); + hex2bin_alloc((char*)e_ptr, strlen(e_ptr), &data->e.buf, &data->e.len); + hex2bin_alloc((char*)d_ptr, strlen(d_ptr), &d.buf, &d.len); + hex2bin_alloc((char*)p_ptr, strlen(p_ptr), &p.buf, &p.len); + hex2bin_alloc((char*)q_ptr, strlen(q_ptr), &q.buf, &q.len); + hex2bin_alloc((char*)dp_ptr, strlen(dp_ptr), &dp.buf, &dp.len); + hex2bin_alloc((char*)dq_ptr, strlen(dq_ptr), &dq.buf, &dq.len); + hex2bin_alloc((char*)qinv_ptr, strlen(qinv_ptr), &qinv.buf, &qinv.len); + + if(rsa_private_key_ber_encode(data, &d, &p, &q, &dp, &dq, &qinv, &pk) < 0) + { + logger(LOGGER_ERR, "rsa: BER encoding of private key failed\n"); + ret = -EFAULT; + goto out; + } + + ret1 = kcapi_akcipher_setkey(handle, pk.buf, pk.len); + if (ret1 <= 0) + { + logger(LOGGER_ERR, "rsa: pivate key setting failed with error = %d\n", ret1); + ret = -EFAULT; + goto out; + } + + CKINT_LOG(alloc_buf(ret1, &(data->sig)), "rsa: signature buffer could not be allocated\n"); + ret = kcapi_akcipher_sign(handle, + mac.buf, mac.len, + data->sig.buf, data->sig.len, 0); +out: + if(dgst.buf) + free_buf(&dgst); + if(pk.buf) + free_buf(&pk); + if(mac.buf) + free_buf(&mac); + if(d.buf) + free_buf(&d); + if(p.buf) + free_buf(&p); + if(q.buf) + free_buf(&q); + if(dp.buf) + free_buf(&dp); + if(dq.buf) + free_buf(&dq); + if(qinv.buf) + free_buf(&qinv); + + kcapi_akcipher_destroy(handle); + kcapi_md_destroy(handle1); + return ret; +} + +static struct rsa_backend kcapi_rsa = +{ + NULL, + rsa_siggen, + rsa_sigver, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, +}; + +ACVP_DEFINE_CONSTRUCTOR(kcapi_rsa_backend) +static void kcapi_rsa_backend(void) +{ + register_rsa_impl(&kcapi_rsa); +} + +static int sym_cipher(uint64_t acvp_cipher, char* cipher) +{ + switch (acvp_cipher) + { + case ACVP_ECB: + strcpy(cipher, "ecb(aes)"); + break; + case ACVP_CBC: + strcpy(cipher, "cbc(aes)"); + break; + case ACVP_CBC_CS3: + strcpy(cipher, "cts(cbc(aes))"); + break; + case ACVP_CFB128: + strcpy(cipher, "cfb(aes)"); + break; + case ACVP_CTR: + strcpy(cipher, "ctr(aes)"); + break; + case ACVP_XTS: + strcpy(cipher, "xts(aes)"); + break; + case ACVP_GCM: + strcpy(cipher, "gcm(aes)"); + break; + case ACVP_CCM: + strcpy(cipher, "ccm(aes)"); + break; + case ACVP_TDESECB: + strcpy(cipher, "ecb(des3_ede)"); + break; + case ACVP_TDESCBC: + strcpy(cipher, "cbc(des3_ede)"); + break; + case ACVP_TDESCTR: + strcpy(cipher, "ctr(des3_ede)"); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int sym_encrypt(struct sym_data *data, flags_t parsed_flags) +{ + int ret=0; + struct kcapi_handle *handle = NULL; + struct buffer pt; + char cipher[CIPHERMAXNAME]; + + if(!data) + { + logger(LOGGER_ERR,"sym: sym_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + if(sym_cipher(data->cipher,cipher)) + { + logger(LOGGER_ERR, "sym: invalid cipher\n"); + return -EINVAL; + } + + pt.len = data->data.len; + pt.buf = data->data.buf; + + if(kcapi_cipher_init(&handle, cipher, 0)) { + logger(LOGGER_ERR, "sym: cipher init failed\n"); + return -EINVAL; + } + + data->data.len = 0; + data->data.buf = NULL; + CKINT_LOG(alloc_buf(pt.len, &data->data), "sym: buffer for plain text could not be allocated\n"); + + if (!data->key.len || + !data->key.buf || + (ret = kcapi_cipher_setkey(handle, data->key.buf, data->key.len))) + { + logger(LOGGER_ERR, "sym: setting key failed with error = %d\n", ret); + goto out; + } + + ret = kcapi_cipher_encrypt(handle, + pt.buf, pt.len, + data->iv.buf, + data->data.buf, data->data.len, + KCAPI_ACCESS_SENDMSG); + + /* error only when ret < 0, success in all other cases */ + if(ret > 0) + ret=0; + +out: + if(pt.buf) + free_buf(&pt); + kcapi_cipher_destroy(handle); + return ret; +} + +static int sym_decrypt(struct sym_data *data, flags_t parsed_flags) +{ + int ret = 0; + struct kcapi_handle *handle = NULL; + struct buffer ct; + char cipher[CIPHERMAXNAME]; + + if(!data) + { + logger(LOGGER_ERR, "sym: sym_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + if(sym_cipher(data->cipher, cipher)) + { + logger(LOGGER_ERR, "sym: invalid cipher\n"); + return -EINVAL; + } + + ct.len = data->data.len; + ct.buf = data->data.buf; + + data->data.len = 0; + data->data.buf = NULL; + CKINT_LOG(alloc_buf(ct.len, &data->data), "sym: buffer for cipher text could not be allocated\n"); + + if(kcapi_cipher_init(&handle, cipher, 0)) + { + logger(LOGGER_ERR, "sym: cipher init Failed\n"); + return -EINVAL; + } + + if (!data->key.len || + !data->key.buf || + (ret = kcapi_cipher_setkey(handle, data->key.buf, data->key.len))) + { + logger(LOGGER_ERR, "sym: setting key failed with error = %d\n", ret); + goto out; + } + + ret = kcapi_cipher_decrypt(handle, + ct.buf, ct.len, + data->iv.buf, + data->data.buf, data->data.len, + KCAPI_ACCESS_SENDMSG); + + /* error only when ret < 0, success in all other cases */ + if(ret > 0) + ret = 0; + +out: + if(ct.buf) + free_buf(&ct); + kcapi_cipher_destroy(handle); + return ret; +} + +struct buffer old; +char orig_iv[500]; +int orig_iv_len; + +static int sym_mct_init(struct sym_data *data, flags_t parsed_flags) +{ + int ret=0; + struct kcapi_handle *handle = NULL; + char cipher[CIPHERMAXNAME]; + + if(!data) + { + logger(LOGGER_ERR, "sym: sym_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + if(old.buf) + free_buf(&old); + + old.buf = NULL; + old.len = 0; + + if(sym_cipher(data->cipher, cipher)) + { + logger(LOGGER_ERR, "sym: invalid cipher\n"); + return -EINVAL; + } + + if(kcapi_cipher_init(&handle, cipher, 0)) + { + logger(LOGGER_ERR, "sym: cipher init Failed\n"); + return -EINVAL; + } + + if (!data->key.len || !data->key.buf || + (ret = kcapi_cipher_setkey(handle, data->key.buf, data->key.len))) + { + logger(LOGGER_ERR, "sym: setting key failed with error = %d\n", ret); + kcapi_cipher_destroy(handle); + goto out; + } + + if(data->iv.buf) + memcpy(orig_iv, data->iv.buf, data->iv.len); + + data->priv = (void*)handle; + +out: + return ret; +} + +static int sym_mct_update(struct sym_data *data, flags_t parsed_flags) +{ + int ret=0; + struct kcapi_handle *handle = NULL; + struct buffer in; + size_t origlen = data->data.len; + + if(!data) + { + logger(LOGGER_ERR, "sym: sym_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + handle = (struct kcapi_handle *)(data->priv); + in.len = data->data.len; + in.buf = data->data.buf; + + if(!(old.buf) && (data->iv.len != 0)) + { + CKINT_LOG(alloc_buf(data->data.len, &old), "sym: old buffer could not be allocated\n"); + if(data->iv.buf) + memcpy(old.buf, data->iv.buf, old.len); + } + + data->data.len = 0; + data->data.buf = NULL; + CKINT_LOG(alloc_buf(in.len, &data->data), "sym: data buffer could not be allocated\n"); + + if (parsed_flags & FLAG_OP_ENC) + { + ret = kcapi_cipher_encrypt(handle, + in.buf, in.len, + old.buf, + data->data.buf, data->data.len, + KCAPI_ACCESS_SENDMSG); + if(old.buf && data->data.buf) + memcpy(old.buf, data->data.buf, old.len); + } + else + { + ret = kcapi_cipher_decrypt(handle, + in.buf, in.len, + old.buf, + data->data.buf, data->data.len, + KCAPI_ACCESS_SENDMSG); + if(old.buf && in.buf) + memcpy(old.buf, in.buf, in.len); + } + + if (data->data.len != origlen) + data->data.len = origlen; + +out: + if(in.buf) + free_buf(&in); + return ret; +} + +static int sym_mct_fini(struct sym_data *data, flags_t parsed_flags) +{ + struct kcapi_handle *handle = NULL; + + if(!data) + { + logger(LOGGER_ERR, "sym: sym_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + handle = (struct kcapi_handle *)(data->priv); + + if(handle) + kcapi_cipher_destroy(handle); + + if(old.buf) + free_buf(&old); + + return 0; +} + +static struct sym_backend kcapi_sym = +{ + sym_encrypt, + sym_decrypt, + sym_mct_init, + sym_mct_update, + sym_mct_fini +}; + +ACVP_DEFINE_CONSTRUCTOR(kcapi_sym_backend) +static void kcapi_sym_backend(void) +{ + register_sym_impl(&kcapi_sym); +} + +int sha_mac_cipher(char *cipher, uint64_t acvp_cipher, size_t *len) +{ + switch(acvp_cipher) + { + + case ACVP_HMACSHA1: + strcpy(cipher, "hmac(sha1)"); + *len = 20; + break; + case ACVP_HMACSHA2_224: + strcpy(cipher, "hmac(sha224)"); + *len = 28; + break; + case ACVP_HMACSHA2_256: + strcpy(cipher, "hmac(sha256)"); + *len = 32; + break; + case ACVP_HMACSHA2_384: + strcpy(cipher, "hmac(sha384)"); + *len = 48; + break; + case ACVP_HMACSHA2_512: + strcpy(cipher, "hmac(sha512)"); + *len = 64; + break; + case ACVP_HMACSHA3_224: + strcpy(cipher, "hmac(sha3-224)"); + *len = 28; + break; + case ACVP_HMACSHA3_256: + strcpy(cipher, "hmac(sha3-256)"); + *len = 32; + break; + case ACVP_HMACSHA3_384: + strcpy(cipher, "hmac(sha3-384)"); + *len = 48; + break; + case ACVP_HMACSHA3_512: + strcpy(cipher, "hmac(sha3-512)"); + *len = 64; + break; + case ACVP_AESCMAC: + strcpy(cipher, "cmac(aes)"); + *len=128; + break; + case ACVP_SHA1: + strcpy(cipher, "sha1"); + *len = 20; + break; + case ACVP_SHA224: + strcpy(cipher, "sha224"); + *len = 28; + break; + case ACVP_SHA256: + strcpy(cipher, "sha256"); + *len = 32; + break; + case ACVP_SHA384: + strcpy(cipher, "sha384"); + *len = 48; + break; + case ACVP_SHA512: + strcpy(cipher, "sha512"); + *len = 64; + break; + case ACVP_SHA3_224: + strcpy(cipher, "sha3-224"); + *len = 28; + break; + case ACVP_SHA3_256: + strcpy(cipher, "sha3-256"); + *len = 32; + break; + case ACVP_SHA3_384: + strcpy(cipher, "sha3-384"); + *len = 48; + break; + case ACVP_SHA3_512: + strcpy(cipher, "sha3-512"); + *len = 64; + break; + default: + return -EINVAL; + } + return 0; +} + +static int sha_generate(struct sha_data *data, flags_t parsed_flags) +{ + struct kcapi_handle *handle = NULL; + int ret = 0; + BUFFER_INIT(msg_p); + size_t len = 0; + + if(!data) + { + logger(LOGGER_ERR, "sha: sha_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + char cipher[CIPHERMAXNAME]; + int rc = 0; + + if(sha_mac_cipher(cipher, data->cipher, &len)) + { + return -EINVAL; + } + + CKINT(sha_ldt_helper(data, &msg_p)); + if (kcapi_md_init(&handle, cipher, 0)) + { + logger(LOGGER_ERR, "sha: allocation of hash %s failed\n", cipher); + return 1; + } + + CKINT_LOG(alloc_buf(len, &data->mac), "sha: mac buffer could not be allocated\n"); + rc = kcapi_md_digest(handle, msg_p.buf, msg_p.len, data->mac.buf, data->mac.len); + + if (rc < 0) + { + logger(LOGGER_ERR, "sha: message digest generation failed: %d\n", rc); + sha_ldt_clear_buf(data, &msg_p); + kcapi_md_destroy(handle); + return 1; + } + +out: + sha_ldt_clear_buf(data, &msg_p); + kcapi_md_destroy(handle); + return 0; +} + +static struct sha_backend kcapi_sha = +{ + sha_generate, + NULL +}; +ACVP_DEFINE_CONSTRUCTOR(kcapi_sha_backend) +static void kcapi_sha_backend(void) +{ + register_sha_impl(&kcapi_sha); +} + +static int mac_generate(struct hmac_data *data, flags_t parsed_flags) +{ + struct kcapi_handle *handle = NULL; + int ret = 0; + size_t len = 0; + + if(!data) + { + logger(LOGGER_ERR,"mac: hmac_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + switch(data->cipher) { + case ACVP_AESCMAC: + case ACVP_TDESCMAC: + break; + default: + break; + } + +#define MAXMD 64 + uint8_t md[MAXMD]; +#define MAXMDHEX (MAXMD * 2 + 1) + char mdhex[MAXMDHEX]; + char cipher[CIPHERMAXNAME]; + int rc = 0; + + if(sha_mac_cipher(cipher, data->cipher, &len)) + { + return -EINVAL; + } + + memset(md, 0, MAXMD); + memset(mdhex, 0, MAXMDHEX); + + if (kcapi_md_init(&handle, cipher, 0)) + { + logger(LOGGER_ERR, "mac: allocation of hash %s failed\n", cipher); + return 1; + } + + CKINT_LOG(alloc_buf(len, &data->mac), "mac: mac buffer could not be allocated\n"); + + if (data->key.len) + { + if ((ret = kcapi_md_setkey(handle, data->key.buf, data->key.len))) + { + logger(LOGGER_ERR, "mac: setting key failed with error = %d\n", ret); + kcapi_md_destroy(handle); + return -EINVAL; + } + } + + rc = kcapi_md_digest(handle, data->msg.buf, data->msg.len, md, MAXMD); + if (rc < 0) + { + logger(LOGGER_ERR, "mac: message digest generation failed\n"); + kcapi_md_destroy(handle); + return 1; + } + + bin2hex(md, rc, mdhex, data->mac.len, 0); + memcpy(data->mac.buf, md, data->mac.len); + data->mac.len = (data->maclen)/8; + +out: + kcapi_md_destroy(handle); + return 0; +} + +static struct hmac_backend kcapi_mac = +{ + mac_generate, +}; +ACVP_DEFINE_CONSTRUCTOR(kcapi_mac_backend) +static void kcapi_mac_backend(void) +{ + register_hmac_impl(&kcapi_mac); +} + +static int ecdsa_keygen(struct ecdsa_keygen_extra_data *data, flags_t parsed_flags) +{ + if(!data) + { + logger(LOGGER_ERR, "ecdsa: ecdsa_keygen_extra_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + struct kcapi_handle *handle = NULL; + struct kcapi_handle *ecdh = NULL; + struct buffer key; + size_t dlen, qxlen, qylen; + int ret=0; + char *curve_str = NULL; + int curve_num = 0; + int curve_id = 0; + + if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP384) + { + curve_str = ECDH_CURVE_STR_P384; + curve_num = ECDH_CURVE_NUM_P384; + curve_id = ECDH_CURVE_ID_P384; + } + else if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP256) + { + curve_str = ECDH_CURVE_STR_P256; + curve_num = ECDH_CURVE_NUM_P256; + curve_id = ECDH_CURVE_ID_P256; + } + else if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP192) + { + curve_str = ECDH_CURVE_STR_P192; + curve_num = ECDH_CURVE_NUM_P192; + curve_id = ECDH_CURVE_ID_P192; + } + else + { + logger(LOGGER_ERR, "ecdsa: curve is not supported\n"); + return -EINVAL; + } + + key.len = 0; + key.buf = NULL; + + if (kcapi_ecc_init(&handle, curve_str)) + { + ret = -EINVAL; + logger(LOGGER_ERR, "ecdsa: allocation of cipher failed\n"); + goto out; + } + + if(curve_num == 384) + ecdsa_get_bufferlen(ACVP_NISTP384, &dlen, &qxlen, &qylen); + else + ecdsa_get_bufferlen(ACVP_NISTP256, &dlen, &qxlen, &qylen); + + CKINT_LOG(alloc_buf(qxlen, &data->Qx), "ecdsa: Qx could not be allocated\n"); + CKINT_LOG(alloc_buf(qylen, &data->Qy), "ecdsa: Qy could not be allocated\n"); + CKINT_LOG(alloc_buf(dlen, &data->d), "ecdaa: private Key buffer could not be allocated\n"); + ret = kcapi_ecc_keygen(handle, curve_num, data->d.buf, data->d.len, data->Qx.buf, + data->Qx.len, data->Qy.buf, data->Qy.len); + if (ret < 0) + { + logger(LOGGER_ERR, "ecdsa: key generation failed with error = %d\n", ret); + goto out; + } + + if (kcapi_kpp_init(&ecdh, curve_str, 0)) + { + ret = -EINVAL; + logger(LOGGER_ERR, "ecdh: allocation of cipher failed\n"); + goto out; + } + + ret = kcapi_kpp_ecdh_setcurve(ecdh, curve_id); + + if (ret < 0) + { + logger(LOGGER_ERR, "ecdh: curve setting failed with error: %d\n", ret); + goto out; + } + + ret = kcapi_kpp_setkey(ecdh, data->d.buf, data->d.len); + if (ret < 0) + { + logger(LOGGER_ERR, "ecdh: key setting failed with error: %d\n", ret); + goto out; + } + + CKINT_LOG(alloc_buf(qxlen + qylen, &key), "ecdh: local public Key buffer could not be allocated\n"); + + ret = kcapi_kpp_keygen(ecdh, key.buf, key.len, 0); + if(ret < 0) + { + ret = -EINVAL; + logger(LOGGER_ERR, "ecdsa: public keygen failed\n"); + goto out; + } + else if(memcmp(data->Qx.buf, key.buf, qxlen) == 0 && memcmp(data->Qy.buf, key.buf+qxlen, qylen) == 0) + { + logger(LOGGER_DEBUG, "ecdsa: public keygen success\n"); + } + else + { + logger(LOGGER_ERR, "ecdsa: public keygen failed\n"); + ret = -EINVAL; + goto out; + } + +out: + kcapi_kpp_destroy(ecdh); + kcapi_ecc_destroy(handle); + if(key.buf) + free_buf(&key); + return ret; +} + +static int ecdsa_keyver(struct ecdsa_pkvver_data *data, flags_t parsed_flags) +{ + if(!data) + { + logger(LOGGER_ERR, "ecdsa: ecdsa_pkvver_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + + struct kcapi_handle *handle = NULL; + int ret =0 , re; + char *curve_str = NULL; + int curve_num = 0; + (void) parsed_flags; + + if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP384) + { + curve_str = ECDH_CURVE_STR_P384; + curve_num = ECDH_CURVE_NUM_P384; + } + else if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP256) + { + curve_str = ECDH_CURVE_STR_P256; + curve_num = ECDH_CURVE_NUM_P256; + } + else if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP192) + { + curve_str = ECDH_CURVE_STR_P192; + curve_num = ECDH_CURVE_NUM_P192; + } + else + { + logger(LOGGER_ERR, "ecdsa: curve is not supported.\n"); + return -EINVAL; + } + + if (kcapi_ecc_init(&handle, curve_str)) + { + logger(LOGGER_ERR, "ecdsa: allocation of cipher failed\n"); + ret = -EINVAL; + goto out; + } + re = kcapi_ecc_verify(handle, curve_num, data->Qx.buf, + data->Qx.len, data->Qy.buf, data->Qy.len); + if(re < 0) + { + logger(LOGGER_ERR, "ecdsa: public keyver failed\n"); + data->keyver_success = 0; + } + else + { + logger(LOGGER_DEBUG, "ecdsa: public keyVer success\n"); + data->keyver_success = 1; + } +out: + kcapi_ecc_destroy(handle); + return ret; +} + +static int ecdsa_sigver(struct ecdsa_sigver_data *data, flags_t parsed_flags) +{ + if(!data) + { + logger(LOGGER_ERR, "ecdsa: ecdsa_sigver_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + + struct kcapi_handle *handle = NULL, *hash_handle = NULL; + int ret = 0, rc = 0; + size_t len = 0; + char *curve_str = NULL; + (void) parsed_flags; + + if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP384) + { + curve_str = "ecdsa-nist-p384"; + } + else if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP256) + { + curve_str = "ecdsa-nist-p256"; + } + else + { + logger(LOGGER_ERR, "ecdsa: curve not FIPS supported.\n"); + return -EINVAL; + } + + if(!data->component) + { + /* We need to generate the msg hash */ + struct buffer msg = data->msg; + data->msg.buf = NULL; + data->msg.len = 0; + char cipher[CIPHERMAXNAME]; + + if(sha_mac_cipher(cipher, data->cipher & ACVP_HASHMASK, &len)) + { + return -EINVAL; + } + + if (kcapi_md_init(&hash_handle, cipher, 0)) + { + logger(LOGGER_ERR, "ecdsa: allocation of hash %s failed\n", cipher); + return 1; + } + + CKINT_LOG(alloc_buf(len, &data->msg), "ecdsa: msg hash buffer could not be allocated\n"); + rc = kcapi_md_digest(hash_handle, msg.buf, msg.len, data->msg.buf, data->msg.len); + if (rc < 0) + { + logger(LOGGER_ERR, "ecdsa: message digest generation failed\n"); + kcapi_md_destroy(hash_handle); + return 1; + } + + kcapi_md_destroy(hash_handle); + if(msg.buf) + free_buf(&msg); + } + + if (kcapi_akcipher_init(&handle, curve_str, 0)) + { + logger(LOGGER_ERR, "ecdsa: allocation of %s cipher failed\n", curve_str); + return -EFAULT; + } + + /* Encoding and setting public key */ + struct buffer pk; + unsigned char *ptr; + pk.len = 0; + pk.buf = NULL; + + CKINT_LOG(alloc_buf(data->Qx.len + data->Qy.len + 1, &pk), "ecdsa: public key buffer could not be allocated\n"); + ptr = (&pk)->buf; + + ptr[0] = 0x04; + ptr = ptr + 1; + + if(data->Qx.buf) + memcpy(ptr, data->Qx.buf, data->Qx.len); + ptr = ptr + data->Qx.len; + + if(data->Qy.buf) + memcpy(ptr, data->Qy.buf, data->Qy.len); + + ret = kcapi_akcipher_setpubkey(handle, pk.buf, pk.len); + if (ret <= 0) + { + logger(LOGGER_ERR, "ecdsa: asymmetric cipher set public key failed\n"); + ret = -EFAULT; + goto out; + } + + /* BER Encoding signature */ + struct buffer in; + struct buffer dgst; + unsigned short int rlen; + unsigned short int slen; + unsigned short int total = 0, extra; + unsigned char *tmp; + + in.len = 0; + in.buf = NULL; + dgst.len = 0; + dgst.buf = NULL; + ptr = NULL; + + CKINT_LOG(alloc_buf(rc, &dgst), "ecdsa: dgst buffer could not be allocated\n"); + + rlen = data->R.len; + slen = data->S.len; + + /* + Metadata for complete key = 0x30 and sum of length of all fields + + BER encoding the length of any field + actual length of a field = 0x02 and len + + if length <= 127 - 1 byte (actual length) + if length > 127 and length <= 255 - 2 bytes (Byte1 = 0x81, Byte2 = actual length) + if length > 255 - 3 bytes (Byte1 = 0x82, Byte2 and Byte3 = actual length) + */ + + + total = rlen; + if(rlen <= 127) + total = total + 2; + else if(rlen >= 128 && rlen <= 255) + total = total + 3; + else + total = total + 4; + + total = total + slen; + if(slen <= 127) + total = total + 2; + else if(slen >= 128 && slen <= 255) + total = total + 3; + else + total = total + 4; + + if(total <= 127) + extra = 2; + else if(total >= 128 && total <= 255) + extra = 3; + else + extra = 4; + + CKINT_LOG(alloc_buf(total + extra + data->msg.len + 1, &in), "ecdsa: in buffer could not be allocated\n"); + ptr = (&in)->buf; + ptr[0] = 0x30; + if(extra == 2) + memcpy(ptr + 1, &total, 1); + if(extra == 3) + { + ptr[1] = 0x81; + memcpy(ptr + 2, &total, 1); + } + if(extra == 4) + { + tmp =(unsigned char*) (&total); + ptr[1] = 0x82; + memcpy(ptr + 2, tmp + 1, 1); + memcpy(ptr + 3, tmp , 1); + } + + ptr = ptr + extra; + ptr = write_field(ptr, data->R.buf, rlen); + ptr = write_field(ptr, data->S.buf, slen); + + if(data->msg.buf) + memcpy(ptr + 1, data->msg.buf, data->msg.len); + + ret = kcapi_akcipher_verify(handle, in.buf, in.len, dgst.buf, dgst.len, 0); + + if(ret < 0) + { + data->sigver_success = 0; + logger(LOGGER_ERR, "ecdsa: SigVer Failed\n"); + } + else + { + data->sigver_success = 1; + logger(LOGGER_DEBUG, "ecdsa: SigVer Success\n"); + } + ret = 0; + +out: + kcapi_akcipher_destroy(handle); + if(in.buf) + free_buf(&in); + if(dgst.buf) + free_buf(&dgst); + if(pk.buf) + free_buf(&pk); + return ret; +} + +static struct ecdsa_backend kcapi_ecdsa = +{ + NULL, + ecdsa_keygen, + ecdsa_keyver, + NULL, + ecdsa_sigver, + NULL, + NULL +}; +ACVP_DEFINE_CONSTRUCTOR(kcapi_ecdsa_backend) +static void kcapi_ecdsa_backend(void) +{ + register_ecdsa_impl(&kcapi_ecdsa); +} + +static int gcm_encrypt(struct aead_data *data, flags_t parsed_flags) +{ + struct kcapi_handle *handle = NULL; + char cipher[CIPHERMAXNAME]; + uint8_t *buf = NULL, *newiv = NULL; + uint32_t outbuflen = 0, inbuflen = 0; + uint32_t newivlen = GCM_IV_SIZE; + uint8_t *assoc = NULL, *o_data = NULL, *tag = NULL; + size_t assoclen = 0, datalen = 0, taglen = 0; + int ret = -EINVAL; + + if(!data) + { + logger(LOGGER_ERR, "aead_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + if(sym_cipher(data->cipher,cipher)) + { + logger(LOGGER_ERR, "sym: invalid cipher\n"); + return -EINVAL; + } + + taglen = data->taglen/8; + datalen = data->data.len; + assoclen = data->assoc.len; + + /* Allocation of aead cipher handle */ + if (kcapi_aead_init(&handle, cipher, 0)) + { + logger(LOGGER_ERR, "gcm: allocation of cipher failed\n"); + return -EFAULT; + } + + /* Setting tag value */ + if (kcapi_aead_settaglen(handle, taglen)) + { + logger(LOGGER_ERR, "gcm: setting of authentication tag length failed\n"); + goto out; + } + + /* Setting length of associated data */ + kcapi_aead_setassoclen(handle, assoclen); + + /* Padding IV to a size of 12 bytes */ + ret = kcapi_pad_iv(handle, data->iv.buf, data->iv.len, &newiv, &newivlen); + if (ret) + { + logger(LOGGER_ERR, "gcm: iv padding failed\n"); + goto out; + } + + ret = -ENOMEM; + outbuflen = kcapi_aead_outbuflen_enc(handle, datalen, assoclen, taglen); + inbuflen = kcapi_aead_inbuflen_enc(handle, datalen, assoclen, taglen); + buf = calloc(1, outbuflen); + if (!buf) + { + logger(LOGGER_ERR, "gcm: allocation of buf failed\n"); + goto out; + } + + kcapi_aead_getdata_output(handle, buf, outbuflen, 1, + &assoc, &assoclen, + &o_data, &datalen, + &tag, &taglen); + + /* Seting key */ + if (!data->key.len || !data->key.buf || kcapi_aead_setkey(handle, data->key.buf, data->key.len)) + { + logger(LOGGER_ERR, "gcm: key setting failed\n"); + goto out; + } + + if(data->assoc.buf) + memcpy(assoc, data->assoc.buf, assoclen); + + if(data->data.buf) + memcpy(o_data, data->data.buf, datalen); + + /* Performing encryption */ + ret = kcapi_aead_encrypt(handle, buf, inbuflen, + newiv, + buf, outbuflen, + KCAPI_ACCESS_SENDMSG); + if (ret < 0) + { + logger(LOGGER_ERR, "gcm: cipher operation of buffer failed: %d %d\n", errno, ret); + goto out; + } + else if ((uint32_t)ret != outbuflen) + { + logger(LOGGER_ERR, "gcm: received data length %d does not match expected length %u\n", ret, outbuflen); + goto out; + } + + free_buf(&(data->iv)); + + if(data->data.buf) + free_buf(&(data->data)); + if(data->tag.buf) + free_buf(&(data->tag)); + + CKINT_LOG(alloc_buf(datalen, &data->data), "gcm: ct buffer could not be allocated\n"); + + if(o_data) + memcpy(data->data.buf, o_data, datalen); + + CKINT_LOG(alloc_buf(taglen, &data->tag), "gcm: tag buffer could not be allocated\n"); + + if(tag) + memcpy(data->tag.buf, tag, taglen); +out: + kcapi_aead_destroy(handle); + if (newiv) + free(newiv); + if (buf) + free(buf); + return ret; +} + +static int gcm_decrypt(struct aead_data *data, flags_t parsed_flags) +{ + struct kcapi_handle *handle = NULL; + char cipher[CIPHERMAXNAME]; + uint8_t *buf = NULL, *newiv = NULL;; + uint32_t outbuflen = 0, inbuflen = 0; + /* Only IV size of 12 bytes is supported by the kernel */ + uint32_t newivlen = GCM_IV_SIZE; + uint8_t *assoc = NULL, *o_data = NULL, *tag = NULL; + size_t assoclen = 0, datalen = 0, taglen = 0; + int ret = -EINVAL; + + if(!data) + { + logger(LOGGER_ERR, "gcm: aead_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + if(sym_cipher(data->cipher,cipher)) + { + logger(LOGGER_ERR, "sym: invalid cipher\n"); + return -EINVAL; + } + + assoclen = data->assoc.len; + datalen = data->data.len; + taglen = data->tag.len; + data->integrity_error = 0; + + if (!data->ivlen || !data->iv.buf) + return -EINVAL; + + /* Allocation of aead cipher handle */ + if (kcapi_aead_init(&handle, cipher, 0)) + { + logger(LOGGER_ERR, "gcm: allocation of cipher failed\n"); + return -EFAULT; + } + + /* Setting tag value */ + if (kcapi_aead_settaglen(handle, taglen)) + { + logger(LOGGER_ERR, "gcm: setting of authentication tag length failed\n"); + goto out; + } + + /* Setting length of associated data */ + kcapi_aead_setassoclen(handle, assoclen); + + /* Padding IV to a size of 12 bytes */ + ret = kcapi_pad_iv(handle, data->iv.buf, data->iv.len, &newiv, &newivlen); + if (ret) + { + logger(LOGGER_ERR, "gcm: iv padding failed\n"); + goto out; + } + + ret = -ENOMEM; + outbuflen = kcapi_aead_outbuflen_dec(handle, datalen, assoclen, taglen); + inbuflen = kcapi_aead_inbuflen_dec(handle, datalen, assoclen, taglen); + + buf = calloc(1, inbuflen); + if (!buf) + { + logger(LOGGER_ERR, "gcm: allocation of buf failed\n"); + goto out; + } + + kcapi_aead_getdata_input(handle, buf, inbuflen, 0, + &assoc, &assoclen, &o_data, &datalen, + &tag, &taglen); + + /* Set key */ + if (!data->key.len || + !data->key.buf || + kcapi_aead_setkey(handle, data->key.buf, data->key.len)) + { + logger(LOGGER_ERR, "gcm: symmetric cipher setkey failed\n"); + goto out; + } + + if(data->assoc.buf) + memcpy(assoc, data->assoc.buf, assoclen); + if(data->data.buf) + memcpy(o_data, data->data.buf, datalen); + if (data->tag.buf) + memcpy(tag, data->tag.buf, taglen); + + /* Performing decryption */ + ret = kcapi_aead_decrypt(handle, buf, inbuflen, + newiv, + buf, outbuflen, + KCAPI_ACCESS_SENDMSG); + + if (ret < 0 && ret != -EBADMSG) + { + logger(LOGGER_ERR, "gcm: cipher operation of buffer failed: %d %d\n", errno, ret); + goto out; + } + else if (ret == -EBADMSG) + { + logger(LOGGER_DEBUG, "gcm: EBADMSG\n"); + data->integrity_error = 1; + ret = 0; + goto out; + } + else if ((uint32_t)ret != outbuflen) + { + logger(LOGGER_ERR, "gcm: received data length %d does not match expected length %u\n", ret, outbuflen); + goto out; + } + + if(data->iv.buf) + free_buf(&(data->iv)); + if(data->data.buf) + free_buf(&(data->data)); + if(data->tag.buf) + free_buf(&(data->tag)); + + CKINT_LOG(alloc_buf(datalen, &data->data), "gcm: pt buffer could not be allocated\n"); + if(o_data) + memcpy(data->data.buf, o_data, datalen); + +out: + kcapi_aead_destroy(handle); + if (newiv) + free(newiv); + if (buf) + free(buf); + return ret; +} + +static int ccm_encrypt(struct aead_data *data, flags_t parsed_flags) +{ + struct kcapi_handle *handle = NULL; + char cipher[CIPHERMAXNAME]; + uint8_t *outbuf = NULL, *newiv = NULL; + uint32_t outbuflen = 0, inbuflen = 0; + /* Only IV size of 16 bytes is supported by the kernel */ + uint32_t newivlen = CCM_IV_SIZE; + uint8_t *assoc = NULL, *o_data = NULL, *tag = NULL; + size_t assoclen = 0, datalen = 0, taglen = 0; + int ret = -EINVAL; + + if(!data) + { + logger(LOGGER_ERR, "ccm: aead_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + if(sym_cipher(data->cipher,cipher)) + { + logger(LOGGER_ERR, "sym: invalid cipher\n"); + return -EINVAL; + } + + taglen = data->taglen/8; + datalen = data->data.len; + assoclen = data->assoc.len; + + if (!data->ivlen || !data->iv.buf) + return -EINVAL; + + /* Allocation of aead cipher handle */ + if (kcapi_aead_init(&handle, cipher, 0)) + { + logger(LOGGER_ERR, "ccm: allocation of cipher failed\n"); + return -EFAULT; + } + + /* Setting tag value */ + if (kcapi_aead_settaglen(handle, taglen)) + { + logger(LOGGER_ERR, "ccm: setting of authentication tag length failed\n"); + goto out; + } + + /* Setting length of associated data */ + kcapi_aead_setassoclen(handle, assoclen); + + /* Convert CCM nonce into IV of size of 16 bytes */ + ret = kcapi_aead_ccm_nonce_to_iv(data->iv.buf, data->iv.len, &newiv, &newivlen); + if (ret) + { + logger(LOGGER_ERR, "ccm: nonce conversion to IV failed\n"); + goto out; + } + + ret = -ENOMEM; + outbuflen = kcapi_aead_outbuflen_enc(handle, datalen, assoclen, taglen); + inbuflen = kcapi_aead_inbuflen_enc(handle, datalen, assoclen, taglen); + outbuf = calloc(1, outbuflen); + if (!outbuf) + { + logger(LOGGER_ERR, "ccm: allocation of buf failed\n"); + goto out; + } + + kcapi_aead_getdata_output(handle, outbuf, outbuflen, 1, + &assoc, &assoclen, &o_data, &datalen, + &tag, &taglen); + + /* Seting key */ + if (!data->key.len || + !data->key.buf || + kcapi_aead_setkey(handle, data->key.buf, data->key.len)) + { + logger(LOGGER_ERR, "ccm: symmetric cipher setkey failed\n"); + goto out; + } + + if(data->assoc.buf) + memcpy(assoc, data->assoc.buf, assoclen); + if(data->data.buf) + memcpy(o_data, data->data.buf, datalen); + + /* Performing encryption */ + ret = kcapi_aead_encrypt(handle, outbuf, inbuflen, + newiv, + outbuf, outbuflen, + KCAPI_ACCESS_SENDMSG); + if (ret < 0) + { + logger(LOGGER_ERR, "ccm: cipher operation of buffer failed: %d %d\n", errno, ret); + goto out; + } + else if ((uint32_t)ret != outbuflen) + { + logger(LOGGER_ERR, "ccm: received data length %d does not match expected length %u\n", ret, outbuflen); + goto out; + } + + if(data->iv.buf) + free_buf(&(data->iv)); + if(data->data.buf) + free_buf(&(data->data)); + if(data->tag.buf) + free_buf(&(data->tag)); + + CKINT_LOG(alloc_buf(datalen, &data->data), "ccm: ct buffer could not be allocated\n"); + + if(o_data) + memcpy(data->data.buf, o_data, datalen); + + CKINT_LOG(alloc_buf(taglen, &data->tag), "ccm: tag buffer could not be allocated\n"); + + if(tag) + memcpy(data->tag.buf, tag, taglen); +out: + kcapi_aead_destroy(handle); + if (newiv) + free(newiv); + if (outbuf) + free(outbuf); + return ret; +} + + +static int ccm_decrypt(struct aead_data *data, flags_t parsed_flags) +{ + struct kcapi_handle *handle = NULL; + char cipher[CIPHERMAXNAME]; + uint8_t *buf = NULL, *newiv = NULL; + uint32_t outbuflen = 0, inbuflen = 0; + /* Only IV size of 16 bytes is supported by the kernel */ + uint32_t newivlen = CCM_IV_SIZE; + uint8_t *assoc = NULL, *o_data = NULL, *tag = NULL; + size_t assoclen = 0, datalen = 0, taglen = 0; + int ret = -EINVAL; + + if(!data) + { + logger(LOGGER_ERR, "ccm: aead_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + if(sym_cipher(data->cipher,cipher)) + { + logger(LOGGER_ERR, "sym: invalid cipher\n"); + return -EINVAL; + } + + assoclen = data->assoc.len; + datalen = data->data.len; + taglen = data->tag.len; + + data->integrity_error = 0; + + if (!data->ivlen || !data->iv.buf) + return -EINVAL; + + /* Allocation of aead cipher handle */ + if (kcapi_aead_init(&handle, cipher, 0)) + { + logger(LOGGER_ERR, "ccm: allocation of cipher failed\n"); + return -EFAULT; + } + + /* Setting tag value */ + if (kcapi_aead_settaglen(handle, taglen)) + { + logger(LOGGER_ERR, "ccm: Setting of authentication tag length failed\n"); + goto out; + } + + /* Setting length of associated data */ + kcapi_aead_setassoclen(handle, assoclen); + + /* Converting CCM nonce into an IV of size 16 bytes */ + ret = kcapi_aead_ccm_nonce_to_iv(data->iv.buf, data->iv.len, &newiv, &newivlen); + if (ret) + { + logger(LOGGER_ERR, "ccm: nonce conversion to IV failed\n"); + goto out; + } + + ret = -ENOMEM; + outbuflen = kcapi_aead_outbuflen_dec(handle, datalen, assoclen, taglen); + inbuflen = kcapi_aead_inbuflen_dec(handle, datalen, assoclen, taglen); + buf = calloc(1, inbuflen); + if (!buf) + { + logger(LOGGER_ERR, "ccm: allocation of buf failed\n"); + goto out; + } + + kcapi_aead_getdata_input(handle, buf, inbuflen, 0, + &assoc, &assoclen, &o_data, &datalen, + &tag, &taglen); + + /* Set key */ + if (!data->key.len || + !data->key.buf || + kcapi_aead_setkey(handle, data->key.buf, data->key.len)) + { + logger(LOGGER_ERR, "ccm: symmetric cipher setkey failed\n"); + goto out; + } + + if(data->assoc.buf) + memcpy(assoc, data->assoc.buf, assoclen); + if(data->data.buf) + memcpy(o_data, data->data.buf, datalen); + if(data->tag.buf) + memcpy(tag, data->tag.buf, taglen); + + /* Performing decryption */ + ret = kcapi_aead_decrypt(handle, buf, inbuflen, + newiv, + buf, outbuflen, + KCAPI_ACCESS_SENDMSG); + if (ret < 0 && ret != -EBADMSG) + { + logger(LOGGER_ERR, "ccm: cipher operation of buffer failed: %d %d\n", errno, ret); + goto out; + } + + if (ret == -EBADMSG) + { + logger(LOGGER_DEBUG, "ccm: EBADMSG\n"); + data->integrity_error = 1; + ret = 0; + goto out; + } + else if ((uint32_t)ret != outbuflen) + { + logger(LOGGER_ERR, "ccm: received data length %d does not match expected length %u\n", ret, outbuflen); + goto out; + } + + if(data->iv.buf) + free_buf(&(data->iv)); + if(data->data.buf) + free_buf(&(data->data)); + + CKINT_LOG(alloc_buf(datalen, &data->data), "ccm: pt buffer could not be allocated\n"); + + if(o_data) + memcpy(data->data.buf, o_data, datalen); + +out: + kcapi_aead_destroy(handle); + if (newiv) + free(newiv); + if (buf) + free(buf); + return ret; +} + +static struct aead_backend kcapi_aead = +{ + gcm_encrypt, + gcm_decrypt, + ccm_encrypt, + ccm_decrypt +}; +ACVP_DEFINE_CONSTRUCTOR(kcapi_aead_backend) +static void kcapi_aead_backend(void) +{ + register_aead_impl(&kcapi_aead); +} + +static int ecdh_ss_ver(struct ecdh_ss_ver_data *data, flags_t parsed_flags) +{ + struct kcapi_handle *handle = NULL; + int ret = 0; + struct buffer key; //IUT Public Key + struct buffer rkey; //Remote Public Key + struct buffer secret; //Shared Secret + char *curve; + int curve_id, ss_key_len; + + if(!data) + { + logger(LOGGER_ERR, "ecdh: ecdh_ss_ver_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + key.len = 0; + key.buf = NULL; + rkey.len = 0; + rkey.buf = NULL; + secret.len = 0; + secret.buf = NULL; + + if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP384) + { + curve = ECDH_CURVE_STR_P384; + curve_id = ECDH_CURVE_ID_P384; + ss_key_len = ECDH_SS_KEYLEN_P384; + } + else if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP256) + { + curve = ECDH_CURVE_STR_P256; + curve_id = ECDH_CURVE_ID_P256; + ss_key_len = ECDH_SS_KEYLEN_P256; + } + else if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP192) + { + curve = ECDH_CURVE_STR_P192; + curve_id = ECDH_CURVE_ID_P192; + ss_key_len = ECDH_SS_KEYLEN_P192; + } + else + { + logger(LOGGER_ERR, "ecdh: curve not supported\n"); + return -EINVAL; + } + + if (kcapi_kpp_init(&handle, curve, 0)) + { + ret = -EINVAL; + logger(LOGGER_ERR, "ecdh: allocation of cipher failed\n"); + goto out1; + } + + ret = kcapi_kpp_ecdh_setcurve(handle, curve_id); + if (ret < 0) + { + logger(LOGGER_ERR, "ecdh: setting ecdh curve failed with error: %d\n", ret); + goto out1; + } + + ret = kcapi_kpp_setkey(handle, data->privloc.buf, data->privloc.len); + if (ret < 0) + { + logger(LOGGER_ERR, "ecdh: kernel keys generation failed with error: %d\n", ret); + goto out; + } + + CKINT_LOG(alloc_buf(data->Qxrem.len + data->Qyrem.len, &key), "ecdh: local pub Key buffer could not be allocated\n"); + ret = kcapi_kpp_keygen(handle, key.buf, key.len, 0); + if(ret < 0) + { + logger(LOGGER_ERR, "ecdh: public keygen failed\n"); + goto out; + } + if(memcmp(data->Qxloc.buf, key.buf, data->Qxrem.len)) + { + logger(LOGGER_ERR, "ecdh: key not matching\n"); + data->validity_success=0; + goto out; + } + if(memcmp(data->Qyloc.buf, key.buf + data->Qxrem.len, data->Qyrem.len)) + { + logger(LOGGER_ERR, "ecdh: key not matching\n"); + data->validity_success=0; + goto out; + } + + CKINT_LOG(alloc_buf(data->Qxrem.len + data->Qyrem.len, &rkey), "ecdh: remote key buffer could not be allocated\n"); + + if(data->Qxrem.buf) + memcpy(rkey.buf, data->Qxrem.buf, data->Qxrem.len); + + if(data->Qyrem.buf) + memcpy(rkey.buf + data->Qxrem.len, data->Qyrem.buf, data->Qyrem.len); + + CKINT_LOG(alloc_buf(ss_key_len * 2, &secret), "ecdh: shared secret buffer could not be allocated\n"); + ret = kcapi_kpp_ssgen(handle, rkey.buf, rkey.len, secret.buf, ss_key_len * 2, 0); + if(ret < 0) + { + logger(LOGGER_ERR, "ecdh: ssgen failed\n"); + goto out; + } + + if(memcmp(data->hashzz.buf, secret.buf, ss_key_len)) + { + logger(LOGGER_ERR, "ecdh: ssver failed\n"); + data->validity_success=0; + } + else + { + data->validity_success=1; + } +out: + if(key.buf) + free_buf(&key); + if(rkey.buf) + free_buf(&rkey); + if(secret.buf) + free_buf(&secret); +out1: + kcapi_kpp_destroy(handle); + return ret; +} + +static int ecdh_ss(struct ecdh_ss_data *data, flags_t parsed_flags) +{ + struct kcapi_handle *handle = NULL; + int ret = 0; + char *curve; + int curve_id, ss_key_len; + struct buffer key; //IUT Pub Key + struct buffer rkey; //Remote Pub Key + struct buffer pkey; //Private Key + struct buffer secret; //Shared Secret + + if(!data) + { + logger(LOGGER_ERR, "ecdh: ecdh_ss_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + key.len = 0; + key.buf = NULL; + pkey.len = 0; + pkey.buf = NULL; + rkey.len = 0; + rkey.buf = NULL; + secret.len = 0; + secret.buf = NULL; + + if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP384) + { + curve = ECDH_CURVE_STR_P384; + curve_id = ECDH_CURVE_ID_P384; + ss_key_len = ECDH_SS_KEYLEN_P384; + } + else if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP256) + { + curve = ECDH_CURVE_STR_P256; + curve_id = ECDH_CURVE_ID_P256; + ss_key_len = ECDH_SS_KEYLEN_P256; + } + else if((data->cipher & ACVP_CURVEMASK) == ACVP_NISTP192) + { + curve = ECDH_CURVE_STR_P192; + curve_id = ECDH_CURVE_ID_P192; + ss_key_len = ECDH_SS_KEYLEN_P192; + } + else + { + logger(LOGGER_ERR, "ecdh: curve not supported\n"); + return -EINVAL; + } + + if (kcapi_kpp_init(&handle, curve, 0)) + { + ret = -EINVAL; + logger(LOGGER_ERR, "ecdh: allocation of cipher failed\n"); + goto out1; + } + + ret = kcapi_kpp_ecdh_setcurve(handle, curve_id); + if (ret < 0) + { + logger(LOGGER_ERR, "ecdh: setting ecdh curve failed: %d\n", ret); + goto out1; + } + + CKINT_LOG(alloc_buf(ss_key_len, &pkey), "ecdh: private key buffer could not be allocated\n"); + ret = kcapi_rng_get_bytes(pkey.buf, ss_key_len); + if (ret < 0) + { + logger(LOGGER_ERR, "ecdh: get RNG failed with error: %d\n", ret); + goto out; + } + + ret = kcapi_kpp_setkey(handle, pkey.buf, ss_key_len); + if (ret < 0) + { + logger(LOGGER_ERR, "ecdh: private key setting failed with error: %d\n", ret); + goto out; + } + + CKINT_LOG(alloc_buf(data->Qxrem.len + data->Qyrem.len, &key), "ecdh: local public key buffer could not be allocated\n"); + ret = kcapi_kpp_keygen(handle, key.buf, key.len, 0); + if(ret<0) + { + logger(LOGGER_ERR, "ecdh: public keygen failed\n"); + goto out; + } + + CKINT_LOG(alloc_buf(data->Qxrem.len , &data->Qxloc), "ecdh: local x key buffer could not be allocated\n"); + CKINT_LOG(alloc_buf(data->Qyrem.len , &data->Qyloc), "ecdh: local y key buffer could not be allocated\n"); + + if(key.buf) + memcpy(data->Qxloc.buf, key.buf, data->Qxrem.len); + + if(key.buf) + memcpy(data->Qyloc.buf, key.buf + data->Qxrem.len, data->Qyrem.len); + + CKINT_LOG(alloc_buf(data->Qxrem.len + data->Qyrem.len, &rkey), "ecdh: remote key buffer could not be allocated\n"); + + if(data->Qxrem.buf) + memcpy(rkey.buf, data->Qxrem.buf, data->Qxrem.len); + + if(data->Qyrem.buf) + memcpy(rkey.buf + data->Qxrem.len, data->Qyrem.buf, data->Qyrem.len); + + CKINT_LOG(alloc_buf(ss_key_len * 2, &secret), "ecdh: shared secret buffer could not be allocated\n"); + ret = kcapi_kpp_ssgen(handle, rkey.buf, rkey.len, secret.buf, ss_key_len * 2, 0); + if(ret < 0) + { + logger(LOGGER_ERR, "ecdh: siggen failed\n"); + goto out; + } + + CKINT_LOG(alloc_buf(ss_key_len, &data->hashzz), "ecdh: shared secret buffer could not be allocated\n"); + + if(secret.buf) + memcpy(data->hashzz.buf, secret.buf, ss_key_len); +out: + if(key.buf) + free_buf(&key); + if(pkey.buf) + free_buf(&pkey); + if(rkey.buf) + free_buf(&rkey); + if(secret.buf) + free_buf(&secret); +out1: + kcapi_kpp_destroy(handle); + return ret; +} + +static struct ecdh_backend kcapi_ecdh = +{ + ecdh_ss, + ecdh_ss_ver, +}; + +ACVP_DEFINE_CONSTRUCTOR(kcapi_ecdh_backend) +static void kcapi_ecdh_backend(void) +{ + register_ecdh_impl(&kcapi_ecdh); +} + +static int drbg_cipher(uint64_t acvp_cipher, uint64_t type, uint32_t pr, char* cipher) +{ + if(pr) + strcpy(cipher, "drbg_pr"); + else + strcpy(cipher, "drbg_nopr"); + + switch(acvp_cipher & ACVP_HASHMASK) + { + case ACVP_SHA1: + if((type & ACVP_DRBGMASK) == ACVP_DRBGHMAC) + strcat(cipher, "_hmac"); + strcat(cipher, "_sha1"); + break; + case ACVP_SHA224: + if((type & ACVP_DRBGMASK) == ACVP_DRBGHMAC) + strcat(cipher, "_hmac"); + strcat(cipher, "_sha224"); + break; + case ACVP_SHA256: + if((type & ACVP_DRBGMASK) == ACVP_DRBGHMAC) + strcat(cipher, "_hmac"); + strcat(cipher, "_sha256"); + break; + case ACVP_SHA384: + if((type & ACVP_DRBGMASK) == ACVP_DRBGHMAC) + strcat(cipher, "_hmac"); + strcat(cipher, "_sha384"); + break; + case ACVP_SHA512: + if((type & ACVP_DRBGMASK) == ACVP_DRBGHMAC) + strcat(cipher, "_hmac"); + strcat(cipher, "_sha512"); + break; + } + + switch(acvp_cipher & ACVP_AESMASK) + { + case ACVP_AES128: + strcat(cipher, "_ctr_aes128"); + break; + case ACVP_AES192: + strcat(cipher, "_ctr_aes192"); + break; + case ACVP_AES256: + strcat(cipher, "_ctr_aes256"); + break; + } + return 0; +} + +static int drbg_generate(struct drbg_data *data, flags_t parsed_flags) +{ + char cipher[CIPHERMAXNAME]; + int ret = 0; + unsigned int i; + static struct kcapi_handle *rng = NULL; + struct buffer ent = {NULL, 0}; + + if(!data) + { + logger(LOGGER_ERR, "drbg: drbg_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + (void)parsed_flags; + + drbg_cipher(data->cipher, data->type, data->pr, cipher); + + ret = kcapi_rng_init(&rng, cipher, 0); + if (ret) + return ret; + + CKINT_LOG(alloc_buf(data->entropy.len + data->nonce.len, &ent), "drbg: entropy buffer could not be allocated\n"); + + if(data->entropy.buf) + memcpy(ent.buf, data->entropy.buf, data->entropy.len); + + if(data->nonce.buf) + memcpy(ent.buf + data->entropy.len, data->nonce.buf, data->nonce.len); + + ret = kcapi_rng_set_entropy(rng, ent.buf, ent.len); + if(ret) + logger(LOGGER_ERR, "drbg: setting entropy failed with error = %d\n", ret); + + ret = kcapi_rng_seed(rng, data->pers.buf, data->pers.len); + if (ret) + goto out; + CKINT_LOG(alloc_buf(data->rnd_data_bits_len/8, &data->random), "drbg: data->random buffer could not be allocated\n"); + + for(i = 1; i <= data->entropy_reseed.arraysize; i++) + { + unsigned char *addn = data->addtl_reseed.buffers[i-1].buf; + int len = data->addtl_reseed.buffers[i-1].len; + struct buffer ent1; + ent1.buf = data->entropy_reseed.buffers[i-1].buf; + ent1.len = data->entropy_reseed.buffers[i-1].len; + ret = kcapi_rng_set_entropy(rng, ent1.buf, ent1.len); + + if(ret < 0) + { + logger(LOGGER_ERR, "drbg: entropy setting failed with error = %d \n", ret); + goto out; + } + + ret = kcapi_rng_seed(rng, addn, len); + if (ret) + { + logger(LOGGER_ERR, "drbg: reseed failed with error = %d\n",ret); + goto out; + } + } + + for(i = 1; i <= data->addtl_generate.arraysize; i++) + { + // calling generate twice is not the same as calling it with 2 * num_bytes + unsigned char *addn = data->addtl_generate.buffers[i-1].buf; + int len = data->addtl_generate.buffers[i-1].len; + + if(data->pr) + { + struct buffer ent1; + ent1.buf = data->entropy_generate.buffers[i-1].buf; + ent1.len = data->entropy_generate.buffers[i-1].len; + ret = kcapi_rng_set_entropy(rng, ent1.buf, ent1.len); + if(ret < 0) + { + logger(LOGGER_ERR, "drbg: entropy set failed with error = %d\n", ret); + goto out; + } + } + + ret = kcapi_rng_send_addtl(rng, addn, len); + if (ret < 0) + { + logger(LOGGER_ERR, "drbg: setting additional data failed with error = %d\n", ret); + goto out; + } + + ret = kcapi_rng_generate(rng, data->random.buf, data->random.len); + if (ret < 0) + { + logger(LOGGER_ERR, "drbg: generation failed with error = %d\n", ret); + goto out; + } + } +out: + if (rng) + kcapi_rng_destroy(rng); + if(ent.buf) + free_buf(&ent); + return ret; +} + +static struct drbg_backend kcapi_drbg = +{ + drbg_generate, +}; + +ACVP_DEFINE_CONSTRUCTOR(kcapi_drbg_backend) +static void kcapi_drbg_backend(void) +{ + register_drbg_impl(&kcapi_drbg); +} diff --git a/backends/rsakeys.c b/backends/rsakeys.c new file mode 100644 index 0000000..d55ff91 --- /dev/null +++ b/backends/rsakeys.c @@ -0,0 +1,232 @@ +#include "backend_common.h" + +char n1[] = "n = 00b67b1cee2ff9f99f94478a23200816e04498458f4b32d8ca345b68865b9c86d17b274bcb4f41ba0957afdbaa2760c9d38aa0bf4a61b00f422884fdeb4d3819461dcfa484ff2369281cb7e121cfe5b12a0007bf997546c56370d511c675c93f6b54e70a09692de5d9c11947f6b1401f3d0a83457acdee25ae02e234d5b7981e25"; + +char e1[] = "e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001"; + +char d1[] = "d = 00a550ab48ed95dd1b40cdfecb0b7dc89bac08f71b75d8bea591012e9469f24801073cf6615d9001e5ecd6987e71e63171bfa919235d948e7e350f26aa40ee8d957c285c2448cd7c26b57ddc72920bc21722b25bb17faf0a24d9c9a97d665c7f48f235ed72c945113a2665411e5f2acd06ef213e27f61219426f893532ebeaaa81"; + +char p1[] = "p = 00dece6876610ee201896273a054e1665106ffc35c9a9e81426412bbb2943b41127ca7ee28d5f295ab83e0ac95b1ffe2c7a2a3169fa15fff59e085b783089c4d3d"; + +char q1[] = "q = 00d1aabd1907dde6e7fee27bf097e9bb2a7f30cc912da5ffb5c160ca0d42405fc52af808e290675e76f47532cb26fbbf2ae5b174717fe28233bd96670595737309"; + +char dp1[] = "dp = 0e1d9590aa657efc09f02ad3258d8225f0039424f1c6c8f9a3cd6c06cc4d54ba0f1bb482f1cb04a0712272cca9124513d0c1f454f8ac54492568535001e3a521"; + +char dq1[] = "dq = 00b4bc87d181f4894dc76c1906e70d36a88587dd6ff077be1c419c5bd05e21fbec8d03cf34eee20c8e62607cee9ea638be93ce0ae0a42aefae066a1658bbe20f71"; + +char qinv1[] = "qinv = 138b87bdf1bba3a7e975f52a7dc05ba728d7bc497e16b9dce2a7ab13b21bbaf067776d4b6f4ae6b3e7c176722c36ebdff27ada9e5a59b71550b1eeeb8bfc3f60"; + +char n2[] = "n = 00cf6dc3ce2b18d8740a4de64a49fb2643bef107c5db64b789e3cfccc92b7baee480534e5e07522752ab8f6e098fff9f893459d97ca1913630077344daf7296da1320b0cdd2711b409a99c8f7f95b10c1603680e552ebb3d0b59f63788b6b713b01eb1e0ef04322cd9254bd577103cc34a537296c92c9f60ea4cf01d4b0bf9c4b4908fbd3ed41087ba7b0c3f6d847aa01eb2111b759a9bf609be24d0ee65643f73187752f88a83f8ab7cffe3918c5a6a1d96fd27d764fae92ad7369e3a81afcfc1111d4557fedf4e9049704539ab9c513a08b93b46e571eb1cd0629dd4b74bb0fcaf36ddab80c345b0092ecc3c416889332327a72f49d17800a535a9ced8de66a9"; + +char e2[] = "e = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001"; + +char d2[] = "d = 00c7e21d2a61cb4a61dfc01b67810cfc5d91f510297076088b5eb4d2c1141ed674a8d81e0f6bfc959a0b6a667dde7e548cd19eb77e6aeed489c9d42108e3ddcf1fe36a549613dcf261d148e5daeb33b5d2ccab8c0c37c1045d18eeb3ab116f3010aa337ceeb65b676e448b64039ce900c371d05d4f34a9cca95b4492e5cb7f7f35485c721e2462a56c467a1131f3bfcf841b7955d0a2f2df99e569b38c90bda580ad883adb94e91e88fe75aeef62d1d4910e4837065189cb658e447d39adddc3716e6a6377954e773fc559311606bb7fff53eb599719af8e13b2e9cb679e43c15b999825566d662fdb3530aee807a84ff19cbed6ae10c6f25ece0397481fa0be01"; + +char p2[] = "p = 00ea9635c04ef5a84a4c6ee7887be339bfdb8323ab361cd10c00ac5567b45ea7a95641b495bf5ea708fc8c40215d53809abb19bd9f11a8ada0a0c6a78da7771bf861dadd944d6496f2dd06bbc64b094d6647bb8acd5cd74f149d06c4e5a56bbb19bc5a136a2c632d622f951a226b06003092f508db26dfd04d6ab86694ab5659e9"; + +char q2[] = "q = 00e25cee4df37ea87dc850bd247d55572f9296dd50fb93fd7c39dccc5ce6b9451593f20f1c4a15395e828c7b4c78d8db6ac6de7c0475f8a9d79f59811e66163562e7fca373507dd934e0a37a5dbe60aa6aa39a74393abf37039ca781e78912224f1aafc010e8eb36061ab3d01e8db8cd6f965e9e7cb52595f449b79e22b0feeec1"; + +char dp2[] = "dp = 528810571d307e49cd84433f185f040544e4695b2609935e86aa1ace067e3abc6fd564043f34bccd839490476cbf2102cf0aaa54d9709fcd606323b5c992352bf8b978b561591f66486ec3076b84d54f43b36e8cfbb9e05f9f332f789fef3bff3cedefe0adc722c3657c2e9aa74e902886bb60a7419102870a21e02d33ee8869"; + +char dq2[] = "dq = 01e0213d561a238d3f3ea4028c634ba0a2474bb8230d7bd92ea58cafec5d769c1228bc4550bbd248dd2e0acb7c68d7908feb41fdcb786ef7d1632d75b204d71665b3ab2b066cb48302a5781b14bbba4dbde346b93eaa5ceb53bdf38e968d26e99edffbe867f5a2f1f400af65c168d992e61d0c951def1cc9f45e681a037b6941"; + +char qinv2[] = "qinv = 248bec97cda4268589666ff56aeef012d915dac5ee1bfb18d1979246675ec7769cacf318b0af387e5a322034b407a76663cfb5916fbfe44a621f19568b53d30e3b75aebe5fac3fd38c74d273465fe06a7aa63ce610b4401d5cdaea503aa959b8930a20fd4bd6676dd0fec539d6b926840ca478bb5f62687da9f501f90cb44b35"; + +char n3[] = "n = 00db3b5c32a21331e2b490f682589ae4e3290d2facdd07a69277b92f3a504d5927db497b91b76e843d16e99de6e24c7c77d0ed87635c1274fbace82e535b2df7c13a51bb23831a64135bd941435fb55facaf13187a516ceb2f1e1e8211881c015dc619d83af678e8e2f343054e9d8f805890f196f154c3d7d3482e5e12fe5b04b586ee344b3f7b138e761419ffeafe33eda7f72c46777d8b7558c3caf4e0942f217216e7d8ce2aecb204d1a41dee496560d512fe595755001d81dc23a910549926fd55b7b9dce4fc768d1e2ef11e87abe24f25e50d3a9dc49494a84d041a28ed3ba86d5ffd4cf11a9c07f1205537d7602bd54112b90d4a49c6ba4461c0992e10637eb4aa74fe8d03f45409b388b053c28bad5a923f947c4bfdfeb51d652f80c359561540da17bb11ae5ec0edd43d20ac7a042724b7e8c28f69b2675e4365c45a6fdc93f9642a4e2bc97f36e44c3500c6af4321d70a69e70f36f13dc4cba926f32b18210dfdc103a6959f8b422a30647d549e3086a8970e548b96526fde1db5fb87"; + +char e3[] = "e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001"; + +char d3[] = "d = 6fb2c3dbec661941a7bc404cd336402e592925c44e6d6a7a2fd3c373539cc5332070452c4e2859ea02358f4526c1cf9d006f354ef38757e12f0cb125b94c277264f36584c77477cec13a651d1db37c86b040eb74ceedceba17ff7547d7706565d0dc34267e93c61c73d30eee2a2b063a99c6eda0120f2274bccf1b1154552d860bb46c2276ba8f91432a24c1168ae40c4f4b095cf1de9e6270927962e0d5bf59ac166d94321efeb008f2834ad8b0be9d6292a5d3014306a7021616793a1fd05372cfa957e90e2f8973fda5c540c2553d8c8749ee148231ec5c59d6c9d0ef167456b90d3b86b2655ff150374c7b75916d0ee83291b2d7a98bfe2dca8e04713b5070d81e02f29fe71673afeb3e6324f0199b875c436b84d04b742ebdf6642aac6b72108dfd95b02a1ab5fe71cbf01fcbb5f83b53c1cb48237748c4a8aa1e326beeb448fe47f5716b8ebb0777578bd6c4021266239367becdd50ed629b6572ee3e813a5bbcbe3eff20edcf85d08b69cb073f616400ebeea1541d4e2a1a5cea9df21"; + +char p3[] = "p = 00eec009bbd011818137ce0ba6d6c7f658455e9463f08e15eb5d72d910fdb9e130e004de70b7beb968c8bb1d9b5835088fa0102630eecef87bf5204c69abf0476d9aa93fe305ebdb154e4f9d8f6794da021a59e2c8237ec1966f1ed38604a1ddcb0f0ea41477ae95ba1d17401d5bab494d966c97d8794939f9f94138095f2fad6e84bcbafd35453aa86c502a3c99d807c4e0aef3136280a7055c6feb53af9d90f9f60c815224c28ba58dc569eb8fe079c412d01b31032de9fd1e7e7141a02e6c51"; + +char q3[] = "q = 00eb124f16d17a268ed912a31a63c818b78eb0bba7ca7a1bcce6f79ab33213e4ec5446f4edd9ea12fb46435e7bdfe10ca1e2e300d582f97a77101ba2fbe64b1a9f1638176a9125231676573b4137da79df1d672143ffcdf85014e8fd10bb5f72b310ff92eb4d4faf4aa3096e17c6057643f93ee6b7e5d563e28dc75abeda5cd0a1b0f6152bbbd6924a5ebb40e93d87d46dff0e3bedcda904d37f63a352821a3b03e13a92b6f19feb77808a4436f68694efb131ed76dd66e5ab6c9bada5ae2d6c57"; + +char dp3[] = "dp = 61b28fc91d11accef5c9091792986d041e0edfe62d8fd704634f15e8500b7a4d07beb64fa5c11419feda22f96894fb15dac800f8d1203caa6cda74aa614387d7200cd629ce487f742e8181d626ead0733fd93c65edb077035a2161295c47e87ca982b23df5e3a93d699e140c6f709e2473c3a8375b1a4df12ec0337012556e40e56c5d9033f64a54954e109a8fd1c90c156d41e6d2ce168aa912db57796b9ee1ca7fbf839fab447dd08fd21224e414afd98af33591397ea0a793d240aa8d94a1"; + +char dq3[] = "dq = 0095aed3e3a0c19a39cda99b681b6f77a5b25b813287b0977133052961bf9a8163a70a83bdcccbcb086ba64c4caeb33bfafd6134cfc015a1d09cd62c43205264823680c3105d99fb2cbb7032500603bd24c03142326d79b70b2f3568a735d8c24d999e53ec370f6d7c2632c402a95a2303877b71285a5635c3362a61f33352749af0f6d16646b68bf2853dd14873a0c138c57747dbd5e0312d876967bf0b0f2ed2faa0f4793f84684870f61a17b184e2e379be640a1353091dce0b9757ef800703"; + +char qinv3[] = "qinv = 26b1983617a16e69482b5851be3a78120b4df636e37967ab50e94311ffa15b7005619689833aeccbaf12814cfce5c14c51dc5d06be97be38f7f647d73bfebf03b22ead82ec37f914b128f9ff3b8fd60ad6bf5ca01339089f1b79cfc9b583e8b1206227be36a3ecdeb7709b487223b0b1d0064965f046e4e1c7a1a7431326e8d89d41036cf66f3a91d9ef4dcaa32e480460bfb3b85ea8961b5660d6899a13d4ad5c5a5f0c177c782ca5138b6f5021138b719da3e9f2839e23400409291a1f4f72"; + +char n4[] = "n = 00b0f8806586b722f4140704f000f51fc90328ad8ec8e40deb6914f9cc4afe296314b9cc6bbc165bf427944ca0d6686bfdab52fed2533a3a86cd6a584cd87aa3aa0fae92ab308ac6967bba04d4c2eab4cafe7e849a692eef1134d10da21b5b8fb29454bbfad6ffb098ecf16cd161521fcc92667f950cd4e34b5424b0c8a20500a993886482a935a8c606bdc9108891f9e8609abe17c39ef46b92f5b4e7a324cda942b8fd0e734b2a2bfc2d7548f88f1badd8aba95a8cde6312e889b4385eaafef139aed6df764fb6e34a5bd3e14de82ee59fd256511b5f66154e0dfaedb574dd4051dc725662d921d273c0346d6734b4cbfcc38344ecba5c4466b5b7ee503fa6795cb57d93c16c0534efb9cdf6b18d26ec3912315d1268d29ce274c4e5bf466eddb692eed39f7b4be48bdef23fd40e5c11409a50ac81ab9f60f5ada7a2b9f957e8c0f3241fa1899531193266d58af5e46665f8a15afbb0c6ef47874a60dd0ca5fed563c4392c2ed8b17b53a628a19f1bf1da28d97edf15c2646181550a793de69f1e59c77416b0754802b576086410536cbafa8e931b55b240934d301b1f11c08a7e73e14546955f2ade09e5111fa0b3a22908ac96283b8aa11eb2228c5ec1e5265b9f62a1b201a2baa075fad3a423d42682eb390a0cc80d8ac3da9262d15ae13f4dd7f270329f4ec9241834fc5ec60500a83d8602f810a44b6bb92c8449ec2245"; + +char e4[] = "e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001"; + +char d4[] = "d = 2a651dbd34aca2befe1d405d8e9d2a64295191626755dacfce78abeef8f83249fe291483aaa76097f8f359f81de51e19c2f53afe7fd9af33a3fa19f52ed712662723971753a5ab3559a69289b5b82c5f84e0223c2b7e86df045c207bf939d20ee1e1fab678d30027627be3a9b53acb4b62b713514da5a25de56674c35bacff1fa0ac4807d52979a916ec584291b506bd5887398acfde408794c92ff15defef24e14b17b462825b33f6519d8b41a066ed1abee4ef4057f63c0d610fbf814e4d8cd458c238fe4ad27158daeec346ba9ca17dcc11c994592247704f8111792ae9e602b660ddb9087345cb5cfc32494b2314cb14bb59c3ac51764174beff64521b3b0976a1aabb1fdae4b98dd77d6bad3f87ace55f6d8666f11a48f0bae89c49b7311b07ad28410a7775911326827f4a9f62969f8054a4a533d06d843c3f9ed8659863e277768f896068cf046335bdb8c05be82eb6b05a066c5302981c517f6b8546667a08c967ca3040ca5c4b85684b7b9d29505b4eaccb9ba4b9e24729db089220ba9df811956cc62257b8d6765e64782e62468cd841bc262a84a47b62232e7812b57b9b891bae7a454b3cf415aca4e8e3e064801a3195afc5d9554d4e68470da75edd5d70e9c20a327a1162925e3706674d688765aadb41356e36bab6647c7984be351643dff9d916c14962495f140a905c60afee09eace87711124cef3296181"; + +char p4[] = "p = 00e3e0d464b3a88f16d033fbfccac54cbcb7c6e86c7155bfe1fa6e12483d94aeb998f4e15924fd79736ec8ad908338028d274c87565ced66bfa05153fa7c870be579f5da3f2b11f5b41ced6a11c6fe732f867620460f9b847633aac5b4fae916bb10e50c3f0268691081304a9029d7fb48c79859b5bfaef6768f6b12af0dc62e2cfe35df6201b7ee49d5294943e4fe3c03eb7a046abcaf44ab7de665a3989c7703184e90133a47818b1f5d116efbe2565296385948ea4e9e25e8a22034a3901f01eea973d9ebcabb3676c764eb74f71058d17741911ef52b86343fe8341e2301f5d636406050ecd522577577753da591c525f0c4e1ab5ba0b748bb44ff822c405d"; + +char q4[] = "q = 00c6cf6459f521df0d49cf814eb4734565a2158933d81d73a1a1bb5e21346eb5b981549bcbc68ff223c021f331cc27d5ae43ecf28e16c1582be9146c1e3e3a96e03a7c39190700978f84a1914ece3b2cc8e5fd45adcb08f59df23880145feff4fb2db14747f6f91d12bf9d8e0ce4d0e99a0e5d8cc7e1ba8922a0568d4bcbb277a8826321047dbee09fa3beafe0eb6cc64a711bfaf2957ef8449e30b87ce59bc7e96758e453a6902a6526687bee4ee109bf583cc876a185d9719af9ebb70fb3145ecaac8d4cd794b2171b1304b9897c64582a1e4028fe817bcd644b24966ae78cd349af51c6fdb70600607e6b0a880687a4036c94043ecd023ccf4d1ea169e36b09"; + +char dp4[] = "dp = 00842848057f0c2ab0185f8dacb60c66ccabe877b32ca78679103bf5ee5f88732cc04084d0a65b3aac6f7b82ed64ac7f0e4dd45c4901ebccc325bf04ed287b49b2f460590a797818ff34279c7462ebfef17911d8f5c8e77092fcb3f5a5583f0627c74c8f259bc7e1e6e8859138ba8bbff81d8985bd9a45663aac4274bb8149864e21c02ca53249f1b07027598e3ea8133652c298fd2e2097babd717950bf993e8c54f47b2a2b8a7cdeaa79d73a7e6a6d95c7f9360ecb947cb38f8f370e502dad4df993dcd46da34d9ff093033c6ac13e81c4395d954456fbbf015e6ed48b05d285388e8e174dd78c643644b1db14bd8924c534357a8b5ec07e8b77d0343ed25b21"; + +char dq4[] = "dq = 00c47c861e8e31caa3f475fbc3507eb87088efa5e932477157a6636ad5805f8684ef78327e042191db9971344cdc0be698d39323ea203d382a35b2b46473762e55301843ca236c875e1564251b70a175529c5363812f300ca7ec93c0a9e2636288b89103f4f0f725afb8e73b542cf4f85b04a59a9495d868de6afeffa8908a32cebd06c1c4118f0bab5b0704065446edf6f6b103a4aaf190e7283cd8a8bfb8e5ac1d32f27e6619077d6ea7470cb0b2a29294df85f411111b65b71817c995df945b570d909d08577267799fa344c7c7c3d88acfd8f36b0d87d0e7b588548d1589cdec7e346169b1706200fc1048994572db3b731d1ad102869a98fb0c31d5582919"; + +char qinv4[] = "qinv = 0087879b3d456cfb6320a1b9f569ce6b96ae69f0e1f28b392a18c8ca58c1302f15ca9389383783856e095badac4323a319fd1dc8a28f7555c8f70e37a852d1b69403c9e1bfde4fd93ca0c42d7d6a5702b61705d70d43cef02b95b331df9603365e5dedbd71c3f2642c3d3b64fa3b83946d07da52446051e54bcf1dec5050a6ea394018171dd8d2dfc94e52f4929549d63d1e03a285d75ca4846c802263146c412023bb54c7055fb7b44ebd797debb647cc70eb0e981209447e22346a11172fdde2ac51e9971cb1e9a23eb2ce259db667ed1193a86249cb3541d2dd9bb5b4cbcfd3d509c4fefe4901c70ae89de309a93d737f208fbb56da272839bcf659fe77b2"; + +extern unsigned char * write_field(unsigned char *ptr, unsigned char *src, unsigned short int len); + +int rsa_private_key_ber_encode(struct rsa_siggen_data *data, struct buffer *d, struct buffer *p, + struct buffer *q, struct buffer *dp, struct buffer *dq, + struct buffer *qinv, struct buffer *pk) +{ + /* + BER encoding for private key* + 1. Calculate total length of Private key + + Metadata for complete key = 0x30 and sum of length of all fields + + 2. BER encoding the length of any field + + actual length of a field = 0x02 and len + + if length <= 127 - 1 byte (actual length) + if length > 127 and length <= 255 - 2 bytes (Byte1 = 0x81, Byte2 = actual length) + if length > 255 - 3 bytes (Byte1 = 0x82, Byte2 and Byte3 = actual length) + */ + + unsigned short int nlen, dlen, plen, qlen, dplen, dqlen, qinvlen; + unsigned short int elen, total=0, extra; + unsigned char *ptr; + unsigned char *tmp; + unsigned char blank[3] = {0x02, 0x01, 0x00}; + + if(!data) + { + logger(LOGGER_ERR, "rsa: rsa_siggen_data is empty, returning -EINVAL...\n"); + return -EINVAL; + } + + nlen = data->n.len; + elen = data->e.len; + dlen = d->len; + plen = p->len; + qlen = q->len; + dplen = dp->len; + dqlen = dq->len; + qinvlen = qinv->len; + + /* + Before the Chinese Remainder Theorem was introduced in kernel code we did not have to encode a total of 6 fields. + 1. version + 2. p + 3. q + 4. dp + 5. dq + 6. qinv + + But now since CRT is present in kernel code, except version we need to additionally + encode the remaining 5 fields mentioned above. + + Hence we are skipping one field with the blank declared above (1 x 3) + */ + + total = 3 + nlen; + if(nlen <= 127) + total = total + 2; + else if(nlen >= 128 && nlen <= 255) + total = total + 3; + else + total = total + 4; + + total = total + elen; + if(elen <= 127) + total = total + 2; + else if(elen >= 128 && elen <= 255) + total = total + 3; + else + total = total + 4; + + total = total + dlen; + if(dlen <= 127) + total = total + 2; + else if(dlen >= 128 && dlen <= 255) + total = total + 3; + else + total = total + 4; + + total = total + plen; + if(plen <= 127) + total = total + 2; + else if(plen >= 128 && plen <= 255) + total = total + 3; + else + total = total + 4; + + total = total + qlen; + if(qlen <= 127) + total = total + 2; + else if(qlen >= 128 && qlen <= 255) + total = total + 3; + else + total = total + 4; + + total = total + dplen; + if(dplen <= 127) + total = total + 2; + else if(dplen >= 128 && dplen <= 255) + total = total + 3; + else + total = total + 4; + + total = total + dqlen; + if(dqlen <= 127) + total = total + 2; + else if(dqlen >= 128 && dqlen <= 255) + total = total + 3; + else + total = total + 4; + + total = total + qinvlen; + if(qinvlen <= 127) + total = total + 2; + else if(qinvlen >= 128 && qinvlen <= 255) + total = total + 3; + else + total = total + 4; + + if(total <= 127) + extra = 2; + else if(total >= 128 && total <= 255) + extra = 3; + else + extra = 4; + +/*Calculated total length and extra bytes*/ +/*Start Prepare buffer*/ + int ret = alloc_buf(total + extra + 1, pk); + if(ret) + return ret; + ptr = pk->buf; + ptr[0] = 0x30; + if(extra == 2) + memcpy(ptr + 1, &total, 1); + if(extra == 3) + { + ptr[1] = 0x81; + memcpy(ptr + 2, &total, 1); + } + if(extra == 4) + { + tmp = (unsigned char*)(&total); + ptr[1] = 0x82; + memcpy(ptr + 2, tmp + 1, 1); + memcpy(ptr + 3, tmp , 1); + } + + ptr = ptr + extra; + /*Write blank version*/ + memcpy(ptr, blank, 3); + ptr = ptr + 3; + /*Write n field*/ + ptr = write_field(ptr, data->n.buf, nlen); + ptr = write_field(ptr, data->e.buf, elen); + ptr = write_field(ptr, d->buf, dlen); + ptr = write_field(ptr, p->buf, plen); + ptr = write_field(ptr, q->buf, qlen); + ptr = write_field(ptr, dp->buf, dplen); + ptr = write_field(ptr, dq->buf, dqlen); + ptr = write_field(ptr, qinv->buf, qinvlen); + + return 0; +}