BUF_MEM * add_iso_pad(const BUF_MEM * m, int block_size) { BUF_MEM * out = NULL; int p_len; check(m, "Invalid arguments"); /* calculate length of padded message */ p_len = (m->length / block_size) * block_size + block_size; out = BUF_MEM_create(p_len); if (!out) goto err; /* Flawfinder: ignore */ memcpy(out->data, m->data, m->length); /* now add iso padding */ memset(out->data + m->length, 0x80, 1); memset(out->data + m->length + 1, 0, p_len - m->length - 1); err: return out; }
static BUF_MEM * cipher(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc, const BUF_MEM * in) { BUF_MEM * out = NULL; EVP_CIPHER_CTX * tmp_ctx = NULL; int i; unsigned long flags; check(in, "Invalid arguments"); if (ctx) tmp_ctx = ctx; else { tmp_ctx = EVP_CIPHER_CTX_new(); if (!tmp_ctx) goto err; EVP_CIPHER_CTX_init(tmp_ctx); if (!EVP_CipherInit_ex(tmp_ctx, type, impl, key, iv, enc)) goto err; } flags = EVP_CIPHER_flags(EVP_CIPHER_CTX_cipher(tmp_ctx)); if (flags & EVP_CIPH_NO_PADDING) { i = in->length; check((in->length % EVP_CIPHER_block_size(type) == 0), "Data is not of blocklength"); } else i = in->length + EVP_CIPHER_block_size(type); out = BUF_MEM_create(i); if (!out) goto err; if (!EVP_CipherUpdate(tmp_ctx, (unsigned char *) out->data, &i, (unsigned char *) in->data, in->length)) goto err; out->length = i; if (!EVP_CipherFinal_ex(tmp_ctx, (unsigned char *) (out->data + out->length), &i)) goto err; if (!(flags & EVP_CIPH_NO_PADDING)) out->length += i; if (!ctx) EVP_CIPHER_CTX_free(tmp_ctx); return out; err: if (out) BUF_MEM_free(out); if (!ctx && tmp_ctx) EVP_CIPHER_CTX_free(tmp_ctx); return NULL; }
BUF_MEM * cmac(CMAC_CTX *ctx, const EVP_CIPHER *type, const BUF_MEM * key, const BUF_MEM * in, size_t maclen) { CMAC_CTX * cmac_ctx = NULL; BUF_MEM * out = NULL, * tmp = NULL; size_t cmac_len = 0; check((key && in && type), "Invalid arguments"); check((key->length >= (size_t) EVP_CIPHER_key_length(type)), "Key is too short"); if (ctx) cmac_ctx = ctx; else { cmac_ctx = CMAC_CTX_new(); } /* Initialize the CMAC context, feed in the data, and get the required * output buffer size */ if (!cmac_ctx || !CMAC_Init(cmac_ctx, key->data, EVP_CIPHER_key_length(type), type, NULL) || !CMAC_Update(cmac_ctx, in->data, in->length) || !CMAC_Final(cmac_ctx, NULL, &cmac_len)) goto err; /* get buffer in required size */ out = BUF_MEM_create(cmac_len); if (!out) goto err; /* get the actual CMAC */ if (!CMAC_Final(cmac_ctx, (unsigned char*) out->data, &out->length)) goto err; /* Truncate the CMAC if necessary */ if (cmac_len > maclen) { tmp = BUF_MEM_create_init(out->data, maclen); BUF_MEM_free(out); out = tmp; } if (!ctx) CMAC_CTX_free(cmac_ctx); return out; err: if (cmac_ctx && !ctx) { CMAC_CTX_free(cmac_ctx); } if (out) { BUF_MEM_free(out); } return NULL; }
BUF_MEM * Comp(EVP_PKEY *key, const BUF_MEM *pub, BN_CTX *bn_ctx, EVP_MD_CTX *md_ctx) { BUF_MEM *out = NULL; const EC_GROUP *group; EC_POINT *ecp = NULL; EC_KEY *ec = NULL; BIGNUM *x = NULL, *y = NULL; check((key && pub), "Invalid arguments"); switch (EVP_PKEY_base_id(key)) { case EVP_PKEY_DH: out = hash(EVP_sha1(), md_ctx, NULL, pub); break; case EVP_PKEY_EC: ec = EVP_PKEY_get1_EC_KEY(key); if (!ec) goto err; group = EC_KEY_get0_group(ec); ecp = EC_POINT_new(group); x = BN_CTX_get(bn_ctx); y = BN_CTX_get(bn_ctx); if(!ecp || !x || !y || !EC_POINT_oct2point(group, ecp, (unsigned char *) pub->data, pub->length, bn_ctx) || !EC_POINT_get_affine_coordinates_GF2m(group, ecp, x, y, bn_ctx)) goto err; out = BUF_MEM_create(BN_num_bytes(x)); if(!out || !BN_bn2bin(x, (unsigned char *) out->data)) goto err; break; default: log_err("Unknown protocol"); goto err; } err: if (ecp) EC_POINT_free(ecp); /* Decrease the reference count, the key is still available in the EVP_PKEY * structure */ if (ec) EC_KEY_free(ec); if (x) BN_free(x); if (y) BN_free(y); return out; }
BUF_MEM * BUF_MEM_create_init(const void *buf, size_t len) { BUF_MEM *out; out = BUF_MEM_create(len); if (!out) return NULL; memcpy(out->data, buf, len); return out; }
BUF_MEM * BN_bn2buf(const BIGNUM *bn) { BUF_MEM * out; if (!bn) return NULL; out = BUF_MEM_create(BN_num_bytes(bn)); if (!out) return NULL; out->length = BN_bn2bin(bn, (unsigned char *) out->data); return out; }
BUF_MEM * BUF_MEM_dup(const BUF_MEM * in) { BUF_MEM * out = NULL; if (!in) return NULL; out = BUF_MEM_create(in->length); check(out, "Failed to allocate memory"); memcpy(out->data, in->data, in->length); out->max = in->max; err: return out; }
BUF_MEM * dh_compute_key(EVP_PKEY *key, const BUF_MEM * in, BN_CTX *bn_ctx) { BUF_MEM * out = NULL; BIGNUM * bn = NULL; DH *dh = NULL; check(key && in, "Invalid arguments"); dh = EVP_PKEY_get1_DH(key); if (!dh) return NULL; /* decode public key */ bn = BN_bin2bn((unsigned char *) in->data, in->length, bn); if (!bn) goto err; out = BUF_MEM_create(DH_size(dh)); if (!out) goto err; out->length = DH_compute_key((unsigned char *) out->data, bn, dh); if ((int) out->length < 0) goto err; BN_clear_free(bn); DH_free(dh); return out; err: if (out) BUF_MEM_free(out); if (bn) BN_clear_free(bn); if (dh) DH_free(dh); return NULL; }
BUF_MEM * EC_POINT_point2buf(const EC_KEY * ecdh, BN_CTX * bn_ctx, const EC_POINT * ecp) { size_t len; BUF_MEM * out; len = EC_POINT_point2oct(EC_KEY_get0_group(ecdh), ecp, EC_KEY_get_conv_form(ecdh), NULL, 0, bn_ctx); if (len == 0) return NULL; out = BUF_MEM_create(len); if (!out) return NULL; out->length = EC_POINT_point2oct(EC_KEY_get0_group(ecdh), ecp, EC_KEY_get_conv_form(ecdh), (unsigned char *) out->data, out->max, bn_ctx); return out; }
BUF_MEM * hash(const EVP_MD * md, EVP_MD_CTX * ctx, ENGINE * impl, const BUF_MEM * in) { BUF_MEM * out = NULL; EVP_MD_CTX * tmp_ctx = NULL; unsigned int tmp_len; check((md && in), "Invalid arguments"); if (ctx) tmp_ctx = ctx; else { tmp_ctx = EVP_MD_CTX_create(); if (!tmp_ctx) goto err; } tmp_len = EVP_MD_size(md); out = BUF_MEM_create(tmp_len); if (!out || !EVP_DigestInit_ex(tmp_ctx, md, impl) || !EVP_DigestUpdate(tmp_ctx, in->data, in->length) || !EVP_DigestFinal_ex(tmp_ctx, (unsigned char *) out->data, &tmp_len)) goto err; out->length = tmp_len; if (!ctx) EVP_MD_CTX_destroy(tmp_ctx); return out; err: if (out) BUF_MEM_free(out); if (tmp_ctx && !ctx) EVP_MD_CTX_destroy(tmp_ctx); return NULL; }
BUF_MEM * EAC_sign(int protocol, EVP_PKEY *key, const BUF_MEM *data) { BUF_MEM *signature = NULL, *signature_data = NULL, *plain_sig = NULL; EVP_PKEY_CTX *tmp_key_ctx = NULL; size_t len; const EVP_MD *md = eac_oid2md(protocol); int type; check((key && data), "Invalid arguments"); tmp_key_ctx = EVP_PKEY_CTX_new(key, NULL); if (!tmp_key_ctx || !md || EVP_PKEY_sign_init(tmp_key_ctx) <= 0 || EVP_PKEY_CTX_set_signature_md(tmp_key_ctx, md) <= 0) goto err; type = EVP_PKEY_base_id(key); if ( protocol == NID_id_TA_ECDSA_SHA_1 || protocol == NID_id_TA_ECDSA_SHA_224 || protocol == NID_id_TA_ECDSA_SHA_256 || protocol == NID_id_TA_ECDSA_SHA_384 || protocol == NID_id_TA_ECDSA_SHA_512) { if (!(type == EVP_PKEY_EC)) goto err; } else if (protocol == NID_id_TA_RSA_v1_5_SHA_1 || protocol == NID_id_TA_RSA_v1_5_SHA_256 || protocol == NID_id_TA_RSA_v1_5_SHA_512) { if (!(type == EVP_PKEY_RSA)) goto err; if (!EVP_PKEY_CTX_set_rsa_padding(tmp_key_ctx, RSA_PKCS1_PADDING)) goto err; } else if (protocol == NID_id_TA_RSA_PSS_SHA_1 || protocol == NID_id_TA_RSA_PSS_SHA_256 || protocol == NID_id_TA_RSA_PSS_SHA_512) { if (!(type == EVP_PKEY_RSA)) goto err; if (!EVP_PKEY_CTX_set_rsa_padding(tmp_key_ctx, RSA_PKCS1_PSS_PADDING)) goto err; } else { goto err; } /* EVP_PKEY_sign doesn't perform hashing (despite EVP_PKEY_CTX_set_signature_md). * Therefore we need to compute the hash ourself. */ signature_data = hash(md, NULL, NULL, data); if (!signature_data) goto err; /* Actual signature creation */ if (EVP_PKEY_sign(tmp_key_ctx, NULL, &len, (unsigned char*) signature_data->data, signature_data->length) <= 0) goto err; signature = BUF_MEM_create(len); if (!signature) goto err; if (EVP_PKEY_sign(tmp_key_ctx, (unsigned char *) signature->data, &signature->length, (unsigned char*) signature_data->data, signature_data->length) <= 0) goto err; /* EAC signatures are always in plain signature format for EC curves but * OpenSSL only creates X.509 format. Therefore we need to convert between * these formats. */ if ( protocol == NID_id_TA_ECDSA_SHA_1 || protocol == NID_id_TA_ECDSA_SHA_224 || protocol == NID_id_TA_ECDSA_SHA_256 || protocol == NID_id_TA_ECDSA_SHA_384 || protocol == NID_id_TA_ECDSA_SHA_512) { plain_sig = convert_to_plain_sig(signature); BUF_MEM_free(signature); signature = plain_sig; } err: if (tmp_key_ctx) EVP_PKEY_CTX_free(tmp_key_ctx); if (signature_data) BUF_MEM_free(signature_data); return signature; }
BUF_MEM * convert_to_plain_sig(const BUF_MEM *x962_sig) { size_t r_len, s_len, rs_max; BUF_MEM *plain_sig_buf = NULL; ECDSA_SIG *tmp_sig = NULL; const unsigned char *tmp; unsigned char *r = NULL, *s = NULL; const BIGNUM *bn_r, *bn_s; check_return(x962_sig, "Invalid arguments"); /* Convert the ASN.1 data to a C structure*/ tmp = (unsigned char*) x962_sig->data; tmp_sig = ECDSA_SIG_new(); if (!tmp_sig) goto err; if (!d2i_ECDSA_SIG(&tmp_sig, &tmp, x962_sig->length)) goto err; ECDSA_SIG_get0(tmp_sig, &bn_r, &bn_s); /* Extract the parameters r and s*/ r_len = BN_num_bytes(bn_r); s_len = BN_num_bytes(bn_s); rs_max = r_len > s_len ? r_len : s_len; r = OPENSSL_malloc(rs_max); s = OPENSSL_malloc(rs_max); if (!r || !s) goto err; /* Convert r and s to a binary representation */ if (!BN_bn2bin(bn_r, r + rs_max - r_len)) goto err; if (!BN_bn2bin(bn_s, s + rs_max - s_len)) goto err; /* r and s must be padded with leading zero bytes to ensure they have the * same length */ memset(r, 0, rs_max - r_len); memset(s, 0, rs_max - s_len); /* concatenate r and s to get the plain signature format */ plain_sig_buf = BUF_MEM_create(rs_max + rs_max); if (!plain_sig_buf) goto err; memcpy(plain_sig_buf->data, r, rs_max); memcpy(plain_sig_buf->data + rs_max, s, rs_max); OPENSSL_free(r); OPENSSL_free(s); ECDSA_SIG_free(tmp_sig); return plain_sig_buf; err: if (r) OPENSSL_free(r); if (s) OPENSSL_free(s); if (tmp_sig) ECDSA_SIG_free(tmp_sig); return NULL; }