-
Notifications
You must be signed in to change notification settings - Fork 32
Add initial support for crypto callbacks. #114
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 8 commits
ec8c0cc
57901a7
b7a0995
67794e4
c7306ed
d2debf4
4532f74
edb22ae
90fce4b
55971eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| # test_cryptocb.py | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 [Medium] Missing test coverage for callback error paths and SHA-2 device_id The new tests cover only the happy path for RNG (SHA-1 hash) and default_device_id. There is no coverage for: (a) a callback returning the wrong number of bytes (the Fix: Extend test_cryptocb.py to cover error paths, unsupported-algo fallthrough, and SHA-256/384/512 device routing.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a Sha256,Sha384,Sha512 and a Sha3 test case. (good flow). |
||
| # | ||
| # Copyright (C) 2026 wolfSSL Inc. | ||
| # | ||
| # This file is part of wolfSSL. (formerly known as CyaSSL) | ||
| # | ||
| # wolfSSL is free software; you can redistribute it and/or modify | ||
| # it under the terms of the GNU General Public License as published by | ||
| # the Free Software Foundation; either version 2 of the License, or | ||
| # (at your option) any later version. | ||
| # | ||
| # wolfSSL is distributed in the hope that it will be useful, | ||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| # GNU General Public License for more details. | ||
| # | ||
| # You should have received a copy of the GNU General Public License | ||
| # along with this program; if not, write to the Free Software | ||
| # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA | ||
| # ty: ignore[possibly-missing-import] | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import struct | ||
|
|
||
| import pytest | ||
| from typing_extensions import override | ||
|
|
||
| from wolfcrypt._ffi import lib as _lib | ||
| from wolfcrypt.random import Random | ||
|
|
||
| if _lib.SHA_ENABLED: | ||
| from wolfcrypt.hashes import Sha | ||
|
|
||
| if not _lib.CRYPTO_CB_ENABLED: | ||
| pytest.skip("Crypto Callbacks not supported", allow_module_level=True) | ||
|
|
||
| from wolfcrypt.cryptocb import CryptoCallback | ||
|
|
||
|
|
||
| def test_default_device_id(): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟠 [Medium] Hash callbacks and error paths are untested; default-device-id test asserts nothing Only the RNG callback path is exercised. There is no coverage for Fix: Add tests for the hash update/finalize paths, the length-mismatch/error paths, and the unknown-algo fallback; make
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed the Added test to check support for crypto callbacks for hash functions. For this some infrastructure had to be added to the |
||
| # In the python implementation the default device ID is the invalid device ID. | ||
| assert CryptoCallback.default_device_id() == _lib.INVALID_DEVID | ||
|
|
||
| class RngCryptoCallback(CryptoCallback): | ||
| @override | ||
| def rng_callback(self, device_id: int, rng: _lib.RNG, size: int) -> bytes: | ||
| # Generate fake random data for testing purposes. | ||
| return bytes(range(1, 1 + size)) | ||
|
|
||
|
|
||
| def test_rng_callback(): | ||
| with RngCryptoCallback(10): | ||
| rng = Random(device_id=10) | ||
|
|
||
| random = rng.byte() | ||
| assert random == b"\01" | ||
|
|
||
| random = rng.bytes(1) | ||
| assert random == b"\01" | ||
|
|
||
| random = rng.bytes(3) | ||
| assert random == b"\01\02\03" | ||
|
|
||
| class HashCryptoCallback(CryptoCallback): | ||
| def __init__(self, device_id): | ||
| super().__init__(device_id) | ||
| self.data: list[bytes] = [] | ||
|
|
||
| @override | ||
| def hash_update_callback(self, device_id: int, hash_type: int, data: bytes) -> None: | ||
| self.data.append(data) | ||
|
|
||
| @override | ||
| def hash_finalize_callback(self, device_id: int, hash_type: int) -> bytes: | ||
| # quite lame hash function, just returns the length of the data as an integer (padded to match the expected hash length). | ||
| return struct.pack("I16x", len(b"".join(self.data))) | ||
|
|
||
|
|
||
| if _lib.SHA_ENABLED: | ||
| def test_hash_callback(): | ||
| with HashCryptoCallback(11): | ||
| sha = Sha(device_id=11) | ||
| sha.update(bytes(10)) | ||
| sha.update(bytes(5)) | ||
| digest = sha.digest() | ||
| assert digest == struct.pack("I16x", 15) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,10 @@ | |
| # along with this program; if not, write to the Free Software | ||
| # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA | ||
|
|
||
| import os | ||
| import sys | ||
| from typing import TYPE_CHECKING | ||
|
|
||
| from wolfcrypt._version import __version__, __wolfssl_version__ | ||
|
|
||
| __title__ = "wolfcrypt" | ||
|
|
@@ -33,21 +37,37 @@ | |
| __all__ = [ | ||
| "__title__", "__summary__", "__uri__", "__version__", "__wolfssl_version__", | ||
| "__author__", "__email__", "__license__", "__copyright__", | ||
| "ciphers", "hashes", "random", "pwdbased" | ||
| "ciphers", "hashes", "random", "pwdbased", "cryptocb" | ||
| ] | ||
|
|
||
| import os | ||
| import sys | ||
|
|
||
| top_level_py = os.path.basename(sys.argv[0]) | ||
|
|
||
| # The code below is intended to only be used after the CFFI is built, so we | ||
| # don't want it invoked whilst building the CFFI with build_ffi.py or setup.py. | ||
| if top_level_py not in ["setup.py", "build_ffi.py"]: | ||
| from wolfcrypt._ffi import ffi as _ffi | ||
| from wolfcrypt._ffi import lib as _lib | ||
|
|
||
| if TYPE_CHECKING: | ||
| if _lib.CRYPTO_CB_ENABLED: | ||
| from wolfcrypt.cryptocb import CryptoCallback # ty: ignore[possibly-missing-import] | ||
| from wolfcrypt.exceptions import WolfCryptApiError | ||
|
|
||
| # Only wolfCrypt_Init() is called here. | ||
| # Calling wolfCrypt_Cleanup() is not needed as the application exit() will clean up the entire process | ||
| # including any wolfcrypt data in any case. | ||
| ret = _lib.wolfCrypt_Init() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔵 [Low] wolfCrypt_Init() added with no corresponding cleanup
Fix: Confirm the omission of
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a comment that it is not needed to call this function. This function initializes a global data structure that lives as long as the application and gets cleaned up together with the process. |
||
| if ret < 0: | ||
| raise WolfCryptApiError("WolfCrypt_Init failed", ret) | ||
|
|
||
| if _lib.CRYPTO_CB_ENABLED: | ||
| @_ffi.def_extern() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔴 [High] Uncaught callback exceptions report success (0) to wolfCrypt with an unfilled buffer
Fix: Pass a negative
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added an Also added a test to check the correct handling of a |
||
| def py_wc_crypto_callback(device_id: int, info: _ffi.CData, ctx: _ffi.CData) -> int: | ||
| if ctx == _ffi.NULL: | ||
| return _lib.CRYPTOCB_UNAVAILABLE | ||
| crypto_cb: CryptoCallback = _ffi.from_handle(ctx) | ||
| return crypto_cb.callback(device_id, info) | ||
|
|
||
| if hasattr(_lib, 'WC_RNG_SEED_CB_ENABLED'): | ||
| if _lib.WC_RNG_SEED_CB_ENABLED: | ||
| ret = _lib.wc_SetSeed_Cb(_ffi.addressof(_lib, "wc_GenerateSeed")) # ty: ignore[no-matching-overload] | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.