diff --git a/README.md b/README.md index db7b1b7c..3acd1bf1 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,45 @@ wolfssl verify -CAfile A.cert B.cert wolfssl verify -CAfile A.cert C.cert ``` +### Creating Chimera Certificates + +Following is a scenario creating Chimera (dual algorithms) certificates for PQC(Post Quantum Cryptography). + +The following demonstrates how to create a root CA and use it to sign other certificates. This example uses ECC and ML-DSA. In this scenario there are three entities A, B, and C, where A is meant to function as a root CA. + +Before running the commands below, ensure you have the `ml-dsa` option enabled in wolfSSL. This can be done by configuring wolfSSL with `--enable-dilithium`, `--enable-dual-alg-certs` and `--enable-experimental`. + +The following steps demonstrate how to generate keys and certificates for A, B, and C, where A is self-signed and B and C are signed by A + +1. Create private ECC and ML-DSA keys for A, B, and C +``` +wolfssl genkey ecc -name secp521r1 -out ecc-key-A -output priv -outform PEM +wolfssl genkey ecc -name secp384r1 -out ecc-key-B -output priv -outform PEM +wolfssl genkey ecc -name secp256r1 -out ecc-key-C -output priv -outform PEM +wolfssl genkey ml-dsa -level 5 -out ml-dsa-key-A -output keypair -outform PEM +wolfssl genkey ml-dsa -level 3 -out ml-dsa-key-B -output keypair -outform PEM +wolfssl genkey ml-dsa -level 2 -out ml-dsa-key-C -output keypair -outform PEM +``` + +2. Create a self-signed conventional certificate for A, root CA certificate. +``` +wolfssl req -new -key ecc-key-A.priv -subj O=org-A/C=US/ST=WA/L=Seattle/CN=A/OU=org-unit-A -x509 -out A.cert -outform PEM +wolfssl ca -altextend -in A.cert -keyfile ecc-key-A.priv -altkey ml-dsa-key-A.priv -altpub ml-dsa-key-A.pub -out A-chimera.cert +``` + +3. Create certificates for B and C. +``` +# first create conventional certificate signing request (CSR) for B and C +wolfssl req -new -key ecc-key-B.priv -subj O=org-B/C=US/ST=WA/L=Seattle/CN=B/OU=org-unit-B -out B.csr -outform PEM +wolfssl req -new -key ecc-key-C.priv -subj O=org-C/C=US/ST=WA/L=Seattle/CN=C/OU=org-unit-C -out C.csr -outform PEM + +# now have conventional signed certs, then add a pub key and Chimera signs the B and C to generate Chimera certificates +wolfssl ca -in B.csr -keyfile ecc-key-A.priv -cert A.cert -out B.cert +wolfssl ca -in C.csr -keyfile ecc-key-B.priv -cert B.cert -out C.cert +wolfssl ca -altextend -in B.cert -keyfile ecc-key-A.priv -altkey ml-dsa-key-A.priv -altpub ml-dsa-key-B.pub -subjkey ecc-key-B.priv -cert A-chimera.cert -out B-chimera.cert +wolfssl ca -altextend -in C.cert -keyfile ecc-key-B.priv -altkey ml-dsa-key-B.priv -altpub ml-dsa-key-C.pub -subjkey ecc-key-C.priv -cert B-chimera.cert -out C-chimera.cert +``` + ## Contacts Please contact support@wolfssl.com with any questions or comments. diff --git a/certs/ca-chimera-cert.pem b/certs/ca-chimera-cert.pem new file mode 100644 index 00000000..91567933 --- /dev/null +++ b/certs/ca-chimera-cert.pem @@ -0,0 +1,88 @@ +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/certs/ca-mldsa44-key.pem b/certs/ca-mldsa44-key.pem new file mode 100644 index 00000000..8bfe20bd --- /dev/null +++ b/certs/ca-mldsa44-key.pem @@ -0,0 +1,56 @@ +-----BEGIN PRIVATE KEY----- +MIIKGAIBADALBglghkgBZQMEAxEEggoEBIIKAKQqu72O1hodYxKQMv+BePNFu0d+ +dhrgd5LMvj1S6eecIEmpHiobdb6dRKT/hjd0WO4gH+kg8oiB0i+oVthYFDYgMEpT +WfnsxK06ia4DbRFFALNvkbYS40l1zjG4un/eHHZ5LO2Teml8Quopz4y7TVU5j4h9 +loR9cWDkqipoDzeY0RSQCRACISJwHAliAJRAIyJpShYoIcVoJIcoAsEs4aBRIgSF +WBKFWagkEKZBEyeEYJaIgaRkJDVAwUJxGyiNDDZQDISEmhBhI0QyHDgyETNk4hBh +iSAJk8JA0EYhE6IowJghIZNAZIZogyQsIgkRS4IswjSQopSAzDiBwJhsokCAiDRx +4bRoTKAg48SASYBQIwRgArMAAyEKzBBsWraNGQJqm7RJGERkW0IimYJIIyQMW6BE +ChdsCDVIJIAxQUAGQQQyAYAQgKBBFLQI0KAg0MQkASAyChWBiLJBWJiJRMJJoQhS +oQBRwCBJ0UCCDMIBmoJEGDRqBAGQ4gJoCTFSgRiCkpAtUwAhikARo8QRYxQGSzRg +2rKN4xZyjIJhi8aJkJZJzMJRyxZJGQlFUQiJCBNoiERIkxJxgShuUjghmzBGEZdM +JDMMSoJtHEdJBMNp0KZgQJABg6iIASghI5cxWaIwkDQhjKhJCTQRkQQNQ8JwGDVM +IrkNAqWRlBASQ6YpRDAIQsRQQxYJ4sKEIiYomJBwEAIKmDgGwTACEbhg4agp5JJA +YKAAFMBghJCAyZJtZIRglCgto6Zw4BBwCUBhQzZJwcRwGbOBAMlwy0aIAhghiwAw +5DiICrZxCkAokUZkUCICxBIkyBSEC8Qkk8RIkQBiG0MsA0mG0iaCpBZoEjhyGgGE +wIZoxABNzESKWEJFQ7iBGaGAAAhuGAUkzIgsZJZpmJIpyJSJCacAw7iIgxRCk6gw +w4BAI7hpkraMwcZsZMYlEhIxEZYNmMRxASAkxERhAZRME7hFWBSO1JAoSBABS0QN +FERyA0gGWUIqSRgpg8JoXCQsSqIkURCAFChwJClpGCIGEUiKyigqGCcmBIhwAokl +yLJxSCiNEIVJ5IIFgDJtEsSBSICBYSBihEJKy7CA4kAhFDIJIBBwhChhWbAhHJZx +1MIkoohpwRBFEjICIaIwGjExUZJwJBBogTiR2ARoWBYyW0REU0AIFKQI1KQwIwZw +SphASBJwWphomIJBF/H/IjdKuLEnqas7d2eP7DJ2BevCpvPlIS/h7J7bdFFdGrs+ +LO7EVI4bjayOhN31i94acGIzqiW7ZPGMbAsLepj08zrFYvhArUp42MkeG8BzTKwq +tm4ltXXR7gvKmBbQVL5wLIUllDD2Y3uUeCnsiU08O0scSX8F6ccq/Dc30t+LgvCN +zXI753Vr0B5nkPwrItowrqaGn2kSpQY/z1FrKMPWQ6GOfeCEmArOAgSDNNht3y6O +VIbvHg9AvMHU8CoQAY2fP0Sw4NOnHbWVz/4vzaHjKaWQKfCP+rZebXed507WfMeo +Y6TmwfIt+Jg2rS+SqqTY9g+CtzWeBJQcxSFwbS0gCv2fA8IorU9WtWH8do+Zp7oF +kWeVUP+fAxx3LJR9ihMlayBGcdS8PUqbHZO0CJQF5gajQK3Bkde6oFCZMADtsbC0 +Mr92dJwaGSQCTHY0RlWw+RdK+OxT57p5xdQ8wDlgHKGc08OnTk/ONhEw72YjSgcF +R3rHi+frBMuJa6UsmdyCfsh49N3YndofKsxIfMzzl/IHggEZDJmhBu+X3b7n364t +gfcMsWEOtPI12QntdWk2EgHQfbz24Z+dV4sgusJB+2438dstAQueVu474wuaM5Gl +51PqRkbKon2zQDodEnPQGcZzeuDPievWU25Xa0oT6Lf1WFUpuG7MCprm1oi2lFxf +6lMtu0RfFRA/xwFakM4qBhA5hq7mmlSbCX/QJ2oFCvmMYeSR9g9BEcX1zXQrKpwY +R7H2qfrK4QGoOVGuKW7hHUD5fclTmscx6ajG8DWmNizTGh+64E+Rt+7cO42rdAdb +X4VC8RPbPx9KPb/MzOdPxQWdrahqFd9EWYCKulr8CHc4HT9/W45fYr0f5O5mDNB7 +3bxzYkLoOJYl1cUXZ9ybzBMgOmE+wQB2zch2ydhjHBq4qXyQt0st3Yf3xsrdKa9K +efFoqBAixPksYbAsS1NTD6OMb9z0hVwMgWb9+Jk1sX/tNm6UynP02kAOrKkk74gU +WdsYpSG2/t8XLKPE81xEOQtgK9uT0oqO0NHkFds9nrbOEWyTA80PCIf6aKDv5dXJ +psA4mI7TT94C3nZ0J4styLUOqnxVCe1UfwrVJDl1adEVaCK8TZJuUTTRJ+GoIo/V +0saS6YKzouG6JVLzhrD9XL9EG3wjZayADfW3rFgVCnApM1Yiv6qnU+kisJJ1tvsY +AbdZbofAmph8H1+TfGtZl3Pv3fPQAKUyICLEWVi2p7DIc+AHTealB4OCdAVN2TMG +GKFIf3CkEEnXFabu1LCMdBM8jVq0g+wacGWv+TUa3JYOBYZXP+ixyhM1V223lGFn +9GYT/GsZnzkUpq/s+KpFA0C0Fj29tZx8KwJC1eOyyTSr5pFmEPgCinJVYCpiBYBI +w2xDc1y+mKJNIulRLL0FY2OMc0lQvLXclASKiwDZjFmbZsX1VNP9X+EGa0Jo4OsU +NHPPDCRBVos4c8wXiCh9MjnvUjOj7zzAtcs0PGAc1/JqDUonyqyFaf0yPGZelNrv +7Q+/Q7a93kKJnPphBfSVJzzJcgfJBpjnnCf8B2okn5+CTkNphPJLNY5X1fFfZUtn +HqWj+R5w7Bu4VKH6KGCEi4zG6Ao43EwtU0jDW22GO6alPmWZbEMZYeJcfPlHzi0g +fNdxPykGCIjyU3QheBsQm6fZoxEBhSiXE6liuVwXtKF3RJES6iRmPOlrDYQ9rr8F +B/Llhd48csi7zatVEsKTiSPsRBcZtVEVf0KLK019Q0pwS/tomHlm83wZ8z9QIpul +etB0Y2S2YLtp3XY8DEHhBayG2KcgLJCqIGEg/YePTF08S2wyj3EWm+TSi/b75L3N +Afw+Lqh2bQW+1elj3wti+kp/qgXJmgBAS5RJXlq7cnFcm83Bh4uK14uSNG+WKNGO +xOzqCfRsfu7L2NOttbppw9ejcVAj6o91WeiCyFVw0IhS4kgIKFa5KAdc51MVTBX5 +rXZolnHvCMFJl0SxZ2nLi2Jw98P5s7lmQ3hem7ReHUuXqg+57VtpsYDi8AxWslYE +JM/Cwf6DpHSvnxFMrpfaY1qOpba3ZGm8A7htiIOFEoBkZlrL+MilrDhPMrOemHpd +xVEevjJy4ZmdEi1mP/sEoLWeMk9DyWeTaNpZHDnglOHwiubOyA3N2j7s7lFHW1aW +691eMXJj+5g/57mWeI2a+uNvI+1XwnFXCA108553v7ZA6FXCakSz+h/s9pc= +-----END PRIVATE KEY----- diff --git a/certs/ca-mldsa44-keyPub.pem b/certs/ca-mldsa44-keyPub.pem new file mode 100644 index 00000000..3de85248 --- /dev/null +++ b/certs/ca-mldsa44-keyPub.pem @@ -0,0 +1,30 @@ +-----BEGIN PUBLIC KEY----- +MIIFMjALBglghkgBZQMEAxEDggUhAKQqu72O1hodYxKQMv+BePNFu0d+dhrgd5LM +vj1S6eecwE90E28o7ddpa4PZP6h1pp7bs+ISgJM1JqK2VXXg97HpPI0+w2NmN6hV +vPO8zwN/piPgB/KSmyCtvBjY5mUKnrR86nldWCLsnecr1qR9tACsJcrE0rjI5U2Z +SFlvSZu2LeYovRtyPUe9MIYyfslvy9otjoMgYnTsae6mJjuESXD/aQmcOWTL1Hfq +p63a6EPueoznnXCxqxdqk30LYACaK7a3syWQy3IMUkncxKGj1YQm6hBCigAbrl3R +IFud/O4hTGs0CD4Ua9jDvHFeZY66yMOnNRR7OVeBzG7jo72RCzWqr9xSQ7RdsK05 +ZC6Yenllwkka7qh5Z8BQDTFNHclrvFz9o0eMeb/VgMTRg8Oajdg9twfk0h3IbR4e +3/Fi77vKq8ATdQCMapJ3a7oiYoEzobaPxos0CsZp5uTNthrku3JxBpJVp/9Vf1MG +xoYLbxdTqmYQyvxpCuOwApzh5Wasi2RhXyg/ElEWE5jG7H9H10ZMT71GzJBnxKyW +dDaKqiMcUKFtI3yW7ILi+LCOEbw1TZg3ezmz8hmQwbyEHCsA6pkddG0h0W+GQj06 +aEcHSvD1u69m8H7vHUUqaI04A8q8n+tK/KDbSeNti3JvqbQxtapsoT4fU2YhCqa9 +g8jlYKk/15pBe32rCziMhWFi/EM4Yv1Ho0N5zfvBOONyvLUedhp5bssMwrIJ5KAF +kBw8SD8G3k4SYeZdTCw7u119i2ExNqqmF7WFHTl18NtHrxHLHc8/9oO6Z44SwC/a +1+0r+2Khe1O0Pr2SnqIhqUUdCGSIm3LMvPrVjI24ut2HjH6Wys9Fbbs98hImzwGS +lpnjENCUnTUswbdBGPAAKHkuQdFPBkFzR8yQEX878Pem3NMkgWbdkx9pkTPLnUR7 +BcVOcHwWfcPchmNX4R+1wvqOL0V6AsxuLZDehyNww5Sktr71RKgVZDeBOliRnj2r ++hgpsXsRSxJHuEwyb0FdnYTOl+ciq0ay9E/KLLvy0Rxzlt1awWShrkSjTK/cJ8a6 +85e02lkOTcK/bSMNCuOS2PLhoyiVaKGceBTFJHb53EbUqSX1G5KCKBv+54DMJdms +A159/9+nrLFEtI1pRSUJdKnW8krj0O3JOHXvI97udGnlMs3edCbrZa/iOPBrh1BT +vmMpc33j37DplPHKHilQi+E+tL0D8tmiwY4nzZ/85b2Ue3MczYjd+5jOml4feVyB +5ov4DWiIfKwqHqKj11nNpRQkYR6O6VDGssLX3Y3FXBAx4Pp3P7UWU49j4AE/E2Zg +vQ79HJV5sKxGR8hoXDo7KEI4WNCaqOlGd90YB8HJbmCWfolzS6YhFSAMAFTKEuj/ +ACtkl2V8DzwxGgvzgKTyU2u2F+ZJ9bWGvg4yIP4kd4MmlFfD+SlCVS2R2GIcjtQP +8ygDIMJlcKjTzbxXRFBNieetqtnr5smCDzVa8TobxaPnEJdnLqHOPB3E0uMVhR88 +YSaq7w1jHso5cBCBqyNKXUmvCyht83jbETgt2QSCDiUtJMHh7kFsZ9mWlwGVdyzw +2r/yeq5hCmDwJBwLFmKu80BctmHt3GSovUM34DKVQWSHzRWQKZlaG7aedGrMQEQX +akZE7cjp4tJQ4uwCY49ojmHipCwW3x6RNyo/nemIv54Xd1Zp3TNkelV0qJo0kADy +YTIil47R4qU1byuvNpYvi/0r7BjjhGA6FfeJoUUqsqg8ITM98Bg= +-----END PUBLIC KEY----- diff --git a/certs/server-chimera-cert.pem b/certs/server-chimera-cert.pem new file mode 100644 index 00000000..b8b01504 --- /dev/null +++ b/certs/server-chimera-cert.pem @@ -0,0 +1,88 @@ +-----BEGIN CERTIFICATE----- +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 +wDXxb/vja1rysBWqpX1U1vqkonzY8b0BRW4= +-----END CERTIFICATE----- diff --git a/certs/server-ecc-key.pem b/certs/server-ecc-key.pem new file mode 100644 index 00000000..92b9bda9 --- /dev/null +++ b/certs/server-ecc-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIDCqAGw53N2jwFt4ecPGws5NnIvtpFTZCfVMN9mw8222oAoGCCqGSM49 +AwEHoUQDQgAERUXWyWxXtPIMhhcd0OFPzwPKOE393WgsOd5wRdWYzmDOH++kgBPn +I37zXZxR2h185ztVwl96vWB9pGMw8dTVlg== +-----END EC PRIVATE KEY----- diff --git a/certs/server-ecc-keyPub.pem b/certs/server-ecc-keyPub.pem new file mode 100644 index 00000000..714ffb5b --- /dev/null +++ b/certs/server-ecc-keyPub.pem @@ -0,0 +1,4 @@ +-----BEGIN PUBLIC KEY----- +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERUXWyWxXtPIMhhcd0OFPzwPKOE39 +3WgsOd5wRdWYzmDOH++kgBPnI37zXZxR2h185ztVwl96vWB9pGMw8dTVlg== +-----END PUBLIC KEY----- diff --git a/certs/server-mldsa44-key.pem b/certs/server-mldsa44-key.pem new file mode 100644 index 00000000..2837a2f8 --- /dev/null +++ b/certs/server-mldsa44-key.pem @@ -0,0 +1,56 @@ +-----BEGIN PRIVATE KEY----- +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 +-----END PRIVATE KEY----- diff --git a/certs/server-mldsa44-keyPub.pem b/certs/server-mldsa44-keyPub.pem new file mode 100644 index 00000000..da027349 --- /dev/null +++ b/certs/server-mldsa44-keyPub.pem @@ -0,0 +1,30 @@ +-----BEGIN PUBLIC KEY----- +MIIFMjALBglghkgBZQMEAxEDggUhAM7LPct3TbjiWth/AfAG9dLB0Wg0TDCiOl0m +3+9pMLcVRQW1ohoFiYO+UWVl3scxup7X2QFeeRfI0TS9ASVmUq1/1Y1PQ/4R1+9f +rgPITcSeMSWdpH8TAKagibCPrvw2fDJfNTxvSqQModDYcnUekdj+N+gWZXjDqFwi +pwbN+fQji0j4sHiqRCpc623l7XakRg9nAV2vM4wMlgP2fktCnyBDjbEJfBJpuLQI +uKrApX7zpPfwu6tcJcG1msP8dpxxrDeOrTPauUvAUEl+BceUVOP8CTTLfhQAQQzF +ImR556P36fwafaKrB6wl+SF3ZU6tc1kXVGxD94WySqmimLOodXlzOaTNVjQApUqA +MFVnLWMACI2Yt2IT8UUUBDDOpYcTEVoLg9KuyDksVlE0TL69YwDYzEszjL43EiXo +L/MlDqVscz78fY2reEuQQzQzlawRHXSQ7l57Gry7jZcIMEgfL1G7Jkk/VyfIDr9X +K8Xp1rYH4RPWPbEle3PrSZs65zYl2789CndotAl58mGIx5qzAlqhC29ToGV3b6o9 +NTZ3UG12NbgUD0yzQkvFj0uuVfvwGzRH5PiYLaA3U6Eby5Eb0u1MIKLzvXMv9dUE ++xuqCS9lg6jJIEK66fDwoi4e3TUwLdq/fBA77DQZ/X2ZwRWU09WuDJFrcRFGHndZ +9v3TLPN2/Iak20k0n7Y8MO9lgtRqk6M/j/raV9O5vzJ6wy2xYatcM5iQ66WSO8uA +yKFt+agV//KEmGuW0nXdn313VFF0IkdlHBLB0/i9y5cuFTYq87bh/kxq7EymIziu +hjgJ+j2Y/u66OfiOHxJ5hs+KmQ+4F8pkk4S49a4JWRNIVBKinbnqt5WyLKKJPNWe +uc531nNXwYVyqz1Bd9H1Irarqj0oCkrbCRy7R2QCgqDMUqHjadaTfvcJE6cmsTSz +/8yu0Bc73num7KmJHAFYMBZn8dG1ikJXZmzURz0uHNI1062X64A8mZ49f5/Bdws5 +6XEbU3+4BBy21VJLl/D8YYQL/8d7St1bIkxuL26MujS1i7oCgfhCCwGD+D7aO1cm +sk4HAvvgy9ie8FLrEkXqrE5CBSftmwElaTCU4MbdQHhJENCYJeD1TKJrLVyHpioN +0JVe0Uf8BVMvfvdMhxzf3NYLhZOB7A4SCu/WtIoxG8KlF8Mn9bwepakIuBjLwSKS +nkSUwl46MSWAOaOPHqP4Hrl2t1hRQHYnGTXRYTzaVaVQ8ssBYChDsqf95xWJT9mx +sk1tYrA/RsG3ORQfhr+9A5NV7sGfbJRp+NQU2aQ0c+kWaykr5qb2DjO1dvyCHiXf +tJ6EbwrEPyUCc6YBT8Kp70CbAyDSMFDBea8DUlw6EuWTs8SDFEgYHoCrO6fO6Yt0 +znog+hK2x+HFbnIFCnXoRTTbAFOQo6uF3IAKdcb88K3mKIYivRxjiKbq0Wut3uvF +D+lz1d745FOIvk5ETyKjxRL/tdpj3AcUIosLT/eTEofT36dNhfsASbjoRqYTlx8z +ZXngccdu/21mMDShCKOwZX+1hTxsnhjIQuXlOn//zn1MrL2hiDUqhghn4177lbHl +xaFFlOd+iNowgRAzM7h+QdxCrB7OOiEp+M5PmP2t3TMptv8JbT8YEgcZ9g7o22FJ +Oh186Y1t9STxTC3IdwSmurlumOvYHuoYANJTvJLxKaKp+t3/hJJzR5ja6d9Ygorh +yZIwMagUgRia3kvfip554HG4iLDyjIdU5BuHqPKbUHIRz72EFBA= +-----END PUBLIC KEY----- diff --git a/src/genkey/clu_genkey.c b/src/genkey/clu_genkey.c index c86cac48..1231e825 100644 --- a/src/genkey/clu_genkey.c +++ b/src/genkey/clu_genkey.c @@ -1044,18 +1044,11 @@ int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, XFILE file = NULL; int fNameSz = 0; - int fExtSz = 6; // size of ".priv\0" or ".pub\0\0" - char fExtPriv[6] = ".priv"; - char fExtPub[6] = ".pub"; + int fExtSz = 6; /* size of ".priv\0" or ".pub\0\0" */ + char fExtPriv[6] = ".priv\0"; + char fExtPub[6] = ".pub\0\0"; char* fOutNameBuf = NULL; - #ifdef NO_AES - /* use 16 bytes for AES block size */ - size_t maxDerBufSz = 4 * keySz * 16; - #else - size_t maxDerBufSz = 4 * keySz * AES_BLOCK_SIZE; - #endif /* NO_AES */ - byte* derBuf = NULL; byte* pemBuf = NULL; byte* outBuf = NULL; @@ -1075,6 +1068,9 @@ int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, #endif if (rng == NULL || fName == NULL) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, HEAP_HINT, DYNAMIC_TYPE_DILITHIUM); +#endif return BAD_FUNC_ARG; } @@ -1086,7 +1082,6 @@ int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, #endif return ret; } - XMEMSET(key, 0, sizeof(dilithium_key)); /* set the level of the dilithium key */ if (wc_dilithium_set_level(key, level) != 0) { @@ -1119,7 +1114,7 @@ int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, XMEMSET(fOutNameBuf, 0, fNameSz + fExtSz); XMEMCPY(fOutNameBuf, fName, fNameSz); - derBuf = (byte*)XMALLOC(maxDerBufSz, HEAP_HINT, + derBuf = (byte*)XMALLOC(keySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (derBuf == NULL) { ret = MEMORY_E; @@ -1138,12 +1133,14 @@ int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, /* Private key to der */ derBufSz = wc_Dilithium_PrivateKeyToDer(key, - derBuf, (word32)maxDerBufSz); + derBuf, (word32)keySz); if (derBufSz < 0) { ret = derBufSz; } - outBuf = derBuf; - outBufSz = derBufSz; + else { + outBuf = derBuf; + outBufSz = derBufSz; + } /* check if should convert to PEM format */ if (ret == WOLFCLU_SUCCESS && fmt == PEM_FORM) { @@ -1152,8 +1149,10 @@ int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, if (pemBufSz <= 0 || pemBuf == NULL) { ret = WOLFCLU_FAILURE; } - outBuf = pemBuf; - outBufSz = pemBufSz; + else { + outBuf = pemBuf; + outBufSz = pemBufSz; + } } /* open file and write Private key */ @@ -1172,7 +1171,7 @@ int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, } } - if (directive != PRIV_AND_PUB_FILES) { + if (ret != WOLFCLU_SUCCESS || directive != PRIV_AND_PUB_FILES) { break; } @@ -1189,14 +1188,14 @@ int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, XMEMCPY(fOutNameBuf + fNameSz, fExtPub, fExtSz); WOLFCLU_LOG(WOLFCLU_L0, "Public key file = %s", fOutNameBuf); - derBuf = (byte*)XMALLOC(maxDerBufSz, HEAP_HINT, + derBuf = (byte*)XMALLOC(keySz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (derBuf == NULL) { ret = MEMORY_E; } - + derBufSz = wc_Dilithium_PublicKeyToDer(key, derBuf, - (word32)maxDerBufSz, withAlg); + (word32)keySz, withAlg); if (derBufSz < 0) { ret = derBufSz; } @@ -1212,8 +1211,10 @@ int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, if (pemBufSz <= 0 || pemBuf == NULL) { ret = WOLFCLU_FAILURE; } - outBuf = pemBuf; - outBufSz = pemBufSz; + else { + outBuf = pemBuf; + outBufSz = pemBufSz; + } } /* open file and write Public key */ @@ -1243,7 +1244,7 @@ int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, XFCLOSE(file); if (derBuf != NULL) { - wolfCLU_ForceZero(derBuf, (unsigned int)maxDerBufSz); + wolfCLU_ForceZero(derBuf, keySz); XFREE(derBuf, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); } @@ -1275,6 +1276,252 @@ int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, #endif /* HAVE_DILITHIUM */ } +int wolfCLU_genKey_ML_DSA(WC_RNG* rng, char* fName, int directive, int fmt, + int keySz, int level, int withAlg) +{ +#ifdef HAVE_DILITHIUM + int ret = WOLFCLU_SUCCESS; + + XFILE file = NULL; + int fNameSz = 0; + int fExtSz = 6; /* size of ".priv\0" or ".pub\0\0" */ + char fExtPriv[6] = ".priv\0"; + char fExtPub[6] = ".pub\0\0"; + char* fOutNameBuf = NULL; + + byte* derBuf = NULL; + byte* pemBuf = NULL; + byte* outBuf = NULL; + int derBufSz = -1; + int pemBufSz = 0; + int outBufSz = 0; + +#ifdef WOLFSSL_SMALL_STACK + MlDsaKey* key; + key = (MlDsaKey*)XMALLOC(sizeof(MlDsaKey), HEAP_HINT, + DYNAMIC_TYPE_DILITHIUM); + if (key == NULL) { + return MEMORY_E; + } +#else + MlDsaKey key[1]; +#endif + + if (rng == NULL || fName == NULL) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, HEAP_HINT, DYNAMIC_TYPE_DILITHIUM); +#endif + return BAD_FUNC_ARG; + } + + /* init the ML-DSA key */ + if (wc_MlDsaKey_Init(key, NULL, 0) != 0) { + wolfCLU_LogError("Failed to initialize ML-DSA Key"); +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, HEAP_HINT, DYNAMIC_TYPE_DILITHIUM); +#endif + return WOLFCLU_FAILURE; + } + + /* set the level of the ML-DSA key */ + if (wc_MlDsaKey_SetParams(key, level) != 0) { + wolfCLU_LogError("Failed to set ML-DSA Key parameters"); + wc_MlDsaKey_Free(key); +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, HEAP_HINT, DYNAMIC_TYPE_DILITHIUM); +#endif + return WOLFCLU_FAILURE; + } + + /* make the ML-DSA key */ + if (wc_MlDsaKey_MakeKey(key, rng) != 0) { + wolfCLU_LogError("Failed to make ML-DSA Key"); + wc_MlDsaKey_Free(key); +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, HEAP_HINT, DYNAMIC_TYPE_DILITHIUM); +#endif + return WOLFCLU_FAILURE; + } + + /* set up the file name output buffer */ + if (ret == WOLFCLU_SUCCESS) { + fNameSz = (int)XSTRLEN(fName); + fOutNameBuf = (char*)XMALLOC(fNameSz + fExtSz + 1, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER); + if (fOutNameBuf == NULL) { + ret = MEMORY_E; + } + } + + if (ret == WOLFCLU_SUCCESS) { + XMEMSET(fOutNameBuf, 0, fNameSz + fExtSz); + XMEMCPY(fOutNameBuf, fName, fNameSz); + + derBuf = (byte*)XMALLOC(keySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + ret = MEMORY_E; + } + } + + if (ret == WOLFCLU_SUCCESS) { + switch (directive) { + case PRIV_AND_PUB_FILES: + /* Fall through to PRIV_ONLY_FILE */ + FALL_THROUGH; + case PRIV_ONLY_FILE: + /* add on the final part of the file name ".priv" */ + XMEMCPY(fOutNameBuf + fNameSz, fExtPriv, fExtSz); + WOLFCLU_LOG(WOLFCLU_L0, "Private key file = %s", fOutNameBuf); + + /* Private key to der */ + derBufSz = wc_MlDsaKey_PrivateKeyToDer(key, + derBuf, (word32)keySz); + if (derBufSz < 0) { + ret = derBufSz; + } + else { + outBuf = derBuf; + outBufSz = derBufSz; + } + + /* check if should convert to PEM format */ + if (ret == WOLFCLU_SUCCESS && fmt == PEM_FORM) { + pemBufSz = wolfCLU_KeyDerToPem(derBuf, derBufSz, &pemBuf, + PKCS8_PRIVATEKEY_TYPE, DYNAMIC_TYPE_TMP_BUFFER); + if (pemBufSz <= 0 || pemBuf == NULL) { + ret = WOLFCLU_FAILURE; + } + else { + outBuf = pemBuf; + outBufSz = pemBufSz; + } + } + + /* open file and write Private key */ + if (ret == WOLFCLU_SUCCESS) { + file = XFOPEN(fOutNameBuf, "wb"); + if (file == XBADFILE) { + wolfCLU_LogError("unable to open file %s", + fOutNameBuf); + ret = OUTPUT_FILE_ERROR; + } + } + + if (ret == WOLFCLU_SUCCESS) { + if ((int)XFWRITE(outBuf, 1, outBufSz, file) <= 0) { + ret = OUTPUT_FILE_ERROR; + } + } + + if (ret != WOLFCLU_SUCCESS || directive != PRIV_AND_PUB_FILES) { + break; + } + + XFCLOSE(file); + file = NULL; + XFREE(derBuf, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + derBuf = NULL; + XFREE(pemBuf, HEAP_HINT, DYNAMIC_TYPE_PRIVATE_KEY); + pemBuf = NULL; + + FALL_THROUGH; + case PUB_ONLY_FILE: + /* add on the final part of the file name ".priv" */ + XMEMCPY(fOutNameBuf + fNameSz, fExtPub, fExtSz); + WOLFCLU_LOG(WOLFCLU_L0, "Public key file = %s", fOutNameBuf); + + derBuf = (byte*)XMALLOC(keySz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER); + if (derBuf == NULL) { + ret = MEMORY_E; + } + + if (ret == WOLFCLU_SUCCESS) { + derBufSz = wc_MlDsaKey_PublicKeyToDer(key, derBuf, + (word32)keySz, withAlg); + if (derBufSz < 0) { + ret = derBufSz; + } + else { + outBuf = derBuf; + outBufSz = derBufSz; + } + } + + /* check if should convert to PEM format */ + if (ret == WOLFCLU_SUCCESS && fmt == PEM_FORM) { + pemBufSz = wolfCLU_KeyDerToPem(derBuf, derBufSz, &pemBuf, + PUBLICKEY_TYPE, DYNAMIC_TYPE_TMP_BUFFER); + if (pemBufSz <= 0 || pemBuf == NULL) { + ret = WOLFCLU_FAILURE; + } + else { + outBuf = pemBuf; + outBufSz = pemBufSz; + } + } + + /* open file and write Public key */ + if (ret == WOLFCLU_SUCCESS) { + file = XFOPEN(fOutNameBuf, "wb"); + if (file == XBADFILE) { + wolfCLU_LogError("unable to open file %s", + fOutNameBuf); + ret = OUTPUT_FILE_ERROR; + } + } + + if (ret == WOLFCLU_SUCCESS) { + if ((int)XFWRITE(outBuf, 1, outBufSz, file) <= 0) { + ret = OUTPUT_FILE_ERROR; + } + } + + break; + default: + wolfCLU_LogError("Invalid directive"); + ret = BAD_FUNC_ARG; + } + } + + if (file != NULL) { + XFCLOSE(file); + } + + if (derBuf != NULL) { + wolfCLU_ForceZero(derBuf, keySz); + XFREE(derBuf, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + } + + if (pemBuf != NULL) { + wolfCLU_ForceZero(pemBuf, pemBufSz); + XFREE(pemBuf, HEAP_HINT, DYNAMIC_TYPE_PRIVATE_KEY); + } + + if (fOutNameBuf != NULL) { + XFREE(fOutNameBuf, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + } + + wc_MlDsaKey_Free(key); +#ifdef WOLFSSL_SMALL_STACK + XFREE(key, HEAP_HINT, DYNAMIC_TYPE_DILITHIUM); +#endif + + return ret; +#else + (void)rng; + (void)fName; + (void)directive; + (void)fmt; + (void)keySz; + (void)level; + (void)withAlg; + + return NOT_COMPILED_IN; +#endif /* HAVE_DILITHIUM */ +} + /* The call back function of the writting xmss key */ #ifdef WOLFSSL_HAVE_XMSS enum wc_XmssRc wolfCLU_XmssKey_WriteCb(const byte * priv, diff --git a/src/genkey/clu_genkey_setup.c b/src/genkey/clu_genkey_setup.c index 821ee9f9..80c63b24 100644 --- a/src/genkey/clu_genkey_setup.c +++ b/src/genkey/clu_genkey_setup.c @@ -339,7 +339,72 @@ int wolfCLU_genKeySetup(int argc, char** argv) #else wolfCLU_LogError("Invalid option, Dithium not enabled."); WOLFCLU_LOG(WOLFCLU_L0, "Please re-configure wolfSSL with " - "--enable-dilithium, --enable-experimental and try again"); + "--enable-dilithium and try again"); + wc_FreeRng(&rng); + return NOT_COMPILED_IN; + #endif /* HAVE_DILITHIUM */ + } + else if (XSTRNCMP(keyType, "ml-dsa", 6) == 0) { + #if defined(HAVE_DILITHIUM) && defined(WOLFSSL_KEY_GEN) + int directiveArg = PRIV_AND_PUB_FILES; + int keySz = ML_DSA_LEVEL2_BOTH_KEY_DER_SIZE; + int level = WC_ML_DSA_44; + int withAlg = DILITHIUM_LEVEL2k; + + WOLFCLU_LOG(WOLFCLU_L0, "Generate ML-DSA Key"); + + /* get the level argument */ + ret = wolfCLU_checkForArg("-level", 6, argc, argv); + if (ret > 0) { + level = XATOI(argv[ret+1]); + switch (level) { + case WC_ML_DSA_44: + keySz = ML_DSA_LEVEL2_BOTH_KEY_DER_SIZE; + withAlg = ML_DSA_LEVEL2k; + break; + case WC_ML_DSA_65: + keySz = ML_DSA_LEVEL3_BOTH_KEY_DER_SIZE; + withAlg = ML_DSA_LEVEL3k; + break; + case WC_ML_DSA_87: + keySz = ML_DSA_LEVEL5_BOTH_KEY_DER_SIZE; + withAlg = ML_DSA_LEVEL5k; + break; + default: + WOLFCLU_LOG(WOLFCLU_L0, "Invalid -level (%s), using level%d", + argv[ret+1], level); + break; + } + } + else { + /* no option -level */ + WOLFCLU_LOG(WOLFCLU_L0, "No -level [ 2 | 3 | 5 ]"); + WOLFCLU_LOG(WOLFCLU_L0, "DEFAULT: use Level %d", level); + } + + /* get the directive argument */ + ret = wolfCLU_checkForArg("-output", 7, argc, argv); + if (ret > 0) { + if (argv[ret+1] != NULL) { + if (XSTRNCMP(argv[ret+1], "pub", 3) == 0) + directiveArg = PUB_ONLY_FILE; + else if (XSTRNCMP(argv[ret+1], "priv", 4) == 0) + directiveArg = PRIV_ONLY_FILE; + else if (XSTRNCMP(argv[ret+1], "keypair", 7) == 0) + directiveArg = PRIV_AND_PUB_FILES; + } + } + else { + WOLFCLU_LOG(WOLFCLU_L0, "No -output "); + WOLFCLU_LOG(WOLFCLU_L0, "DEFAULT: output public and private key pair"); + } + + ret = wolfCLU_genKey_ML_DSA(&rng, keyOutFName, directiveArg, + formatArg, keySz, level, withAlg); + #else + wolfCLU_LogError("Invalid option, ML-DSA not enabled."); + WOLFCLU_LOG(WOLFCLU_L0, "Please re-configure wolfSSL with " + "--enable-dilithium and try again"); wc_FreeRng(&rng); return NOT_COMPILED_IN; #endif /* HAVE_DILITHIUM */ diff --git a/src/tools/clu_funcs.c b/src/tools/clu_funcs.c index 27b9af94..aa639ad6 100644 --- a/src/tools/clu_funcs.c +++ b/src/tools/clu_funcs.c @@ -468,6 +468,7 @@ void wolfCLU_genKeyHelp(void) #endif #ifdef HAVE_DILITHIUM ,"dilithium" + ,"ml-dsa" #endif #ifdef WOLFSSL_HAVE_XMSS ,"xmss" @@ -489,6 +490,8 @@ void wolfCLU_genKeyHelp(void) #ifdef HAVE_DILITHIUM WOLFCLU_LOG(WOLFCLU_L0, "wolfssl -genkey dilithium -level " "[2|3|5] -out mykey -outform der -output KEYPAIR"); + WOLFCLU_LOG(WOLFCLU_L0, "wolfssl -genkey ml-dsa -level " + "[2|3|5] -out mykey -outform der -output KEYPAIR"); #endif #ifdef WOLFSSL_HAVE_XMSS WOLFCLU_LOG(WOLFCLU_L0, "wolfssl -genkey xmss -height [10|16|20] -out mykey -outform raw" diff --git a/src/x509/clu_ca_setup.c b/src/x509/clu_ca_setup.c index 77e003e3..cf2c6c5b 100644 --- a/src/x509/clu_ca_setup.c +++ b/src/x509/clu_ca_setup.c @@ -33,13 +33,18 @@ static const struct option ca_options[] = { {"-in", required_argument, 0, WOLFCLU_INFILE }, {"-out", required_argument, 0, WOLFCLU_OUTFILE }, {"-keyfile", required_argument, 0, WOLFCLU_KEY }, + {"-subjkey", required_argument, 0, WOLFCLU_SUBJKEY }, + {"-altkey", required_argument, 0, WOLFCLU_ALTKEY }, + {"-altpub", required_argument, 0, WOLFCLU_ALTPUB }, {"-cert", required_argument, 0, WOLFCLU_CAFILE }, {"-extensions",required_argument, 0, WOLFCLU_EXTENSIONS}, {"-md", required_argument, 0, WOLFCLU_MD }, {"-inform", required_argument, 0, WOLFCLU_INFORM }, + {"-outform", required_argument, 0, WOLFCLU_OUTFORM }, {"-config", required_argument, 0, WOLFCLU_CONFIG }, {"-days", required_argument, 0, WOLFCLU_DAYS }, - {"-selfsign", no_argument, 0, WOLFCLU_SELFSIGN }, + {"-selfsign", no_argument, 0, WOLFCLU_SELFSIGN }, + {"-altextend", no_argument, 0, WOLFCLU_ALTEXTEND }, {"-h", no_argument, 0, WOLFCLU_HELP }, {"-help", no_argument, 0, WOLFCLU_HELP }, @@ -56,9 +61,16 @@ static void wolfCLU_CAHelp(void) WOLFCLU_LOG(WOLFCLU_L0, "\t-extensions section in config file to parse extensions from"); WOLFCLU_LOG(WOLFCLU_L0, "\t-md type of hash i.e sha256"); WOLFCLU_LOG(WOLFCLU_L0, "\t-inform type PEM/DER of CSR input"); + WOLFCLU_LOG(WOLFCLU_L0, "\t-outform type PEM/DER of output"); WOLFCLU_LOG(WOLFCLU_L0, "\t-config file to read configuration from"); WOLFCLU_LOG(WOLFCLU_L0, "\t-days number of days for certificate to be valid"); WOLFCLU_LOG(WOLFCLU_L0, "\t-selfsign sign with key associated with cert"); +#if defined(WOLFSSL_DUAL_ALG_CERTS) && defined(HAVE_DILITHIUM) + WOLFCLU_LOG(WOLFCLU_L0, "\t-altextend sign with alternate key"); + WOLFCLU_LOG(WOLFCLU_L0, "\t-altkey file to read alternate private key from"); + WOLFCLU_LOG(WOLFCLU_L0, "\t-altpub file to read alternate public key from"); + WOLFCLU_LOG(WOLFCLU_L0, "\t-subjkey file to read subject key from"); +#endif /* WOLFSSL_DUAL_ALG_CERTS && HAVE_DILITHIUM */ } #endif @@ -67,10 +79,13 @@ int wolfCLU_CASetup(int argc, char** argv) { #ifndef WOLFCLU_NO_FILESYSTEM WOLFCLU_CERT_SIGN* signer = NULL; - WOLFSSL_BIO *keyIn = NULL; - WOLFSSL_BIO *reqIn = NULL; - WOLFSSL_X509 *x509 = NULL; - WOLFSSL_X509 *ca = NULL; + WOLFSSL_BIO *keyIn = NULL; + WOLFSSL_BIO *subjKey = NULL; + WOLFSSL_BIO *altKey = NULL; + WOLFSSL_BIO *altKeyPub = NULL; + WOLFSSL_BIO *reqIn = NULL; + WOLFSSL_X509 *x509 = NULL; + WOLFSSL_X509 *ca = NULL; WOLFSSL_EVP_PKEY* pkey = NULL; enum wc_HashType hashType = WC_HASH_TYPE_NONE; @@ -80,10 +95,12 @@ int wolfCLU_CASetup(int argc, char** argv) char* ext = NULL; int inForm = PEM_FORM; + int outForm = PEM_FORM; int option; int longIndex = 1; int days = 0; int selfSigned = 0; + int altSign = 0; opterr = 0; /* do not display unrecognized options */ optind = 0; /* start at indent 0 */ @@ -112,13 +129,49 @@ int wolfCLU_CASetup(int argc, char** argv) ret = WOLFCLU_FATAL_ERROR; } break; +#if defined(WOLFSSL_DUAL_ALG_CERTS) && defined(HAVE_DILITHIUM) + case WOLFCLU_SUBJKEY: + subjKey = wolfSSL_BIO_new_file(optarg, "rb"); + if (subjKey == NULL) { + wolfCLU_LogError("Unable to open subject key file %s", + optarg); + ret = WOLFCLU_FATAL_ERROR; + } + break; + + case WOLFCLU_ALTKEY: + altKey = wolfSSL_BIO_new_file(optarg, "rb"); + if (altKey == NULL) { + wolfCLU_LogError("Unable to open alternate key file %s", + optarg); + ret = WOLFCLU_FATAL_ERROR; + } + break; + + case WOLFCLU_ALTPUB: + altKeyPub = wolfSSL_BIO_new_file(optarg, "rb"); + if (altKeyPub == NULL) { + wolfCLU_LogError("Unable to open \ + alternate public key file %s", optarg); + ret = WOLFCLU_FATAL_ERROR; + } + break; +#endif /* WOLFSSL_DUAL_ALG_CERTS && HAVE_DILITHIUM */ + + case WOLFCLU_ALTEXTEND: + altSign = 1; + break; case WOLFCLU_CAFILE: ca = wolfSSL_X509_load_certificate_file(optarg, WOLFSSL_FILETYPE_PEM); if (ca == NULL) { - wolfCLU_LogError("Unable to open ca file %s", - optarg); + ca = wolfSSL_X509_load_certificate_file(optarg, + WOLFSSL_FILETYPE_ASN1); + } + + if (ca == NULL) { + wolfCLU_LogError("Unable to open CA file %s", optarg); ret = WOLFCLU_FATAL_ERROR; } break; @@ -139,6 +192,10 @@ int wolfCLU_CASetup(int argc, char** argv) inForm = wolfCLU_checkInform(optarg); break; + case WOLFCLU_OUTFORM: + outForm = wolfCLU_checkOutform(optarg); + break; + case WOLFCLU_CONFIG: config = optarg; break; @@ -168,7 +225,7 @@ int wolfCLU_CASetup(int argc, char** argv) } } - if (reqIn == NULL) { + if (reqIn == NULL && !altSign) { wolfCLU_LogError("Expecting CSR input"); ret = WOLFCLU_FATAL_ERROR; } @@ -206,7 +263,10 @@ int wolfCLU_CASetup(int argc, char** argv) } if (ret == WOLFCLU_SUCCESS) { - if (inForm == PEM_FORM) { + if (altSign) { + wolfSSL_PEM_read_bio_X509(reqIn, &x509, NULL, NULL); + } + else if (inForm == PEM_FORM) { wolfSSL_PEM_read_bio_X509_REQ(reqIn, &x509, NULL, NULL); } else { @@ -218,11 +278,17 @@ int wolfCLU_CASetup(int argc, char** argv) } } - if (ret == WOLFCLU_SUCCESS && (pkey != NULL || ca != NULL)) { + if (ret == WOLFCLU_SUCCESS && (pkey != NULL || ca != NULL || + altKey != NULL || altKeyPub != NULL)) { if (selfSigned) { wolfCLU_CertSignSetCA(signer, x509, pkey, wolfCLU_GetTypeFromPKEY(pkey)); } + else if (altSign) { + ret = wolfCLU_GenChimeraCertSign(keyIn, altKey, altKeyPub, subjKey, ca, + wolfSSL_X509_NAME_oneline(wolfSSL_X509_get_subject_name(x509), 0, 0), + out, outForm); + } else { wolfCLU_CertSignSetCA(signer, ca, pkey, wolfCLU_GetTypeFromPKEY(pkey)); @@ -231,21 +297,28 @@ int wolfCLU_CASetup(int argc, char** argv) /* default to version 3 which supports extensions */ if (ret == WOLFCLU_SUCCESS && - wolfSSL_X509_set_version(x509, WOLFSSL_X509_V3) != WOLFSSL_SUCCESS) { + wolfSSL_X509_set_version(x509, WOLFSSL_X509_V3) != WOLFSSL_SUCCESS && + !altSign) { wolfCLU_LogError("Unable to set version 3 for cert"); ret = WOLFCLU_FATAL_ERROR; } - if (ret == WOLFCLU_SUCCESS && ext != NULL) { + if (ret == WOLFCLU_SUCCESS && ext != NULL && !altSign) { wolfCLU_CertSignSetExt(signer, ext); } - if (ret == WOLFCLU_SUCCESS) { + if (ret == WOLFCLU_SUCCESS && !altSign) { ret = wolfCLU_CertSign(signer, x509); } wolfSSL_BIO_free(reqIn); wolfSSL_BIO_free(keyIn); + if (altKey != NULL) { + wolfSSL_BIO_free(altKey); + } + if (altKeyPub != NULL) { + wolfSSL_BIO_free(altKeyPub); + } if (!selfSigned) { wolfSSL_X509_free(x509); } diff --git a/src/x509/clu_x509_sign.c b/src/x509/clu_x509_sign.c index 651a903b..0afb6d37 100644 --- a/src/x509/clu_x509_sign.c +++ b/src/x509/clu_x509_sign.c @@ -24,6 +24,10 @@ #include #include #include +#include +#ifdef HAVE_DILITHIUM + #include +#endif /* HAVE_DILITHIUM */ #define WOLFCLU_CN_MATCH 0x00000001 /* country name must match */ #define WOLFCLU_CN_SUPPLIED 0x00000002 /* country name must be set */ @@ -208,6 +212,716 @@ void wolfCLU_CertSignSetCA(WOLFCLU_CERT_SIGN* csign, WOLFSSL_X509* ca, } } +/* ref: https://github.com/wolfssl/wolfssl-examples/X9.146/gen_ecdsa_mldsa_dual_keysig_cert.c */ +int wolfCLU_GenChimeraCertSign(WOLFSSL_BIO *bioCaKey, WOLFSSL_BIO *bioAltCaKey, + WOLFSSL_BIO *bioAltSubjPubKey, WOLFSSL_BIO *bioSubjKey, + WOLFSSL_X509 *caCert, const char *subject, + const char *outFileName, int outForm) +{ +#if defined(WOLFSSL_DUAL_ALG_CERTS) && defined(HAVE_DILITHIUM) + int ret = WOLFCLU_SUCCESS; + int isCA = 0; + + WC_RNG rng; + ecc_key caKey; + ecc_key serverKey; + MlDsaKey altCaKey; + word32 idx = 0; + byte level = 0; + + Cert newCert; + DecodedCert preTBS; + + int initRNG = 0; + int initCaKey = 0; + int initServerKey = 0; + int initAltCaKey = 0; + int initPreTBS = 0; + + XFILE caKeyFp = NULL; + XFILE altCaKeyFp = NULL; + XFILE altCaPubKeyFp = NULL; + XFILE serverKeyFp = NULL; + WOLFSSL_BIO *out = NULL; + + char *token = NULL; + char *key = NULL; + char *value = NULL; + char *saveptr = NULL; + char *subj = NULL; + int subjSz = 0; + + /* custom cert extension oid */ + const char *subjectAltPubKeyOid = "2.5.29.72"; + const char *altSigAlgOid = "2.5.29.73"; + const char *altSigValOid = "2.5.29.74"; + + /* + * LARGE_TEMO_SZ defines the size of temporary buffers used for signature key, + * verification key and signature value buffers. + * The value 11264 is enough for P-521 and ML-DSA-87 PEM certs. + */ + const int LARGE_TEMP_SZ = 11264; + byte caKeyBuf[LARGE_TEMP_SZ]; + int caKeySz = LARGE_TEMP_SZ; + byte altCaKeyBuf[LARGE_TEMP_SZ]; + int altCaKeySz = LARGE_TEMP_SZ; + byte sapkiBuf[LARGE_TEMP_SZ]; + int sapkiSz = LARGE_TEMP_SZ; + byte altSigAlgBuf[LARGE_TEMP_SZ]; + int altSigAlgSz = LARGE_TEMP_SZ; + byte scratchBuf[LARGE_TEMP_SZ]; + int scratchSz = LARGE_TEMP_SZ; + byte preTbsBuf[LARGE_TEMP_SZ]; + int preTbsSz = LARGE_TEMP_SZ; + byte altSigValBuf[LARGE_TEMP_SZ]; + int altSigValSz = LARGE_TEMP_SZ; + byte derBuf[LARGE_TEMP_SZ]; + int derSz = LARGE_TEMP_SZ; + byte outBuf[LARGE_TEMP_SZ]; + int outSz = LARGE_TEMP_SZ; + DerBuffer *derObj = NULL; + + /* if generate server cert */ + byte caCertBuf[LARGE_TEMP_SZ]; + int caCertSz = LARGE_TEMP_SZ; + byte serverKeyBuf[LARGE_TEMP_SZ]; + int serverKeySz = LARGE_TEMP_SZ; + + if (bioCaKey == NULL || bioAltCaKey == NULL || bioAltSubjPubKey == NULL + || subject == NULL || outFileName == NULL) { + wolfCLU_LogError("Error invalid argument wolfCLU_GenChimeraCertSign"); + ret = BAD_FUNC_ARG; + } + else if (bioSubjKey == NULL && caCert == NULL) { + isCA = 1; + } + else if (bioSubjKey != NULL && caCert != NULL) { + isCA = 0; + } + else { + wolfCLU_LogError("Error invalid argument wolfCLU_GenChimeraCertSign"); + ret = BAD_FUNC_ARG; + } + + XMEMSET(caKeyBuf, 0, caKeySz); + XMEMSET(altCaKeyBuf, 0, altCaKeySz); + XMEMSET(sapkiBuf, 0, sapkiSz); + XMEMSET(altSigAlgBuf, 0, altSigAlgSz); + XMEMSET(scratchBuf, 0, scratchSz); + XMEMSET(preTbsBuf, 0, preTbsSz); + XMEMSET(altSigValBuf, 0, altSigValSz); + XMEMSET(outBuf, 0, outSz); + XMEMSET(caCertBuf, 0, caCertSz); + XMEMSET(serverKeyBuf, 0, serverKeySz); + + if (ret == WOLFCLU_SUCCESS) { + ret = wc_InitRng(&rng); + if (ret != 0) { + wolfCLU_LogError("Error init RNG"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + initRNG = 1; + ret = WOLFCLU_SUCCESS; + } + } + + /* open the CA der certificate */ + if (ret == WOLFCLU_SUCCESS && !isCA) { + const byte *tmpBuf = wolfSSL_X509_get_der(caCert, &caCertSz); + if (tmpBuf == NULL || caCertSz <= 0) { + wolfCLU_LogError("Error getting DER from CA cert"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + XMEMCPY(caCertBuf, tmpBuf, caCertSz); + ret = WOLFCLU_SUCCESS; + } + } + + /* open CA ecc private key */ + if (ret == WOLFCLU_SUCCESS) { + ret = wolfSSL_BIO_get_fp(bioCaKey, &caKeyFp); + if (ret != WOLFCLU_SUCCESS) { + wolfCLU_LogError("Error cannot get CA key fd"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + XFSEEK(caKeyFp, 0, SEEK_SET); + ret = (int)XFREAD(caKeyBuf, 1, caKeySz, caKeyFp); + if (ret <= 0) { + wolfCLU_LogError("Error reading CA key"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + caKeySz = ret; + ret = WOLFCLU_SUCCESS; + } + } + } + + /* open server ecc private key */ + if (ret == WOLFCLU_SUCCESS && !isCA) { + ret = wolfSSL_BIO_get_fp(bioSubjKey, &serverKeyFp); + if (ret != WOLFCLU_SUCCESS) { + wolfCLU_LogError("Error cannot get server key fd"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + XFSEEK(serverKeyFp, 0, SEEK_SET); + ret = (int)XFREAD(serverKeyBuf, 1, serverKeySz, serverKeyFp); + if (ret <= 0) { + wolfCLU_LogError("Error reading server key"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + serverKeySz = ret; + ret = WOLFCLU_SUCCESS; + } + } + } + + /* open CA ecc private key */ + if (ret == WOLFCLU_SUCCESS) { + /* Try EC PRIVATE KEY format first */ + ret = wc_PemToDer(caKeyBuf, caKeySz, ECC_PRIVATEKEY_TYPE, + &derObj, HEAP_HINT, NULL, NULL); + if (ret < 0) { + /* Try PRIVATE KEY format (PKCS#8) */ + ret = wc_PemToDer(caKeyBuf, caKeySz, PRIVATEKEY_TYPE, + &derObj, HEAP_HINT, NULL, NULL); + if (ret != 0) { + wolfCLU_LogError("Error convert pem to der"); + ret = WOLFCLU_FATAL_ERROR; + } + } + + if (ret == 0) { + XMEMSET(caKeyBuf, 0, caKeySz); /* clear original buffer */ + caKeySz = derObj->length; + XMEMCPY(caKeyBuf, derObj->buffer, caKeySz); + wc_FreeDer(&derObj); + ret = WOLFCLU_SUCCESS; + } + } + + if (ret == WOLFCLU_SUCCESS) { + ret = wc_ecc_init(&caKey); + if (ret != 0) { + wolfCLU_LogError("Error init ecc key"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + initCaKey = 1; + ret = WOLFCLU_SUCCESS; + } + } + + if (ret == WOLFCLU_SUCCESS) { + idx = 0; + ret = wc_EccPrivateKeyDecode(caKeyBuf, &idx, &caKey, caKeySz); + if (ret != 0) { + wolfCLU_LogError("Error decoding ECC key"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = WOLFCLU_SUCCESS; + } + } + + /* load server ecc private key */ + if (ret == WOLFCLU_SUCCESS && !isCA) { + ret = wc_PemToDer(serverKeyBuf, serverKeySz, ECC_PRIVATEKEY_TYPE, + &derObj, HEAP_HINT, NULL, NULL); + if (ret < 0) { + /* Try PRIVATE KEY format (PKCS#8) */ + ret = wc_PemToDer(serverKeyBuf, serverKeySz, PRIVATEKEY_TYPE, + &derObj, HEAP_HINT, NULL, NULL); + if (ret < 0) { + wolfCLU_LogError("Error convert pem to der"); + ret = WOLFCLU_FATAL_ERROR; + } + } + + if (ret == 0) { + XMEMSET(serverKeyBuf, 0, serverKeySz); /* clear original buffer */ + serverKeySz = derObj->length; + XMEMCPY(serverKeyBuf, derObj->buffer, serverKeySz); + wc_FreeDer(&derObj); + ret = WOLFCLU_SUCCESS; + } + } + + if (ret == WOLFCLU_SUCCESS && !isCA) { + ret = wc_ecc_init(&serverKey); + if (ret != 0) { + wolfCLU_LogError("Error init server key"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + initServerKey = 1; + ret = WOLFCLU_SUCCESS; + } + } + + if (ret == WOLFCLU_SUCCESS && !isCA) { + idx = 0; + ret = wc_EccPrivateKeyDecode(serverKeyBuf, &idx, + &serverKey, serverKeySz); + if (ret != 0) { + wolfCLU_LogError("Error decoding server key"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = WOLFCLU_SUCCESS; + } + } + + /* load alternative CA public key */ + if (ret == WOLFCLU_SUCCESS) { + ret = wolfSSL_BIO_get_fp(bioAltSubjPubKey, &altCaPubKeyFp); + if (ret != WOLFCLU_SUCCESS) { + wolfCLU_LogError("Error get AltCAkey fd"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + XFSEEK(altCaPubKeyFp, 0, SEEK_SET); + ret = (int)XFREAD(sapkiBuf, 1, sapkiSz, altCaPubKeyFp); + if (ret <= 0) { + wolfCLU_LogError("Error cannot read ML-DSA key"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + sapkiSz = ret; + ret = WOLFCLU_SUCCESS; + } + } + } + + if (ret == WOLFCLU_SUCCESS) { + ret = wc_PemToDer(sapkiBuf, sapkiSz, PUBLICKEY_TYPE, + &derObj, HEAP_HINT, NULL, NULL); + if (ret < 0) { + wolfCLU_LogError("Error convert file pem to der"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + XMEMSET(sapkiBuf, 0, sapkiSz); /* clear original buffer */ + sapkiSz = derObj->length; + XMEMCPY(sapkiBuf, derObj->buffer, sapkiSz); + wc_FreeDer(&derObj); + ret = WOLFCLU_SUCCESS; + } + } + + /* load alternative CA private key */ + if (ret == WOLFCLU_SUCCESS) { + ret = wc_MlDsaKey_Init(&altCaKey, NULL, 0); + if (ret != 0) { + wolfCLU_LogError("Error init ML-DSA key"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + initAltCaKey = 1; + ret = WOLFCLU_SUCCESS; + } + } + + if (ret == WOLFCLU_SUCCESS) { + ret = wolfSSL_BIO_get_fp(bioAltCaKey, &altCaKeyFp); + if (ret != WOLFCLU_SUCCESS) { + wolfCLU_LogError("Error cannot get AltCA key fd"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + XFSEEK(altCaKeyFp, 0, SEEK_SET); + ret = (int)XFREAD(altCaKeyBuf, 1, altCaKeySz, altCaKeyFp); + if (ret <= 0) { + wolfCLU_LogError("Error reading alternative CA key"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + altCaKeySz = ret; + ret = WOLFCLU_SUCCESS; + } + } + } + + if (ret == WOLFCLU_SUCCESS) { + ret = wc_PemToDer(altCaKeyBuf, altCaKeySz, PKCS8_PRIVATEKEY_TYPE, + &derObj, HEAP_HINT, NULL, NULL); + if (ret < 0) { + wolfCLU_LogError("Error convert pem to der"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + XMEMSET(altCaKeyBuf, 0, altCaKeySz); /* clear original buffer */ + altCaKeySz = derObj->length; + XMEMCPY(altCaKeyBuf, derObj->buffer, altCaKeySz); + wc_FreeDer(&derObj); + ret = WOLFCLU_SUCCESS; + } + } + + if (ret == WOLFCLU_SUCCESS) { + idx = 0; + ret = wc_Dilithium_PrivateKeyDecode(altCaKeyBuf, &idx, + &altCaKey, (word32)altCaKeySz); + if (ret != 0) { + wolfCLU_LogError("Error decoding ML-DSA key"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + wc_MlDsaKey_GetParams(&altCaKey, &level); + ret = WOLFCLU_SUCCESS; + } + } + + if (ret == WOLFCLU_SUCCESS) { + switch (level) { + case 2: + altSigAlgSz = SetAlgoID(CTC_ML_DSA_LEVEL2, + altSigAlgBuf, oidSigType, 0); + break; + case 3: + altSigAlgSz = SetAlgoID(CTC_ML_DSA_LEVEL3, + altSigAlgBuf, oidSigType, 0); + break; + case 5: + altSigAlgSz = SetAlgoID(CTC_ML_DSA_LEVEL5, + altSigAlgBuf, oidSigType, 0); + break; + default: + wolfCLU_LogError("Error Invalid ML-DSA level %d", level); + altSigAlgSz = 0; + break; + } + + if (altSigAlgSz <= 0) { + wolfCLU_LogError("Error SetAlgoID(%d) returned: %d\n", + level, altSigAlgSz); + ret = WOLFCLU_FATAL_ERROR; + } + } + + if (ret == WOLFCLU_SUCCESS) { + ret = wc_InitCert(&newCert); + if (ret != 0) { + wolfCLU_LogError("Error init newCert"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = WOLFCLU_SUCCESS; + } + } + + if (ret == WOLFCLU_SUCCESS) { + subjSz = XSTRLEN(subject) + 1; + subj = (char*)XMALLOC(subjSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + if (subj == NULL) { + wolfCLU_LogError("Failed to allocate memory for subject"); + ret = MEMORY_E; + } + else { + XMEMCPY(subj, subject, subjSz); + token = XSTRTOK(subj, "/", &saveptr); + while (token != NULL) { + key = XSTRTOK(token, "=", &saveptr); + value = XSTRTOK(NULL, "=", &saveptr); + + if (key == NULL || value == NULL) { + /* exit loop if key or value is NULL */ + break; + } + if (XSTRCMP(key, "C") == 0) { + XSTRLCPY(newCert.subject.country, value, CTC_NAME_SIZE); + } + else if (XSTRCMP(key, "ST") == 0) { + XSTRLCPY(newCert.subject.state, value, CTC_NAME_SIZE); + } + else if (XSTRCMP(key, "L") == 0) { + XSTRLCPY(newCert.subject.locality, value, CTC_NAME_SIZE); + } + else if (XSTRCMP(key, "O") == 0) { + XSTRLCPY(newCert.subject.org, value, CTC_NAME_SIZE); + } + else if (XSTRCMP(key, "OU") == 0) { + XSTRLCPY(newCert.subject.unit, value, CTC_NAME_SIZE); + } + else if (XSTRCMP(key, "CN") == 0) { + XSTRLCPY(newCert.subject.commonName, value, CTC_NAME_SIZE); + } + else if (XSTRCMP(key, "emailAddress") == 0) { + XSTRLCPY(newCert.subject.email, value, CTC_NAME_SIZE); + } + + token = XSTRTOK(NULL, "/", &saveptr); + } + + XFREE(subj, HEAP_HINT, NULL); + } + } + + if (ret == WOLFCLU_SUCCESS) { + switch (level) { + case 2: + newCert.sigType = CTC_SHA256wECDSA; + break; + case 3: + newCert.sigType = CTC_SHA384wECDSA; + break; + case 5: + newCert.sigType = CTC_SHA512wECDSA; + break; + } + + if (isCA) { + newCert.isCA = 1; + } + else { + newCert.isCA = 0; + ret = wc_SetIssuerBuffer(&newCert, caCertBuf, caCertSz); + if (ret != 0) { + wolfCLU_LogError("Error setting issuer buffer"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = WOLFCLU_SUCCESS; + } + } + } + + if (ret == WOLFCLU_SUCCESS) { + ret = wc_SetCustomExtension(&newCert, 0, subjectAltPubKeyOid, + sapkiBuf, sapkiSz); + if (ret < 0) { + wolfCLU_LogError("Error setting custom extension"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = wc_SetCustomExtension(&newCert, 0, altSigAlgOid, + altSigAlgBuf, altSigAlgSz); + if (ret < 0) { + wolfCLU_LogError("Error setting custom extension"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = WOLFCLU_SUCCESS; + } + } + } + + if (ret == WOLFCLU_SUCCESS && isCA) { + ret = wc_MakeCert(&newCert, scratchBuf, + scratchSz, NULL, &caKey, &rng); + if (ret <= 0) { + wolfCLU_LogError("Error making certificate"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = wc_SignCert(newCert.bodySz, newCert.sigType, scratchBuf, + scratchSz, NULL, &caKey, &rng); + if (ret <= 0) { + wolfCLU_LogError("Error signing certificate"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + scratchSz = ret; + ret = WOLFCLU_SUCCESS; + } + } + } + else if (ret == WOLFCLU_SUCCESS && !isCA) { + ret = wc_MakeCert(&newCert, scratchBuf, scratchSz, + NULL, &serverKey, &rng); + if (ret <= 0) { + wolfCLU_LogError("Error making server certificate"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = wc_SignCert(newCert.bodySz, newCert.sigType, scratchBuf, + scratchSz, NULL, &caKey, &rng); + if (ret <= 0) { + wolfCLU_LogError("Error signing server certificate"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + scratchSz = ret; + ret = WOLFCLU_SUCCESS; + } + } + } + + if (ret == WOLFCLU_SUCCESS) { + wc_InitDecodedCert(&preTBS, scratchBuf, scratchSz, 0); + initPreTBS = 1; + ret = wc_ParseCert(&preTBS, CERT_TYPE, NO_VERIFY, NULL); + if (ret < 0) { + wolfCLU_LogError("Error parsing certificate"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = wc_GeneratePreTBS(&preTBS, preTbsBuf, preTbsSz); + if (ret < 0) { + wolfCLU_LogError("Error generating preTBS"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + preTbsSz = ret; + ret = WOLFCLU_SUCCESS; + } + } + } + + if (ret == WOLFCLU_SUCCESS) { + switch (level) { + case 2: + ret = wc_MakeSigWithBitStr(altSigValBuf, altSigValSz, + CTC_ML_DSA_LEVEL2, preTbsBuf, preTbsSz, + ML_DSA_LEVEL2_TYPE, &altCaKey, &rng); + break; + case 3: + ret = wc_MakeSigWithBitStr(altSigValBuf, altSigValSz, + CTC_ML_DSA_LEVEL3, preTbsBuf, preTbsSz, + ML_DSA_LEVEL3_TYPE, &altCaKey, &rng); + break; + case 5: + ret = wc_MakeSigWithBitStr(altSigValBuf, altSigValSz, + CTC_ML_DSA_LEVEL5, preTbsBuf, preTbsSz, + ML_DSA_LEVEL5_TYPE, &altCaKey, &rng); + break; + } + + if (ret < 0) { + wolfCLU_LogError("Error making signature with bit string"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + altSigValSz = ret; + ret = WOLFCLU_SUCCESS; + } + } + + if (ret == WOLFCLU_SUCCESS) { + ret = wc_SetCustomExtension(&newCert, 0, altSigValOid, + altSigValBuf, altSigValSz); + if (ret < 0) { + wolfCLU_LogError("Error setting custom extension"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = WOLFCLU_SUCCESS; + } + } + + if (ret == WOLFCLU_SUCCESS && isCA) { + ret = wc_MakeCert(&newCert, derBuf, derSz, NULL, &caKey, &rng); + if (ret < 0) { + wolfCLU_LogError("Error making certificate"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = wc_SignCert(newCert.bodySz, newCert.sigType, + derBuf, derSz, NULL, &caKey, &rng); + if (ret < 0) { + wolfCLU_LogError("Error signing certificate"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + derSz = ret; + ret = WOLFCLU_SUCCESS; + } + } + } + else if (ret == WOLFCLU_SUCCESS && !isCA) { + ret = wc_MakeCert(&newCert, derBuf, derSz, NULL, &serverKey, &rng); + if (ret < 0) { + wolfCLU_LogError("Error making server certificate"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + ret = wc_SignCert(newCert.bodySz, newCert.sigType, + derBuf, derSz, NULL, &caKey, &rng); + if (ret < 0) { + wolfCLU_LogError("Error signing server certificate"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + derSz = ret; + ret = WOLFCLU_SUCCESS; + } + } + } + + if (ret == WOLFCLU_SUCCESS && outForm == PEM_FORM) { + ret = wc_DerToPem(derBuf, derSz, outBuf, outSz, CERT_TYPE); + if (ret < 0) { + wolfCLU_LogError("Error converting DER to PEM"); + ret = WOLFCLU_FATAL_ERROR; + } + else { + outSz = ret; + ret = WOLFCLU_SUCCESS; + } + } + else if (ret == WOLFCLU_SUCCESS && outForm == DER_FORM) { + outSz = derSz; + XMEMCPY(outBuf, derBuf, outSz); + } + + if (ret == WOLFCLU_SUCCESS) { + out = wolfSSL_BIO_new_file(outFileName, "wb"); + if (out == NULL) { + wolfCLU_LogError("Unable to open out file %s", outFileName); + ret = WOLFCLU_FATAL_ERROR; + } + else { + wolfSSL_BIO_write(out, outBuf, outSz); + } + } + + if (initRNG) { + wc_FreeRng(&rng); + } + if (initCaKey) { + wc_ecc_free(&caKey); + } + if (initServerKey) { + wc_ecc_free(&serverKey); + } + if (initAltCaKey) { + wc_MlDsaKey_Free(&altCaKey); + } + if (initPreTBS) { + wc_FreeDecodedCert(&preTBS); + } + if (out != NULL) { + wolfSSL_BIO_free(out); + } + + if (ret != WOLFCLU_SUCCESS) { + wolfCLU_LogError("Error in wolfCLU_ChimeraCertSignSetCA: %d", ret); + } + + return ret; + +#else + (void)bioCaKey; + (void)bioAltCaKey; + (void)bioAltSubjPubKey; + (void)bioSubjKey; + (void)caCert; + (void)subject; + (void)outFileName; + (void)outForm; + + wolfCLU_LogError("Please compile wolfSSL with --enable-dual-alg-certs " + "--enable-experimental --enable-dilithium\n"); + + return NOT_COMPILED_IN; +#endif /* WOLFSSL_DUAL_ALG_CERTS && HAVE_DILITHIUM */ +} void wolfCLU_CertSignSetSerial(WOLFCLU_CERT_SIGN* csign, WOLFSSL_BIO* s) { diff --git a/tests/x509/x509-ca-test.sh b/tests/x509/x509-ca-test.sh index d1bf5c11..f0177f32 100755 --- a/tests/x509/x509-ca-test.sh +++ b/tests/x509/x509-ca-test.sh @@ -259,6 +259,25 @@ run_success "ca -config ca.conf -in tmp-ca.csr -out tmp.pem -md sha256 -keyfile run_success "req -key ./certs/server-key.pem -subj O=Sawtooth/CN=www.wolfclu.com/C=US/ST=MT/L=Bozeman/OU=org-unit -out tmp-ca.csr" run_fail "ca -config ca-match.conf -in tmp-ca.csr -out tmp.pem -md sha256 -keyfile ./certs/ca-key.pem" +# chimera certificate test +if ./wolfssl ca -help 2>&1 | grep altextend &> /dev/null; then + echo "Testing chimera certificate extension" + run_success "req -new -x509 -key ./certs/ca-ecc-key.pem -subj O=org-A/C=US/ST=WA/L=Seattle/CN=A/OU=org-unit-A -out tmp-ca-cert.pem -outform PEM" + run_success "ca -altextend -in tmp-ca-cert.pem -keyfile ./certs/ca-ecc-key.pem -altkey ./certs/ca-mldsa44-key.pem -altpub ./certs/ca-mldsa44-keyPub.pem -out tmp-ca-chimera-cert.pem" + + run_success "req -new -key ./certs/server-ecc-key.pem -subj O=org-B/C=US/ST=WA/L=Seattle/CN=B/OU=org-unit-B -out tmp-server.csr -outform PEM" + run_success "ca -in tmp-server.csr -keyfile ./certs/ca-ecc-key.pem -cert tmp-ca-cert.pem -out tmp-server-cert.pem" + run_success "ca -altextend -in tmp-server-cert.pem -keyfile ./certs/ca-ecc-key.pem -altkey ./certs/ca-mldsa44-key.pem -altpub ./certs/server-mldsa44-keyPub.pem -subjkey ./certs/server-ecc-key.pem -cert tmp-ca-chimera-cert.pem -out tmp-server-chimera-cert.pem" + + echo "Chimera certificate test passed" + + rm -f tmp-ca-cert.pem + rm -f tmp-ca-chimera-cert.pem + rm -f tmp-server.csr + rm -f tmp-server-cert.pem + rm -f tmp-server-chimera-cert.pem +fi + rm -f test_ca.pem rm -f tmp.pem rm -f rand-file-test diff --git a/wolfclu/clu_optargs.h b/wolfclu/clu_optargs.h index 04957af1..13981b50 100644 --- a/wolfclu/clu_optargs.h +++ b/wolfclu/clu_optargs.h @@ -72,6 +72,9 @@ enum { WOLFCLU_PASSWORD_SOURCE, WOLFCLU_MODULUS, WOLFCLU_KEY, + WOLFCLU_SUBJKEY, + WOLFCLU_ALTKEY, + WOLFCLU_ALTPUB, WOLFCLU_IV, WOLFCLU_NEW, WOLFCLU_NEWKEY, @@ -81,6 +84,7 @@ enum { WOLFCLU_TIME, WOLFCLU_SIGN, WOLFCLU_SELFSIGN, + WOLFCLU_ALTEXTEND, WOLFCLU_VERIFY, WOLFCLU_DGST, WOLFCLU_VERBOSE, diff --git a/wolfclu/genkey/clu_genkey.h b/wolfclu/genkey/clu_genkey.h index 64a68209..a670c5ef 100644 --- a/wolfclu/genkey/clu_genkey.h +++ b/wolfclu/genkey/clu_genkey.h @@ -111,7 +111,7 @@ int wolfCLU_KeyDerToPem(const byte* der, int derSz, byte** out, int pemType, /** * generate a Dilithium key * - * @param rng the randam number generator + * @param rng the random number generator * @param fName name of the file to write to * @param directive which key to output, public or private, maybe both * @param fmt output format (PEM/DER) @@ -123,6 +123,21 @@ int wolfCLU_KeyDerToPem(const byte* der, int derSz, byte** out, int pemType, int wolfCLU_genKey_Dilithium(WC_RNG* rng, char* fName, int directive, int fmt, int keySz, int level, int withAlg); +/** + * generate a ML-DSA key + * + * @param rng the random number generator + * @param fName name of the file to write to + * @param directive which key to output, public or private, maybe both + * @param fmt output format (PEM/DER) + * @param level the ML-DSA level 2, 3 or 5 + * @param withAlg Whether to use SubjectPublicKeyInfo format + * + * return WOLFCLU_SUCCESS on success +*/ +int wolfCLU_genKey_ML_DSA(WC_RNG* rng, char* fName, int directive, int fmt, + int keySz, int level, int withAlg); + /** * call back function of read/write a XMSS private key * @@ -140,7 +155,7 @@ enum wc_XmssRc wolfCLU_XmssKey_ReadCb(byte* priv, word32 privSz, void* context); /** * generate a XMSS key * - * @param rng the randam number generator + * @param rng the random number generator * @param fName name of the file to write to * @param directive which key to output, public or private, maybe both * @param paramStr the XMSS parameter diff --git a/wolfclu/x509/clu_x509_sign.h b/wolfclu/x509/clu_x509_sign.h index 1a581387..67ab5d1a 100644 --- a/wolfclu/x509/clu_x509_sign.h +++ b/wolfclu/x509/clu_x509_sign.h @@ -30,6 +30,9 @@ int wolfCLU_CertSignFree(WOLFCLU_CERT_SIGN* csign); void wolfCLU_CertSignSetSerial(WOLFCLU_CERT_SIGN* csign, WOLFSSL_BIO* s); void wolfCLU_CertSignSetCA(WOLFCLU_CERT_SIGN* csign, WOLFSSL_X509* ca, void* key, int keyType); +int wolfCLU_GenChimeraCertSign(WOLFSSL_BIO *bioCaKey, WOLFSSL_BIO *bioAltCaKey, + WOLFSSL_BIO *bioAltSubjPubKey, WOLFSSL_BIO *bioSubjKey, WOLFSSL_X509 *caCert, + const char *subject, const char *outFileName, int outForm); void wolfCLU_CertSignSetHash(WOLFCLU_CERT_SIGN* csign, enum wc_HashType hashType); void wolfCLU_CertSignSetDate(WOLFCLU_CERT_SIGN* csign, int d);