Repository navigation
Conversation
|
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Portability failures, unsafe failure paths, RNG lifetime defects, and mutex initialization races remain unresolved.
10 open findings
Protect rngInited reads with the mutex · New Assert holder size without rejecting valid tail padding · New Synchronize lazy mutex initialization · New Clear copied PKEY context before deep-copy failure · New Prevent RSA from retaining a dangling EVP_PKEY RNG · New Propagate deferred-encoding failure · New Free decoded key object in test · New Correct GCM IV comment mislabeled as CCM · New Correct ARIA-GCM IV comment mislabeled as CCM · New Correct SM4-GCM IV comment · New
What changed in this PR
Optimizes OpenSSL compatibility APIs while correcting EVP, PEM, CCM, Base64, key-lifecycle, and X509 caching behavior.
Changes:
- Defers costly RNG and DER initialization and caches decoded X509 public keys.
- Optimizes cipher/digest lookup, Base64 processing, and PEM BIO parsing.
- Expands compatibility and regression coverage.
| File | Description |
|---|---|
wolfssl/wolfcrypt/types.h |
Adds XMEMCHR portability support. |
wolfssl/wolfcrypt/coding.h |
Declares streaming Base64 decoding. |
wolfssl/ssl.h |
Tracks deferred PKEY state. |
wolfssl/openssl/sha3.h |
Corrects SHA3 holder sizing. |
wolfssl/openssl/rsa.h |
Tracks deferred RSA RNG state. |
wolfssl/openssl/evp.h |
Adds CCM message state. |
wolfssl/internal.h |
Adds cached X509 key support. |
wolfcrypt/src/wc_port.c |
Implements wc_memchr. |
wolfcrypt/src/evp_pk.c |
Integrates deferred DER generation. |
wolfcrypt/src/coding.c |
Optimizes Base64 encoding and decoding. |
wolfcrypt/src/evp.c |
Implements EVP optimizations and compatibility fixes. |
wolfcrypt/src/aes.c |
Removes invalid GMULT macros. |
tests/api/test_port.c |
Tests wc_memchr. |
tests/api/test_ossl_x509_pk.h |
Registers X509 cache tests. |
tests/api/test_ossl_x509_pk.c |
Tests cached-key reference handling. |
tests/api/test_ossl_x509_io.h |
Registers PEM BIO tests. |
tests/api/test_ossl_x509_io.c |
Tests multi-certificate BIO parsing. |
tests/api/test_ossl_rsa.h |
Registers lazy-RNG tests. |
tests/api/test_ossl_rsa.c |
Tests deferred RSA blinding RNGs. |
tests/api/test_evp.h |
Registers chunked Base64 tests. |
tests/api/test_evp.c |
Tests chunk-independent encoding. |
tests/api/test_evp_pkey.h |
Registers deferred-DER tests. |
tests/api/test_evp_pkey.c |
Tests lazy PKEY encoding and ownership. |
tests/api/test_evp_digest.h |
Registers digest regression tests. |
tests/api/test_evp_digest.c |
Tests digest context lookup and copying. |
tests/api/test_evp_cipher.h |
Registers cipher and CCM tests. |
tests/api/test_evp_cipher.c |
Tests CCM semantics and cipher lookup. |
tests/api/test_coding.h |
Registers Base64 vectors. |
tests/api/test_coding.c |
Adds Base64 known-answer tests. |
src/x509.c |
Caches keys and optimizes PEM parsing. |
src/ssl.c |
Enables shared RNG use where safe. |
src/ssl_p7p12.c |
Ensures DER before PKCS operations. |
src/ssl_load.c |
Ensures DER before loading keys. |
src/ssl_crypto.c |
Adds SHA3 size validation. |
src/pk.c |
Ensures DER before key serialization. |
src/pk_rsa.c |
Defers RSA blinding RNG creation. |
src/internal.c |
Releases cached X509 keys. |
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
SparkiDev
force-pushed
the
openssl_compat_api_perf_fixes_1
branch
from
October 8, 2026 08:47
c923bc3 to
7602e88
Compare
…ound Performance: - Size WOLFSSL_SHA3_CTX's holder in pointers, not bytes. It reserved sizeof(wc_Sha3) pointers for a 440 byte object, so WOLFSSL_Hasher goes 3520 -> 448 bytes and WOLFSSL_EVP_MD_CTX 3552 -> 944. A static assert now catches the same mistake. - Resolve digests and ciphers by table pointer before comparing names, and return the table's own pointer from the accessors. EVP_sha256() 47.4 -> 1.2ns, EVP_MD_type 64.7 -> 4.3ns, EVP_CIPHER_nid 101.2 -> 8.1ns. - Copy only the fields past the hash union in EVP_MD_CTX_copy_ex, and leave the cipher union alone in EVP_CIPHER_CTX_init. - Set up an EVP_PKEY's RNG, an RSA key's blinding RNG and an EVP_PKEY's DER encoding on first use rather than at creation. Seeding a DRBG cost more than everything else about making a key put together. EVP_PKEY_new + free 13366 -> 34ns, RSA_new + free 13748 -> 230ns, EVP_PKEY_set1_RSA 13994 -> 45ns. Certificate parsing roughly halves as a result: d2i_X509 45978 -> 17198ns, X509_dup 45945 -> 17116ns, both now faster than OpenSSL. set1_DSA still encodes immediately, as WOLFSSL_DSA is not reference counted and the pkey only borrows the caller's key. - Keep the decoded public key on the X509 and hand out a reference, as OpenSSL does. X509_get_pubkey + free 27692 -> 9.8ns, against 9.6ns. - Give public key operations the shared global RNG instead of seeding one per call, where the instance locks itself or the build is single threaded. WOLFSSL_PK_LOCAL_RNG forces an RNG per call. EVP_DigestSign with ECDSA P-256 32291 -> 17008ns, against 18852ns. - Encode base64 without a call per output character, and hand whole blocks to Base64_Encode() rather than one 48 byte line at a time. EVP_EncodeUpdate 6446 -> 1855ns per 4KB. Skip the call into Base64_SkipNewline() for characters needing no skipping: EVP_DecodeUpdate 37059 -> 16194ns. What remains there is the constant time character decode, which is deliberate; wc_PemToDer() already picks the table decoder by PEM type. - Search cipher_tbl before the alias table in EVP_get_cipherbyname(), since over half the aliases only spell a name already there in another case, and compare without the platform's strcasecmp: 330 -> 67ns. The comparison is ASCII only, so it no longer follows the locale and works on platforms whose XSTRCASECMP is strcmp. - Find the PEM footer in a memory BIO's buffer and read up to it, rather than reading a byte at a time through the whole input. Loading a certificate from a file that carries a text dump alongside it 100311 -> 23301ns, against 33006ns. Fixes: - AES-CCM through EVP now behaves as OpenSSL's does: the payload length comes from the first Update() carrying payload, AAD before the length is refused, and Final() has nothing left to do. Of 376 observables compared against OpenSSL - the tag and IV length matrices, the defaults, length inference over 48 sizes, and an encrypt/decrypt matrix with the tag then corrupted - 375 agree. The one that differs, EVP_CIPHER_iv_length() reporting CCM_NONCE_MIN_SZ where OpenSSL reports 12, is unchanged by this work. - EVP_get_cipherbyname(NULL) and EVP_get_digestbyname(NULL) dereferenced the name; OpenSSL returns NULL. - EVP_EncodeUpdate() wrote the block it was holding and then wrote over it, so a caller feeding data in pieces got wrong bytes, including bytes never written. - EVP_PKEY_keygen() on DH read the parameters after replacing the key object they came from, which is the same object when a caller passes its own key back in. - EVP_PKEY_set1_EC_KEY() with an empty EC_KEY now succeeds. It reported failure only as a side effect of encoding eagerly; OpenSSL returns 1 and the empty key is caught when the encoding is asked for. - Remove three GMULT macros naming functions that do not exist. Portability: - Add XMEMCHR, with wc_memchr() for builds naming their own string functions through STRING_USER that have no memchr among them. Tests: - Known answer vectors for the base64 encoders, generated independently of wolfSSL. testwolfcrypt passed with the encoder deliberately corrupted, as it only checked return codes. - EVP_EncodeUpdate() over every chunking of ten sizes straddling the 48 byte block, and PEM_read_bio_X509() reading several certificates from one BIO while leaving nothing behind after one. - EVP_get_cipherbyname() over canonical names, alternative spellings, every casing of each, and NULL. - One RSA private key operation per freshly decoded key: sharing a key lets the first operation provide the blinding RNG and hides a missing one in the rest. Plus EVP_PKEY_set1_DSA() followed by the caller releasing its key. - The reference counting behind the cached X509 public key: outliving the certificate and the caller, replacement, and duplication. - wc_memchr(), guarded by USE_WOLF_MEMCHR so it runs where that function is built.
SparkiDev
force-pushed
the
openssl_compat_api_perf_fixes_1
branch
from
October 8, 2026 09:22
7602e88 to
0591bab
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
Performance:
Fixes:
Portability:
Tests:
Testing
Tested on ARM64 with SM algorithms.
Note: wolfsm fixes required:
wolfSSL/wolfsm#37