Skip to content

Commit 0ccd210

Browse files
committed
Provide a way to export PKCS12 in a way compatible with major OS (closes #7293)
1 parent 7bd86c3 commit 0ccd210

File tree

5 files changed

+38
-0
lines changed

5 files changed

+38
-0
lines changed

docs/hazmat/primitives/asymmetric/serialization.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,6 +1002,16 @@ Serialization Encryption Types
10021002

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

1005+
.. class:: PKCS12CompatibilityEncryption(password)
1006+
1007+
Encrypt using 3DES and SHA1 for a given key.
1008+
This is an option that should be only used to allow exporting PKCS12
1009+
to devices/software that does not support stronger encryption of PKCS12
1010+
like macOS 15.x or Android 12.
1011+
1012+
:param bytes password: The password to use for encryption.
1013+
1014+
10051015
.. class:: NoEncryption
10061016

10071017
Do not encrypt.

src/cryptography/hazmat/backends/openssl/backend.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2247,6 +2247,7 @@ def serialize_key_and_certificates_to_pkcs12(
22472247
nid_key = -1
22482248
pkcs12_iter = 0
22492249
mac_iter = 0
2250+
mac_alg = self._ffi.NULL
22502251
elif isinstance(
22512252
encryption_algorithm, serialization.BestAvailableEncryption
22522253
):
@@ -2261,6 +2262,17 @@ def serialize_key_and_certificates_to_pkcs12(
22612262
# Did we mention how lousy PKCS12 encryption is?
22622263
mac_iter = 1
22632264
password = encryption_algorithm.password
2265+
mac_alg = self._ffi.NULL
2266+
elif isinstance(encryption_algorithm, serialization.PKCS12CompatibilityEncryption):
2267+
# This is currently mostly identical with BestAvailableEncryption but
2268+
# is meant to stay 3DES/SHA1 to be able to support things like Android <= 12/13
2269+
# and other operating systems like macOS 15 that do not support anything stronger
2270+
nid_cert = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC
2271+
nid_key = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC
2272+
mac_iter = 1
2273+
pkcs12_iter = 20000
2274+
password = encryption_algorithm.password
2275+
mac_alg = self._evp_md_non_null_from_algorithm(hashes.SHA1)
22642276
else:
22652277
raise ValueError("Unsupported key encryption type")
22662278

@@ -2310,6 +2322,9 @@ def serialize_key_and_certificates_to_pkcs12(
23102322
0,
23112323
)
23122324

2325+
if self._lib.Cryptography_HAS_PKCS12_SET_MAC and mac_alg != self._ffi.NULL:
2326+
self._lib.PKCS12_set_mac(p12, password_buf, -1, self._ffi.NULL, 0, mac_iter, mac_alg)
2327+
23132328
self.openssl_assert(p12 != self._ffi.NULL)
23142329
p12 = self._ffi.gc(p12, self._lib.PKCS12_free)
23152330

src/cryptography/hazmat/primitives/_serialization.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,15 @@ def __init__(self, password: bytes):
5151
self.password = password
5252

5353

54+
class PKCS12CompatibilityEncryption(KeySerializationEncryption):
55+
""""
56+
Provides the most compatible encryption using 3DES and SHA1 for PKCS12.
57+
"""
58+
def __init__(self, password):
59+
if not isinstance(password, bytes) or len(password) == 0:
60+
raise ValueError("Password must be 1 or more bytes.")
61+
62+
self.password = password
63+
5464
class NoEncryption(KeySerializationEncryption):
5565
pass

src/cryptography/hazmat/primitives/serialization/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
from cryptography.hazmat.primitives._serialization import (
77
BestAvailableEncryption,
8+
PKCS12CompatibilityEncryption,
89
Encoding,
910
KeySerializationEncryption,
1011
NoEncryption,
@@ -41,5 +42,6 @@
4142
"ParameterFormat",
4243
"KeySerializationEncryption",
4344
"BestAvailableEncryption",
45+
"PKCS12CompatibilityEncryption",
4446
"NoEncryption",
4547
]

tests/hazmat/primitives/test_pkcs12.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,7 @@ class TestPKCS12Creation:
341341
("algorithm", "password"),
342342
[
343343
(serialization.BestAvailableEncryption(b"password"), b"password"),
344+
(serialization.PKCS12CompatibilityEncryption(b"password"), b"password"),
344345
(serialization.NoEncryption(), None),
345346
],
346347
)

0 commit comments

Comments
 (0)