Skip to content

Commit 8295068

Browse files
committed
Port tests from 25a6aa and accept -output case-insensitively
Port the regression and argument-handling tests added in merge 25a6aa across the Python test suite (bench, dgst, enc, genkey-sign-ver, hash, rsa, CRL-verify, x509-process, x509-req). The ed25519 signature-size test exercises `-output KEYPAIR`, which the genkey setup was comparing case-sensitively against "keypair" — the uppercase form caused an error-path return for ed25519 and silently worked for other algorithms only because their directiveArg was already initialized to PRIV_AND_PUB_FILES. OpenSSL treats option values like `-outform PEM` case-insensitively, and wolfCLU's own help text for `-output` uses uppercase PUB/PRIV/KEYPAIR, so switch the PUB/PRIV/KEYPAIR comparisons to XSTRNCASECMP throughout clu_genkey_setup.c.
1 parent 840211a commit 8295068

10 files changed

Lines changed: 315 additions & 22 deletions

File tree

src/genkey/clu_genkey_setup.c

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -104,13 +104,13 @@ int wolfCLU_genKeySetup(int argc, char** argv)
104104
ret = wolfCLU_checkForArg("-output", 7, argc, argv);
105105
if (ret > 0) {
106106
if (argv[ret+1] != NULL) {
107-
if (XSTRNCMP(argv[ret+1], "pub", 3) == 0)
107+
if (XSTRNCASECMP(argv[ret+1], "pub", 3) == 0)
108108
ret = wolfCLU_genKey_ED25519(&rng, keyOutFName, PUB_ONLY_FILE,
109109
formatArg);
110-
else if (XSTRNCMP(argv[ret+1], "priv", 4) == 0)
110+
else if (XSTRNCASECMP(argv[ret+1], "priv", 4) == 0)
111111
ret = wolfCLU_genKey_ED25519(&rng, keyOutFName, PRIV_ONLY_FILE,
112112
formatArg);
113-
else if (XSTRNCMP(argv[ret+1], "keypair", 7) == 0)
113+
else if (XSTRNCASECMP(argv[ret+1], "keypair", 7) == 0)
114114
ret = wolfCLU_genKey_ED25519(&rng, keyOutFName,
115115
PRIV_AND_PUB_FILES, formatArg);
116116
}
@@ -141,11 +141,11 @@ int wolfCLU_genKeySetup(int argc, char** argv)
141141
ret = wolfCLU_checkForArg("-output", 7, argc, argv);
142142
if (ret > 0) {
143143
if (argv[ret+1] != NULL) {
144-
if (XSTRNCMP(argv[ret+1], "pub", 3) == 0)
144+
if (XSTRNCASECMP(argv[ret+1], "pub", 3) == 0)
145145
directiveArg = PUB_ONLY_FILE;
146-
else if (XSTRNCMP(argv[ret+1], "priv", 4) == 0)
146+
else if (XSTRNCASECMP(argv[ret+1], "priv", 4) == 0)
147147
directiveArg = PRIV_ONLY_FILE;
148-
else if (XSTRNCMP(argv[ret+1], "keypair", 7) == 0)
148+
else if (XSTRNCASECMP(argv[ret+1], "keypair", 7) == 0)
149149
directiveArg = PRIV_AND_PUB_FILES;
150150
}
151151
}
@@ -196,11 +196,11 @@ int wolfCLU_genKeySetup(int argc, char** argv)
196196
ret = wolfCLU_checkForArg("-output", 7, argc, argv);
197197
if (ret > 0) {
198198
if (argv[ret+1] != NULL) {
199-
if (XSTRNCMP(argv[ret+1], "pub", 3) == 0)
199+
if (XSTRNCASECMP(argv[ret+1], "pub", 3) == 0)
200200
directiveArg = PUB_ONLY_FILE;
201-
else if (XSTRNCMP(argv[ret+1], "priv", 4) == 0)
201+
else if (XSTRNCASECMP(argv[ret+1], "priv", 4) == 0)
202202
directiveArg = PRIV_ONLY_FILE;
203-
else if (XSTRNCMP(argv[ret+1], "keypair", 7) == 0)
203+
else if (XSTRNCASECMP(argv[ret+1], "keypair", 7) == 0)
204204
directiveArg = PRIV_AND_PUB_FILES;
205205
}
206206
}
@@ -320,11 +320,11 @@ int wolfCLU_genKeySetup(int argc, char** argv)
320320
ret = wolfCLU_checkForArg("-output", 7, argc, argv);
321321
if (ret > 0) {
322322
if (argv[ret+1] != NULL) {
323-
if (XSTRNCMP(argv[ret+1], "pub", 3) == 0)
323+
if (XSTRNCASECMP(argv[ret+1], "pub", 3) == 0)
324324
directiveArg = PUB_ONLY_FILE;
325-
else if (XSTRNCMP(argv[ret+1], "priv", 4) == 0)
325+
else if (XSTRNCASECMP(argv[ret+1], "priv", 4) == 0)
326326
directiveArg = PRIV_ONLY_FILE;
327-
else if (XSTRNCMP(argv[ret+1], "keypair", 7) == 0)
327+
else if (XSTRNCASECMP(argv[ret+1], "keypair", 7) == 0)
328328
directiveArg = PRIV_AND_PUB_FILES;
329329
}
330330
}
@@ -386,11 +386,11 @@ int wolfCLU_genKeySetup(int argc, char** argv)
386386
ret = wolfCLU_checkForArg("-output", 7, argc, argv);
387387
if (ret > 0) {
388388
if (argv[ret+1] != NULL) {
389-
if (XSTRNCMP(argv[ret+1], "pub", 3) == 0)
389+
if (XSTRNCASECMP(argv[ret+1], "pub", 3) == 0)
390390
directiveArg = PUB_ONLY_FILE;
391-
else if (XSTRNCMP(argv[ret+1], "priv", 4) == 0)
391+
else if (XSTRNCASECMP(argv[ret+1], "priv", 4) == 0)
392392
directiveArg = PRIV_ONLY_FILE;
393-
else if (XSTRNCMP(argv[ret+1], "keypair", 7) == 0)
393+
else if (XSTRNCASECMP(argv[ret+1], "keypair", 7) == 0)
394394
directiveArg = PRIV_AND_PUB_FILES;
395395
}
396396
}
@@ -430,11 +430,11 @@ int wolfCLU_genKeySetup(int argc, char** argv)
430430
ret = wolfCLU_checkForArg("-output", 7, argc, argv);
431431
if (ret > 0) {
432432
if (argv[ret+1] != NULL) {
433-
if (XSTRNCMP(argv[ret+1], "pub", 3) == 0)
433+
if (XSTRNCASECMP(argv[ret+1], "pub", 3) == 0)
434434
directiveArg = PUB_ONLY_FILE;
435-
else if (XSTRNCMP(argv[ret+1], "priv", 4) == 0)
435+
else if (XSTRNCASECMP(argv[ret+1], "priv", 4) == 0)
436436
directiveArg = PRIV_ONLY_FILE;
437-
else if (XSTRNCMP(argv[ret+1], "keypair", 7) == 0)
437+
else if (XSTRNCASECMP(argv[ret+1], "keypair", 7) == 0)
438438
directiveArg = PRIV_AND_PUB_FILES;
439439
}
440440
}
@@ -590,11 +590,11 @@ int wolfCLU_genKeySetup(int argc, char** argv)
590590
ret = wolfCLU_checkForArg("-output", 7, argc, argv);
591591
if (ret > 0) {
592592
if (argv[ret+1] != NULL) {
593-
if (XSTRNCMP(argv[ret+1], "pub", 3) == 0)
593+
if (XSTRNCASECMP(argv[ret+1], "pub", 3) == 0)
594594
directiveArg = PUB_ONLY_FILE;
595-
else if (XSTRNCMP(argv[ret+1], "priv", 4) == 0)
595+
else if (XSTRNCASECMP(argv[ret+1], "priv", 4) == 0)
596596
directiveArg = PRIV_ONLY_FILE;
597-
else if (XSTRNCMP(argv[ret+1], "keypair", 7) == 0)
597+
else if (XSTRNCASECMP(argv[ret+1], "keypair", 7) == 0)
598598
directiveArg = PRIV_AND_PUB_FILES;
599599
}
600600
}

tests/bench/bench-test.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ def test_bench_md5(self):
2323
result = run_wolfssl("-bench", "md5", "-time", "1")
2424
self.assertEqual(result.returncode, 0, result.stderr)
2525

26+
def test_bench_missing_time_value(self):
27+
"""-time with no value must fail gracefully (no segfault)."""
28+
result = run_wolfssl("-bench", "-time")
29+
self.assertNotEqual(result.returncode, 0,
30+
"expected failure for missing -time value")
31+
self.assertGreaterEqual(result.returncode, 0,
32+
"-bench -time crashed with signal "
33+
"{}".format(result.returncode))
34+
2635

2736
if __name__ == "__main__":
2837
test_main()

tests/dgst/dgst-test.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,25 @@ def test_fail_wrong_digest(self):
7474
os.path.join(CERTS_DIR, "server-key.der"))
7575
self.assertNotEqual(r.returncode, 0)
7676

