You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 2295f64
Browse filesBrowse the repository at this point in the historyBrowse files
openssl compat: cut EVP, EVP_PKEY and PEM overhead, and fix defects found
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.
0 commit comments