blob: 5dec3c96032485880a91009b6c725f52fd2304f4 [file] [log] [blame]
/*
* Handle the RSA specific openssl crypto functions
*
* Copyright (C) 2019 James.Bottomley@HansenPartnership.com
*
* SPDX-License-Identifier: LGPL-2.1-only
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/buffer.h>
#include <openssl/err.h>
#include "openssl-pkcs11.h"
#include "crypto.h"
void
crypto_rsa_populate(int sec_num, EVP_PKEY *pkey)
{
RSA *rsa = EVP_PKEY_get1_RSA(pkey);
unsigned long size = RSA_size(rsa);
const BIGNUM *n, *e;
EVP_MD_CTX *ctx;
#if OPENSSL_VERSION_NUMBER < 0x10100000
n = rsa->n;
e = rsa->e;
#else
RSA_get0_key(rsa, &n, &e, NULL);
#endif
ctx = EVP_MD_CTX_create();
EVP_DigestInit(ctx, EVP_sha256());
crypto_add_BN(sec_num, "CKA_PUBLIC_EXPONENT", e, ctx);
crypto_add_BN(sec_num, "CKA_MODULUS", n, ctx);
crypto_add_serial(sec_num, ctx);
cache_add_by_secnum(sec_num, "CKA_MODULUS_BITS",
(const char *)size, CACHE_INT);
cache_add_by_secnum(sec_num, "CKA_KEY_TYPE",
(const char *)CKK_RSA, CACHE_INT);
/* booleans: only need to add true ones */
cache_add_by_secnum(sec_num, "CKA_ENCRYPT",
(const char *)BOOL_FOR_PUBLIC, CACHE_INT);
cache_add_by_secnum(sec_num, "CKA_DECRYPT",
(const char *)BOOL_FOR_PRIVATE, CACHE_INT);
cache_add_by_secnum(sec_num, "CKA_VERIFY_RECOVER",
(const char *)BOOL_FOR_PUBLIC, CACHE_INT);
RSA_free(rsa);
}
const EVP_MD *get_mgf1(unsigned long mgf1)
{
switch (mgf1) {
case CKG_MGF1_SHA1:
return EVP_sha1();
case CKG_MGF1_SHA224:
return EVP_sha224();
case CKG_MGF1_SHA256:
return EVP_sha256();
case CKG_MGF1_SHA384:
return EVP_sha384();
case CKG_MGF1_SHA512:
return EVP_sha512();
default:
fprintf(stderr, "Unknown mgf1 type %ld\n", mgf1);
return NULL;
}
}
const EVP_MD *get_hash(unsigned long hash)
{
switch (hash) {
case CKM_SHA_1:
return EVP_sha1();
case CKM_SHA224:
return EVP_sha224();
case CKM_SHA256:
return EVP_sha256();
case CKM_SHA384:
return EVP_sha384();
case CKM_SHA512:
return EVP_sha512();
default:
fprintf(stderr, "Unknown hash type %ld\n", hash);
return NULL;
}
}
EVP_PKEY_CTX *crypto_rsa_add_padding(EVP_PKEY_CTX *ctx, CK_MECHANISM_PTR mech)
{
if (mech->mechanism == CKM_RSA_PKCS) {
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING);
} else if (mech->mechanism == CKM_RSA_X_509) {
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING);
} else if (mech->mechanism == CKM_RSA_PKCS_PSS) {
CK_RSA_PKCS_PSS_PARAMS *p = mech->pParameter;
if (mech->ulParameterLen != sizeof(*p)) {
fprintf(stderr, "PSS mechanism parameter length %ld != %ld\n",
mech->ulParameterLen, (long)sizeof(*p));
goto err;
}
EVP_PKEY_CTX_set_signature_md(ctx, get_hash(p->hashAlg));
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING);
EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, get_mgf1(p->mgf));
EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, p->sLen);
} else if (mech->mechanism == CKM_RSA_PKCS_OAEP) {
CK_RSA_PKCS_OAEP_PARAMS *p = mech->pParameter;
if (mech->ulParameterLen != sizeof(*p)) {
fprintf(stderr, "OAEP mechanism parameter length %ld != %ld\n",
mech->ulParameterLen, (long)sizeof(*p));
goto err;
}
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_OAEP_PADDING);
EVP_PKEY_CTX_set_rsa_oaep_md(ctx, get_hash(p->hashAlg));
EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, get_mgf1(p->mgf));
if (p->source & CKZ_DATA_SPECIFIED) {
void *l = BUF_memdup(p->pSourceData,
p->ulSourceDataLen);
EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, l,
p->ulSourceDataLen);
}
} else {
fprintf(stderr, "unknown mechanism %ld\n", mech->mechanism);
goto err;
}
return ctx;
err:
EVP_PKEY_CTX_free(ctx);
return NULL;
}
/* decrypt is a RSA only operation */
void *crypto_decrypt_init(int sec_num, CK_MECHANISM_PTR mech)
{
EVP_PKEY_CTX *ctx;
ctx = crypto_get_key(sec_num);
EVP_PKEY_decrypt_init(ctx);
return crypto_rsa_add_padding(ctx, mech);
}
int crypto_decrypt(void *opdata, void *enc_data, unsigned long enc_len,
void *data, unsigned long *data_len)
{
EVP_PKEY_CTX *ctx = opdata;
int ret = 0;
size_t len;
if (data_len)
len = *data_len;
if (!data) {
*data_len = EVP_PKEY_size(EVP_PKEY_CTX_get0_pkey(ctx));
return 0;
}
if (EVP_PKEY_decrypt(ctx, data, &len, enc_data, enc_len) <= 0) {
ERR_print_errors_fp(stderr);
ret = -1;
}
if (data_len)
*data_len = len;
EVP_PKEY_CTX_free(ctx);
return ret;
}
static CK_MECHANISM_TYPE mechanism_types[] = {
CKM_RSA_PKCS,
CKM_RSA_X_509,
CKM_RSA_PKCS_PSS,
CKM_RSA_PKCS_OAEP,
};
void crypto_rsa_fill_mechanism_list(int sec_num, unsigned long *mechs,
unsigned long *count)
{
*count = ARRAY_SIZE(mechanism_types);
if (mechs)
memcpy(mechs, mechanism_types, sizeof(mechanism_types));
}
int crypto_rsa_check_mechanism(int sec_num, CK_MECHANISM_TYPE mech,
CK_MECHANISM_INFO_PTR info)
{
int i, found = 0;
for (i = 0; i < ARRAY_SIZE(mechanism_types); i++)
if (mech == mechanism_types[i])
found = 1;
if (!found)
return 0;
info->ulMinKeySize = 1024;
info->ulMaxKeySize = 4096;
info->flags = CKF_HW|CKF_ENCRYPT|CKF_DECRYPT;
return 1;
}