77+
def test_dgst_out_roundtrip(self):
78+
"""dgst -out creates the signature file; -signature round-trips."""
79+
sig_file = "dgst-out-test.sig"
80+
self.addCleanup(lambda: os.remove(sig_file)
81+
if os.path.exists(sig_file) else None)
82+
input_file = os.path.join(CERTS_DIR, "server-key.der")
83+
84+
r = run_wolfssl("dgst", "-sha256", "-sign",
85+
os.path.join(CERTS_DIR, "server-key.pem"),
86+
"-out", sig_file, input_file)
87+
self.assertEqual(r.returncode, 0, r.stderr)
88+
self.assertTrue(os.path.isfile(sig_file),
89+
"dgst -out did not create output file")
90+
91+
r = run_wolfssl("dgst", "-sha256", "-verify",
92+
os.path.join(CERTS_DIR, "server-keyPub.pem"),
93+
"-signature", sig_file, input_file)
94+
self.assertEqual(r.returncode, 0, r.stderr)
95+
7796

7897
class DgstLargeFileTest(unittest.TestCase):
7998

tests/encrypt/enc-test.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,23 @@ def test_small_file(self):
130130
self.assertTrue(filecmp.cmp(small, dec, shallow=False),
131131
"small file decryption mismatch")
132132

