Repository: certbot/certbot (Python)

Issue:
Private keys are now issuing as PKCS1 instead of PKCS8
If you're having trouble using Certbot and aren't sure you've found a bug or
request for a new feature, please first try asking for help at
https://community.letsencrypt.org/. There is a much larger community there of
people familiar with the project who will be able to more quickly answer your
questions.

## My operating system is (include version):
Debian 12

## I installed Certbot with (snap, OS package manager, pip, certbot-auto, etc):
pip

## I ran this command and it produced this output:
sudo certbot certonly --standalone -d {{DOMAIN}} --non-interactive --agree-tos --email {{EMAIL}} --http-01-port=8888 --force-renewal --text

## Certbot's behavior differed from what I expected because:
Prior to version 3.1.0, private keys were generated in PKCS8 format (BEGIN PRIVATE KEY) rather than PKCS1 (BEGIN RSA PRIVATE KEY) or EC (BEGIN EC PRIVATE KEY) 

This introduced a breaking change to our workflow, where we upload the certificate chain and private key to Azure Keyvault, which only accepts the PKCS8 format. I couldn't see any mention of a breaking change in the release notes.

I would like to check if this change was intentional, as rolling back to version 3.0.1 goes back to a PKCS8 private key.


Discussion:
I could be miles off the mark, but is it possible that this:

https://github.com/certbot/certbot/commit/06ea141ca98ff33d1e900f69130868d394c5df02#diff-0deff6f4df6ae73704b7c2a40240378c569c5e9782e314193e86e90ba1a06985L257

`dump_privatekey`

Was previously converting this to PKCS8? In which case, would it keep in line to change the now returned cryptography version to use `PrivateFormat.PKCS8`, or should this be intended behaviour now and will remain, and I should convert this externally?
this is indeed an unintended regression for which you correctly identified the cause. thanks a lot Jonno12345. i wrote https://github.com/certbot/certbot/pull/10134 to fix this
> this is indeed an unintended regression for which you correctly identified the cause. thanks a lot Jonno12345. i wrote #10134 to fix this

Great, thanks, glad I could help!



Patch:
diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md
index 8305679a501..36bcc2d6dc1 100644
--- a/certbot/CHANGELOG.md
+++ b/certbot/CHANGELOG.md
@@ -16,6 +16,8 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
 
 ### Fixed
 
+* Private keys are now saved in PKCS#8 format instead of PKCS#1. Using PKCS#1
+  was a regression introduced in Certbot 3.1.0.
 * Allow nginx plugin to parse non-breaking spaces in nginx configuration files.
 * Honor --reuse-key when --allow-subset-of-names is set
 * Fixed regression in symlink parsing on Windows that was introduced in Certbot
diff --git a/certbot/certbot/crypto_util.py b/certbot/certbot/crypto_util.py
index fd77d5342f4..4dd062ab21f 100644
--- a/certbot/certbot/crypto_util.py
+++ b/certbot/certbot/crypto_util.py
@@ -216,7 +216,8 @@ def make_key(bits: int = 2048, key_type: str = "rsa",
 
     :returns: new RSA or ECDSA key in PEM form with specified number of bits
               or of type ec_curve when key_type ecdsa is used.
-    :rtype: str
+    :rtype: bytes
+
     """
     key: Union[rsa.RSAPrivateKey, ec.EllipticCurvePrivateKey]
     if key_type == 'rsa':
@@ -247,7 +248,7 @@ def make_key(bits: int = 2048, key_type: str = "rsa",
         raise errors.Error("Invalid key_type specified: {}.  Use [rsa|ecdsa]".format(key_type))
     return key.private_bytes(
         encoding=Encoding.PEM,
-        format=PrivateFormat.TraditionalOpenSSL,
+        format=PrivateFormat.PKCS8,
         encryption_algorithm=NoEncryption()
     )
 


Test patch:
diff --git a/certbot/certbot/_internal/tests/crypto_util_test.py b/certbot/certbot/_internal/tests/crypto_util_test.py
index 44bc6363945..9e5fda6cea8 100644
--- a/certbot/certbot/_internal/tests/crypto_util_test.py
+++ b/certbot/certbot/_internal/tests/crypto_util_test.py
@@ -207,6 +207,14 @@ def test_bad_key_type(self):
                            match=re.escape('Invalid key_type specified: unf.  Use [rsa|ecdsa]')):
             make_key(2048, key_type='unf')
 
+    def test_for_pkcs8_format(self):
+        from certbot.crypto_util import make_key
+
+        # PKCS#1 format will instead have text like "BEGIN RSA PRIVATE KEY" or "BEGIN EC PRIVATE
+        # KEY"
+        assert b"BEGIN PRIVATE KEY" in make_key(2048)
+        assert b"BEGIN PRIVATE KEY" in make_key(elliptic_curve='secp256r1', key_type='ecdsa')
+
 
 class VerifyCertSetup(unittest.TestCase):
     """Refactoring for verification tests."""