Skip to content

Commit

Permalink
Merge pull request #4494 from jmcrawford45/PS-4631
Browse files Browse the repository at this point in the history
lemur: add legacy PBES1 openssl export support
  • Loading branch information
jmcrawford45 authored Jul 5, 2023
2 parents 22f81be + 77a6bde commit 21ae705
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 17 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ Removed flask-script.
Updated werkzeug to 2.3.6 and jinja2 to 3.1.2.
Updated CORS settings to use Flask-CORS Configuration Options.
Added new Custom Response Headers option to Lemur Configuration.
Added legacy p12 export type to openssl plugin. New versions of openssl produce keystores incompatible with older
versions of JDK8, so in some cases it may be useful to export in this format. Note that legacy p12 files do *NOT* feature
strong encryption, and you should not rely on confidentiality of the exported resource.

CLI Command Updates:
- `runserver` cmd has been replaced by the default `run` cmd.
Expand Down
66 changes: 49 additions & 17 deletions lemur/plugins/lemur_openssl/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,25 @@ def run_process(command):
raise Exception(stderr)


def create_pkcs12(cert, chain, p12_tmp, key, alias, passphrase):
def get_openssl_version():
"""
:return: the openssl version, if it can be determined
"""
command = ['openssl', 'version']
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
current_app.logger.debug(command)
stdout, stderr = p.communicate()

if p.returncode != 0:
current_app.logger.debug(" ".join(command))
current_app.logger.error(stderr)
raise Exception(stderr)

if stdout.startswith(b'OpenSSL'):
return stdout.split()[1]


def create_pkcs12(cert, chain, p12_tmp, key, alias, passphrase, legacy: bool = False):
"""
Creates a pkcs12 formated file.
:param cert:
Expand All @@ -44,6 +62,7 @@ def create_pkcs12(cert, chain, p12_tmp, key, alias, passphrase):
:param key:
:param alias:
:param passphrase:
:param legacy: should legacy insecure encryption be used (for support with ancient Java versions)
"""
assert isinstance(cert, str)
if chain is not None:
Expand All @@ -61,23 +80,29 @@ def create_pkcs12(cert, chain, p12_tmp, key, alias, passphrase):
f.writelines([cert.strip() + "\n", chain.strip() + "\n"])
else:
f.writelines([cert.strip() + "\n"])
cmd = [
"openssl",
"pkcs12",
"-export",
"-name",
alias,
"-in",
cert_tmp,
"-inkey",
key_tmp,
"-out",
p12_tmp,
"-password",
"pass:{}".format(passphrase),
]

if legacy:
version = get_openssl_version()
if version and version >= b'3':
cmd.append("-legacy")

run_process(
[
"openssl",
"pkcs12",
"-export",
"-name",
alias,
"-in",
cert_tmp,
"-inkey",
key_tmp,
"-out",
p12_tmp,
"-password",
"pass:{}".format(passphrase),
]
cmd
)


Expand All @@ -95,7 +120,7 @@ class OpenSSLExportPlugin(ExportPlugin):
"name": "type",
"type": "select",
"required": True,
"available": ["PKCS12 (.p12)"],
"available": ["PKCS12 (.p12)", "legacy PKCS12 (.p12)"],
"helpMessage": "Choose the format you wish to export",
},
{
Expand Down Expand Up @@ -142,6 +167,13 @@ def export(self, body, chain, key, options, **kwargs):

create_pkcs12(body, chain, output_tmp, key, alias, passphrase)
extension = "p12"
elif type == "legacy PKCS12 (.p12)":
if not key:
raise Exception("Private Key required by {0}".format(type))

create_pkcs12(body, chain, output_tmp, key, alias, passphrase, legacy=True)
extension = "p12"

else:
raise Exception("Unable to export, unsupported type: {0}".format(type))

Expand Down
19 changes: 19 additions & 0 deletions lemur/plugins/lemur_openssl/tests/test_openssl.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
from unittest import mock

import pytest

from lemur.plugins.lemur_openssl.plugin import run_process, get_openssl_version
from lemur.tests.vectors import INTERNAL_PRIVATE_KEY_A_STR, INTERNAL_CERTIFICATE_A_STR


Expand All @@ -15,3 +19,18 @@ def test_export_certificate_to_pkcs12(app):

raw = p.export(INTERNAL_CERTIFICATE_A_STR, "", INTERNAL_PRIVATE_KEY_A_STR, options)
assert raw != b""


def test_export_certificate_to_pkcs12_legacy(app):
from lemur.plugins.base import plugins

p = plugins.get("openssl-export")
options = [
{"name": "passphrase", "value": "test1234"},
{"name": "type", "value": "legacy PKCS12 (.p12)"},
]

with mock.patch('lemur.plugins.lemur_openssl.plugin.run_process', mock.Mock(wraps=run_process)) as mock_run_process:
p.export(INTERNAL_CERTIFICATE_A_STR, "", INTERNAL_PRIVATE_KEY_A_STR, options)
assert mock_run_process.call_count == 1
assert ("-legacy" in mock_run_process.call_args_list[0][0][0] or get_openssl_version() < b'3')

0 comments on commit 21ae705

Please sign in to comment.