133+
def test_explicit_hex_key_iv(self):
134+
"""Regression: explicit --key/--iv hex strings must be copied correctly."""
135+
src = "enc_hex_test.txt"
136+
enc = "enc_hex_test.enc"
137+
self._cleanup(src, enc)
138+
139+
with open(src, "w") as f:
140+
f.write("testing explicit hex IV and key\n")
141+
142+
r = run_wolfssl("enc", "-aes-128-cbc", "-nosalt",
143+
"-in", src, "-out", enc,
144+
"--key", "00112233445566778899aabbccddeeff",
145+
"--iv", "00112233445566778899aabb0011aab7")
146+
self.assertEqual(r.returncode, 0,
147+
"encrypt with explicit hex key/iv failed: "
148+
"{}".format(r.stderr))
149+
133150

134151
class EncInteropTest(unittest.TestCase):
135152
"""Test interoperability with OpenSSL (skipped if openssl not available)."""

tests/genkey_sign_ver/genkey-sign-ver-test.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,18 @@ def test_ed25519_pem(self):
135135
def test_ed25519_raw(self):
136136
self._gen_sign_verify("ed25519", "edkey", "ed-signed.sig", "raw")
137137

138+
def test_ed25519_signature_size(self):
139+
"""ED25519 signatures must be exactly 64 bytes."""
140+
priv, pub = self._genkey("ed25519", "edkey-sztest", "der",
141+
use_output_flag=True)
142+
sig_file = "ed-sz-test.sig"
143+
self._sign("ed25519", priv, "der", sig_file)
144+
145+
sig_size = os.path.getsize(sig_file)
146+
self.assertEqual(sig_size, 64,
147+
"ED25519 signature size is {}, expected 64".format(
148+
sig_size))
149+
138150

139151
class EccTest(_GenkeySignVerifyBase):
140152

@@ -160,6 +172,55 @@ def test_ecc_der(self):
160172
def test_ecc_pem(self):
161173
self._gen_sign_verify("ecc", "ecckey", "ecc-signed.sig", "pem")
162174

