mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
ipapython: use python-cryptography instead of libcrypto in p11helper
Replace CFFI calls to libcrypto with equivalent python-cryptography code. https://fedorahosted.org/freeipa/ticket/5596 Reviewed-By: Martin Basti <mbasti@redhat.com>
This commit is contained in:
committed by
Martin Basti
parent
500ee7e2b1
commit
b808376e2f
@@ -6,6 +6,9 @@ import random
|
||||
import ctypes.util
|
||||
|
||||
import six
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa
|
||||
from cffi import FFI
|
||||
|
||||
if six.PY3:
|
||||
@@ -15,71 +18,6 @@ if six.PY3:
|
||||
_ffi = FFI()
|
||||
|
||||
_ffi.cdef('''
|
||||
/* stdlib.h */
|
||||
|
||||
void free(void *ptr);
|
||||
|
||||
|
||||
/* openssl/ossl_typ.h */
|
||||
|
||||
typedef ... BIGNUM;
|
||||
|
||||
typedef ... EVP_PKEY;
|
||||
|
||||
typedef struct rsa_st RSA;
|
||||
typedef ... RSA_METHOD;
|
||||
|
||||
typedef ... ENGINE;
|
||||
|
||||
typedef ... CRYPTO_EX_DATA;
|
||||
|
||||
|
||||
/* openssl/x509.h */
|
||||
|
||||
int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp);
|
||||
EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length);
|
||||
|
||||
|
||||
/* openssl/evp.h */
|
||||
|
||||
int EVP_PKEY_set1_RSA(EVP_PKEY *pkey, struct rsa_st *key);
|
||||
struct rsa_st *EVP_PKEY_get1_RSA(EVP_PKEY *pkey);
|
||||
|
||||
EVP_PKEY *EVP_PKEY_new(void);
|
||||
void EVP_PKEY_free(EVP_PKEY *pkey);
|
||||
|
||||
|
||||
/* openssl/bn.h */
|
||||
|
||||
int BN_num_bits(const BIGNUM *a);
|
||||
BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret);
|
||||
int BN_bn2bin(const BIGNUM *a, unsigned char *to);
|
||||
|
||||
void BN_free(BIGNUM *a);
|
||||
|
||||
|
||||
/* openssl/rsa.h */
|
||||
|
||||
struct rsa_st {
|
||||
/*
|
||||
* The first parameter is used to pickup errors where this is passed
|
||||
* instead of aEVP_PKEY, it is set to 0
|
||||
*/
|
||||
int pad;
|
||||
long version;
|
||||
const RSA_METHOD *meth;
|
||||
/* functional reference if 'meth' is ENGINE-provided */
|
||||
ENGINE *engine;
|
||||
BIGNUM *n;
|
||||
BIGNUM *e;
|
||||
/* ...; */
|
||||
};
|
||||
|
||||
RSA *RSA_new(void);
|
||||
|
||||
void RSA_free(RSA *r);
|
||||
|
||||
|
||||
/* p11-kit/pkcs11.h */
|
||||
|
||||
typedef unsigned long CK_FLAGS;
|
||||
@@ -366,8 +304,6 @@ struct ck_rsa_pkcs_oaep_params {
|
||||
typedef struct ck_rsa_pkcs_oaep_params CK_RSA_PKCS_OAEP_PARAMS;
|
||||
''')
|
||||
|
||||
_libc = _ffi.dlopen(None)
|
||||
_libcrypto = _ffi.dlopen(ctypes.util.find_library('crypto'))
|
||||
_libp11_kit = _ffi.dlopen(ctypes.util.find_library('p11-kit'))
|
||||
|
||||
|
||||
@@ -376,8 +312,6 @@ _libp11_kit = _ffi.dlopen(ctypes.util.find_library('p11-kit'))
|
||||
NULL = _ffi.NULL
|
||||
|
||||
unsigned_char = _ffi.typeof('unsigned char')
|
||||
unsigned_char_ptr = _ffi.typeof('unsigned char *')
|
||||
unsigned_int = _ffi.typeof('unsigned int')
|
||||
unsigned_long = _ffi.typeof('unsigned long')
|
||||
|
||||
sizeof = _ffi.sizeof
|
||||
@@ -391,47 +325,6 @@ def new_array(ctype, *args):
|
||||
return _ffi.new(_ffi.getctype(ctype, '[]'), *args)
|
||||
|
||||
|
||||
# stdlib.h
|
||||
|
||||
free = _libc.free
|
||||
|
||||
|
||||
# openssl/x509.h
|
||||
|
||||
i2d_PUBKEY = _libcrypto.i2d_PUBKEY
|
||||
d2i_PUBKEY = _libcrypto.i2d_PUBKEY
|
||||
|
||||
|
||||
# openssl/evp.h
|
||||
|
||||
EVP_PKEY_RSA = 6
|
||||
EVP_PKEY_DSA = 116
|
||||
EVP_PKEY_EC = 408
|
||||
|
||||
EVP_PKEY_set1_RSA = _libcrypto.EVP_PKEY_set1_RSA
|
||||
EVP_PKEY_get1_RSA = _libcrypto.EVP_PKEY_get1_RSA
|
||||
EVP_PKEY_new = _libcrypto.EVP_PKEY_new
|
||||
EVP_PKEY_free = _libcrypto.EVP_PKEY_free
|
||||
|
||||
|
||||
# openssl/bn.h
|
||||
|
||||
def BN_num_bytes(a):
|
||||
return (_libcrypto.BN_num_bits(a) + 7) // 8
|
||||
|
||||
BN_bin2bn = _libcrypto.BN_bin2bn
|
||||
BN_bn2bin = _libcrypto.BN_bn2bin
|
||||
|
||||
BN_free = _libcrypto.BN_free
|
||||
|
||||
|
||||
# openssl/rsa.h
|
||||
|
||||
RSA_new = _libcrypto.RSA_new
|
||||
|
||||
RSA_free = _libcrypto.RSA_free
|
||||
|
||||
|
||||
# p11-kit/pkcs11.h
|
||||
|
||||
CK_SESSION_HANDLE = _ffi.typeof('CK_SESSION_HANDLE')
|
||||
@@ -656,6 +549,17 @@ def char_array_to_unicode(array, l):
|
||||
return _ffi.buffer(array, l)[:].decode('utf-8')
|
||||
|
||||
|
||||
def int_to_bytes(value):
|
||||
try:
|
||||
return '{0:x}'.format(value).decode('hex')
|
||||
except TypeError:
|
||||
return '0{0:x}'.format(value).decode('hex')
|
||||
|
||||
|
||||
def bytes_to_int(value):
|
||||
return int(value.encode('hex'), 16)
|
||||
|
||||
|
||||
def check_return_value(rv, message):
|
||||
"""
|
||||
Tests result value of pkc11 operations
|
||||
@@ -1279,11 +1183,6 @@ class P11_Helper(object):
|
||||
"""
|
||||
export RSA public key
|
||||
"""
|
||||
pp_ptr = new_ptr(unsigned_char_ptr, NULL)
|
||||
pkey = NULL
|
||||
e = NULL
|
||||
n = NULL
|
||||
rsa = NULL
|
||||
class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_PUBLIC_KEY)
|
||||
key_type_ptr = new_ptr(CK_KEY_TYPE, CKK_RSA)
|
||||
|
||||
@@ -1320,46 +1219,37 @@ class P11_Helper(object):
|
||||
raise Error("export_RSA_public_key: required RSA key type")
|
||||
|
||||
try:
|
||||
rsa = RSA_new()
|
||||
pkey = EVP_PKEY_new()
|
||||
n = BN_bin2bn(modulus,
|
||||
obj_template[0].ulValueLen * sizeof(CK_BYTE), NULL)
|
||||
if n == NULL:
|
||||
raise Error("export_RSA_public_key: internal error: unable to "
|
||||
"convert modulus")
|
||||
n = bytes_to_int(string_to_pybytes_or_none(
|
||||
modulus, obj_template[0].ulValueLen))
|
||||
except Exception:
|
||||
raise Error("export_RSA_public_key: internal error: unable to "
|
||||
"convert modulus")
|
||||
|
||||
e = BN_bin2bn(exponent,
|
||||
obj_template[1].ulValueLen * sizeof(CK_BYTE), NULL)
|
||||
if e == NULL:
|
||||
raise Error("export_RSA_public_key: internal error: unable to "
|
||||
"convert exponent")
|
||||
try:
|
||||
e = bytes_to_int(string_to_pybytes_or_none(
|
||||
exponent, obj_template[1].ulValueLen))
|
||||
except Exception:
|
||||
raise Error("export_RSA_public_key: internal error: unable to "
|
||||
"convert exponent")
|
||||
|
||||
# set modulus and exponent
|
||||
rsa.n = n
|
||||
rsa.e = e
|
||||
# set modulus and exponent
|
||||
rsa_ = rsa.RSAPublicNumbers(e, n)
|
||||
|
||||
if EVP_PKEY_set1_RSA(pkey, rsa) == 0:
|
||||
raise Error("export_RSA_public_key: internal error: "
|
||||
"EVP_PKEY_set1_RSA failed")
|
||||
try:
|
||||
pkey = rsa_.public_key(default_backend())
|
||||
except Exception:
|
||||
raise Error("export_RSA_public_key: internal error: "
|
||||
"EVP_PKEY_set1_RSA failed")
|
||||
|
||||
pp_len = i2d_PUBKEY(pkey, pp_ptr)
|
||||
ret = string_to_pybytes_or_none(pp_ptr[0], pp_len)
|
||||
try:
|
||||
ret = pkey.public_bytes(
|
||||
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
||||
encoding=serialization.Encoding.DER,
|
||||
)
|
||||
except Exception:
|
||||
ret = None
|
||||
|
||||
return ret
|
||||
finally:
|
||||
if rsa != NULL:
|
||||
# this frees also 'n' and 'e'
|
||||
RSA_free(rsa)
|
||||
else:
|
||||
if n != NULL:
|
||||
BN_free(n)
|
||||
if e != NULL:
|
||||
BN_free(e)
|
||||
|
||||
if pkey != NULL:
|
||||
EVP_PKEY_free(pkey)
|
||||
if pp_ptr[0] != NULL:
|
||||
free(pp_ptr[0])
|
||||
return ret
|
||||
|
||||
def export_public_key(self, key_handle):
|
||||
"""
|
||||
@@ -1400,57 +1290,50 @@ class P11_Helper(object):
|
||||
class_ptr = new_ptr(CK_OBJECT_CLASS, CKO_PUBLIC_KEY)
|
||||
keyType_ptr = new_ptr(CK_KEY_TYPE, CKK_RSA)
|
||||
cka_token = true_ptr
|
||||
rsa = NULL
|
||||
|
||||
if pkey.type != EVP_PKEY_RSA:
|
||||
if not isinstance(pkey, rsa.RSAPublicKey):
|
||||
raise Error("Required RSA public key")
|
||||
|
||||
try:
|
||||
rsa = EVP_PKEY_get1_RSA(pkey)
|
||||
if rsa == NULL:
|
||||
raise Error("import_RSA_public_key: EVP_PKEY_get1_RSA error")
|
||||
rsa_ = pkey.public_numbers()
|
||||
|
||||
# convert BIGNUM to binary array
|
||||
modulus = new_array(CK_BYTE, BN_num_bytes(rsa.n))
|
||||
modulus_len = BN_bn2bin(rsa.n, modulus)
|
||||
if modulus_len == 0:
|
||||
raise Error("import_RSA_public_key: BN_bn2bin modulus error")
|
||||
# convert BIGNUM to binary array
|
||||
modulus = new_array(CK_BYTE, int_to_bytes(rsa_.n))
|
||||
modulus_len = sizeof(modulus) - 1
|
||||
if modulus_len == 0:
|
||||
raise Error("import_RSA_public_key: BN_bn2bin modulus error")
|
||||
|
||||
exponent = new_array(CK_BYTE, BN_num_bytes(rsa.e))
|
||||
exponent_len = BN_bn2bin(rsa.e, exponent)
|
||||
if exponent_len == 0:
|
||||
raise Error("import_RSA_public_key: BN_bn2bin exponent error")
|
||||
exponent = new_array(CK_BYTE, int_to_bytes(rsa_.e))
|
||||
exponent_len = sizeof(exponent) - 1
|
||||
if exponent_len == 0:
|
||||
raise Error("import_RSA_public_key: BN_bn2bin exponent error")
|
||||
|
||||
template = new_array(CK_ATTRIBUTE, (
|
||||
(CKA_ID, id, id_length),
|
||||
(CKA_CLASS, class_ptr, sizeof(CK_OBJECT_CLASS)),
|
||||
(CKA_KEY_TYPE, keyType_ptr, sizeof(CK_KEY_TYPE)),
|
||||
(CKA_TOKEN, cka_token, sizeof(CK_BBOOL)),
|
||||
(CKA_LABEL, label, label_length),
|
||||
(CKA_MODULUS, modulus, modulus_len),
|
||||
(CKA_PUBLIC_EXPONENT, exponent, exponent_len),
|
||||
# TODO Softhsm doesn't support it
|
||||
# (CKA_COPYABLE, cka_copyable, sizeof(CK_BBOOL)),
|
||||
(CKA_DERIVE, cka_derive, sizeof(CK_BBOOL)),
|
||||
(CKA_ENCRYPT, cka_encrypt, sizeof(CK_BBOOL)),
|
||||
(CKA_MODIFIABLE, cka_modifiable, sizeof(CK_BBOOL)),
|
||||
(CKA_PRIVATE, cka_private, sizeof(CK_BBOOL)),
|
||||
(CKA_TRUSTED, cka_trusted, sizeof(CK_BBOOL)),
|
||||
(CKA_VERIFY, cka_verify, sizeof(CK_BBOOL)),
|
||||
(CKA_VERIFY_RECOVER, cka_verify_recover, sizeof(CK_BBOOL)),
|
||||
(CKA_WRAP, cka_wrap, sizeof(CK_BBOOL)),
|
||||
))
|
||||
object_ptr = new_ptr(CK_OBJECT_HANDLE)
|
||||
template = new_array(CK_ATTRIBUTE, (
|
||||
(CKA_ID, id, id_length),
|
||||
(CKA_CLASS, class_ptr, sizeof(CK_OBJECT_CLASS)),
|
||||
(CKA_KEY_TYPE, keyType_ptr, sizeof(CK_KEY_TYPE)),
|
||||
(CKA_TOKEN, cka_token, sizeof(CK_BBOOL)),
|
||||
(CKA_LABEL, label, label_length),
|
||||
(CKA_MODULUS, modulus, modulus_len),
|
||||
(CKA_PUBLIC_EXPONENT, exponent, exponent_len),
|
||||
# TODO Softhsm doesn't support it
|
||||
# (CKA_COPYABLE, cka_copyable, sizeof(CK_BBOOL)),
|
||||
(CKA_DERIVE, cka_derive, sizeof(CK_BBOOL)),
|
||||
(CKA_ENCRYPT, cka_encrypt, sizeof(CK_BBOOL)),
|
||||
(CKA_MODIFIABLE, cka_modifiable, sizeof(CK_BBOOL)),
|
||||
(CKA_PRIVATE, cka_private, sizeof(CK_BBOOL)),
|
||||
(CKA_TRUSTED, cka_trusted, sizeof(CK_BBOOL)),
|
||||
(CKA_VERIFY, cka_verify, sizeof(CK_BBOOL)),
|
||||
(CKA_VERIFY_RECOVER, cka_verify_recover, sizeof(CK_BBOOL)),
|
||||
(CKA_WRAP, cka_wrap, sizeof(CK_BBOOL)),
|
||||
))
|
||||
object_ptr = new_ptr(CK_OBJECT_HANDLE)
|
||||
|
||||
rv = self.p11.C_CreateObject(self.session, template,
|
||||
(sizeof(template) //
|
||||
sizeof(CK_ATTRIBUTE)), object_ptr)
|
||||
check_return_value(rv, "create public key object")
|
||||
rv = self.p11.C_CreateObject(self.session, template,
|
||||
(sizeof(template) //
|
||||
sizeof(CK_ATTRIBUTE)), object_ptr)
|
||||
check_return_value(rv, "create public key object")
|
||||
|
||||
return object_ptr[0]
|
||||
finally:
|
||||
if rsa != NULL:
|
||||
RSA_free(rsa)
|
||||
return object_ptr[0]
|
||||
|
||||
def import_public_key(self, label, id, data, cka_copyable=True,
|
||||
cka_derive=False, cka_encrypt=False,
|
||||
@@ -1467,11 +1350,7 @@ class P11_Helper(object):
|
||||
|
||||
label_unicode = label
|
||||
id_ = new_array(CK_BYTE, id)
|
||||
data_ = new_array(CK_BYTE, data)
|
||||
data_ptr = new_ptr(CK_BYTE_PTR, data_)
|
||||
id_length = len(id)
|
||||
data_length = len(data)
|
||||
pkey = NULL
|
||||
|
||||
attrs_pub = (
|
||||
cka_copyable,
|
||||
@@ -1495,34 +1374,31 @@ class P11_Helper(object):
|
||||
cka_private_ptr, cka_trusted_ptr, cka_verify_ptr,
|
||||
cka_verify_recover_ptr, cka_wrap_ptr,) = convert_py2bool(attrs_pub)
|
||||
|
||||
# decode from ASN1 DER
|
||||
try:
|
||||
# decode from ASN1 DER
|
||||
pkey = d2i_PUBKEY(NULL, data_ptr, data_length)
|
||||
if pkey == NULL:
|
||||
raise Error("import_public_key: d2i_PUBKEY error")
|
||||
if pkey.type == EVP_PKEY_RSA:
|
||||
ret = self._import_RSA_public_key(label, label_length, id_,
|
||||
id_length, pkey,
|
||||
cka_copyable_ptr,
|
||||
cka_derive_ptr,
|
||||
cka_encrypt_ptr,
|
||||
cka_modifiable_ptr,
|
||||
cka_private_ptr,
|
||||
cka_trusted_ptr,
|
||||
cka_verify_ptr,
|
||||
cka_verify_recover_ptr,
|
||||
cka_wrap_ptr)
|
||||
elif pkey.type == EVP_PKEY_DSA:
|
||||
raise Error("DSA is not supported")
|
||||
elif pkey.type == EVP_PKEY_EC:
|
||||
raise Error("EC is not supported")
|
||||
else:
|
||||
raise Error("Unsupported key type")
|
||||
pkey = serialization.load_der_public_key(data, default_backend())
|
||||
except Exception:
|
||||
raise Error("import_public_key: d2i_PUBKEY error")
|
||||
if isinstance(pkey, rsa.RSAPublicKey):
|
||||
ret = self._import_RSA_public_key(label, label_length, id_,
|
||||
id_length, pkey,
|
||||
cka_copyable_ptr,
|
||||
cka_derive_ptr,
|
||||
cka_encrypt_ptr,
|
||||
cka_modifiable_ptr,
|
||||
cka_private_ptr,
|
||||
cka_trusted_ptr,
|
||||
cka_verify_ptr,
|
||||
cka_verify_recover_ptr,
|
||||
cka_wrap_ptr)
|
||||
elif isinstance(pkey, dsa.DSAPublicKey):
|
||||
raise Error("DSA is not supported")
|
||||
elif isinstance(pkey, ec.EllipticCurvePublicKey):
|
||||
raise Error("EC is not supported")
|
||||
else:
|
||||
raise Error("Unsupported key type")
|
||||
|
||||
return ret
|
||||
finally:
|
||||
if pkey != NULL:
|
||||
EVP_PKEY_free(pkey)
|
||||
return ret
|
||||
|
||||
def export_wrapped_key(self, key, wrapping_key, wrapping_mech):
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user