Add signature generation and verification.
parent
10ba23046b
commit
7a847cf9b1
|
@ -461,6 +461,11 @@ if ASN_ENABLED:
|
|||
static const long PRIVATEKEY_TYPE;
|
||||
static const long PUBLICKEY_TYPE;
|
||||
static const long CERT_TYPE;
|
||||
static const long MAX_DER_DIGEST_SZ;
|
||||
static const long SHAh;
|
||||
static const long SHA256h;
|
||||
static const long SHA384h;
|
||||
static const long SHA512h;
|
||||
|
||||
typedef struct DerBuffer {
|
||||
byte* buffer;
|
||||
|
@ -476,6 +481,8 @@ if ASN_ENABLED:
|
|||
int* keyFormat);
|
||||
int wc_DerToPemEx(const byte* der, word32 derSz, byte* output, word32 outSz,
|
||||
byte *cipher_info, int type);
|
||||
word32 wc_EncodeSignature(byte* out, const byte* digest, word32 digSz,
|
||||
int hashOID);
|
||||
"""
|
||||
|
||||
ffibuilder.cdef(_cdef)
|
||||
|
|
|
@ -22,9 +22,16 @@
|
|||
|
||||
from wolfcrypt._ffi import ffi as _ffi
|
||||
from wolfcrypt._ffi import lib as _lib
|
||||
|
||||
from wolfcrypt.exceptions import WolfCryptError
|
||||
|
||||
if _lib.SHA_ENABLED:
|
||||
from wolfcrypt.hashes import Sha
|
||||
if _lib.SHA256_ENABLED:
|
||||
from wolfcrypt.hashes import Sha256
|
||||
if _lib.SHA384_ENABLED:
|
||||
from wolfcrypt.hashes import Sha384
|
||||
if _lib.SHA512_ENABLED:
|
||||
from wolfcrypt.hashes import Sha512
|
||||
|
||||
if _lib.ASN_ENABLED:
|
||||
def pem_to_der(pem, pem_type):
|
||||
|
@ -52,3 +59,40 @@ if _lib.ASN_ENABLED:
|
|||
raise WolfCryptError(err)
|
||||
|
||||
return _ffi.buffer(pem, pem_length)[:]
|
||||
|
||||
def hash_oid_from_class(hash_cls):
|
||||
if hash_cls == Sha:
|
||||
return _lib.SHAh
|
||||
elif hash_cls == Sha256:
|
||||
return _lib.SHA256h
|
||||
elif hash_cls == Sha384:
|
||||
return _lib.SHA384h
|
||||
elif hash_cls == Sha512:
|
||||
return _lib.SHA512h
|
||||
else:
|
||||
err = "Unknown hash class {}.".format(hash_cls.__name__)
|
||||
raise WolfCryptError(err)
|
||||
|
||||
def make_signature(data, hash_cls, key=None):
|
||||
hash_obj = hash_cls()
|
||||
hash_obj.update(data)
|
||||
digest = hash_obj.digest()
|
||||
|
||||
plaintext_sig = _ffi.new("byte[%d]" % _lib.MAX_DER_DIGEST_SZ)
|
||||
hash_oid = hash_oid_from_class(hash_cls)
|
||||
plaintext_len = _lib.wc_EncodeSignature(plaintext_sig, digest,
|
||||
len(digest), hash_oid)
|
||||
if plaintext_len == 0:
|
||||
err = "Error calling wc_EncodeSignature. ({})".format(plaintext_len)
|
||||
raise WolfCryptError(err)
|
||||
|
||||
plaintext_sig = _ffi.buffer(plaintext_sig, plaintext_len)[:]
|
||||
if key:
|
||||
return key.sign(plaintext_sig)
|
||||
else:
|
||||
return plaintext_sig
|
||||
|
||||
def check_signature(signature, data, hash_cls, pub_key):
|
||||
computed_signature = make_signature(data, hash_cls)
|
||||
decrypted_signature = pub_key.verify(signature)
|
||||
return computed_signature == decrypted_signature
|
||||
|
|
|
@ -5,7 +5,7 @@ from wolfcrypt._ffi import lib as _lib
|
|||
from wolfcrypt.utils import h2b
|
||||
|
||||
if _lib.ASN_ENABLED:
|
||||
from wolfcrypt.asn import pem_to_der, der_to_pem
|
||||
from wolfcrypt.asn import pem_to_der, der_to_pem, make_signature, check_signature
|
||||
if _lib.SHA256_ENABLED:
|
||||
from wolfcrypt.hashes import Sha256
|
||||
if _lib.RSA_ENABLED:
|
||||
|
@ -38,6 +38,42 @@ def pem_der_conversion_vectors():
|
|||
|
||||
return vectors
|
||||
|
||||
@pytest.fixture
|
||||
def signature_vectors():
|
||||
TestVector = namedtuple("TestVector", """data signature hash_cls pub_key
|
||||
priv_key""")
|
||||
TestVector.__new__.__defaults__ = (None,) * len(TestVector._fields)
|
||||
|
||||
vectors = []
|
||||
|
||||
with open(os.path.join(certs_dir, "server-keyPub.pem"), "rb") as f:
|
||||
pub_key_pem = f.read()
|
||||
with open(os.path.join(certs_dir, "server-key.pem"), "rb") as f:
|
||||
priv_key_pem = f.read()
|
||||
|
||||
# Signature computed with:
|
||||
# echo -n "wolfcrypt is the best crypto around" | \
|
||||
# openssl dgst -hex -sha256 -sign tests/certs/server-key.pem
|
||||
if _lib.ASN_ENABLED and _lib.SHA256_ENABLED and _lib.RSA_ENABLED:
|
||||
vectors.append(TestVector(
|
||||
data="wolfcrypt is the best crypto around",
|
||||
signature=h2b("1d65f21df8fdc9f3c2351792840423481c6b0f2332105abd9248"
|
||||
"9e0dc8f6f8c740e267cf49f522f771eabd484f961eaf9f907c97"
|
||||
"b513bb9de7411b508c4e7ab7dc4438890ca161a9e24addaffd3c"
|
||||
"86821f2431f55fde5d131dfbe5805dea74e8882bfbfbf451f809"
|
||||
"ed792dfb0b17c799e6a39f866ed9cf613138c9e5e99f757ea13a"
|
||||
"2b9c167c294cd89f38365ab40175d4e29c24d672cd5ad2d57fec"
|
||||
"e9ea2b29c1866235c791ec5b635b858512c2b832b1b8f1dc6854"
|
||||
"cd4927df5519eefee439848c7f109548b3a3c8265658e009899a"
|
||||
"51a4edaf9f1199f93e448482f27c43a53e0bc65b04e9848128e3"
|
||||
"60314e864190e6bb9812bfbf4b40994f2c1d4ca7aad9"),
|
||||
hash_cls=Sha256,
|
||||
pub_key=RsaPublic.from_pem(pub_key_pem),
|
||||
priv_key=RsaPrivate.from_pem(priv_key_pem)
|
||||
))
|
||||
|
||||
return vectors
|
||||
|
||||
def test_pem_der_conversion(pem_der_conversion_vectors):
|
||||
for vector in pem_der_conversion_vectors:
|
||||
computed_der = pem_to_der(vector.pem, vector.type)
|
||||
|
@ -45,3 +81,9 @@ def test_pem_der_conversion(pem_der_conversion_vectors):
|
|||
|
||||
computed_pem = der_to_pem(vector.der, vector.type)
|
||||
assert computed_pem == vector.pem
|
||||
|
||||
def test_signature(signature_vectors):
|
||||
for vector in signature_vectors:
|
||||
assert make_signature(vector.data, vector.hash_cls, vector.priv_key) == vector.signature
|
||||
assert check_signature(vector.signature, vector.data, vector.hash_cls,
|
||||
vector.pub_key)
|
||||
|
|
Loading…
Reference in New Issue