175+
def test_ecc_der_key_size_and_roundtrip(self):
176+
"""Regression: ECC DER private key must be reasonably sized, and the
177+
full sign/verify round-trip must succeed on the generated keypair."""
178+
priv, pub = self._genkey("ecc", "ecc-rt-test", "der",
179+
use_output_flag=True)
180+
181+
key_size = os.path.getsize(priv)
182+
self.assertLessEqual(key_size, 256,
183+
"ECC DER private key too large ({} bytes), "
184+
"may contain trailing garbage".format(key_size))
185+
186+
data_file = "ecc-rt-data.txt"
187+
sig_file = "ecc-rt-test.sig"
188+
self._track(data_file, sig_file)
189+
with open(data_file, "w") as f:
190+
f.write("ECC round trip test data\n")
191+
192+
r = run_wolfssl("-ecc", "-sign", "-inkey", priv, "-inform", "der",
193+
"-in", data_file, "-out", sig_file)
194+
self.assertEqual(r.returncode, 0,
195+
"ECC sign round-trip failed: {}".format(r.stderr))
196+
197+
r = run_wolfssl("-ecc", "-verify", "-inkey", pub, "-pubin",
198+
"-inform", "der", "-sigfile", sig_file,
199+
"-in", data_file)
200+
self.assertEqual(r.returncode, 0,
201+
"ECC verify round-trip failed: {}".format(r.stderr))
202+
203+
def test_ecc_sign_invalid_key_fails(self):
204+
"""Signing with an empty key file must fail gracefully."""
205+
bad_key = "bad-ecc-key.der"
206+
bad_sig = "bad-ecc-sign.sig"
207+
self._track(bad_key, bad_sig)
208+
open(bad_key, "wb").close()
209+
210+
r = run_wolfssl("-ecc", "-sign", "-inkey", bad_key, "-inform", "der",
211+
"-in", self.SIGN_FILE, "-out", bad_sig)
212+
self.assertNotEqual(r.returncode, 0,
213+
"ECC signing with empty key should have failed")
214+
215+
def test_ecc_sign_missing_inkey_value(self):
216+
"""-inkey with no value must fail gracefully (no segfault)."""
217+
r = run_wolfssl("-ecc", "-sign", "-inkey")
218+
self.assertNotEqual(r.returncode, 0,
219+
"expected failure for missing -inkey value")
220+
self.assertGreaterEqual(r.returncode, 0,
221+
"-inkey without value crashed with signal "
222+
"{}".format(r.returncode))
223+
163224

164225
class RsaTest(_GenkeySignVerifyBase):
165226

@@ -197,6 +258,18 @@ def test_rsa_exponent_flag(self):
197258
self.assertEqual(r.returncode, 0,
198259
f"rsa genkey with -exponent failed: {r.stderr}")
199260

261+
def test_rsa_sign_invalid_key_fails(self):
262+
"""RSA signing with an empty key file must fail gracefully."""
263+
bad_key = "bad-rsa-key.der"
264+
bad_sig = "bad-rsa-sign.sig"
265+
self._track(bad_key, bad_sig)
266+
open(bad_key, "wb").close()
267+
268+
r = run_wolfssl("-rsa", "-sign", "-inkey", bad_key, "-inform", "der",
269+
"-in", self.SIGN_FILE, "-out", bad_sig)
270+
self.assertNotEqual(r.returncode, 0,
271+
"RSA signing with empty key should have failed")
272+
200273

201274
@unittest.skipUnless(_has_algorithm("dilithium"),
202275
"dilithium not available")
@@ -252,6 +325,18 @@ def test_sign_bad_path(self):
252325
self.assertNotEqual(r.returncode, 0,
253326
"sign to invalid path should have failed")
254327

328+
def test_sign_nonexistent_key_fails(self):
329+
"""Dilithium sign with nonexistent key file must fail gracefully."""
330+
bad_sig = "bad-dil.sig"
331+
self._track(bad_sig)
332+
r = run_wolfssl("-dilithium", "-sign",
333+
"-inkey", os.path.join("nonexistent_dir", "key.priv"),
334+
"-inform", "der", "-in", self.SIGN_FILE,
335+
"-out", bad_sig)
336+
self.assertNotEqual(r.returncode, 0,
337+
"Dilithium sign with nonexistent key should have "
338+
"failed")
339+
255340

256341
@unittest.skipUnless(_has_algorithm("xmss"), "xmss not available")
257342
class XmssTest(_GenkeySignVerifyBase):
@@ -264,6 +349,17 @@ def test_xmss_raw(self):
264349
extra_genkey_args=["-height", "10"],
265350
skip_priv_verify=True, use_output_flag=True)
266351

