|
Packit |
6b81fa |
/* libp11, a simple layer on to of PKCS#11 API
|
|
Packit |
6b81fa |
* Copyright (C) 2005 Olaf Kirch <okir@lst.de>
|
|
Packit |
6b81fa |
* Copyright (C) 2011, 2013 Douglas E. Engert <deengert@anl.gov>
|
|
Packit |
6b81fa |
* Copyright (C) 2014, 2016 Douglas E. Engert <deengert@gmail.com>
|
|
Packit |
6b81fa |
* Copyright (C) 2016-2018 MichaĆ Trojnara <Michal.Trojnara@stunnel.org>
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* This library is free software; you can redistribute it and/or
|
|
Packit |
6b81fa |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
6b81fa |
* License as published by the Free Software Foundation; either
|
|
Packit |
6b81fa |
* version 2.1 of the License, or (at your option) any later version.
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
6b81fa |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
6b81fa |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
6b81fa |
* Lesser General Public License for more details.
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
6b81fa |
* License along with this library; if not, write to the Free Software
|
|
Packit |
6b81fa |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/*
|
|
Packit |
6b81fa |
* This file implements the handling of EC keys stored on a
|
|
Packit |
6b81fa |
* PKCS11 token
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#include "libp11-int.h"
|
|
Packit |
6b81fa |
#include <string.h>
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#ifndef OPENSSL_NO_EC
|
|
Packit |
6b81fa |
#include <openssl/ec.h>
|
|
Packit |
6b81fa |
#include <openssl/bn.h>
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
#ifndef OPENSSL_NO_ECDSA
|
|
Packit |
6b81fa |
#include <openssl/ecdsa.h>
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
#ifndef OPENSSL_NO_ECDH
|
|
Packit |
6b81fa |
#include <openssl/ecdh.h>
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#ifndef OPENSSL_NO_EC
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
typedef int (*compute_key_fn)(unsigned char **, size_t *,
|
|
Packit |
6b81fa |
const EC_POINT *, const EC_KEY *);
|
|
Packit |
6b81fa |
#else
|
|
Packit |
6b81fa |
typedef int (*compute_key_fn)(void *, size_t,
|
|
Packit |
6b81fa |
const EC_POINT *, const EC_KEY *,
|
|
Packit |
6b81fa |
void *(*)(const void *, size_t, void *, size_t *));
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
static compute_key_fn ossl_ecdh_compute_key;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static int ec_ex_index = 0;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/********** Missing ECDSA_METHOD functions for OpenSSL < 1.1.0 */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
typedef ECDSA_SIG *(*sign_sig_fn)(const unsigned char *, int,
|
|
Packit |
6b81fa |
const BIGNUM *, const BIGNUM *, EC_KEY *);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* ecdsa_method maintains unchanged layout between 0.9.8 and 1.0.2 */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Data pointers and function pointers may have different sizes on some
|
|
Packit |
6b81fa |
* architectures */
|
|
Packit |
6b81fa |
struct ecdsa_method {
|
|
Packit |
6b81fa |
char *name;
|
|
Packit |
6b81fa |
sign_sig_fn ecdsa_do_sign;
|
|
Packit |
6b81fa |
void (*ecdsa_sign_setup)();
|
|
Packit |
6b81fa |
void (*ecdsa_do_verify)();
|
|
Packit |
6b81fa |
int flags;
|
|
Packit |
6b81fa |
char *app_data;
|
|
Packit |
6b81fa |
};
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER < 0x10002000L || defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Define missing functions */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ECDSA_METHOD *ECDSA_METHOD_new(const ECDSA_METHOD *m)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
ECDSA_METHOD *out;
|
|
Packit |
6b81fa |
out = OPENSSL_malloc(sizeof(ECDSA_METHOD));
|
|
Packit |
6b81fa |
if (out == NULL)
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
if (m)
|
|
Packit |
6b81fa |
memcpy(out, m, sizeof(ECDSA_METHOD));
|
|
Packit |
6b81fa |
else
|
|
Packit |
6b81fa |
memset(out, 0, sizeof(ECDSA_METHOD));
|
|
Packit |
6b81fa |
return out;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
void ECDSA_METHOD_free(ECDSA_METHOD *m)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
OPENSSL_free(m);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
void ECDSA_METHOD_set_sign(ECDSA_METHOD *m, sign_sig_fn f)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
m->ecdsa_do_sign = f;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/********** Missing ECDH_METHOD functions for OpenSSL < 1.1.0 */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* ecdh_method maintains unchanged layout between 0.9.8 and 1.0.2 */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Data pointers and function pointers may have different sizes on some
|
|
Packit |
6b81fa |
* architectures */
|
|
Packit |
6b81fa |
struct ecdh_method {
|
|
Packit |
6b81fa |
char *name;
|
|
Packit |
6b81fa |
compute_key_fn compute_key;
|
|
Packit |
6b81fa |
int flags;
|
|
Packit |
6b81fa |
char *data;
|
|
Packit |
6b81fa |
};
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Define missing functions */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ECDH_METHOD *ECDH_METHOD_new(const ECDH_METHOD *m)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
ECDH_METHOD *out;
|
|
Packit |
6b81fa |
out = OPENSSL_malloc(sizeof(ECDH_METHOD));
|
|
Packit |
6b81fa |
if (out == NULL)
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
if (m)
|
|
Packit |
6b81fa |
memcpy(out, m, sizeof(ECDH_METHOD));
|
|
Packit |
6b81fa |
else
|
|
Packit |
6b81fa |
memset(out, 0, sizeof(ECDH_METHOD));
|
|
Packit |
6b81fa |
return out;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
void ECDH_METHOD_free(ECDH_METHOD *m)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
OPENSSL_free(m);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
void ECDH_METHOD_get_compute_key(ECDH_METHOD *m, compute_key_fn *f)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
*f = m->compute_key;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
void ECDH_METHOD_set_compute_key(ECDH_METHOD *m, compute_key_fn f)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
m->compute_key = f;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/********** Manage EC ex_data */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* NOTE: ECDH also uses ECDSA ex_data and *not* ECDH ex_data */
|
|
Packit |
6b81fa |
static void alloc_ec_ex_index()
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
if (ec_ex_index == 0) {
|
|
Packit |
6b81fa |
while (ec_ex_index == 0) /* Workaround for OpenSSL RT3710 */
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100002L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
ec_ex_index = EC_KEY_get_ex_new_index(0, "libp11 ec_key",
|
|
Packit |
6b81fa |
NULL, NULL, NULL);
|
|
Packit |
6b81fa |
#else
|
|
Packit |
6b81fa |
ec_ex_index = ECDSA_get_ex_new_index(0, "libp11 ecdsa",
|
|
Packit |
6b81fa |
NULL, NULL, NULL);
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
if (ec_ex_index < 0)
|
|
Packit |
6b81fa |
ec_ex_index = 0; /* Fallback to app_data */
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#if 0
|
|
Packit |
6b81fa |
/* TODO: Free the indexes on unload */
|
|
Packit |
6b81fa |
static void free_ec_ex_index()
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
if (ec_ex_index > 0) {
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100002L
|
|
Packit |
6b81fa |
/* CRYPTO_free_ex_index requires OpenSSL version >= 1.1.0-pre1 */
|
|
Packit |
6b81fa |
CRYPTO_free_ex_index(CRYPTO_EX_INDEX_EC_KEY, ec_ex_index);
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
ec_ex_index = 0;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/********** EVP_PKEY retrieval */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Retrieve EC parameters from key into ec
|
|
Packit |
6b81fa |
* return nonzero on error */
|
|
Packit |
6b81fa |
static int pkcs11_get_params(EC_KEY *ec, PKCS11_KEY *key)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
CK_BYTE *params;
|
|
Packit |
6b81fa |
size_t params_len = 0;
|
|
Packit |
6b81fa |
const unsigned char *a;
|
|
Packit |
6b81fa |
int rv;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (key_getattr_alloc(key, CKA_EC_PARAMS, ¶ms, ¶ms_len))
|
|
Packit |
6b81fa |
return -1;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
a = params;
|
|
Packit |
6b81fa |
rv = d2i_ECParameters(&ec, &a, (long)params_len) == NULL;
|
|
Packit |
6b81fa |
OPENSSL_free(params);
|
|
Packit |
6b81fa |
return rv;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Retrieve EC point from key into ec
|
|
Packit |
6b81fa |
* return nonzero on error */
|
|
Packit |
6b81fa |
static int pkcs11_get_point_key(EC_KEY *ec, PKCS11_KEY *key)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
CK_BYTE *point;
|
|
Packit |
6b81fa |
size_t point_len = 0;
|
|
Packit |
6b81fa |
const unsigned char *a;
|
|
Packit |
6b81fa |
ASN1_OCTET_STRING *os;
|
|
Packit |
6b81fa |
int rv = -1;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (key == NULL ||
|
|
Packit |
6b81fa |
key_getattr_alloc(key, CKA_EC_POINT, &point, &point_len))
|
|
Packit |
6b81fa |
return -1;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* PKCS#11-compliant modules should return ASN1_OCTET_STRING */
|
|
Packit |
6b81fa |
a = point;
|
|
Packit |
6b81fa |
os = d2i_ASN1_OCTET_STRING(NULL, &a, (long)point_len);
|
|
Packit |
6b81fa |
if (os) {
|
|
Packit |
6b81fa |
a = os->data;
|
|
Packit |
6b81fa |
rv = o2i_ECPublicKey(&ec, &a, os->length) == NULL;
|
|
Packit |
6b81fa |
ASN1_STRING_free(os);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
if (rv) { /* Workaround for broken PKCS#11 modules */
|
|
Packit |
6b81fa |
a = point;
|
|
Packit |
6b81fa |
rv = o2i_ECPublicKey(&ec, &a, (long)point_len) == NULL;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
OPENSSL_free(point);
|
|
Packit |
6b81fa |
return rv;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Retrieve EC point from cert into ec
|
|
Packit |
6b81fa |
* return nonzero on error */
|
|
Packit |
6b81fa |
static int pkcs11_get_point_cert(EC_KEY *ec, PKCS11_CERT *cert)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
EVP_PKEY *pubkey = NULL;
|
|
Packit |
6b81fa |
EC_KEY *pubkey_ec;
|
|
Packit |
6b81fa |
const EC_POINT *point;
|
|
Packit |
6b81fa |
int rv = -1;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (cert == NULL)
|
|
Packit |
6b81fa |
goto error;
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
pubkey = X509_get0_pubkey(cert->x509);
|
|
Packit |
6b81fa |
#else
|
|
Packit |
6b81fa |
pubkey = X509_get_pubkey(cert->x509);
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
if (pubkey == NULL)
|
|
Packit |
6b81fa |
goto error;
|
|
Packit |
6b81fa |
pubkey_ec = EVP_PKEY_get0_EC_KEY(pubkey);
|
|
Packit |
6b81fa |
if (pubkey_ec == NULL)
|
|
Packit |
6b81fa |
goto error;
|
|
Packit |
6b81fa |
point = EC_KEY_get0_public_key(pubkey_ec);
|
|
Packit |
6b81fa |
if (point == NULL)
|
|
Packit |
6b81fa |
goto error;
|
|
Packit |
6b81fa |
if (EC_KEY_set_public_key(ec, point) == 0)
|
|
Packit |
6b81fa |
goto error;
|
|
Packit |
6b81fa |
rv = 0;
|
|
Packit |
6b81fa |
error:
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
EVP_PKEY_free(pubkey);
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
return rv;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static EC_KEY *pkcs11_get_ec(PKCS11_KEY *key)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
EC_KEY *ec;
|
|
Packit |
6b81fa |
int no_params, no_point;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ec = EC_KEY_new();
|
|
Packit |
6b81fa |
if (ec == NULL)
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* For OpenSSL req we need at least the
|
|
Packit |
6b81fa |
* EC_KEY_get0_group(ec_key)) to return the group.
|
|
Packit |
6b81fa |
* Continue even if it fails, as the sign operation does not need
|
|
Packit |
6b81fa |
* it if the PKCS#11 module or the hardware can figure this out
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
no_params = pkcs11_get_params(ec, key);
|
|
Packit |
6b81fa |
no_point = pkcs11_get_point_key(ec, key);
|
|
Packit |
6b81fa |
if (no_point && key->isPrivate) /* Retry with the public key */
|
|
Packit |
6b81fa |
no_point = pkcs11_get_point_key(ec, pkcs11_find_key_from_key(key));
|
|
Packit |
6b81fa |
if (no_point && key->isPrivate) /* Retry with the certificate */
|
|
Packit |
6b81fa |
no_point = pkcs11_get_point_cert(ec, pkcs11_find_certificate(key));
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (key->isPrivate && EC_KEY_get0_private_key(ec) == NULL) {
|
|
Packit |
6b81fa |
BIGNUM *bn = BN_new();
|
|
Packit |
6b81fa |
EC_KEY_set_private_key(ec, bn);
|
|
Packit |
6b81fa |
BN_free(bn);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* A public keys requires both the params and the point to be present */
|
|
Packit |
6b81fa |
if (!key->isPrivate && (no_params || no_point)) {
|
|
Packit |
6b81fa |
EC_KEY_free(ec);
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
return ec;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
PKCS11_KEY *pkcs11_get_ex_data_ec(const EC_KEY *ec)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
return EC_KEY_get_ex_data(ec, ec_ex_index);
|
|
Packit |
6b81fa |
#else
|
|
Packit |
6b81fa |
return ECDSA_get_ex_data((EC_KEY *)ec, ec_ex_index);
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static void pkcs11_set_ex_data_ec(EC_KEY *ec, PKCS11_KEY *key)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
EC_KEY_set_ex_data(ec, ec_ex_index, key);
|
|
Packit |
6b81fa |
#else
|
|
Packit |
6b81fa |
ECDSA_set_ex_data(ec, ec_ex_index, key);
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static void pkcs11_update_ex_data_ec(PKCS11_KEY *key)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
EVP_PKEY *evp = key->evp_key;
|
|
Packit |
6b81fa |
EC_KEY *ec;
|
|
Packit |
6b81fa |
if (evp == NULL)
|
|
Packit |
6b81fa |
return;
|
|
Packit |
6b81fa |
if (EVP_PKEY_base_id(evp) != EVP_PKEY_EC)
|
|
Packit |
6b81fa |
return;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ec = EVP_PKEY_get1_EC_KEY(evp);
|
|
Packit |
6b81fa |
pkcs11_set_ex_data_ec(ec, key);
|
|
Packit |
6b81fa |
EC_KEY_free(ec);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/*
|
|
Packit |
6b81fa |
* Get EC key material and stash pointer in ex_data
|
|
Packit |
6b81fa |
* Note we get called twice, once for private key, and once for public
|
|
Packit |
6b81fa |
* We need to get the EC_PARAMS and EC_POINT into both,
|
|
Packit |
6b81fa |
* as lib11 dates from RSA only where all the pub key components
|
|
Packit |
6b81fa |
* were also part of the private key. With EC the point
|
|
Packit |
6b81fa |
* is not in the private key, and the params may or may not be.
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
static EVP_PKEY *pkcs11_get_evp_key_ec(PKCS11_KEY *key)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
EVP_PKEY *pk;
|
|
Packit |
6b81fa |
EC_KEY *ec;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ec = pkcs11_get_ec(key);
|
|
Packit |
6b81fa |
if (ec == NULL)
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
pk = EVP_PKEY_new();
|
|
Packit |
6b81fa |
if (pk == NULL) {
|
|
Packit |
6b81fa |
EC_KEY_free(ec);
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
EVP_PKEY_set1_EC_KEY(pk, ec); /* Also increments the ec ref count */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (key->isPrivate) {
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
EC_KEY_set_method(ec, PKCS11_get_ec_key_method());
|
|
Packit |
6b81fa |
#else
|
|
Packit |
6b81fa |
ECDSA_set_method(ec, PKCS11_get_ecdsa_method());
|
|
Packit |
6b81fa |
ECDH_set_method(ec, PKCS11_get_ecdh_method());
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
/* TODO: Retrieve the ECDSA private key object attributes instead,
|
|
Packit |
6b81fa |
* unless the key has the "sensitive" attribute set */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
pkcs11_set_ex_data_ec(ec, key);
|
|
Packit |
6b81fa |
EC_KEY_free(ec); /* Drops our reference to it */
|
|
Packit |
6b81fa |
return pk;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/********** ECDSA signing */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Signature size is the issue, will assume the caller has a big buffer! */
|
|
Packit |
6b81fa |
/* No padding or other stuff needed. We can call PKCS11 from here */
|
|
Packit |
6b81fa |
static int pkcs11_ecdsa_sign(const unsigned char *msg, unsigned int msg_len,
|
|
Packit |
6b81fa |
unsigned char *sigret, unsigned int *siglen, PKCS11_KEY *key)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
int rv;
|
|
Packit |
6b81fa |
PKCS11_SLOT *slot = KEY2SLOT(key);
|
|
Packit |
6b81fa |
PKCS11_CTX *ctx = KEY2CTX(key);
|
|
Packit |
6b81fa |
PKCS11_KEY_private *kpriv = PRIVKEY(key);
|
|
Packit |
6b81fa |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit |
6b81fa |
CK_MECHANISM mechanism;
|
|
Packit |
6b81fa |
CK_ULONG ck_sigsize;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ck_sigsize = *siglen;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
memset(&mechanism, 0, sizeof(mechanism));
|
|
Packit |
6b81fa |
mechanism.mechanism = CKM_ECDSA;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
CRYPTO_THREAD_write_lock(PRIVCTX(ctx)->rwlock);
|
|
Packit |
6b81fa |
rv = CRYPTOKI_call(ctx,
|
|
Packit |
6b81fa |
C_SignInit(spriv->session, &mechanism, kpriv->object));
|
|
Packit |
6b81fa |
if (!rv && kpriv->always_authenticate == CK_TRUE)
|
|
Packit |
6b81fa |
rv = pkcs11_authenticate(key);
|
|
Packit |
6b81fa |
if (!rv)
|
|
Packit |
6b81fa |
rv = CRYPTOKI_call(ctx,
|
|
Packit |
6b81fa |
C_Sign(spriv->session, (CK_BYTE *)msg, msg_len, sigret, &ck_sigsize));
|
|
Packit |
6b81fa |
CRYPTO_THREAD_unlock(PRIVCTX(ctx)->rwlock);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (rv) {
|
|
Packit |
6b81fa |
CKRerr(CKR_F_PKCS11_ECDSA_SIGN, rv);
|
|
Packit |
6b81fa |
return -1;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
*siglen = ck_sigsize;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
return ck_sigsize;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/**
|
|
Packit |
6b81fa |
* ECDSA signing method (replaces ossl_ecdsa_sign_sig)
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* @param dgst hash value to sign
|
|
Packit |
6b81fa |
* @param dlen length of the hash value
|
|
Packit |
6b81fa |
* @param kinv precomputed inverse k (from the sign_setup method)
|
|
Packit |
6b81fa |
* @param rp precomputed rp (from the sign_setup method)
|
|
Packit |
6b81fa |
* @param ec private EC signing key
|
|
Packit |
6b81fa |
* @return pointer to a ECDSA_SIG structure or NULL if an error occurred
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
static ECDSA_SIG *pkcs11_ecdsa_sign_sig(const unsigned char *dgst, int dlen,
|
|
Packit |
6b81fa |
const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *ec)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
unsigned char sigret[512]; /* HACK for now */
|
|
Packit |
6b81fa |
ECDSA_SIG *sig;
|
|
Packit |
6b81fa |
PKCS11_KEY *key;
|
|
Packit |
6b81fa |
unsigned int siglen;
|
|
Packit |
6b81fa |
BIGNUM *r, *s, *order;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
(void)kinv; /* Precomputed values are not used for PKCS#11 */
|
|
Packit |
6b81fa |
(void)rp; /* Precomputed values are not used for PKCS#11 */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
key = pkcs11_get_ex_data_ec(ec);
|
|
Packit |
6b81fa |
if (check_key_fork(key) < 0) {
|
|
Packit |
6b81fa |
sign_sig_fn orig_sign_sig;
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
const EC_KEY_METHOD *meth = EC_KEY_OpenSSL();
|
|
Packit |
6b81fa |
EC_KEY_METHOD_get_sign((EC_KEY_METHOD *)meth,
|
|
Packit |
6b81fa |
NULL, NULL, &orig_sign_sig);
|
|
Packit |
6b81fa |
#else
|
|
Packit |
6b81fa |
const ECDSA_METHOD *meth = ECDSA_OpenSSL();
|
|
Packit |
6b81fa |
orig_sign_sig = meth->ecdsa_do_sign;
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
return orig_sign_sig(dgst, dlen, kinv, rp, ec);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Truncate digest if its byte size is longer than needed */
|
|
Packit |
6b81fa |
order = BN_new();
|
|
Packit |
6b81fa |
if (order) {
|
|
Packit |
6b81fa |
const EC_GROUP *group = EC_KEY_get0_group(ec);
|
|
Packit |
6b81fa |
if (group && EC_GROUP_get_order(group, order, NULL)) {
|
|
Packit |
6b81fa |
int klen = BN_num_bits(order);
|
|
Packit |
6b81fa |
if (klen < 8*dlen)
|
|
Packit |
6b81fa |
dlen = (klen+7)/8;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
BN_free(order);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
siglen = sizeof sigret;
|
|
Packit |
6b81fa |
if (pkcs11_ecdsa_sign(dgst, dlen, sigret, &siglen, key) <= 0)
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
r = BN_bin2bn(sigret, siglen/2, NULL);
|
|
Packit |
6b81fa |
s = BN_bin2bn(sigret + siglen/2, siglen/2, NULL);
|
|
Packit |
6b81fa |
sig = ECDSA_SIG_new();
|
|
Packit |
6b81fa |
if (sig == NULL)
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
ECDSA_SIG_set0(sig, r, s);
|
|
Packit |
6b81fa |
#else
|
|
Packit |
6b81fa |
BN_free(sig->r);
|
|
Packit |
6b81fa |
sig->r = r;
|
|
Packit |
6b81fa |
BN_free(sig->s);
|
|
Packit |
6b81fa |
sig->s = s;
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
return sig;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/********** ECDH key derivation */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static CK_ECDH1_DERIVE_PARAMS *pkcs11_ecdh_params_alloc(
|
|
Packit |
6b81fa |
const EC_GROUP *group, const EC_POINT *point)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
CK_ECDH1_DERIVE_PARAMS *parms;
|
|
Packit |
6b81fa |
size_t len;
|
|
Packit |
6b81fa |
unsigned char *buf = NULL;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (group == NULL || point == NULL)
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
len = EC_POINT_point2oct(group, point,
|
|
Packit |
6b81fa |
POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
|
|
Packit |
6b81fa |
if (len == 0)
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
buf = OPENSSL_malloc(len);
|
|
Packit |
6b81fa |
if (buf == NULL)
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
len = EC_POINT_point2oct(group, point,
|
|
Packit |
6b81fa |
POINT_CONVERSION_UNCOMPRESSED, buf, len, NULL);
|
|
Packit |
6b81fa |
if (len == 0) {
|
|
Packit |
6b81fa |
OPENSSL_free(buf);
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
parms = OPENSSL_malloc(sizeof(CK_ECDH1_DERIVE_PARAMS));
|
|
Packit |
6b81fa |
if (parms == NULL) {
|
|
Packit |
6b81fa |
OPENSSL_free(buf);
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
parms->kdf = CKD_NULL;
|
|
Packit |
6b81fa |
parms->pSharedData = NULL;
|
|
Packit |
6b81fa |
parms->ulSharedDataLen = 0;
|
|
Packit |
6b81fa |
parms->pPublicData = buf;
|
|
Packit |
6b81fa |
parms->ulPublicDataLen = len;
|
|
Packit |
6b81fa |
return parms;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
static void pkcs11_ecdh_params_free(CK_ECDH1_DERIVE_PARAMS *parms)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
OPENSSL_free(parms->pPublicData);
|
|
Packit |
6b81fa |
OPENSSL_free(parms);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* initial code will only support what is needed for pkcs11_ec_ckey
|
|
Packit |
6b81fa |
* i.e. CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE
|
|
Packit |
6b81fa |
* and CK_EC_KDF_TYPE supported by token
|
|
Packit |
6b81fa |
* The secret key object is deleted
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* In future CKM_ECMQV_DERIVE with CK_ECMQV_DERIVE_PARAMS
|
|
Packit |
6b81fa |
* could also be supported, and the secret key object could be returned.
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
static int pkcs11_ecdh_derive(unsigned char **out, size_t *outlen,
|
|
Packit |
6b81fa |
const unsigned long ecdh_mechanism,
|
|
Packit |
6b81fa |
const void *ec_params,
|
|
Packit |
6b81fa |
void *outnewkey,
|
|
Packit |
6b81fa |
PKCS11_KEY *key)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
PKCS11_SLOT *slot = KEY2SLOT(key);
|
|
Packit |
6b81fa |
PKCS11_CTX *ctx = KEY2CTX(key);
|
|
Packit |
6b81fa |
PKCS11_TOKEN *token = KEY2TOKEN(key);
|
|
Packit |
6b81fa |
PKCS11_KEY_private *kpriv = PRIVKEY(key);
|
|
Packit |
6b81fa |
PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
|
|
Packit |
6b81fa |
CK_MECHANISM mechanism;
|
|
Packit |
6b81fa |
int rv;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
CK_BBOOL true = TRUE;
|
|
Packit |
6b81fa |
CK_BBOOL false = FALSE;
|
|
Packit |
6b81fa |
CK_OBJECT_HANDLE newkey = CK_INVALID_HANDLE;
|
|
Packit |
6b81fa |
CK_OBJECT_CLASS newkey_class= CKO_SECRET_KEY;
|
|
Packit |
6b81fa |
CK_KEY_TYPE newkey_type = CKK_GENERIC_SECRET;
|
|
Packit |
6b81fa |
CK_OBJECT_HANDLE *tmpnewkey = (CK_OBJECT_HANDLE *)outnewkey;
|
|
Packit |
6b81fa |
CK_ATTRIBUTE newkey_template[] = {
|
|
Packit |
6b81fa |
{CKA_TOKEN, &false, sizeof(false)}, /* session only object */
|
|
Packit |
6b81fa |
{CKA_CLASS, &newkey_class, sizeof(newkey_class)},
|
|
Packit |
6b81fa |
{CKA_KEY_TYPE, &newkey_type, sizeof(newkey_type)},
|
|
Packit |
6b81fa |
{CKA_ENCRYPT, &true, sizeof(true)},
|
|
Packit |
6b81fa |
{CKA_DECRYPT, &true, sizeof(true)}
|
|
Packit |
6b81fa |
};
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
memset(&mechanism, 0, sizeof(mechanism));
|
|
Packit |
6b81fa |
mechanism.mechanism = ecdh_mechanism;
|
|
Packit |
6b81fa |
mechanism.pParameter = (void*)ec_params;
|
|
Packit |
6b81fa |
switch (ecdh_mechanism) {
|
|
Packit |
6b81fa |
case CKM_ECDH1_DERIVE:
|
|
Packit |
6b81fa |
case CKM_ECDH1_COFACTOR_DERIVE:
|
|
Packit |
6b81fa |
mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS);
|
|
Packit |
6b81fa |
break;
|
|
Packit |
6b81fa |
#if 0
|
|
Packit |
6b81fa |
/* TODO */
|
|
Packit |
6b81fa |
case CK_ECMQV_DERIVE_PARAMS:
|
|
Packit |
6b81fa |
mechanism.ulParameterLen = sizeof(CK_ECMQV_DERIVE_PARAMS);
|
|
Packit |
6b81fa |
break;
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
default:
|
|
Packit |
6b81fa |
P11err(P11_F_PKCS11_ECDH_DERIVE, P11_R_NOT_SUPPORTED);
|
|
Packit |
6b81fa |
return -1;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
rv = CRYPTOKI_call(ctx, C_DeriveKey(spriv->session, &mechanism, kpriv->object, newkey_template, 5, &newkey));
|
|
Packit |
6b81fa |
CRYPTOKI_checkerr(CKR_F_PKCS11_ECDH_DERIVE, rv);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* Return the value of the secret key and/or the object handle of the secret key */
|
|
Packit |
6b81fa |
if (out && outlen) { /* pkcs11_ec_ckey only asks for the value */
|
|
Packit |
6b81fa |
if (pkcs11_getattr_alloc(token, newkey, CKA_VALUE, out, outlen)) {
|
|
Packit |
6b81fa |
CKRerr(CKR_F_PKCS11_ECDH_DERIVE, CKR_ATTRIBUTE_VALUE_INVALID);
|
|
Packit |
6b81fa |
CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, newkey));
|
|
Packit |
6b81fa |
return -1;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
if (tmpnewkey) /* For future use (not used by pkcs11_ec_ckey) */
|
|
Packit |
6b81fa |
*tmpnewkey = newkey;
|
|
Packit |
6b81fa |
else /* Destroy the temporary key */
|
|
Packit |
6b81fa |
CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, newkey));
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/**
|
|
Packit |
6b81fa |
* ECDH key derivation method (replaces ossl_ecdh_compute_key)
|
|
Packit |
6b81fa |
* Implementation for OpenSSL 1.1.0-pre4 and later
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* @param out derived key
|
|
Packit |
6b81fa |
* @param outlen derived key length
|
|
Packit |
6b81fa |
* @param peer_point public key point
|
|
Packit |
6b81fa |
* @param ecdh private key
|
|
Packit |
6b81fa |
* @return 1 on success or 0 on error
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
static int pkcs11_ec_ckey(unsigned char **out, size_t *outlen,
|
|
Packit |
6b81fa |
const EC_POINT *peer_point, const EC_KEY *ecdh)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
PKCS11_KEY *key;
|
|
Packit |
6b81fa |
CK_ECDH1_DERIVE_PARAMS *parms;
|
|
Packit |
6b81fa |
unsigned char *buf = NULL;
|
|
Packit |
6b81fa |
size_t buflen;
|
|
Packit |
6b81fa |
int rv;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
key = pkcs11_get_ex_data_ec(ecdh);
|
|
Packit |
6b81fa |
if (check_key_fork(key) < 0)
|
|
Packit |
6b81fa |
return ossl_ecdh_compute_key(out, outlen, peer_point, ecdh);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* both peer and ecdh use same group parameters */
|
|
Packit |
6b81fa |
parms = pkcs11_ecdh_params_alloc(EC_KEY_get0_group(ecdh), peer_point);
|
|
Packit |
6b81fa |
if (parms == NULL)
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
rv = pkcs11_ecdh_derive(&buf, &buflen, CKM_ECDH1_DERIVE, parms, NULL, key);
|
|
Packit |
6b81fa |
pkcs11_ecdh_params_free(parms);
|
|
Packit |
6b81fa |
if (rv < 0)
|
|
Packit |
6b81fa |
return 0;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
*out = buf;
|
|
Packit |
6b81fa |
*outlen = buflen;
|
|
Packit |
6b81fa |
return 1;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#else
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/**
|
|
Packit |
6b81fa |
* ECDH key derivation method (replaces ossl_ecdh_compute_key)
|
|
Packit |
6b81fa |
* Implementation for OpenSSL 1.1.0-pre3 and earlier
|
|
Packit |
6b81fa |
*
|
|
Packit |
6b81fa |
* @param out derived key
|
|
Packit |
6b81fa |
* @param outlen derived key length
|
|
Packit |
6b81fa |
* @param peer_point public key point
|
|
Packit |
6b81fa |
* @param ecdh private key
|
|
Packit |
6b81fa |
* @param KCF key derivation function
|
|
Packit |
6b81fa |
* @return the length of the derived key or -1 if an error occurred
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
static int pkcs11_ec_ckey(void *out, size_t outlen,
|
|
Packit |
6b81fa |
const EC_POINT *peer_point, const EC_KEY *ecdh,
|
|
Packit |
6b81fa |
void *(*KDF)(const void *, size_t, void *, size_t *))
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
PKCS11_KEY *key;
|
|
Packit |
6b81fa |
CK_ECDH1_DERIVE_PARAMS *parms;
|
|
Packit |
6b81fa |
unsigned char *buf = NULL;
|
|
Packit |
6b81fa |
size_t buflen;
|
|
Packit |
6b81fa |
int rv;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
key = pkcs11_get_ex_data_ec(ecdh);
|
|
Packit |
6b81fa |
if (check_key_fork(key) < 0)
|
|
Packit |
6b81fa |
return ossl_ecdh_compute_key(out, outlen, peer_point, ecdh, KDF);
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* both peer and ecdh use same group parameters */
|
|
Packit |
6b81fa |
parms = pkcs11_ecdh_params_alloc(EC_KEY_get0_group(ecdh), peer_point);
|
|
Packit |
6b81fa |
if (parms == NULL)
|
|
Packit |
6b81fa |
return -1;
|
|
Packit |
6b81fa |
rv = pkcs11_ecdh_derive(&buf, &buflen, CKM_ECDH1_DERIVE, parms, NULL, key);
|
|
Packit |
6b81fa |
pkcs11_ecdh_params_free(parms);
|
|
Packit |
6b81fa |
if (rv < 0)
|
|
Packit |
6b81fa |
return -1;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (KDF) {
|
|
Packit |
6b81fa |
if (KDF(buf, buflen, out, &outlen) == NULL) {
|
|
Packit |
6b81fa |
OPENSSL_free(buf);
|
|
Packit |
6b81fa |
return -1;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
} else {
|
|
Packit |
6b81fa |
if (outlen > buflen)
|
|
Packit |
6b81fa |
outlen = buflen;
|
|
Packit |
6b81fa |
memcpy(out, buf, outlen);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
OPENSSL_free(buf);
|
|
Packit |
6b81fa |
return outlen;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#endif
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/********** Set OpenSSL EC methods */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/*
|
|
Packit |
6b81fa |
* Overload the default OpenSSL methods for ECDSA
|
|
Packit |
6b81fa |
* If OpenSSL supports ECDSA_METHOD_new we will use it.
|
|
Packit |
6b81fa |
* First introduced in 1.0.2, changed in 1.1-pre
|
|
Packit |
6b81fa |
*/
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* New way to allocate an ECDSA_METOD object */
|
|
Packit |
6b81fa |
/* OpenSSL 1.1 has single method EC_KEY_METHOD for ECDSA and ECDH */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
EC_KEY_METHOD *PKCS11_get_ec_key_method(void)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
static EC_KEY_METHOD *ops = NULL;
|
|
Packit |
6b81fa |
int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
|
|
Packit |
6b81fa |
unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
alloc_ec_ex_index();
|
|
Packit |
6b81fa |
if (ops == NULL) {
|
|
Packit |
6b81fa |
ops = EC_KEY_METHOD_new((EC_KEY_METHOD *)EC_KEY_OpenSSL());
|
|
Packit |
6b81fa |
EC_KEY_METHOD_get_sign(ops, &orig_sign, NULL, NULL);
|
|
Packit |
6b81fa |
EC_KEY_METHOD_set_sign(ops, orig_sign, NULL, pkcs11_ecdsa_sign_sig);
|
|
Packit |
6b81fa |
EC_KEY_METHOD_get_compute_key(ops, &ossl_ecdh_compute_key);
|
|
Packit |
6b81fa |
EC_KEY_METHOD_set_compute_key(ops, pkcs11_ec_ckey);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
return ops;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* define old way to keep old engines working without ECDSA */
|
|
Packit |
6b81fa |
void *PKCS11_get_ecdsa_method(void)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
void *PKCS11_get_ecdh_method(void)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#else /* OPENSSL_VERSION_NUMBER */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* define new way to keep new engines from crashing with older libp11 */
|
|
Packit |
6b81fa |
void *PKCS11_get_ec_key_method(void)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ECDSA_METHOD *PKCS11_get_ecdsa_method(void)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
static ECDSA_METHOD *ops = NULL;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (ops == NULL) {
|
|
Packit |
6b81fa |
alloc_ec_ex_index();
|
|
Packit |
6b81fa |
ops = ECDSA_METHOD_new((ECDSA_METHOD *)ECDSA_OpenSSL());
|
|
Packit |
6b81fa |
ECDSA_METHOD_set_sign(ops, pkcs11_ecdsa_sign_sig);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
return ops;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ECDH_METHOD *PKCS11_get_ecdh_method(void)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
static ECDH_METHOD *ops = NULL;
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
if (ops == NULL) {
|
|
Packit |
6b81fa |
alloc_ec_ex_index();
|
|
Packit |
6b81fa |
ops = ECDH_METHOD_new((ECDH_METHOD *)ECDH_OpenSSL());
|
|
Packit |
6b81fa |
ECDH_METHOD_get_compute_key(ops, &ossl_ecdh_compute_key);
|
|
Packit |
6b81fa |
ECDH_METHOD_set_compute_key(ops, pkcs11_ec_ckey);
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
return ops;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#endif /* OPENSSL_VERSION_NUMBER */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
PKCS11_KEY_ops pkcs11_ec_ops_s = {
|
|
Packit |
6b81fa |
EVP_PKEY_EC,
|
|
Packit |
6b81fa |
pkcs11_get_evp_key_ec,
|
|
Packit |
6b81fa |
pkcs11_update_ex_data_ec,
|
|
Packit |
6b81fa |
};
|
|
Packit |
6b81fa |
PKCS11_KEY_ops *pkcs11_ec_ops = {&pkcs11_ec_ops_s};
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#else /* OPENSSL_NO_EC */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
PKCS11_KEY_ops *pkcs11_ec_ops = {NULL};
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* if not built with EC or OpenSSL does not support ECDSA
|
|
Packit |
6b81fa |
* add these routines so engine_pkcs11 can be built now and not
|
|
Packit |
6b81fa |
* require further changes */
|
|
Packit |
6b81fa |
#warning "ECDSA support not built with libp11"
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
ECDSA_METHOD *PKCS11_get_ecdsa_method(void)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
return NULL;
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
#endif /* OPENSSL_NO_EC */
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* TODO: remove this function in libp11 0.5.0 */
|
|
Packit |
6b81fa |
void PKCS11_ecdsa_method_free(void)
|
|
Packit |
6b81fa |
{
|
|
Packit |
6b81fa |
/* no op */
|
|
Packit |
6b81fa |
}
|
|
Packit |
6b81fa |
|
|
Packit |
6b81fa |
/* vim: set noexpandtab: */
|