@@ -412,6 +412,36 @@ def test_create_and_verify(self):
412412 self .assertEqual (r2 .returncode , 0 , r2 .stderr )
413413
414414
415+ def test_create_der_outform (self ):
416+ """Conventional (RSA/ECDSA) CA signing honors -outform der.
417+
418+ Passes the relative ``out_name`` to ``-out`` (matching
419+ ``test_create_and_verify``) so that the ``new_certs_dir``
420+ path-prepending logic inside ``wolfCLU_CertSign`` is exercised even
421+ when ``-outform der`` is in effect.
422+ """
423+ out_name = "test_ca_cv.der"
424+ out = _tmp (out_name )
425+ self ._clean (out )
426+ r = run_wolfssl ("ca" , "-config" , self .conf ,
427+ "-in" , self .csr , "-out" , out_name ,
428+ "-outform" , "der" )
429+ self .assertEqual (r .returncode , 0 , r .stderr )
430+ self .assertTrue (os .path .isfile (out ),
431+ "Signed cert not written to {}" .format (out ))
432+ self .assertGreater (os .path .getsize (out ), 0 , "Signed cert file is empty" )
433+
434+ r2 = run_wolfssl ("x509" , "-in" , out , "-inform" , "der" ,
435+ "-text" , "-noout" )
436+ self .assertEqual (r2 .returncode , 0 ,
437+ "DER signed cert not parseable: " + r2 .stderr )
438+
439+ r3 = run_wolfssl ("verify" , "-CAfile" ,
440+ os .path .join (CERTS_DIR , "ca-cert.pem" ),
441+ "-inform" , "der" , out )
442+ self .assertEqual (r3 .returncode , 0 , r3 .stderr )
443+
444+
415445class TestCAOverrideConfig (unittest .TestCase ):
416446 """Override config options with command-line flags."""
417447
@@ -1365,5 +1395,118 @@ def test_mldsa_verify_partial_chain_intermediate(self):
13651395
13661396
13671397
1398+ @unittest .skipUnless (_has_ed25519 (), "Ed25519 not available" )
1399+ def test_config_unsupported_private_key_fails (self ):
1400+ """Config private_key with unsupported type must not emit unsigned cert.
1401+
1402+ The assertion block below is intentionally similar to
1403+ ``TestCAUnsupportedConfigKey.test_read_sign_config_unsupported_key_fails``.
1404+ Both tests verify that an Ed25519 ``private_key`` in the config is
1405+ rejected before any output is written, but they differ in the signing
1406+ CA used: this test uses the ML-DSA CA cert (exercises
1407+ ``wolfCLU_readSignConfig`` via the ML-DSA code path), while
1408+ ``TestCAUnsupportedConfigKey`` uses the default RSA CA cert. Keep
1409+ both tests in sync if the assertion logic changes.
1410+ """
1411+ ed_key = _tmp ("ca_mldsa_badconf_ed" )
1412+ bad_conf = _tmp ("ca_mldsa_bad_key.conf" )
1413+ out = _tmp ("tmp_mldsa_badconf.pem" )
1414+ self ._clean (ed_key + ".priv" , ed_key + ".pub" , bad_conf , out )
1415+
1416+ r = run_wolfssl ("-genkey" , "ed25519" , "-out" , ed_key ,
1417+ "-output" , "keypair" , "-outform" , "PEM" )
1418+ if r .returncode != 0 :
1419+ self .skipTest ("Ed25519 keygen failed: " + r .stderr )
1420+
1421+ bad_conf_body = CA_CONF .replace (
1422+ f"private_key = { _CERTS } /ca-key.pem" ,
1423+ f"private_key = { ed_key } .priv" )
1424+ with open (bad_conf , "w" , encoding = "utf-8" , newline = "\n " ) as f :
1425+ f .write (bad_conf_body )
1426+
1427+ r = run_wolfssl ("ca" , "-config" , bad_conf ,
1428+ "-in" , self .rsa_csr , "-out" , out ,
1429+ "-cert" , self .mldsa_ca_cert )
1430+ self .assertNotEqual (r .returncode , 0 ,
1431+ "unsupported config private_key should fail" )
1432+ msg = (r .stdout + r .stderr ).lower ()
1433+ self .assertTrue (
1434+ "unsupported" in msg or "signing key" in msg
1435+ or "unable to load private key" in msg ,
1436+ "expected unsupported-key error, got: " + msg )
1437+ self .assertFalse (
1438+ os .path .isfile (out ) and os .path .getsize (out ) > 0 ,
1439+ "no unsigned certificate should be written" )
1440+
1441+
1442+ @unittest .skipUnless (_has_ed25519 (), "Ed25519 not available" )
1443+ class TestCAUnsupportedConfigKey (unittest .TestCase ):
1444+ """Regression: wolfCLU_readSignConfig must reject unsupported private_key."""
1445+
1446+ @classmethod
1447+ def setUpClass (cls ):
1448+ cls .ed_key = _tmp ("ca_ed25519_key" )
1449+ r = run_wolfssl ("-genkey" , "ed25519" , "-out" , cls .ed_key ,
1450+ "-output" , "keypair" , "-outform" , "PEM" )
1451+ assert r .returncode == 0 , "Ed25519 keygen failed: " + r .stderr
1452+
1453+ cls .conf = _tmp ("ca_ed25519_bad.conf" )
1454+ bad_conf_body = CA_CONF .replace (
1455+ f"private_key = { _CERTS } /ca-key.pem" ,
1456+ f"private_key = { cls .ed_key } .priv" )
1457+ with open (cls .conf , "w" , encoding = "utf-8" , newline = "\n " ) as f :
1458+ f .write (bad_conf_body )
1459+
1460+ cls .csr = _tmp ("ca_ed25519_bad.csr" )
1461+ r = run_wolfssl ("req" , "-key" ,
1462+ os .path .join (CERTS_DIR , "server-key.pem" ),
1463+ "-subj" , "/O=wolfSSL/C=US/ST=MT/L=Bozeman/CN=server" ,
1464+ "-out" , cls .csr )
1465+ assert r .returncode == 0 , "CSR creation failed: " + r .stderr
1466+
1467+ @classmethod
1468+ def tearDownClass (cls ):
1469+ _cleanup (cls .ed_key + ".priv" , cls .ed_key + ".pub" ,
1470+ cls .conf , cls .csr , _tmp ("index.txt" ))
1471+
1472+ def setUp (self ):
1473+ _cleanup (_tmp ("index.txt" ))
1474+ _touch (_tmp ("index.txt" ))
1475+
1476+ def tearDown (self ):
1477+ _cleanup (_tmp ("index.txt" ))
1478+
1479+ def _clean (self , * files ):
1480+ for f in files :
1481+ self .addCleanup (lambda p = f : _cleanup (p ))
1482+
1483+ def test_read_sign_config_unsupported_key_fails (self ):
1484+ """ca -config with Ed25519 private_key must fail without writing cert.
1485+
1486+ The assertion block below mirrors
1487+ ``TestCAMLDSA.test_config_unsupported_private_key_fails``. Both
1488+ tests verify that an Ed25519 ``private_key`` in the config is
1489+ rejected before any output is written, but the signing CA differs:
1490+ this test uses the default RSA CA cert (exercises the
1491+ ``wolfCLU_readSignConfig`` RSA code path), while ``TestCAMLDSA``
1492+ uses the ML-DSA CA cert. Keep both tests in sync if the assertion
1493+ logic changes.
1494+ """
1495+ out = _tmp ("tmp_ed25519_bad_ca.pem" )
1496+ self ._clean (out )
1497+ r = run_wolfssl ("ca" , "-config" , self .conf ,
1498+ "-in" , self .csr , "-out" , out )
1499+ self .assertNotEqual (r .returncode , 0 ,
1500+ "Ed25519 config private_key should fail" )
1501+ msg = (r .stdout + r .stderr ).lower ()
1502+ self .assertTrue (
1503+ "unsupported" in msg or "signing key" in msg
1504+ or "unable to load private key" in msg ,
1505+ "expected unsupported-key error, got: " + msg )
1506+ self .assertFalse (
1507+ os .path .isfile (out ) and os .path .getsize (out ) > 0 ,
1508+ "no unsigned certificate should be written" )
1509+
1510+
13681511if __name__ == "__main__" :
13691512 test_main ()
0 commit comments