352+
def test_xmss_missing_height_value(self):
353+
"""-height with no value must fail gracefully (no crash)."""
354+
self._track("xmss-bad.priv", "xmss-bad.pub")
355+
r = run_wolfssl("-genkey", "xmss", "-out", "xmss-bad",
356+
"-outform", "raw", "-output", "KEYPAIR", "-height")
357+
self.assertNotEqual(r.returncode, 0,
358+
"expected failure for missing -height value")
359+
self.assertGreaterEqual(r.returncode, 0,
360+
"-height without value crashed with signal "
361+
"{}".format(r.returncode))
362+
267363

268364
if __name__ == "__main__":
269365
test_main()

tests/hash/hash-test.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,5 +88,18 @@ def test_sha512(self):
8888
self.assertEqual(r.stdout.strip(), _read_expected("sha512-expect.hex"))
8989

9090

91+
class HashArgErrorTest(unittest.TestCase):
92+
"""Argument-handling regression tests."""
93+
94+
def test_missing_in_value(self):
95+
"""-in with no value must fail gracefully (no segfault)."""
96+
r = run_wolfssl("-hash", "sha256", "-in")
97+
self.assertNotEqual(r.returncode, 0,
98+
"expected failure for missing -in value")
99+
self.assertGreaterEqual(r.returncode, 0,
100+
"-in without value crashed with signal "
101+
"{}".format(r.returncode))
102+
103+
91104
if __name__ == "__main__":
92105
test_main()

tests/pkey/rsa-test.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33

44
import filecmp
55
import os
6+
import subprocess
67
import sys
78
import unittest
89

910
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
10-
from wolfclu_test import CERTS_DIR, run_wolfssl, test_main
11+
from wolfclu_test import CERTS_DIR, WOLFSSL_BIN, run_wolfssl, test_main
1112

1213
RSA_PUBKEY_PEM = """\
1314
-----BEGIN PUBLIC KEY-----
@@ -138,6 +139,23 @@ def test_modulus_noout(self):
138139
self.assertIn("Modulus", r.stdout)
139140
self.assertNotIn("BEGIN", r.stdout)
140141

142+
def test_invalid_outform_error_message(self):
143+
"""Invalid -outform value must produce an outform-related error.
144+
145+
When the output is redirected to a file/pipe the command may also
146+
emit the raw key bytes on stdout, so capture everything as bytes
147+
and search the combined output for a human-readable error mention.
148+
"""
149+
r = subprocess.run(
150+
[WOLFSSL_BIN, "rsa", "-in",
151+
os.path.join(CERTS_DIR, "server-key.pem"),
152+
"-outform", "INVALID"],
153+
capture_output=True, stdin=subprocess.DEVNULL, timeout=60)
154+
combined = (r.stdout + r.stderr).lower()
155+
self.assertIn(b"outform", combined,
156+
"Expected 'outform' in error output, got: {!r}".format(
157+
combined[:200]))
158+
141159

142160
if __name__ == "__main__":
143161
test_main()

tests/x509/CRL-verify-test.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,15 @@ def test_crl_fail_no_output_file(self):
140140
self.assertFalse(os.path.isfile(out),
141141
"output file should not be created on failure")
142142

143+
def test_crl_invalid_outform_error_message(self):
144+
"""Invalid -outform value must produce an outform-related error."""
145+
r = run_wolfssl("crl", "-in", os.path.join(CERTS_DIR, "crl.pem"),
146+
"-outform", "INVALID")
147+
combined = (r.stdout + r.stderr).lower()
148+
self.assertIn("outform", combined,
149+
"Expected 'outform' in error output, got: {}".format(
150+
combined))
151+
143152

144153
class TestCRLText(unittest.TestCase):
145154
"""CRL -text output tests."""

tests/x509/x509-process-test.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,5 +504,19 @@ def test_4f_nonexistent_file_pem(self):
504504
self.assertNotEqual(r.returncode, 0)
505505

506506

507+
class TestX509ModulusNoout(unittest.TestCase):
508+
"""Regression: x509 -modulus -noout must not crash."""
509+
510+
def test_modulus_noout(self):
511+
r = run_wolfssl("x509", "-in",
512+
os.path.join(CERTS_DIR, "server-cert.pem"),
513+
"-modulus", "-noout")
514+
self.assertEqual(r.returncode, 0,
515+
"x509 -modulus -noout failed: {}".format(r.stderr))
516+
self.assertGreaterEqual(r.returncode, 0,
517+
"x509 -modulus -noout crashed with signal "
518+
"{}".format(r.returncode))
519+
520+
507521
if __name__ == "__main__":
508522
test_main()

0 commit comments

Comments
 (0)