Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added pem data #74

Merged
merged 11 commits into from
Jun 20, 2023
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ You can find out backwards-compatibility policy [here](https://github.com/hynek/
- Support for RFC 4880 OpenPGP private & public keys: `pem.OpenPGPPublicKey` and `pem.OpenPGPPrivateKey`.
[#72](https://github.com/hynek/pem/issues/72)
- `pem.parse_file()` now accepts also [`pathlib.Path`](https://docs.python.org/3/library/pathlib.html#pathlib.Path) objects.
- Added `payload_as_text`, `payload_as_bytes` and `payload_decoded`
[#74](https://github.com/hynek/pem/pull/74)


## [21.2.0](https://github.com/hynek/pem/compare/21.1.0...21.2.0) - 2021-04-07
Expand Down
2 changes: 1 addition & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ The following objects can be returned by the parsing functions.
Their shared provided API is minimal:

.. autoclass:: AbstractPEMObject
:members: __str__, as_bytes, as_text, sha1_hexdigest
:members: __str__, as_bytes, as_text, sha1_hexdigest, payload_as_bytes, payload_as_text, payload_decoded


Twisted
Expand Down
47 changes: 40 additions & 7 deletions src/pem/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import re

from abc import ABCMeta
from base64 import b64decode
from pathlib import Path


Expand All @@ -21,13 +22,19 @@ class AbstractPEMObject(metaclass=ABCMeta):
"""

_pem_bytes: bytes
_pem_payload: bytes
_sha1_hexdigest: str | None

def __init__(self, pem_bytes: bytes | str):
if isinstance(pem_bytes, str):
self._pem_bytes = pem_bytes.encode("ascii")
else:
self._pem_bytes = pem_bytes
def __init__(self, pem_bytes: bytes | str, pem_data: bytes | str):
self._pem_bytes = (
pem_bytes.encode("ascii")
if isinstance(pem_bytes, str)
else pem_bytes
)
self._pem_payload = (
pem_data.encode("ascii") if isinstance(pem_data, str) else pem_data
)

self._sha1_hexdigest = None

def __str__(self) -> str:
Expand Down Expand Up @@ -75,6 +82,30 @@ def as_text(self) -> str:
"""
return self._pem_bytes.decode("utf-8")

def payload_as_bytes(self) -> bytes:
"""
Return the payload of the PEM-encoded content as :obj:`bytes`.

.. versionadded:: 23.1.0
"""
return self._pem_payload

def payload_as_text(self) -> str:
"""
Return the payload of the PEM-encoded content as Unicode text.

.. versionadded:: 23.1.0
"""
return self._pem_payload.decode("utf-8")

def payload_decoded(self) -> bytes:
"""
Return the decoded payload of the PEM-encoded content as :obj:`bytes`.

.. versionadded:: 23.1.0
"""
return b64decode(self._pem_payload)

def __eq__(self, other: object) -> bool:
if not isinstance(other, type(self)):
return NotImplemented
Expand Down Expand Up @@ -252,7 +283,7 @@ class OpenPGPPrivateKey(PrivateKey):
b"----[- ]BEGIN ("
+ b"|".join(_PEM_TO_CLASS.keys())
+ b""")[- ]----\r?
.+?\r?
(?P<data>.+?)\r?
----[- ]END \\1[- ]----\r?\n?""",
re.DOTALL,
)
Expand All @@ -266,7 +297,9 @@ def parse(pem_str: bytes) -> list[AbstractPEMObject]:
:return: list of :ref:`pem-objects`
"""
return [
_PEM_TO_CLASS[match.group(1)](match.group(0))
_PEM_TO_CLASS[match.group(1)](
match.group(0), b"".join(match.group("data").splitlines())
)
for match in _PEM_RE.finditer(pem_str)
]

Expand Down
10 changes: 10 additions & 0 deletions tests/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,16 @@
-----END RSA PRIVATE KEY-----
"""

KEY_PEM_PKCS5_UNENCRYPTED_PAYLOAD = (
b"MIIBOwIBAAJBAKX6cRhPHvdyoftEHGiRje3tTLRDnddg01AvgsJJcCFoIjwdgfa9"
b"aKFdzCcgD/htjvfRZl24M7E89sMUBMNHk8ECAwEAAQJABcBi8OO1AAAh6tIWZe09"
b"TNRfRxPcwVzilbG/xznCP/YMf72E8hsZazu+HGMKITg9dFeJOyjXZ4e8sD/pL/I6"
b"0QIhANzULu4JjJxpoTK8NnF/CemF7neLROA18NDB/mao5ZZtAiEAwGnYobinxuHS"
b"UQh8cT3w7aLsVlarZmCtoapxjW+ObiUCIQCcAltVV/G63vU/PrDH5hQ+opwiYIW8"
b"UN9c3HC6XkA00QIhAJ8YpfwKgAfNfyZrmuHTspv7Q+mb3jtXoxnyodOtsxpVAiBC"
b"a4FDqkr+bDwV4SwaGdG/AC40fR3P8hhOADAhtFDwlw=="
)

# PKCS#5 RSA encrypted with `test` as password.
# Generated with:
# openssl genrsa -des3 -out private.pem 512
Expand Down
Loading