Skip to content

Commit

Permalink
Provide a way to export PKCS12 in a way compatible with major OS (closes
Browse files Browse the repository at this point in the history
  • Loading branch information
schwabe committed Jul 30, 2022
1 parent 7bd86c3 commit c66801a
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 0 deletions.
9 changes: 9 additions & 0 deletions docs/hazmat/primitives/asymmetric/serialization.rst
Expand Up @@ -1002,6 +1002,15 @@ Serialization Encryption Types

:param bytes password: The password to use for encryption.

.. class:: PKCS12CompatibilityEncryption(password)

Encrypt using 3DES and SHA1 for a given key.
This is an option that should be only used to allow exporting PKCS12
to devices/software that does not support stronger encryption of PKCS12
like macOS 15.x or Android 12.

:param bytes password: The password to use for encryption.

.. class:: NoEncryption

Do not encrypt.
Expand Down
29 changes: 29 additions & 0 deletions src/cryptography/hazmat/backends/openssl/backend.py
Expand Up @@ -2247,6 +2247,7 @@ def serialize_key_and_certificates_to_pkcs12(
nid_key = -1
pkcs12_iter = 0
mac_iter = 0
mac_alg = self._ffi.NULL
elif isinstance(
encryption_algorithm, serialization.BestAvailableEncryption
):
Expand All @@ -2261,6 +2262,20 @@ def serialize_key_and_certificates_to_pkcs12(
# Did we mention how lousy PKCS12 encryption is?
mac_iter = 1
password = encryption_algorithm.password
mac_alg = self._ffi.NULL
elif isinstance(
encryption_algorithm, serialization.PKCS12CompatibilityEncryption
):
# This is currently mostly identical with BestAvailableEncryption
# but is meant to stay 3DES/SHA1 to be able to support operating
# systems like Android <= 12/13 and macOS <= 15 that do not support
# anything stronger
nid_cert = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC
nid_key = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC
mac_iter = 1
pkcs12_iter = 20000
password = encryption_algorithm.password
mac_alg = self._evp_md_non_null_from_algorithm(hashes.SHA1)
else:
raise ValueError("Unsupported key encryption type")

Expand Down Expand Up @@ -2310,6 +2325,20 @@ def serialize_key_and_certificates_to_pkcs12(
0,
)

if (
self._lib.Cryptography_HAS_PKCS12_SET_MAC
and mac_alg != self._ffi.NULL
):
self._lib.PKCS12_set_mac(
p12,
password_buf,
-1,
self._ffi.NULL,
0,
mac_iter,
mac_alg,
)

self.openssl_assert(p12 != self._ffi.NULL)
p12 = self._ffi.gc(p12, self._lib.PKCS12_free)

Expand Down
12 changes: 12 additions & 0 deletions src/cryptography/hazmat/primitives/_serialization.py
Expand Up @@ -51,5 +51,17 @@ def __init__(self, password: bytes):
self.password = password


class PKCS12CompatibilityEncryption(KeySerializationEncryption):
""" "
Provides the most compatible encryption using 3DES and SHA1 for PKCS12.
"""

def __init__(self, password):
if not isinstance(password, bytes) or len(password) == 0:
raise ValueError("Password must be 1 or more bytes.")

self.password = password


class NoEncryption(KeySerializationEncryption):
pass
2 changes: 2 additions & 0 deletions src/cryptography/hazmat/primitives/serialization/__init__.py
Expand Up @@ -8,6 +8,7 @@
Encoding,
KeySerializationEncryption,
NoEncryption,
PKCS12CompatibilityEncryption,
ParameterFormat,
PrivateFormat,
PublicFormat,
Expand Down Expand Up @@ -41,5 +42,6 @@
"ParameterFormat",
"KeySerializationEncryption",
"BestAvailableEncryption",
"PKCS12CompatibilityEncryption",
"NoEncryption",
]
1 change: 1 addition & 0 deletions tests/hazmat/primitives/test_pkcs12.py
Expand Up @@ -341,6 +341,7 @@ class TestPKCS12Creation:
("algorithm", "password"),
[
(serialization.BestAvailableEncryption(b"password"), b"password"),
(serialization.PKCS12CompatibilityEncryption(b"pass"), b"pass"),
(serialization.NoEncryption(), None),
],
)
Expand Down

0 comments on commit c66801a

Please sign in to comment.