1# -*- coding: utf-8 -*-
2"""Encoding and base64 utilities for acme2certifier"""
3
4import base64
5import textwrap
6import logging
7
8
9def b64decode_pad(logger: logging.Logger, string: str) -> bytes:
10 """b64 decoding and padding of missing "=" """
11 logger.debug("Helper.b64decode_pad()")
12 try:
13 b64dec = base64.urlsafe_b64decode(string + "=" * (4 - len(string) % 4))
14 except Exception:
15 b64dec = b"ERR: b64 decoding error"
16 return b64dec.decode("utf-8")
17
18
19def b64_decode(logger: logging.Logger, string: str) -> str:
20 """b64 decoding"""
21 logger.debug("Helper.b64decode()")
22 return convert_byte_to_string(base64.b64decode(string))
23
24
25def b64_encode(logger: logging.Logger, string: str) -> str:
26 """encode a bytestream in base64"""
27 logger.debug("Helper.b64_encode()")
28 return convert_byte_to_string(base64.b64encode(string))
29
30
31def b64_url_encode(logger: logging.Logger, string: str) -> str:
32 """encode a bytestream in base64 url and remove padding"""
33 logger.debug("Helper.b64_url_encode()")
34 string = convert_string_to_byte(string)
35 encoded = base64.urlsafe_b64encode(string)
36 return encoded.rstrip(b"=")
37
38
39def b64_url_recode(logger: logging.Logger, string: str) -> str:
40 """recode base64_url to base64"""
41 logger.debug("Helper.b64_url_recode()")
42 padding_factor = (4 - len(string) % 4) % 4
43 string = convert_byte_to_string(string)
44 string += "=" * padding_factor
45 result = str(string).translate(dict(zip(map(ord, "-_"), "+/")))
46 return result
47
48
49def b64_url_decode(logger: logging.Logger, string: str) -> str:
50 """decode base64url encoded string"""
51 logger.debug("Helper.b64_url_decode()")
52 # Remove whitespace
53 string = string.strip()
54 # Add padding if missing
55 pad = "=" * (-len(string) % 4)
56 string_padded = string + pad
57 return convert_byte_to_string(base64.urlsafe_b64decode(string_padded))
58
59
60def build_pem_file(logger: logging.Logger, existing, certificate, wrap, csr=False):
61 """construct pem_file"""
62 logger.debug("Helper.build_pem_file()")
63 if csr:
64 pem_file = f"-----BEGIN CERTIFICATE REQUEST-----\n{textwrap.fill(convert_byte_to_string(certificate), 64)}\n-----END CERTIFICATE REQUEST-----\n"
65 else:
66 if existing:
67 if wrap:
68 pem_file = f"{existing}-----BEGIN CERTIFICATE-----\n{textwrap.fill(convert_byte_to_string(certificate), 64)}\n-----END CERTIFICATE-----\n"
69 else:
70 pem_file = f"{convert_byte_to_string(existing)}-----BEGIN CERTIFICATE-----\n{convert_byte_to_string(certificate)}\n-----END CERTIFICATE-----\n"
71 else:
72 if wrap:
73 pem_file = f"-----BEGIN CERTIFICATE-----\n{textwrap.fill(convert_byte_to_string(certificate), 64)}\n-----END CERTIFICATE-----\n"
74 else:
75 pem_file = f"-----BEGIN CERTIFICATE-----\n{convert_byte_to_string(certificate)}\n-----END CERTIFICATE-----\n"
76 return pem_file
77
78
79def convert_byte_to_string(value: bytes) -> str:
80 """convert a variable to string if needed"""
81 if hasattr(value, "decode"):
82 try:
83 return value.decode()
84 except Exception:
85 return value
86 else:
87 return value
88
89
90def convert_string_to_byte(value: str) -> bytes:
91 """convert a variable to byte if needed"""
92 if hasattr(value, "encode"):
93 result = value.encode()
94 else:
95 result = value
96 return result